Merge pull request #376 from Rsl1122/4.0.3

Pull Request for 4.0.3
This commit is contained in:
Rsl1122 2017-10-29 13:21:23 +02:00 committed by GitHub
commit fefe7e0824
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 548 additions and 279 deletions

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.djrapitops</groupId>
<artifactId>Plan</artifactId>
<version>4.0.0</version>
<version>4.0.3</version>
<packaging>jar</packaging>
<repositories>
<repository>
@ -70,7 +70,7 @@
<dependency>
<groupId>com.djrapitops</groupId>
<artifactId>PlanPluginBridge</artifactId>
<version>4.0.0</version>
<version>4.0.3</version>
<scope>compile</scope>
</dependency>
<!-- Testing -->

View File

@ -10,7 +10,7 @@ import com.djrapitops.plugin.settings.ColorScheme;
import com.djrapitops.plugin.task.AbsRunnable;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.api.exceptions.DatabaseInitException;
import main.java.com.djrapitops.plan.command.commands.ReloadCommand;
import main.java.com.djrapitops.plan.command.PlanBungeeCommand;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.databases.MySQLDB;
import main.java.com.djrapitops.plan.locale.Locale;
@ -27,7 +27,7 @@ import main.java.com.djrapitops.plan.utilities.Benchmark;
import net.md_5.bungee.api.ChatColor;
import java.io.InputStream;
import java.util.List;
import java.sql.SQLException;
import java.util.UUID;
/**
@ -66,10 +66,10 @@ public class PlanBungee extends BungeePlugin<PlanBungee> implements IPlan {
Log.info(Locale.get(Msg.ENABLE_DB_INIT).toString());
initDatabase();
registerCommand(new ReloadCommand(this));
registerCommand(new PlanBungeeCommand(this));
String ip = variableHolder.getIp();
if ("0.0.0.0" .equals(ip)) {
if ("0.0.0.0".equals(ip)) {
Log.error("IP setting still 0.0.0.0 - Configure AlternativeIP/IP that connects to the Proxy server.");
Log.info("Player Analytics partially enabled (Use /planbungee to reload config)");
return;
@ -98,6 +98,12 @@ public class PlanBungee extends BungeePlugin<PlanBungee> implements IPlan {
}).runTaskAsynchronously();
getRunnableFactory().createNew("Player Count task", new TPSCountTimer(this))
.runTaskTimerAsynchronously(1000, TimeAmount.SECOND.ticks());
getRunnableFactory().createNew("NetworkPageContentUpdateTask", new AbsRunnable("NetworkPageContentUpdateTask") {
@Override
public void run() {
infoManager.updateNetworkPageContent();
}
}).runTaskTimerAsynchronously(1500, TimeAmount.MINUTE.ticks());
// getProxy().registerChannel("Plan");
// registerListener(new BungeePluginChannelListener(this));
@ -122,10 +128,20 @@ public class PlanBungee extends BungeePlugin<PlanBungee> implements IPlan {
@Override
public void onDisable() {
if (processingQueue != null) {
List<Processor> processors = processingQueue.stopAndReturnLeftovers();
Log.info("Processing unprocessed processors. (" + processors.size() + ")");
for (Processor processor : processors) {
processor.process();
try {
processingQueue.stop();
} catch (IllegalArgumentException ignored) {
/*ignored*/
}
}
if (webServer != null) {
webServer.stop();
}
if (db != null) {
try {
db.close();
} catch (SQLException e) {
Log.toLog(this.getClass().getName(), e);
}
}
Log.info(Locale.get(Msg.DISABLED).toString());

View File

@ -26,6 +26,7 @@ public enum Settings {
WRITE_NEW_LOCALE("Plugin.WriteNewLocaleFileOnStart"),
DEV_MODE("Plugin.Dev"),
USE_SERVER_TIME("Customization.UseServerTime"),
DISPLAY_SESSIONS_AS_TABLE("Customization.Display.SessionsAsTable"),
// Integer
WEBSERVER_PORT("WebServer.Port"),

View File

@ -27,14 +27,14 @@ import java.util.UUID;
* @author Rsl1122
* @see PluginData
* @see AnalysisType
* @since 2.0.0
* @since 4.0.0
*/
public class API {
private final Plan plugin;
/**
* Class Constructor.
* Creates a new API instance - not supposed to be called outside {@code Plan.onEnable}.
*
* @param plugin Current instance of Plan
*/
@ -78,7 +78,7 @@ public class API {
* {@code <a href="Link">PlayerName</a>}
*
* @param name Name of the player
* @return ./player/PlayerName
* @return {@code ../player/PlayerName}
*/
public String getPlayerInspectPageLink(String name) {
String link = "../player/" + name;
@ -86,7 +86,7 @@ public class API {
}
/**
* Check if Players's Inspect page is cached to pagecache.
* Check if Players's Inspect page is cached to PageCache.
*
* @param uuid UUID of the player.
* @return true/false
@ -97,12 +97,21 @@ public class API {
return isPlayerHtmlCached(uuid);
}
/**
* Check if Players's Inspect page is cached to PageCache of the providing WebServer.
* <p>
* Using BungeeCord: Will send a {@code IsCachedWebAPI} request to check if the page is in Bungee's PageCache.
* Only Bukkit: Checks PageCache for page.
*
* @param uuid UUID of the player.
* @return true/false
*/
public boolean isPlayerHtmlCached(UUID uuid) {
return plugin.getInfoManager().isCached(uuid);
}
/**
* Cache Players's Inspect page to the PageCache of the WebServer.
* Cache Players's Inspect page to the PageCache of the providing WebServer.
*
* @param uuid UUID of the player.
* @deprecated use {@code cachePlayerHtml}
@ -113,9 +122,13 @@ public class API {
}
/**
* Cache Players's Inspect page to the PageCache of the WebServer.
* Cache Players's Inspect page to the PageCache of the providing WebServer.
* <p>
* Using BungeeCord: Will send a {@code PostHtmlWebAPI} request after calculating the inspect page.
* Only Bukkit: Calculates inspect page and places it in the PageCache.
*
* @param uuid UUID of the player.
* @deprecated use {@code cachePlayerHtml}
*/
public void cachePlayerHtml(UUID uuid) {
plugin.getInfoManager().cachePlayer(uuid);
@ -124,7 +137,7 @@ public class API {
/**
* Used to get the full Html of the Inspect page as a string.
* <p>
* Check if the data is cached to InspectCache before calling this.
* Re-calculates the inspect html on this server.
*
* @param uuid UUID of the player.
* @return player.html with all placeholders replaced.

View File

@ -5,7 +5,7 @@
package main.java.com.djrapitops.plan.api.exceptions;
/**
* Thrown when something goes wrong with creating tables with Table#createTable.
* Thrown when something goes wrong with creating tables with {@code Table#createTable}.
*
* @author Rsl1122
*/

View File

@ -5,7 +5,7 @@
package main.java.com.djrapitops.plan.api.exceptions;
/**
* Thrown when something goes wrong in the database, generic exception.
* Thrown when something goes wrong with the Database, generic exception.
*
* @author Rsl1122
*/

View File

@ -5,7 +5,7 @@
package main.java.com.djrapitops.plan.api.exceptions;
/**
* Thrown when something goes wrong with Database#init.
* Thrown when something goes wrong with {@code Database#init}.
*
* @author Rsl1122
*/

View File

@ -5,7 +5,7 @@
package main.java.com.djrapitops.plan.api.exceptions;
/**
* Exception thrown when Html page parsing fails.
* Exception thrown when PageParser encounters an Exception.
*
* @author Rsl1122
*/

View File

@ -5,7 +5,7 @@
package main.java.com.djrapitops.plan.api.exceptions;
/**
* Thrown when WebAPI fails to connect.
* Thrown when WebAPI fails to connect to an address.
*
* @author Rsl1122
*/

View File

@ -5,7 +5,7 @@
package main.java.com.djrapitops.plan.api.exceptions;
/**
* Thrown when web api post request fails.
* Thrown when WebAPI POST-request fails, general Exception.
*
* @author Rsl1122
*/

View File

@ -0,0 +1,50 @@
package main.java.com.djrapitops.plan.command;
import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.TreeCommand;
import com.djrapitops.plugin.command.defaultcmds.StatusCommand;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.PlanBungee;
import main.java.com.djrapitops.plan.command.commands.*;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
/**
* TreeCommand for the /plan command, and all subcommands.
* <p>
* Uses the Abstract Plugin Framework for easier command management.
*
* @author Rsl1122
* @since 1.0.0
*/
public class PlanBungeeCommand extends TreeCommand<PlanBungee> {
/**
* CommandExecutor class Constructor.
* <p>
* Initializes Subcommands
*
* @param plugin Current instance of Plan
*/
public PlanBungeeCommand(PlanBungee plugin) {
super(plugin, "planbungee", CommandType.CONSOLE, "", "", "planbungee");
super.setDefaultCommand("help");
}
@Override
public String[] addHelp() {
return Locale.get(Msg.CMD_HELP_PLAN).toArray();
}
@Override
public void addCommands() {
commands.add(new ReloadCommand(plugin));
commands.add(new StatusCommand<>(plugin, Permissions.MANAGE.getPermission()));
commands.add(new ListCommand());
RegisterCommand registerCommand = new RegisterCommand(plugin);
commands.add(registerCommand);
commands.add(new WebUserCommand(plugin, registerCommand));
commands.add(new NetworkCommand(plugin));
commands.add(new ListServersCommand(plugin));
}
}

View File

@ -5,9 +5,9 @@ import com.djrapitops.plugin.command.CommandUtils;
import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
/**
* Command used to display link to the player list webpage.
@ -43,7 +43,7 @@ public class ListCommand extends SubCommand {
sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).parse());
// Link
String url = Plan.getInstance().getInfoManager().getLinkTo("/players");
String url = MiscUtils.getIPlan().getInfoManager().getLinkTo("/players/");
String message = Locale.get(Msg.CMD_INFO_LINK).toString();
boolean console = !CommandUtils.isPlayer(sender);
if (console) {

View File

@ -6,7 +6,6 @@ import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.settings.ColorScheme;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
@ -29,11 +28,11 @@ public class ListServersCommand extends SubCommand {
*
* @param plugin Current instance of Plan
*/
public ListServersCommand(Plan plugin) {
public ListServersCommand(IPlan plugin) {
super("servers, serverlist, listservers, sl",
CommandType.CONSOLE,
Permissions.MANAGE.getPermission(),
Locale.get(Msg.CMD_USG_RELOAD).toString());
"List servers in the network");
this.plugin = plugin;
}

View File

@ -5,7 +5,7 @@ import com.djrapitops.plugin.command.CommandUtils;
import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
@ -19,22 +19,21 @@ import main.java.com.djrapitops.plan.locale.Msg;
*/
public class NetworkCommand extends SubCommand {
private final Plan plugin;
private final IPlan plugin;
/**
* Class Constructor.
*/
public NetworkCommand(Plan plugin) {
super("network, n, netw", CommandType.CONSOLE, Permissions.ANALYZE.getPermission(), Locale.get(Msg.CMD_USG_LIST).toString(), "");
public NetworkCommand(IPlan plugin) {
super("network, n, netw",
CommandType.CONSOLE,
Permissions.ANALYZE.getPermission(),
"Get the link to the network page");
this.plugin = plugin;
}
@Override
public boolean onCommand(ISender sender, String commandLabel, String[] args) {
if (plugin.getInfoManager().isUsingAnotherWebServer()) {
sender.sendMessage("§cNot using Bungee WebServer!");
return true;
}
sendNetworkMsg(sender);
return true;
}
@ -43,7 +42,7 @@ public class NetworkCommand extends SubCommand {
sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).parse());
// Link
String url = Plan.getInstance().getInfoManager().getLinkTo("/network");
String url = plugin.getInfoManager().getLinkTo("/network/");
String message = Locale.get(Msg.CMD_INFO_LINK).toString();
boolean console = !CommandUtils.isPlayer(sender);
if (console) {

View File

@ -5,17 +5,16 @@ import com.djrapitops.plugin.command.CommandUtils;
import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.utilities.Compatibility;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.data.WebUser;
import main.java.com.djrapitops.plan.database.tables.SecurityTable;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.utilities.Check;
import main.java.com.djrapitops.plan.utilities.PassEncryptUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;
/**
* Command for registering web users.
@ -31,16 +30,18 @@ import org.apache.logging.log4j.core.Logger;
*/
public class RegisterCommand extends SubCommand {
private final Plan plugin;
private final IPlan plugin;
public RegisterCommand(Plan plugin) {
public RegisterCommand(IPlan plugin) {
super("register",
CommandType.CONSOLE_WITH_ARGUMENTS,
"", // No Permission Requirement
Locale.get(Msg.CMD_USG_WEB_REGISTER).toString(),
"<password> [name] [access lvl]");
this.plugin = plugin;
setupFilter();
if (Compatibility.isBukkitAvailable()) {
setupFilter();
}
}
@Override
@ -140,7 +141,6 @@ public class RegisterCommand extends SubCommand {
* Setups the command console output filter
*/
private void setupFilter() {
Logger logger = (Logger) LogManager.getRootLogger();
logger.addFilter(new RegisterCommandFilter());
new RegisterCommandFilter().registerFilter();
}
}

View File

@ -2,6 +2,7 @@ package main.java.com.djrapitops.plan.command.commands;
import com.google.common.collect.ImmutableSet;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
@ -20,6 +21,11 @@ public class RegisterCommandFilter extends AbstractFilter {
private final Set<String> censoredCommands = ImmutableSet.of("/plan web register", "/plan webuser register", "/plan register");
public void registerFilter() {
Logger logger = (Logger) LogManager.getRootLogger();
logger.addFilter(this);
}
@Override
public Result filter(LogEvent event) {
if (event == null) {

View File

@ -4,8 +4,6 @@ import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.PlanBungee;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
@ -25,7 +23,7 @@ public class ReloadCommand extends SubCommand {
*
* @param plugin Current instance of Plan
*/
public ReloadCommand(Plan plugin) {
public ReloadCommand(IPlan plugin) {
super("reload",
CommandType.CONSOLE,
Permissions.MANAGE.getPermission(),
@ -34,15 +32,6 @@ public class ReloadCommand extends SubCommand {
this.plugin = plugin;
}
public ReloadCommand(PlanBungee plugin) {
super("planbungee",
CommandType.CONSOLE,
Permissions.MANAGE.getPermission(),
Locale.get(Msg.CMD_USG_RELOAD).toString());
this.plugin = plugin;
}
@Override
public boolean onCommand(ISender sender, String commandLabel, String[] args) {
plugin.restart();

View File

@ -3,7 +3,7 @@ package main.java.com.djrapitops.plan.command.commands;
import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.TreeCommand;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.command.commands.webuser.WebCheckCommand;
import main.java.com.djrapitops.plan.command.commands.webuser.WebDeleteCommand;
import main.java.com.djrapitops.plan.command.commands.webuser.WebLevelCommand;
@ -17,9 +17,9 @@ import main.java.com.djrapitops.plan.locale.Msg;
* @author Rsl1122
* @since 3.5.2
*/
public class WebUserCommand extends TreeCommand<Plan> {
public class WebUserCommand extends TreeCommand<IPlan> {
public WebUserCommand(Plan plugin, RegisterCommand register) {
public WebUserCommand(IPlan plugin, RegisterCommand register) {
super(plugin, "webuser, web",
CommandType.CONSOLE,
Permissions.MANAGE_WEB.getPerm(),

View File

@ -55,6 +55,10 @@ public class ManageSetupCommand extends SubCommand {
return true;
}
String address = args[0].toLowerCase();
if (!address.startsWith("http")) {
sender.sendMessage("§cMake sure you're using the full address (Starts with http:// or https://) - Check Bungee enable log for the full address.");
return true;
}
if (address.endsWith("/")) {
address = address.substring(0, address.length() - 1);
}

View File

@ -6,7 +6,7 @@ import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.data.WebUser;
import main.java.com.djrapitops.plan.database.tables.SecurityTable;
import main.java.com.djrapitops.plan.locale.Locale;
@ -22,9 +22,9 @@ import org.bukkit.ChatColor;
*/
public class WebCheckCommand extends SubCommand {
private final Plan plugin;
private final IPlan plugin;
public WebCheckCommand(Plan plugin) {
public WebCheckCommand(IPlan plugin) {
super("check",
CommandType.CONSOLE_WITH_ARGUMENTS,
Permissions.MANAGE_WEB.getPerm(),

View File

@ -6,7 +6,7 @@ import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.database.tables.SecurityTable;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
@ -21,9 +21,9 @@ import net.md_5.bungee.api.ChatColor;
*/
public class WebDeleteCommand extends SubCommand {
private final Plan plugin;
private final IPlan plugin;
public WebDeleteCommand(Plan plugin) {
public WebDeleteCommand(IPlan plugin) {
super("delete, remove",
CommandType.CONSOLE_WITH_ARGUMENTS,
Permissions.MANAGE_WEB.getPerm(),

View File

@ -5,7 +5,7 @@ import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.settings.ColorScheme;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
@ -17,9 +17,9 @@ import main.java.com.djrapitops.plan.locale.Msg;
*/
public class WebLevelCommand extends SubCommand {
private final Plan plugin;
private final IPlan plugin;
public WebLevelCommand(Plan plugin) {
public WebLevelCommand(IPlan plugin) {
super("level",
CommandType.CONSOLE,
Permissions.MANAGE_WEB.getPerm(),

View File

@ -7,7 +7,7 @@ import com.djrapitops.plugin.settings.ColorScheme;
import com.djrapitops.plugin.task.AbsRunnable;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.data.WebUser;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
@ -23,9 +23,9 @@ import java.util.List;
*/
public class WebListUsersCommand extends SubCommand {
private final Plan plugin;
private final IPlan plugin;
public WebListUsersCommand(Plan plugin) {
public WebListUsersCommand(IPlan plugin) {
super("list", CommandType.CONSOLE, Permissions.MANAGE_WEB.getPerm(), "List registered web users & permission levels.");
this.plugin = plugin;
}

View File

@ -1,6 +1,5 @@
package main.java.com.djrapitops.plan.data;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.data.analysis.*;
import main.java.com.djrapitops.plan.utilities.Benchmark;
@ -38,7 +37,6 @@ public class AnalysisData extends RawData {
private final TPSPart tpsPart;
private final WorldPart worldPart;
private long refreshDate;
private String planVersion;
private String pluginsTabLayout;
private Map<String, Serializable> additionalDataReplaceMap;
private String playersTable;
@ -97,26 +95,10 @@ public class AnalysisData extends RawData {
worldPart);
}
public String getPlanVersion() {
return planVersion;
}
public void setPlanVersion(String planVersion) {
this.planVersion = planVersion;
}
public String getPluginsTabLayout() {
return pluginsTabLayout;
}
public void setPluginsTabLayout(String pluginsTabLayout) {
this.pluginsTabLayout = pluginsTabLayout;
}
public Map<String, Serializable> getAdditionalDataReplaceMap() {
return additionalDataReplaceMap;
}
public void setAdditionalDataReplaceMap(Map<String, Serializable> additionalDataReplaceMap) {
this.additionalDataReplaceMap = additionalDataReplaceMap;
}
@ -127,12 +109,15 @@ public class AnalysisData extends RawData {
@Override
protected void analyse() {
Verify.nullCheck(playersTable);
Verify.nullCheck(pluginsTabLayout);
Verify.nullCheck(planVersion);
if (playersTable == null) {
playersTable = "";
}
if (pluginsTabLayout == null) {
pluginsTabLayout = "";
}
addValue("tableBodyPlayerList", playersTable);
addValue("version", planVersion);
addValue("version", MiscUtils.getIPlan().getVersion());
final List<RawData> parts = getAllParts();
parts.forEach(part -> {
@ -157,8 +142,4 @@ public class AnalysisData extends RawData {
public long getRefreshDate() {
return refreshDate;
}
public void setRefreshDate(long refreshDate) {
this.refreshDate = refreshDate;
}
}

View File

@ -27,6 +27,7 @@ public class UserInfo {
this.registered = registered;
this.opped = opped;
this.banned = banned;
lastSeen = 0L;
}
public UUID getUuid() {

View File

@ -5,6 +5,7 @@ import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import main.java.com.djrapitops.plan.utilities.html.structure.SessionTabStructureCreator;
import main.java.com.djrapitops.plan.utilities.html.tables.SessionsTableCreator;
import java.util.*;
@ -61,7 +62,10 @@ public class JoinInfoPart extends RawData {
}
private void sessionTables() {
String[] tables = SessionsTableCreator.createTables(this);
String[] tables = SessionsTableCreator.createTable(this);
String[] sessionContent = SessionTabStructureCreator.creteStructure(this);
addValue("contentSessions", sessionContent[0]);
addValue("sessionTabGraphViewFunctions", sessionContent[1]);
addValue("tableBodySessions", tables[0]);
addValue("tableBodyRecentLogins", tables[1]);
}

View File

@ -109,7 +109,7 @@ public abstract class SQLDB extends Database {
if (newDatabase) {
Log.info("New Database created.");
setVersion(11);
setVersion(12);
}
int version = getVersion();
@ -131,6 +131,11 @@ public abstract class SQLDB extends Database {
serverTable.alterTableV11();
setVersion(11);
}
if (version < 12) {
actionsTable.alterTableV12();
ipsTable.alterTableV12();
setVersion(12);
}
} catch (SQLException e) {
throw new DatabaseInitException("Failed to set-up Database", e);
}

View File

@ -68,12 +68,18 @@ public class ActionsTable extends UserIDTable {
.column(columnServerID, Sql.INT).notNull()
.column(columnDate, Sql.LONG).notNull()
.column(columnActionID, Sql.INT).notNull()
.column(columnAdditionalInfo, Sql.varchar(100))
.column(columnAdditionalInfo, Sql.varchar(300))
.foreignKey(columnUserID, usersTable.toString(), usersTable.getColumnID())
.foreignKey(columnServerID, serverTable.toString(), serverTable.getColumnID())
.toString());
}
public void alterTableV12() throws SQLException {
if (usingMySQL) {
executeUnsafe("ALTER TABLE " + tableName + " MODIFY " + columnAdditionalInfo + " VARCHAR(300)");
}
}
public void insertAction(UUID uuid, Action action) throws SQLException {
execute(new ExecStatement(insertStatement) {
@Override

View File

@ -43,13 +43,19 @@ public class IPsTable extends UserIDTable {
public void createTable() throws DBCreateTableException {
createTable(TableSqlParser.createTable(tableName)
.column(columnUserID, Sql.INT).notNull()
.column(columnIP, Sql.varchar(20)).notNull()
.column(columnIP, Sql.varchar(39)).notNull()
.column(columnGeolocation, Sql.varchar(50)).notNull()
.foreignKey(columnUserID, usersTable.getTableName(), usersTable.getColumnID())
.toString()
);
}
public void alterTableV12() throws SQLException {
if (usingMySQL) {
executeUnsafe("ALTER TABLE " + tableName + " MODIFY " + columnIP + " VARCHAR(39) NOT NULL");
}
}
/**
* @param uuid UUID of the user.
* @return Users's Login Geolocations.

View File

@ -130,7 +130,7 @@ public class BukkitInformationManager extends InformationManager {
HookHandler hookHandler = plugin.getHookHandler();
List<PluginData> plugins = hookHandler.getAdditionalDataSources();
Map<String, Serializable> replaceMap = hookHandler.getAdditionalInspectReplaceRules(uuid);
String contents = HtmlStructure.createInspectPageTabContent(serverName, plugins, replaceMap);
String contents = HtmlStructure.createInspectPluginsTabContent(serverName, plugins, replaceMap);
cacheInspectPluginsTab(uuid, contents);
}
}

View File

@ -15,16 +15,14 @@ import main.java.com.djrapitops.plan.systems.info.parsing.NetworkPageParser;
import main.java.com.djrapitops.plan.systems.info.server.BungeeServerInfoManager;
import main.java.com.djrapitops.plan.systems.info.server.ServerInfo;
import main.java.com.djrapitops.plan.systems.webserver.PageCache;
import main.java.com.djrapitops.plan.systems.webserver.response.InspectPageResponse;
import main.java.com.djrapitops.plan.systems.webserver.response.InternalErrorResponse;
import main.java.com.djrapitops.plan.systems.webserver.response.NotFoundResponse;
import main.java.com.djrapitops.plan.systems.webserver.response.Response;
import main.java.com.djrapitops.plan.systems.webserver.response.*;
import main.java.com.djrapitops.plan.systems.webserver.webapi.WebAPIManager;
import main.java.com.djrapitops.plan.systems.webserver.webapi.bukkit.AnalysisReadyWebAPI;
import main.java.com.djrapitops.plan.systems.webserver.webapi.bukkit.AnalyzeWebAPI;
import main.java.com.djrapitops.plan.systems.webserver.webapi.bukkit.InspectWebAPI;
import main.java.com.djrapitops.plan.systems.webserver.webapi.bukkit.IsOnlineWebAPI;
import main.java.com.djrapitops.plan.systems.webserver.webapi.bungee.RequestPluginsTabWebAPI;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.html.HtmlStructure;
import java.sql.SQLException;
@ -158,7 +156,14 @@ public class BungeeInformationManager extends InformationManager {
*/
private ServerInfo getInspectRequestProcessorServer(UUID uuid) {
if (bukkitServers.isEmpty()) {
throw new IllegalStateException("No Bukkit Servers.");
try {
refreshBukkitServerMap();
} catch (SQLException e) {
Log.toLog(this.getClass().getName(), e);
}
if (bukkitServers.isEmpty()) {
throw new IllegalStateException("No Bukkit Servers.");
}
}
Collection<ServerInfo> onlineServers = serverInfoManager.getOnlineBukkitServers();
@ -319,6 +324,7 @@ public class BungeeInformationManager extends InformationManager {
public void cacheNetworkPageContent(UUID serverUUID, String html) {
networkPageContent.put(serverUUID, html);
updateNetworkPageContent();
}
public void removeNetworkPageContent(UUID serverUUID) {
@ -348,9 +354,7 @@ public class BungeeInformationManager extends InformationManager {
@Override
public void updateNetworkPageContent() {
Collection<ServerInfo> online = serverInfoManager.getOnlineBukkitServers();
online.stream().map(ServerInfo::getUuid)
.forEach(this::removeNetworkPageContent);
PageCache.cachePage("analysisPage:" + MiscUtils.getIPlan().getServerUuid(), () -> new AnalysisPageResponse(this));
}
public void sendConfigSettings() {

View File

@ -13,6 +13,8 @@ import main.java.com.djrapitops.plan.data.Action;
import main.java.com.djrapitops.plan.data.PlayerKill;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.UserInfo;
import main.java.com.djrapitops.plan.data.time.GMTimes;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.tables.SessionsTable;
import main.java.com.djrapitops.plan.database.tables.UsersTable;
@ -98,10 +100,10 @@ public class InspectPageParser extends PageParser {
Map<String, List<Session>> sessions = sessionsTable.getSessions(uuid);
List<Session> allSessions = sessions.values().stream()
.flatMap(Collection::stream)
.sorted(new SessionStartComparator())
.sorted(new SessionStartComparator()) // Sorted Newest first.
.collect(Collectors.toList());
String[] sessionsTabContent = HtmlStructure.createSessionsTabContent(sessions, allSessions);
String[] sessionsTabContent = HtmlStructure.createSessionsTabContentInspectPage(sessions, allSessions, uuid);
addValue("contentSessions", sessionsTabContent[0]);
addValue("sessionTabGraphViewFunctions", sessionsTabContent[1]);
addValue("contentServerOverview", HtmlStructure.createServerOverviewColumn(sessions));
@ -154,7 +156,18 @@ public class InspectPageParser extends PageParser {
addValue("playtimeTotal", FormatUtils.formatTimeAmount(playTime));
String punchCardData = PunchCardGraphCreator.createDataSeries(allSessions);
String[] worldPieData = WorldPieCreator.createSeriesData(db.getWorldTimesTable().getWorldTimesOfUser(uuid));
WorldTimes worldTimes = db.getWorldTimesTable().getWorldTimesOfUser(uuid);
// Add 0 time for worlds not present.
Set<String> nonZeroWorlds = worldTimes.getWorldTimes().keySet();
for (String world : db.getWorldTable().getWorlds()) {
if (nonZeroWorlds.contains(world)) {
continue;
}
worldTimes.setGMTimesForWorld(world, new GMTimes());
}
String[] worldPieData = WorldPieCreator.createSeriesData(worldTimes);
addValue("worldPieSeries", worldPieData[0]);
addValue("gmSeries", worldPieData[1]);

View File

@ -48,7 +48,6 @@ public class NetworkPageParser extends PageParser {
addValue("playersOnlineSeries", PlayerActivityGraphCreator.buildSeriesDataString(networkOnlineData));
addValue("playersGraphColor", Colors.PLAYERS_ONLINE.getColor());
addValue("playersOnline", plugin.getProxy().getOnlineCount());
addValue("playersMax", plugin.getProxy().getConfig().getPlayerLimit());
addValue("playersTotal", db.getUsersTable().getPlayerCount());

View File

@ -97,7 +97,7 @@ public class BukkitServerInfoManager {
}
private UUID generateNewUUID(ServerVariableHolder variableHolder) {
String seed = variableHolder.getName() + variableHolder.getIp() + variableHolder.getPort() + variableHolder.getVersion() + variableHolder.getImplVersion();
String seed = plugin.getServer().getServerId() + variableHolder.getName() + variableHolder.getIp() + variableHolder.getPort() + variableHolder.getVersion() + variableHolder.getImplVersion();
return UUID.nameUUIDFromBytes(seed.getBytes());
}

View File

@ -129,6 +129,9 @@ public class BungeeServerInfoManager {
}
public void serverConnected(UUID serverUUID) {
if (plugin.getServerUuid().equals(serverUUID)) {
return;
}
Log.info("Received a connection from a Bukkit server..");
if (onlineServers.contains(serverUUID)) {
sendConfigSettings(serverUUID);

View File

@ -34,9 +34,7 @@ public class NewNickActionProcessor extends PlayerProcessor {
public void process() {
UUID uuid = getUUID();
String n = HtmlUtils.swapColorsToSpan(displayName);
String info = HtmlUtils.removeXSS(n);
String info = HtmlUtils.removeXSS(displayName);
Action action = new Action(MiscUtils.getTime(), Actions.NEW_NICKNAME, info);

View File

@ -49,12 +49,12 @@ public class RegisterProcessor extends PlayerProcessor {
if (!usersTable.isRegistered(uuid)) {
usersTable.registerUser(uuid, registered, name);
}
if (db.getActionsTable().getActions(uuid).size() > 0) {
return;
}
if (!userInfoTable.isRegistered(uuid)) {
userInfoTable.registerUserInfo(uuid, registered);
}
if (db.getActionsTable().getActions(uuid).size() > 0) {
return;
}
plugin.getDataCache().markFirstSession(uuid);
db.getActionsTable().insertAction(uuid, new Action(time, Actions.FIRST_SESSION, "Online: " + playersOnline + " Players"));
} catch (SQLException e) {

View File

@ -13,6 +13,7 @@ import main.java.com.djrapitops.plan.api.exceptions.WebAPIException;
import main.java.com.djrapitops.plan.systems.info.BukkitInformationManager;
import main.java.com.djrapitops.plan.systems.webserver.response.Response;
import main.java.com.djrapitops.plan.systems.webserver.webapi.WebAPI;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import java.io.IOException;
import java.util.Map;
@ -53,6 +54,7 @@ public class PingWebAPI extends WebAPI {
public void sendRequest(String address, String accessCode) throws WebAPIException {
addVariable("accessKey", accessCode);
addVariable("version", MiscUtils.getIPlan().getVersion());
sendRequest(address);
}
}

View File

@ -119,6 +119,11 @@ public class FormatUtils {
}
if (minutes != 0) {
String m = Settings.FORMAT_MINUTES.toString().replace("%minutes%", String.valueOf(minutes));
if (hours == 0 && m.contains("%hours%")) {
m = m.replace("%hours%", Settings.FORMAT_MINUTES.toString().replace("%zero%", "0") + "0");
} else {
m = m.replace("%hours", "");
}
if (m.contains("%zero%") && String.valueOf(minutes).length() == 1) {
builder.append('0');
}
@ -126,6 +131,11 @@ public class FormatUtils {
}
if (seconds != 0) {
String s = Settings.FORMAT_SECONDS.toString().replace("%seconds%", String.valueOf(seconds));
if (minutes == 0 && s.contains("%minutes%")) {
s = s.replace("%minutes%", Settings.FORMAT_MINUTES.toString().replace("%hours", "").replace("%zero%", "0") + 0);
} else {
s = s.replace("%minutes%", "");
}
if (s.contains("%zero%") && String.valueOf(seconds).length() == 1) {
builder.append('0');
}

View File

@ -11,6 +11,7 @@ import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.data.analysis.*;
import main.java.com.djrapitops.plan.data.time.GMTimes;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.tables.TPSTable;
@ -110,7 +111,6 @@ public class Analysis {
AnalysisData analysisData = new AnalysisData();
List<PluginData> thirdPartyPlugins = plugin.getHookHandler().getAdditionalDataSources();
analysisData.setPluginsTabLayout(HtmlStructure.createAnalysisPluginsTabLayout(thirdPartyPlugins));
analysisData.setPlanVersion(plugin.getVersion());
Benchmark.stop("Analysis", "Create Empty dataset");
fillDataset(analysisData, db);
@ -261,17 +261,12 @@ public class Analysis {
}
}
Map<UUID, UserInfo> mappedUserInfo = new HashMap<>();
userInfo.forEach(u -> mappedUserInfo.put(u.getUuid(), u));
Map<UUID, Long> lastSeen = db.getSessionsTable().getLastSeenForAllPlayers();
for (Map.Entry<UUID, Long> entry : lastSeen.entrySet()) {
UserInfo user = mappedUserInfo.get(entry.getKey());
if (user == null) {
continue;
}
user.setLastSeen(entry.getValue());
for (UserInfo info : userInfo) {
Long userLastSeen = lastSeen.getOrDefault(info.getUuid(), 0L);
info.setLastSeen(userLastSeen);
}
userInfo.sort(new UserInfoLastPlayedComparator());
activity.setRecentPlayersUUIDs(userInfo.stream().map(UserInfo::getUuid).collect(Collectors.toList()));
@ -279,7 +274,7 @@ public class Analysis {
playerCount.addPlayers(userInfo.stream().map(UserInfo::getUuid).collect(Collectors.toSet()));
Map<UUID, Long> registered = mappedUserInfo.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getRegistered()));
Map<UUID, Long> registered = userInfo.stream().collect(Collectors.toMap(UserInfo::getUuid, UserInfo::getRegistered));
joinInfo.addRegistered(registered);
activity.addBans(userInfo.stream().filter(UserInfo::isBanned).map(UserInfo::getUuid).collect(Collectors.toSet()));
@ -292,15 +287,25 @@ public class Analysis {
joinInfo.addSessions(sessions);
}
Map<UUID, List<String>> geolocations = db.getIpsTable().getAllGeolocations();
geolocPart.addGeoLocations(geolocations);
analysisData.setPlayersTable(PlayersTableCreator.createTable(userInfo, joinInfo, geolocPart));
Map<UUID, List<PlayerKill>> playerKills = db.getKillsTable().getPlayerKills();
killPart.addKills(playerKills);
Map<UUID, List<String>> geolocations = db.getIpsTable().getAllGeolocations();
geolocPart.addGeoLocations(geolocations);
WorldTimes worldTimes = db.getWorldTimesTable().getWorldTimesOfServer();
// Add 0 time for worlds not present.
Set<String> nonZeroWorlds = worldTimes.getWorldTimes().keySet();
for (String world : db.getWorldTable().getWorlds()) {
if (nonZeroWorlds.contains(world)) {
continue;
}
worldTimes.setGMTimesForWorld(world, new GMTimes());
}
worldPart.setWorldTimes(worldTimes);
playtime.setTotalPlaytime(db.getSessionsTable().getPlaytimeOfServer());

View File

@ -1,6 +1,5 @@
package main.java.com.djrapitops.plan.utilities.html;
import com.djrapitops.plugin.utilities.Verify;
import org.apache.commons.lang3.text.StrSubstitutor;
import java.io.Serializable;
@ -34,13 +33,27 @@ public enum Html {
BUTTON("<a class=\"button\" href=\"${0}\">${1}</a>"),
BUTTON_CLASS("class=\"button\""),
LINK("<a class=\"link\" href=\"${0}\">${1}</a>"),
LINK_TOOLTIP("<a title=\"${2}\" class=\"link\" href=\"${0}\">${1}</a>"),
LINK_EXTERNAL("<a class=\"link\" target=\"_blank\" href=\"${0}\">${1}</a>"),
LINK_CLASS("class=\"link\""),
IMG("<img src=\"${0}\">"),
//
PARAGRAPH("<p>${0}</p>"),
HEADER("<h1>${0}</h1>"),
HEADER_2("<h2>${0}</h2>"),
//
DIV_W_CLASS("<div class=\"${0}\">${1}</div>"),
DIV_W_CLASS_STYLE("<div class=\"${0}\" style=\"${1}\">${2}</div>"),
//
ROW(DIV_W_CLASS.parse("row", "${0}")),
//
TABLE_END("</tbody></table>"),
TABLE_START_2("<table class=\"sortable table\"><thead><tr><th>${0}</th><th>${1}</th></tr></thead><tbody>"),
TABLE_START_3("<table class=\"sortable table\"><thead><tr><th>${0}</th><th>${1}</th><th>${2}</th></tr></thead><tbody>"),
TABLE_START_4("<table class=\"sortable table\"><thead><tr><th>${0}</th><th>${1}</th><th>${2}</th><th>${3}</th></tr></thead><tbody>"),
TABLE_SESSIONS(DIV_W_CLASS_STYLE.parse("box-footer scrollbar", "padding: 2px;",
TABLE_START_4.parse("Player", "Started", "Length", "World - Time") + "${0}" + TABLE_END.parse())
),
TABLE_SESSIONS_START(TABLE_START_3.parse("Session Started", "Session Ended", "Session Length")),
TABLE_KILLS_START(TABLE_START_3.parse(FONT_AWESOME_ICON.parse("clock-o") + " Time", "Killed", "With")),
TABLE_FACTIONS_START(TABLE_START_4.parse(FONT_AWESOME_ICON.parse("flag") + " Faction", FONT_AWESOME_ICON.parse("bolt") + " Power", FONT_AWESOME_ICON.parse("map-o") + " Land", FONT_AWESOME_ICON.parse("user") + " Leader")),
@ -50,8 +63,7 @@ public enum Html {
TABLELINE_4("<tr><td><b>${0}</b></td><td>${1}</td><td>${2}</td><td>${3}</td></tr>"),
TABLELINE_PLAYERS("<tr><td>${0}</td><td>${1}</td><td sorttable_customkey=\"${2}\">${3}</td><td>${4}</td><td sorttable_customkey=\"${5}\">${6}</td>" + "<td sorttable_customkey=\"${7}\">${8}</td><td>${9}</td></tr>"),
TABLELINE_3_CUSTOMKEY("<tr><td sorttable_customkey=\"${0}\">${1}</td><td sorttable_customkey=\"${2}\">${3}</td><td sorttable_customkey=\"${4}\">${5}</td></tr>"),
TABLELINE_3_CUSTOMKEY_1("<tr><td sorttable_customkey=\"${0}\">${1}</td><td>${2}</td><td>${3}</td></tr>"),
TABLE_END("</tbody></table>");
TABLELINE_3_CUSTOMKEY_1("<tr><td sorttable_customkey=\"${0}\">${1}</td><td>${2}</td><td>${3}</td></tr>");
private final String html;

View File

@ -12,8 +12,8 @@ import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.systems.info.BukkitInformationManager;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import main.java.com.djrapitops.plan.utilities.html.graphs.WorldPieCreator;
import main.java.com.djrapitops.plan.utilities.html.tables.KillsTableCreator;
import main.java.com.djrapitops.plan.utilities.html.structure.SessionTabStructureCreator;
import main.java.com.djrapitops.plan.utilities.html.tables.SessionsTableCreator;
import org.apache.commons.lang3.text.StrSubstitutor;
import java.io.FileNotFoundException;
@ -92,114 +92,33 @@ public class HtmlStructure {
return builder.toString();
}
public static String[] createSessionsTabContent(Map<String, List<Session>> sessions, List<Session> allSessions) throws FileNotFoundException {
Map<Integer, String> serverNameIDRelationMap = new HashMap<>();
if (Verify.isEmpty(allSessions)) {
return new String[]{"<div class=\"session column\">" +
"<div class=\"session-header\">" +
"<div class=\"session-col\" style=\"width: 200%;\">" +
"<h3>No Sessions</h3>" +
"</div></div></div>", ""};
}
for (Map.Entry<String, List<Session>> entry : sessions.entrySet()) {
String serverName = entry.getKey();
List<Session> serverSessions = entry.getValue();
for (Session session : serverSessions) {
serverNameIDRelationMap.put(session.getSessionID(), serverName);
}
}
StringBuilder html = new StringBuilder();
StringBuilder viewScript = new StringBuilder();
int i = 0;
for (Session session : allSessions) {
if (i >= 50) {
break;
}
String sessionStart = FormatUtils.formatTimeStampYear(session.getSessionStart());
String sessionLength = FormatUtils.formatTimeAmount(session.getLength());
String sessionEnd = FormatUtils.formatTimeStampYear(session.getSessionEnd());
String dotSeparated = separateWithDots(sessionStart, sessionLength);
// Session-column starts & header.
html.append("<div class=\"session column\">")
.append("<div class=\"session-header\">")
.append("<div class=\"session-col\" style=\"width: 200%;\">")
.append("<h3><i style=\"color:#777\" class=\"fa fa-chevron-down\" aria-hidden=\"true\"></i> ").append(dotSeparated).append("</h3>")
.append("</div>")
.append("</div>");
String serverName = serverNameIDRelationMap.get(session.getSessionID());
// Left side of Session box
html.append("<div class=\"session-content\">")
.append("<div class=\"row\">") //
.append("<div class=\"session-col\" style=\"padding: 0px;\">");
// Left side header
html.append("<div class=\"box-header\" style=\"margin: 0px;\">")
.append("<h2><i class=\"fa fa-calendar\" aria-hidden=\"true\"></i> ")
.append(sessionStart)
.append("</h2>")
.append("</div>");
// Left side content
html.append("<div class=\"box\" style=\"margin: 0px;\">")
.append("<p>Session Length: ").append(sessionLength).append("<br>")
.append("Session Ended: ").append(sessionEnd).append("<br>")
.append("Server: ").append(serverName).append("<br><br>")
.append("Mob Kills: ").append(session.getMobKills()).append("<br>")
.append("Deaths: ").append(session.getDeaths()).append("</p>");
html.append(KillsTableCreator.createTable(session.getPlayerKills()))
.append("</div>"); // Left Side content ends
// Left side ends & Right side starts
html.append("</div>")
.append("<div class=\"session-col\">");
String id = "worldPie" + session.getSessionStart() + i;
html.append("<div id=\"").append(id).append("\" style=\"width: 100%; height: 400px;\"></div>");
String[] worldData = WorldPieCreator.createSeriesData(session.getWorldTimes());
html.append("<script>")
.append("var ").append(id).append("series = {name:'World Playtime',colors: worldPieColors,colorByPoint:true,data:").append(worldData[0]).append("};")
.append("var ").append(id).append("gmseries = ").append(worldData[1]).append(";")
.append("</script>");
viewScript.append("worldPie(")
.append(id).append(", ")
.append(id).append("series, ")
.append(id).append("gmseries")
.append(");");
// Session-col, Row, Session-Content, Session-column ends.
html.append("</div>")
.append("</div>")
.append("</div>")
.append("</div>");
i++;
}
return new String[]{html.toString(), viewScript.toString()};
public static String[] createSessionsTabContentInspectPage(Map<String, List<Session>> sessions, List<Session> allSessions, UUID uuid) throws FileNotFoundException {
Map<UUID, Map<String, List<Session>>> map = new HashMap<>();
map.put(uuid, sessions);
return SessionTabStructureCreator.creteStructure(map, allSessions, false);
}
public static String createInspectPageTabContent(String serverName, List<PluginData> plugins, Map<String, Serializable> replaceMap) {
private static String[] getSessionsAsTable(Map<String, List<Session>> sessions, List<Session> allSessions, UUID uuid) {
Map<Integer, UUID> uuidByID = new HashMap<>();
for (List<Session> sessionList : sessions.values()) {
for (Session session : sessionList) {
uuidByID.put(session.getSessionID(), uuid);
}
}
return new String[]{Html.TABLE_SESSIONS.parse(SessionsTableCreator.createTable(uuidByID, allSessions)[0]), ""};
}
public static String createInspectPluginsTabContent(String serverName, List<PluginData> plugins, Map<String, Serializable> replaceMap) {
if (plugins.isEmpty()) {
return "<div class=\"plugins-server\">" +
"<div class=\"plugins-header\">" +
"<div class=\"row\">" +
"<div class=\"column\">" +
"<div class=\"box-header\">" +
"<h2><i class=\"fa fa-server\" aria-hidden=\"true\"></i> " + serverName +
"</h2><p>No Compatible Plugins</p>" +
"</div></div></div></div></div>";
String icon = Html.FONT_AWESOME_ICON.parse("server");
// TODO Move plain text to Locale
String headerText = Html.HEADER_2.parse(icon + " " + serverName) + Html.PARAGRAPH.parse("No Compatible Plugins");
return Html.DIV_W_CLASS.parse("plugins-server",
Html.DIV_W_CLASS.parse("plugins-header",
Html.ROW.parse(Html.DIV_W_CLASS.parse("box-header", headerText))
)
);
}
Map<String, List<String>> placeholders = getPlaceholdersInspect(plugins);
@ -213,7 +132,7 @@ public class HtmlStructure {
.append("<div class=\"box-header\">")
.append("<h2><i style=\"padding: 8px;\" class=\"fa fa-chevron-down\" aria-hidden=\"true\"></i> ")
.append(serverName)
.append(" <i class=\"fa fa-server\" aria-hidden=\"true\"></i></h2>")
.append("</h2>")
.append("</div>")
.append("</div>")
.append("</div>")
@ -385,6 +304,7 @@ public class HtmlStructure {
int i = 0;
StringBuilder b = new StringBuilder();
List<String> values = new ArrayList<>(networkPageContents.values());
Collections.sort(values);
int size = values.size();
int extra = size % 3;
for (int j = 0; j < extra; j++) {

View File

@ -3,6 +3,9 @@ package main.java.com.djrapitops.plan.utilities.html.graphs;
import main.java.com.djrapitops.plan.data.time.GMTimes;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@ -25,11 +28,13 @@ public class WorldPieCreator {
Map<String, Long> playtimePerWorld = worldTimes.getWorldTimes().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getTotal()));
List<String> worlds = new ArrayList<>(playtimePerWorld.keySet());
Collections.sort(worlds);
int size = playtimePerWorld.size();
for (Map.Entry<String, Long> world : playtimePerWorld.entrySet()) {
String worldName = world.getKey();
for (String worldName : worlds) {
seriesBuilder.append("{name:'").append(worldName)
.append("',y:").append(world.getValue())
.append("',y:").append(playtimePerWorld.getOrDefault(worldName, 0L))
.append(",drilldown: '").append(worldName).append("'");
seriesBuilder.append("}");

View File

@ -0,0 +1,197 @@
/*
* Licence is provided in the jar as license.yml also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
*/
package main.java.com.djrapitops.plan.utilities.html.structure;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.analysis.JoinInfoPart;
import main.java.com.djrapitops.plan.data.time.GMTimes;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.comparators.SessionStartComparator;
import main.java.com.djrapitops.plan.utilities.html.Html;
import main.java.com.djrapitops.plan.utilities.html.HtmlStructure;
import main.java.com.djrapitops.plan.utilities.html.graphs.WorldPieCreator;
import main.java.com.djrapitops.plan.utilities.html.tables.KillsTableCreator;
import main.java.com.djrapitops.plan.utilities.html.tables.SessionsTableCreator;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;
/**
* //TODO Class Javadoc Comment
*
* @author Rsl1122
*/
public class SessionTabStructureCreator {
public static String[] creteStructure(Map<UUID, Map<String, List<Session>>> sessions, List<Session> allSessions, boolean appendName) {
Map<Integer, UUID> uuidsByID = generateIDtoUUIDMap(sessions);
if (Settings.DISPLAY_SESSIONS_AS_TABLE.isTrue()) {
return new String[]{Html.TABLE_SESSIONS.parse(SessionsTableCreator.createTable(uuidsByID, allSessions)[0]), ""};
}
if (Verify.isEmpty(allSessions)) {
return new String[]{"<div class=\"session column\">" +
"<div class=\"session-header\">" +
"<div class=\"session-col\" style=\"width: 200%;\">" +
"<h3>No Sessions</h3>" +
"</div></div></div>", ""};
}
Map<Integer, String> serverNameIDMap = generateIDtoServerNameMap(sessions);
StringBuilder html = new StringBuilder();
StringBuilder viewScript = new StringBuilder();
int i = 0;
for (Session session : allSessions) {
if (i >= 50) {
break;
}
int sessionID = session.getSessionID();
UUID uuid = uuidsByID.get(sessionID);
String serverName = serverNameIDMap.get(sessionID);
String sessionStart = FormatUtils.formatTimeStampYear(session.getSessionStart());
String sessionLength = FormatUtils.formatTimeAmount(session.getLength());
String sessionEnd = FormatUtils.formatTimeStampYear(session.getSessionEnd());
String name = Plan.getInstance().getDataCache().getName(uuid);
String link = Html.LINK.parse(Plan.getPlanAPI().getPlayerInspectPageLink(name), name);
String dotSeparated = appendName ?
HtmlStructure.separateWithDots(link, sessionStart, sessionLength) :
HtmlStructure.separateWithDots(sessionStart, sessionLength);
// Session-column starts & header.
html.append("<div class=\"session column\">")
.append("<div title=\"Session ID: ").append(sessionID).append("\" class=\"session-header\">")
.append("<div class=\"session-col\" style=\"width: 200%;\">")
.append("<h3><i style=\"color:#777\" class=\"fa fa-chevron-down\" aria-hidden=\"true\"></i> ").append(dotSeparated).append("</h3>")
.append("</div>")
.append("</div>");
// Left side of Session box
html.append("<div class=\"session-content\">")
.append("<div class=\"row\">") //
.append("<div class=\"session-col\" style=\"padding: 0px;\">");
// Left side header
html.append("<div class=\"box-header\" style=\"margin: 0px;\">")
.append("<h2><i class=\"fa fa-calendar\" aria-hidden=\"true\"></i> ")
.append(sessionStart)
.append("</h2>")
.append("</div>");
// Left side content
html.append("<div class=\"box\" style=\"margin: 0px;\">")
.append("<p>Session Length: ").append(sessionLength).append("<br>")
.append("Session Ended: ").append(sessionEnd).append("<br>")
.append("Server: ").append(serverName).append("<br><br>")
.append("Mob Kills: ").append(session.getMobKills()).append("<br>")
.append("Deaths: ").append(session.getDeaths()).append("</p>");
html.append(KillsTableCreator.createTable(session.getPlayerKills()))
.append("</div>"); // Left Side content ends
// Left side ends & Right side starts
html.append("</div>")
.append("<div class=\"session-col\">");
String id = "worldPie" + session.getSessionStart() + i;
html.append("<div id=\"").append(id).append("\" style=\"width: 100%; height: 400px;\"></div>");
WorldTimes worldTimes = session.getWorldTimes();
try {
// Add 0 time for worlds not present.
Set<String> nonZeroWorlds = worldTimes.getWorldTimes().keySet();
for (String world : MiscUtils.getIPlan().getDB().getWorldTable().getWorlds()) {
if (nonZeroWorlds.contains(world)) {
continue;
}
worldTimes.setGMTimesForWorld(world, new GMTimes());
}
} catch (SQLException e) {
Log.toLog("SessionTabStructureCreator", e);
}
String[] worldData = WorldPieCreator.createSeriesData(worldTimes);
html.append("<script>")
.append("var ").append(id).append("series = {name:'World Playtime',colors: worldPieColors,colorByPoint:true,data:").append(worldData[0]).append("};")
.append("var ").append(id).append("gmseries = ").append(worldData[1]).append(";")
.append("</script>");
viewScript.append("worldPie(")
.append(id).append(", ")
.append(id).append("series, ")
.append(id).append("gmseries")
.append(");");
// Session-col, Row, Session-Content, Session-column ends.
html.append("</div>")
.append("</div>")
.append("</div>")
.append("</div>");
i++;
}
return new String[]{html.toString(), viewScript.toString()};
}
private static Map<Integer, String> generateIDtoServerNameMap(Map<UUID, Map<String, List<Session>>> sessions) {
Map<Integer, String> serverNameIDRelationMap = new HashMap<>();
for (Map<String, List<Session>> map : sessions.values()) {
for (Map.Entry<String, List<Session>> entry : map.entrySet()) {
String serverName = entry.getKey();
List<Session> serverSessions = entry.getValue();
for (Session session : serverSessions) {
serverNameIDRelationMap.put(session.getSessionID(), serverName);
}
}
}
return serverNameIDRelationMap;
}
private static Map<Integer, UUID> generateIDtoUUIDMap(Map<UUID, Map<String, List<Session>>> sessions) {
Map<Integer, UUID> uuidsByID = new HashMap<>();
for (Map.Entry<UUID, Map<String, List<Session>>> entry : sessions.entrySet()) {
UUID uuid = entry.getKey();
for (List<Session> sessionList : entry.getValue().values()) {
for (Session session : sessionList) {
uuidsByID.put(session.getSessionID(), uuid);
}
}
}
return uuidsByID;
}
public static String[] creteStructure(JoinInfoPart joinInfoPart) {
Map<UUID, Map<String, List<Session>>> map = new HashMap<>();
Map<UUID, List<Session>> sessions = joinInfoPart.getSessions();
for (Map.Entry<UUID, List<Session>> entry : sessions.entrySet()) {
Map<String, List<Session>> serverSpecificMap = new HashMap<>();
serverSpecificMap.put("This server", entry.getValue());
map.put(entry.getKey(), serverSpecificMap);
}
List<Session> allSessions = sessions.values().stream()
.flatMap(Collection::stream)
.sorted(new SessionStartComparator())
.collect(Collectors.toList());
return creteStructure(map, allSessions, true);
}
}

View File

@ -24,7 +24,7 @@ import java.util.*;
*/
public class SessionsTableCreator {
public static String[] createTables(JoinInfoPart joinInfoPart) {
public static String[] createTable(JoinInfoPart joinInfoPart) {
Map<Integer, UUID> uuidByID = new HashMap<>();
for (Map.Entry<UUID, List<Session>> entry : joinInfoPart.getSessions().entrySet()) {
List<Session> sessions = entry.getValue();
@ -34,6 +34,10 @@ public class SessionsTableCreator {
}
List<Session> allSessions = joinInfoPart.getAllSessions();
return createTable(uuidByID, allSessions);
}
public static String[] createTable(Map<Integer, UUID> uuidByID, List<Session> allSessions) {
if (allSessions.isEmpty()) {
return new String[]{Html.TABLELINE_4.parse("<b>No Sessions</b>", "", "", ""),
Html.TABLELINE_2.parse("<b>No Sessions</b>", "")};
@ -73,8 +77,9 @@ public class SessionsTableCreator {
String world = getLongestWorldPlayed(session);
String inspectUrl = Plan.getPlanAPI().getPlayerInspectPageLink(name);
String toolTip = "Session ID: " + (session.isFetchedFromDB() ? session.getSessionID() : "Not Saved.");
sessionTableBuilder.append(Html.TABLELINE_4.parse(
Html.LINK.parse(inspectUrl, name),
Html.LINK_TOOLTIP.parse(inspectUrl, name, toolTip),
start,
length,
world

View File

@ -1,4 +1,4 @@
name: Plan
author: Rsl1122
main: main.java.com.djrapitops.plan.PlanBungee
version: 4.0.2
version: 4.0.3

View File

@ -52,6 +52,8 @@ Data:
Customization:
UseServerTime: true
Display:
SessionsAsTable: false
Formatting:
DecimalPoints: '#.##'
TimeAmount:

View File

@ -41,7 +41,7 @@
<h2><i class="fa fa-info-circle"></i> Information</h2>
</div>
<div class="box" style="height: 75%;">
<p>${playersOnline}/${playersMax} Players Online</p>
<p>${playersOnline} Players Online</p>
<p>${playersTotal} Total Players</p>
<p>${playersNewDay} New Players Today<br>${playersNewWeek} New Players This Week</p>
</div>

View File

@ -14,6 +14,10 @@
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>
<body>
<script>
var worldPieColors = [${worldPieColors}];
var gmPieColors = [${gmPieColors}];
</script>
<header>
<div>
<div class="right fa-stack fa-lg" style="padding: 23px; margin:8px">
@ -183,21 +187,7 @@
<div class="box-header">
<h2><i class="fa fa-calendar"></i> 50 Most Recent Sessions</h2>
</div>
<div class="box-footer scrollbar" style="padding: 2px;">
<table class="sortable table">
<thead>
<tr>
<th>Player</th>
<th>Started</th>
<th>Length</th>
<th>World - Time</th>
</tr>
</thead>
<tbody>
${tableBodySessions}
</tbody>
</table>
</div>
${contentSessions}
</div>
</div>
<div class="row">
@ -358,6 +348,7 @@
<script src="./js/performanceGraph.js"></script>
<script src="./js/worldMap.js"></script>
<script src="./js/worldPie.js"></script>
<script src="./js/sessionTabExpand.js"></script>
<script>
Highcharts.setOptions({
lang: {noData: "No Data to Display"},
@ -449,8 +440,6 @@
y: ${banned}
}]
};
var worldPieColors = [${worldPieColors}];
var gmPieColors = [${gmPieColors}];
var worldSeries = {
name: 'World Playtime',
colorByPoint: true,
@ -473,7 +462,14 @@
</script>
<script>
$( function() {
$( "#tabs" ).tabs();
var resourceTab = window.sessionStorage.getItem("AnalysisResourceTab");
if (resourceTab == null) {
resourceTab = 1;
}
$( "#tabs" ).tabs({active: resourceTab});
$( "#tabs" ).on("tabsactivate", function(event, ui) {
window.sessionStorage.setItem("AnalysisResourceTab", $( "#tabs" ).tabs( "option", "active" ));
});
});
</script>
<script>
@ -502,6 +498,7 @@
worldChart('worldGraph', entitySeries, chunkSeries, playersOnlineSeries);
worldMap('choropleth', '#EEFFEE', '#267f00', mapSeries);
punchCard('punchcard', punchcardSeries);
${sessionTabGraphViewFunctions}
/*countUpTimer();*/
function openFunc(i) {

View File

@ -1,7 +1,7 @@
name: Plan
author: Rsl1122
main: main.java.com.djrapitops.plan.Plan
version: 4.0.2
version: 4.0.3
softdepend:
- OnTime
- EssentialsX

View File

@ -437,6 +437,11 @@ public class DatabaseTest {
assertNull(sessions.get(worlds.get(1)));
assertEquals(session, savedSessions.get(0));
Map<UUID, Long> lastSeen = sessionsTable.getLastSeenForAllPlayers();
assertTrue(lastSeen.containsKey(uuid));
assertFalse(lastSeen.containsKey(uuid2));
assertEquals(22345L, (long) lastSeen.get(uuid));
}
@Test

View File

@ -67,9 +67,10 @@ public class ComparatorTest {
longValues.sort(Long::compare);
Collections.reverse(longValues);
System.out.println(longValues);
userInfo.sort(new UserInfoLastPlayedComparator());
List<Long> afterSort = userInfo.stream().map(UserInfo::getLastSeen).collect(Collectors.toList());
System.out.println(afterSort);
assertEquals(longValues, afterSort);
}

View File

@ -8,6 +8,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import test.java.utils.MockUtils;
import test.java.utils.RandomData;
import test.java.utils.TestInit;
@ -47,7 +48,7 @@ public class HtmlStructureTest {
@Test
public void createSessionsTabContent() throws Exception {
List<Session> allSessions = sessions.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
String[] sessionsTab = HtmlStructure.createSessionsTabContent(sessions, allSessions);
String[] sessionsTab = HtmlStructure.createSessionsTabContentInspectPage(sessions, allSessions, MockUtils.getPlayerUUID());
int opened = StringUtils.countMatches(sessionsTab[0], "<div");
int closed = StringUtils.countMatches(sessionsTab[0], "</div");

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.djrapitops</groupId>
<artifactId>PlanPluginBridge</artifactId>
<version>4.0.0</version>
<version>4.0.3</version>
<packaging>jar</packaging>
<repositories>
<repository>

View File

@ -13,6 +13,8 @@ import com.djrapitops.pluginbridge.plan.superbvote.SuperbVoteHook;
import com.djrapitops.pluginbridge.plan.towny.TownyHook;
import com.djrapitops.pluginbridge.plan.vault.VaultHook;
import com.djrapitops.pluginbridge.plan.viaversion.ViaVersionHook;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
/**
@ -56,7 +58,10 @@ public class Bridge {
for (Hook hook : hooks) {
try {
hook.hook();
} catch (Exception | NoClassDefFoundError ignore) {
} catch (Exception | NoClassDefFoundError e) {
if (Settings.DEV_MODE.isTrue()) {
Log.toLog("PluginBridge", e);
}
}
}
}

View File

@ -21,6 +21,10 @@ public abstract class Hook {
protected HookHandler hookHandler;
private Hook() {
throw new IllegalStateException();
}
/**
* Class constructor.
* <p>
@ -45,8 +49,9 @@ public abstract class Hook {
/**
* Constructor to set enabled to false.
*/
public Hook() {
public Hook(HookHandler hookHandler) {
enabled = false;
this.hookHandler = hookHandler;
}
protected void addPluginDataSource(PluginData pluginData) {

View File

@ -25,7 +25,7 @@ public class LiteBansHook extends Hook {
*/
@SuppressWarnings("ResultOfMethodCallIgnored")
public LiteBansHook(HookHandler hookH) {
super();
super(hookH);
try {
Database.get();
enabled = true;