TotalFreedomMod/commons/src/main/java/me/totalfreedom/totalfreedommod/admin/AdminList.java

344 lines
9.6 KiB
Java

package me.totalfreedom.totalfreedommod.admin;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import me.totalfreedom.totalfreedommod.FreedomService;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.rank.GroupProvider;
import me.totalfreedom.totalfreedommod.sql.ResultSetProvider;
import me.totalfreedom.totalfreedommod.rank.Hierarchy;
import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.kyori.adventure.text.Component;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.*;
import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class AdminList extends FreedomService
{
public static final List<UUID> vanished = new ArrayList<>();
public static final String SQL_SAVE_FAILED = "Failed to save admin: ";
private final Set<Admin> allAdmins = Sets.newHashSet(); // Includes disabled admins
// Only active admins below
private final Set<Admin> activeAdmins = Sets.newHashSet();
private final Map<UUID, Admin> uuidTable = Maps.newHashMap();
private final Map<String, Admin> nameTable = Maps.newHashMap();
private final Map<String, Admin> ipTable = Maps.newHashMap();
@Override
public void onStart()
{
load();
deactivateOldEntries(false);
}
@Override
public void onStop()
{
// This does nothing. This comment is here to prevent SonarLint from complaining.
}
public void load()
{
allAdmins.clear();
plugin.sql.getAdminList().thenAcceptAsync(provider ->
{
AtomicInteger row = new AtomicInteger(1);
provider.getAllRowsResultSet().forEach(adminSet ->
{
try
{
tryAddAdmin(ResultSetProvider.fromRow(adminSet));
row.set(row.get() + 1);
} catch (Throwable e)
{
FLog.warning("An error occurred whilst reading the admin entry at row #" + row.get());
throw new CompletionException(e); // handle downstream.
}
});
}).whenComplete((result, throwable) ->
{
if (throwable != null)
{
FLog.severe(throwable.getMessage());
return;
}
updateTables();
FLog.info("Loaded " + allAdmins.size() + " admins (" + uuidTable.size() + " active, " + ipTable.size() + " IPs)");
});
}
private void tryAddAdmin(ResultSetProvider adminSet)
{
Admin admin = new Admin(adminSet);
allAdmins.add(admin);
}
public void messageAllAdmins(Component message)
{
server.getOnlinePlayers().stream().filter(this::isAdmin).forEach(player -> player.sendMessage(message));
}
public void potionSpyMessage(String message)
{
for (Player player : server.getOnlinePlayers())
{
Admin admin = getAdmin(player.getPlayer());
if (isAdmin(player) && admin.getPotionSpy())
{
player.sendMessage(message);
}
}
}
public synchronized boolean isAdminSync(CommandSender sender)
{
return isAdmin(sender);
}
public boolean isAdmin(CommandSender sender)
{
if (!(sender instanceof Player))
{
return true;
}
Admin admin = getAdmin((Player) sender);
return admin != null && admin.isActive();
}
public boolean isAdmin(Player player)
{
if (Hierarchy.getHierarchy().isUserOnAdminTrack(player)) return true;
return isAdmin((OfflinePlayer) player);
}
public boolean isAdmin(OfflinePlayer player)
{
if (player == null)
{
return true;
}
Admin admin = getAdmin(player);
return admin != null && admin.isActive();
}
public Admin getAdmin(CommandSender sender)
{
if (sender instanceof Player player)
{
return getAdmin(player);
}
return getEntryByName(sender.getName());
}
public Admin getAdmin(OfflinePlayer player)
{
return getEntryByUuid(player.getUniqueId());
}
public Admin getEntryByUuid(UUID uuid)
{
return uuidTable.get(uuid);
}
public Admin getEntryByName(String name)
{
return nameTable.get(name.toLowerCase());
}
public Admin getEntryByIp(String ip)
{
return ipTable.get(ip);
}
// To cast against OfflinePlayer
public Admin getAdmin(Player player)
{
return getAdmin((OfflinePlayer) player);
}
public void updateLastLogin(Player player)
{
final Admin admin = getAdmin(player);
if (admin == null)
{
return;
}
admin.setLastLogin(new Date());
save(admin);
}
public void addAdmin(Admin admin)
{
if (!admin.isValid())
{
FLog.warning("Could not add admin: " + admin.getName() + ". Admin is missing details!");
return;
}
// Store admin, update views
allAdmins.add(admin);
updateTables();
// Save admin
plugin.sql.addAdmin(admin).whenComplete((result, exception) ->
{
if (exception != null)
{
FLog.warning(SQL_SAVE_FAILED + admin.getName() + " to the database.\n" + exception.getMessage());
}
});
}
public boolean removeAdmin(Admin admin)
{
if (admin.getRank().isAtLeast(GroupProvider.ADMIN.getGroup()) && (plugin.btb != null))
{
plugin.btb.killTelnetSessions(admin.getName());
}
// Remove admin, update views
if (!allAdmins.remove(admin))
{
return false;
}
updateTables();
// Unsave admin
plugin.sql.removeAdmin(admin).whenComplete((result, exception) ->
{
if (exception != null)
{
FLog.warning("Failed to remove admin: " + admin.getName() + " from the database.\n" + exception.getMessage());
}
});
return true;
}
public void updateTables()
{
activeAdmins.clear();
uuidTable.clear();
nameTable.clear();
ipTable.clear();
for (Admin admin : allAdmins)
{
if (!admin.isActive())
{
continue;
}
activeAdmins.add(admin);
uuidTable.put(admin.getUuid(), admin);
if (admin.getName() != null)
{
nameTable.put(admin.getName().toLowerCase(), admin);
}
for (String ip : admin.getIps())
{
ipTable.put(ip, admin);
}
}
}
public Set<String> getAdminNames()
{
return nameTable.keySet();
}
public Set<String> getAdminIps()
{
return ipTable.keySet();
}
public void save(Admin admin)
{
plugin.sql.getAdminByUuid(admin.getUuid()).thenApplyAsync(result ->
{
for (Map.Entry<String, Object> entry : admin.toSQLStorable().entrySet())
{
Object storedValue = plugin.sql.getValue(result, entry.getKey(), entry.getValue());
if (storedValue != null && !storedValue.equals(entry.getValue()) || storedValue == null && entry.getValue() != null || entry.getValue() == null)
{
plugin.sql.setAdminValue(admin, entry.getKey(), entry.getValue()).whenComplete((result2, exception) ->
{
if (exception != null)
{
throw new CompletionException(exception); // We want to handle downstream in #whenComplete()
}
});
}
}
return null;
}).whenComplete((result, exception) ->
{
if (exception != null)
{
FLog.severe(SQL_SAVE_FAILED + exception.getMessage());
}
});
}
public void deactivateOldEntries(boolean verbose)
{
allAdmins.stream()
.filter(admin -> admin.isActive() && !admin.getRank().isAtLeast(GroupProvider.SENIOR_ADMIN.getGroup()))
.forEach(admin ->
{
final Date lastLogin = admin.getLastLogin();
final long lastLoginHours = TimeUnit.HOURS.convert(new Date().getTime() - lastLogin.getTime(), TimeUnit.MILLISECONDS);
if (lastLoginHours < ConfigEntry.ADMINLIST_CLEAN_THESHOLD_HOURS.getInteger())
{
return;
}
if (verbose)
{
FUtil.adminAction("TotalFreedomMod", "Deactivating admin " + admin.getName() + ", inactive for " + lastLoginHours + " hours", true);
}
admin.setActive(false);
save(admin);
});
updateTables();
}
public boolean isVanished(UUID uuid)
{
return vanished.contains(uuid);
}
public Set<Admin> getAllAdmins()
{
return allAdmins;
}
public Set<Admin> getActiveAdmins()
{
return activeAdmins;
}
public Map<String, Admin> getNameTable()
{
return nameTable;
}
public Map<String, Admin> getIpTable()
{
return ipTable;
}
}