diff --git a/paper/src/main/java/vg/civcraft/mc/namelayer/GroupManager.java b/paper/src/main/java/vg/civcraft/mc/namelayer/GroupManager.java index d40343f1..c96fdaf9 100644 --- a/paper/src/main/java/vg/civcraft/mc/namelayer/GroupManager.java +++ b/paper/src/main/java/vg/civcraft/mc/namelayer/GroupManager.java @@ -11,6 +11,7 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitScheduler; import vg.civcraft.mc.namelayer.database.GroupManagerDao; import vg.civcraft.mc.namelayer.events.GroupCreateEvent; import vg.civcraft.mc.namelayer.events.GroupDeleteEvent; @@ -107,7 +108,7 @@ private void doCreateGroupAsync(final Group group, final RunnableOnGroup postCre final String name = event.getGroupName(); final UUID owner = event.getOwner(); final String password = event.getPassword(); - NameLayerPlugin.getBlackList().initEmptyBlackList(name); + NameLayerPlugin.getBlackList().initEmptyBlackList(group.getGroupId()); Bukkit.getScheduler().runTaskAsynchronously(NameLayerPlugin.getInstance(), new Runnable() { @Override public void run() { @@ -151,19 +152,14 @@ private int internalCreateGroup(Group group, boolean savetodb, String name, UUID return id; } - public boolean deleteGroup(String groupName){ - return deleteGroup(groupName,true); + public boolean deleteGroup(int groupId){ + return deleteGroup(groupId,true); } - public boolean deleteGroup(String groupName, boolean savetodb){ - if (groupName == null) { - NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "Group delete failed, caller passed in null", new Exception()); - return false; - } - groupName = groupName.toLowerCase(); - Group group = getGroup(groupName); + public boolean deleteGroup(int groupId, boolean savetodb){ + Group group = getGroup(groupId); if (group == null) { - NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "Group delete failed, failed to find group " + groupName); + NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "Group delete failed, failed to find group " + groupId); return false; } @@ -171,16 +167,14 @@ public boolean deleteGroup(String groupName, boolean savetodb){ GroupDeleteEvent event = new GroupDeleteEvent(group, false); Bukkit.getPluginManager().callEvent(event); if (event.isCancelled()) { - NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "Group delete was cancelled for "+ groupName); + NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "Group delete was cancelled for "+ groupId); return false; } // Unlinks subgroups. group.prepareForDeletion(); deleteGroupPerms(group); groupsByName.remove(group.getName()); - for (int id : group.getGroupIds()) { - groupsById.remove(id); - } + groupsById.remove(group.getGroupId()); // Call after actual delete to alert listeners that we're done. event = new GroupDeleteEvent(group, true); @@ -189,7 +183,7 @@ public boolean deleteGroup(String groupName, boolean savetodb){ group.setDisciplined(true); group.setValid(false); if (savetodb){ - groupManagerDao.deleteGroup(groupName); + groupManagerDao.deleteGroup(groupId); } return true; } @@ -245,15 +239,11 @@ public void doneMergeGroup(Group group, Group toMerge) { Bukkit.getPluginManager().callEvent(event); // Then invalidate. Updating the cache was proving unreliable; we'll address it later. - GroupManager.invalidateCache(group.getName()); - GroupManager.invalidateCache(toMerge.getName()); + GroupManager.invalidateCache(group.getGroupId()); + GroupManager.invalidateCache(toMerge.getGroupId()); } - public void mergeGroup(Group group, Group to){ - mergeGroup(group,to,true); - } - - public void mergeGroup(final Group group, final Group toMerge, boolean savetodb){ + public void mergeGroup(final Group group, final Group toMerge){ if (group == null || toMerge == null) { NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "Group merge failed, caller passed in null", new Exception()); return; @@ -268,52 +258,40 @@ public void mergeGroup(final Group group, final Group toMerge, boolean savetodb) group.getName() + " and " + toMerge.getName()); return; } - group.isValid(); - group.setDisciplined(true, false); - toMerge.setDisciplined(true, false); - - if (savetodb){ - // This basically just fires starting events and disciplines groups on target server. - // They then wait for merge to complete. Botched merges will lock groups, basically. :shrug: - NameLayerPlugin.getInstance().getServer().getScheduler().runTaskAsynchronously( - NameLayerPlugin.getInstance(), new Runnable(){ + BukkitScheduler sched = NameLayerPlugin.getInstance().getServer().getScheduler(); + sched.runTaskAsynchronously( + NameLayerPlugin.getInstance(), () -> { + if (!groupManagerDao.mergeGroup(group.getGroupId(), toMerge.getGroupId()) ){ + NameLayerPlugin.log(Level.WARNING, "Merging groups failed to execute SQL, rolling back merge. Groups: " + + group.getName() + " and " + toMerge.getName()); + return; + } - @Override - public void run() { - groupManagerDao.mergeGroup(group.getName(), toMerge.getName()); // At this point, at the DB level all non-overlap members are in target group, name is reset to target, // unique group header record is removed, and faction_id all point to new name. + sched.runTask(NameLayerPlugin.getInstance(), () -> { + // We handle supergroup right here right now; does its own mercury message to update in cache. + if (toMerge.getSuperGroup() != null) { + Group sup = toMerge.getSuperGroup(); + Group.unlink(sup, toMerge); + // The above handles the need to unlink any supergroup from merge in DB. + } - // We handle supergroup right here right now; does its own mercury message to update in cache. - if (toMerge.getSuperGroup() != null) { - Group sup = toMerge.getSuperGroup(); - Group.unlink(sup, toMerge); - // The above handles the need to unlink any supergroup from merge in DB. - } - - // Subgroup update is handled in doneMerge, as its a cache-only update. + // Subgroup update is handled in doneMerge, as its a cache-only update. - deleteGroupPerms(toMerge); // commit perm updates to DB. + deleteGroupPerms(toMerge); // commit perm updates to DB. - doneMergeGroup(group, toMerge); - } - }); - } + doneMergeGroup(group, toMerge); + }); + }); } - public static List getSubGroups(String name) { - if (name == null) { - NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "Group getSubGroups event failed, caller passed in null", new Exception()); - return new ArrayList<>(); - } - - List groups = groupManagerDao.getSubGroups(name); + public static List getSubGroups(int id) { + List groups = groupManagerDao.getSubGroups(id); for (Group group : groups) { groupsByName.put(group.getName().toLowerCase(), group); - for (int j : group.getGroupIds()){ - groupsById.put(j, group); - } + groupsById.put(group.getGroupId(), group); } return groups; } @@ -335,9 +313,7 @@ public static Group getGroup(String name){ Group group = groupManagerDao.getGroup(name); if (group != null) { groupsByName.put(lower, group); - for (int j : group.getGroupIds()){ - groupsById.put(j, group); - } + groupsById.put(group.getGroupId(), group); } else { NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "getGroup by Name failed, unable to find the group " + name); } @@ -352,9 +328,7 @@ public static Group getGroup(int groupId){ Group group = groupManagerDao.getGroup(groupId); if (group != null) { groupsByName.put(group.getName().toLowerCase(), group); - for (int j : group.getGroupIds()){ - groupsById.put(j, group); - } + groupsById.put(group.getGroupId(), group); } else { NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "getGroup by ID failed, unable to find the group " + groupId); } @@ -393,9 +367,7 @@ public static Group getSpecialCircumstanceGroup(String name){ Group group = groupManagerDao.getGroup(name); if (group != null) { groupsByName.put(lower, group); - for (int j : group.getGroupIds()){ - groupsById.put(j, group); - } + groupsById.put(group.getGroupId(), group); } else { group = groupManagerDao.getGroup(NameLayerPlugin.getSpecialAdminGroup()); } @@ -508,27 +480,16 @@ public String getDefaultGroup(UUID uuid){ * Invalidates a group from cache. * @param group the group to invalidate cache for */ - public static void invalidateCache(String group){ - if (group == null) { - NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "invalidateCache failed, caller passed in null", new Exception()); - return; - } - - Group g = groupsByName.get(group.toLowerCase()); + public static void invalidateCache(int group){ + Group g = groupsById.get(group); if (g != null) { g.setValid(false); - Listk = g.getGroupIds(); - groupsByName.remove(group.toLowerCase()); + groupsByName.remove(g.getName()); NameLayerPlugin.getBlackList().removeFromCache(g.getName()); - - boolean fail = true; + // You have a freaking hashmap, use it. - for (int j : k) { - if (groupsById.remove(j) != null) { - fail = false; - } - } - + boolean fail = groupsById.remove(g.getGroupId()) == null; + // FALLBACK is hardloop if (fail) { // can't find ID or cache is wrong. for (Group x: groupsById.values()) { diff --git a/paper/src/main/java/vg/civcraft/mc/namelayer/NameLayerPlugin.java b/paper/src/main/java/vg/civcraft/mc/namelayer/NameLayerPlugin.java index fe4d0081..a4cad769 100644 --- a/paper/src/main/java/vg/civcraft/mc/namelayer/NameLayerPlugin.java +++ b/paper/src/main/java/vg/civcraft/mc/namelayer/NameLayerPlugin.java @@ -146,8 +146,6 @@ public void loadDatabases() { if (loadGroups) { groupManagerDao = new GroupManagerDao(getLogger(), db); groupManagerDao.registerMigrations(); - NameLayerPlugin.log(Level.INFO, "Removing any cycles..."); - groupManagerDao.removeCycles(); } long begin_time = System.currentTimeMillis(); diff --git a/paper/src/main/java/vg/civcraft/mc/namelayer/command/CommandHandler.java b/paper/src/main/java/vg/civcraft/mc/namelayer/command/CommandHandler.java index 3ca900be..7f3209e4 100644 --- a/paper/src/main/java/vg/civcraft/mc/namelayer/command/CommandHandler.java +++ b/paper/src/main/java/vg/civcraft/mc/namelayer/command/CommandHandler.java @@ -34,7 +34,9 @@ public void registerCommands(){ registerCommand(new ListGroups()); registerCommand(new ListMembers()); registerCommand(new ListPermissions()); - //addCommands(new MergeGroups("MergeGroups")); Disabled as it's currently semi broken + registerCommand(new MergeGroups()); + registerCommand(new LinkGroups()); + registerCommand(new UnlinkGroups()); registerCommand(new ModifyPermissions()); registerCommand(new RemoveMember()); registerCommand(new SetPassword()); diff --git a/paper/src/main/java/vg/civcraft/mc/namelayer/command/commands/DeleteGroup.java b/paper/src/main/java/vg/civcraft/mc/namelayer/command/commands/DeleteGroup.java index 1505b4c7..2bbb80de 100644 --- a/paper/src/main/java/vg/civcraft/mc/namelayer/command/commands/DeleteGroup.java +++ b/paper/src/main/java/vg/civcraft/mc/namelayer/command/commands/DeleteGroup.java @@ -46,7 +46,7 @@ public void execute(Player sender, String groupName) { if(now.getTime() < Long.parseLong(entry[1])) { //good to go delete the group - if(gm.deleteGroup(gD.getName())) + if(gm.deleteGroup(gD.getGroupId())) p.sendMessage(ChatColor.GREEN + "Group was successfully deleted."); else p.sendMessage(ChatColor.GREEN + "Group is now disciplined." diff --git a/paper/src/main/java/vg/civcraft/mc/namelayer/database/GroupManagerDao.java b/paper/src/main/java/vg/civcraft/mc/namelayer/database/GroupManagerDao.java index 39f66060..489846c3 100644 --- a/paper/src/main/java/vg/civcraft/mc/namelayer/database/GroupManagerDao.java +++ b/paper/src/main/java/vg/civcraft/mc/namelayer/database/GroupManagerDao.java @@ -24,6 +24,7 @@ import vg.civcraft.mc.namelayer.GroupManager; import vg.civcraft.mc.namelayer.GroupManager.PlayerType; import vg.civcraft.mc.namelayer.NameLayerPlugin; +import vg.civcraft.mc.namelayer.events.AsyncGroupMergeEvent; import vg.civcraft.mc.namelayer.group.Group; import vg.civcraft.mc.namelayer.listeners.PlayerListener; import vg.civcraft.mc.namelayer.permission.PermissionType; @@ -35,157 +36,120 @@ public class GroupManagerDao { private Logger logger; private ManagedDatasource db; protected NameLayerPlugin plugin = NameLayerPlugin.getInstance(); - - private static final String removeCycles = "delete a from subgroup a join faction_id a2 ON a.group_id = a2.group_id " - + "JOIN subgroup b JOIN faction_id b2 on b.sub_group_id = b2.group_id where a2.group_name = b2.group_name;"; + private static final String createGroup = "call createGroup(?,?,?,?)"; - private static final String getGroup = "select f.group_name, f.founder, f.password, f.discipline_flags, fi.group_id, f.last_timestamp " + - "from faction f " - + "inner join faction_id fi on fi.group_name = f.group_name " - + "where f.group_name = ?"; - private static final String getGroupIDs = "SELECT f.group_id, count(DISTINCT fm.member_name) AS sz FROM faction_id f " - + "INNER JOIN faction_member fm ON f.group_id = fm.group_id WHERE f.group_name = ? GROUP BY f.group_id ORDER BY sz DESC"; - private static final String getGroupById = "select f.group_name, f.founder, f.password, f.discipline_flags, fi.group_id, f.last_timestamp " + - "from faction f " - + "inner join faction_id fi on fi.group_id = ? " - + "where f.group_name = fi.group_name"; - private static final String getAllGroupsNames = "select f.group_name from faction_id f " - + "inner join faction_member fm on f.group_id = fm.group_id " + private static final String getGroup = "select f.group_name, f.founder, f.password, f.discipline_flags, f.id, f.last_timestamp " + + "from faction f where f.group_name = ?"; + private static final String getGroupById = "select f.group_name, f.founder, f.password, f.discipline_flags, f.id, f.last_timestamp " + + "from faction f where f.id = ?"; + private static final String getAllGroupsNames = "select f.group_name from faction f " + + "inner join faction_member fm on f.id = fm.group_id " + "where fm.member_name = ?"; - private static final String deleteGroup = "call deletegroupfromtable(?, ?)"; + private static final String deleteGroup = "call deletegroupfromtable(?)"; private static final String addMember = "insert into faction_member(" + - "group_id, member_name, role) select group_id, ?, ? from " - + "faction_id where group_name = ?"; + "group_id, member_name, role) VALUES (?, ?, ?)"; private static final String getMembers = "select fm.member_name from faction_member fm " - + "inner join faction_id id on id.group_name = ? " - + "where fm.group_id = id.group_id and fm.role = ?"; + + "where fm.group_id = ? and fm.role = ?"; private static final String removeMember = "delete fm.* from faction_member fm " - + "inner join faction_id fi on fi.group_id = fm.group_id " - + "where fm.member_name = ? and fi.group_name =?"; - + + "where fm.member_name = ? and fm.group_id = ?"; + private static final String removeAllMembers = "delete fm.* from faction_member fm " - + "inner join faction_id fi on fi.group_id = fm.group_id " - + "where fi.group_name =?"; - + + "where fm.group_id = ?"; + private static final String removeAllMembersLegacy = "delete fm.* from faction_member fm " + + "inner join faction_id fi on fi.group_id = fm.group_id " + + "where fi.group_name =?"; + + private static final String detectCycles = "WITH RECURSIVE cte (id, parent_id) AS (SELECT ?, CAST(NULL AS INT) UNION DISTINCT SELECT faction.id, faction.parent_id FROM faction, cte WHERE faction.parent_id = cte.id FOR UPDATE) SELECT 1 FROM cte WHERE id = ?"; + // So this will link all instances (name/id pairs) of the subgroup to all instances (name/id pairs) of the supergroup. - private static final String addSubGroup = "INSERT INTO subgroup (group_id, sub_group_id) " - + "SELECT super.group_id, sub.group_id " - + "FROM faction_id super " - + "INNER JOIN faction_id sub " - + "ON sub.group_name = ? " - + "WHERE super.group_name = ?"; - + private static final String addSubGroup = "UPDATE faction SET parent_id = ? WHERE id = ?"; + // This undoes the above. It unlinks all instances (name/id pairs) of the subgroup from all instances (name/id pairs) of the supergroup. - private static final String removeSubGroup ="DELETE FROM subgroup " - + "WHERE group_id IN (SELECT group_id FROM faction_id WHERE group_name = ?) " - + "AND sub_group_id IN (SELECT group_id FROM faction_id WHERE group_name = ?)"; - + private static final String removeSubGroup = "UPDATE faction SET parent_id = NULL WHERE parent_id = ? AND id = ?"; + // This lists all unique subgroups (names) for all instances (name/id pairs) of the supergroup. - private static final String getSubGroups = "SELECT DISTINCT sub.group_name FROM faction_id sub " - + "INNER JOIN faction_id super " - + "ON super.group_name = ? " - + "INNER JOIN subgroup other " - + "ON other.group_id = super.group_id " - + "WHERE sub.group_id = other.sub_group_id"; - - // This lists all unique supergroups (names) which are parent(s) for all instances (name/id pairs) of the subgroup. - // I expect most implementations to ignore if this has multiple results; a "safe" implementation will check. - private static final String getSuperGroup ="SELECT DISTINCT f.group_name FROM faction_id f " - + "INNER JOIN faction_id sf ON sf.group_name = ? " - + "INNER JOIN subgroup sg ON sg.group_id = sf.group_id " - + "WHERE f.group_id = sg.sub_group_id"; - + private static final String getSubGroups = "SELECT id FROM faction WHERE parent_id = ?"; + // returns count of unique names, but not (name / id pairs) of all groups. private static final String countGroups = "select count(DISTINCT group_name) as count from faction"; - + // returns count of unique names of groups owned by founder private static final String countGroupsFromUUID = "select count(DISTINCT group_name) as count from faction where founder = ?"; - + private static final String mergeGroup = "call mergeintogroup(?,?)"; - + private static final String updatePassword = "update faction set `password` = ? " + "where group_name = ?"; - + private static final String updateOwner = "update faction set founder = ? " + "where group_name = ?"; - + private static final String updateDisciplined = "update faction set discipline_flags = ? " + "where group_name = ?"; - + private static final String addAutoAcceptGroup = "insert into toggleAutoAccept(uuid)" + "values(?)"; private static final String getAutoAcceptGroup = "select uuid from toggleAutoAccept " + "where uuid = ?"; private static final String removeAutoAcceptGroup = "delete from toggleAutoAccept where uuid = ?"; - + private static final String loadAllAutoAcceptGroup = "select uuid from toggleAutoAccept;"; - + private static final String setDefaultGroup = "insert into default_group values(?, ?)"; - + private static final String changeDefaultGroup = "update default_group set defaultgroup = ? where uuid = ?"; - - + + private static final String getDefaultGroup = "select defaultgroup from default_group " + "where uuid = ?"; private static final String getAllDefaultGroups = "select uuid,defaultgroup from default_group"; - + private static final String loadGroupsInvitations = "select uuid, groupName, role from group_invitation"; - + private static final String addGroupInvitation = "insert into group_invitation(uuid, groupName, role) values(?, ?, ?) on duplicate key update role=values(role), date=now();"; - + private static final String removeGroupInvitation = "delete from group_invitation where uuid = ? and groupName = ?"; - + private static final String loadGroupInvitation = "select role from group_invitation where uuid = ? and groupName = ?"; - + private static final String loadGroupInvitationsForGroup = "select uuid,role from group_invitation where groupName=?"; - - // Gets all unique names (not instances) of groups having this member at that role. - private static final String getGroupNameFromRole = "SELECT DISTINCT faction_id.group_name FROM faction_member " - + "inner join faction_id on faction_member.group_id = faction_id.group_id " - + "WHERE member_name = ? " - + "AND role = ?;"; - - + // updates "most recent" of all groups with a given name. private static final String updateLastTimestamp = "UPDATE faction SET faction.last_timestamp = NOW() " + "WHERE group_name = ?;"; - + // Breaking the pattern. Here we directly access a role based on _group ID_ rather then group_name. TODO: evaluate safety. private static final String getPlayerType = "SELECT role FROM faction_member " + "WHERE group_id = ? " + "AND member_name = ?;"; private static final String logNameChange = "insert into nameLayerNameChanges (uuid,oldName,newName) values(?,?,?);"; private static final String checkForNameChange = "select * from nameLayerNameChanges where uuid=?;"; - - private static final String addPermission = "insert into permissionByGroup(group_id,role,perm_id) select g.group_id, ?, ? from faction_id g where g.group_name = ?;"; + + private static final String addPermission = "insert into permissionByGroup(group_id,role,perm_id) VALUES (?, ?, ?)"; private static final String addPermissionById = "insert into permissionByGroup(group_id,role,perm_id) values(?,?,?);"; - - private static final String addDefaultPermission = "insert into permissionByGroup(group_id,role,perm_id) select group_id,?,? from faction_id group by group_id"; - private static final String getPermission = "select pg.role,pg.perm_id from permissionByGroup pg inner join faction_id fi on fi.group_name=? " - + "where pg.group_id = fi.group_id"; - private static final String removePermission = "delete from permissionByGroup where group_id IN (SELECT group_id FROM faction_id WHERE group_name = ?) and role=? and perm_id=?;"; - private static final String registerPermission = "insert into permissionIdMapping(perm_id,name) values(?,?);"; + private static final String addDefaultPermission = "insert into permissionByGroup(group_id,role,perm_id) select id,?,? from faction group by id"; + + private static final String getPermission = "select pg.role,pg.perm_id from permissionByGroup pg where pg.group_id = ?"; + private static final String removePermission = "delete from permissionByGroup where group_id=? and role=? and perm_id=?;"; + private static final String registerPermission = "insert into permissionIdMapping(perm_id,name) values(?,?);"; private static final String getPermissionMapping = "select * from permissionIdMapping;"; - - private static final String addBlacklistMember = "insert into blacklist(group_id, member_name) select group_id,? from faction_id where group_name=?;"; - private static final String removeBlackListMember = "delete from blacklist WHERE group_id IN (SELECT group_id FROM faction_id WHERE group_name = ?) and member_name=?;"; - private static final String getBlackListMembers = "select b.member_name from blacklist b inner join faction_id fi on fi.group_name=? where b.group_id=fi.group_id;"; - - private static final String getAllGroupIds = "select group_id from faction_id"; + private static final String addBlacklistMember = "insert into blacklist(group_id, member_name) VALUES (?, ?);"; + private static final String removeBlackListMember = "delete from blacklist WHERE group_id=? and member_name=?;"; + private static final String getBlackListMembers = "select b.member_name from blacklist b where b.group_id=?;"; public GroupManagerDao(Logger logger, ManagedDatasource db){ this.logger = logger; this.db = db; } - + /** * Not going to lie, I can't make heads or tails out of half of this. */ public void registerMigrations() { - db.registerMigration(2, true, + db.registerMigration(2, true, "alter table faction drop `version`;", "alter table faction add type int default 0;", "create table faction_id(" @@ -234,7 +198,7 @@ public void registerMigrations() { "insert into permissions (group_id, role, tier) " + "select f.group_id, 'ADMINS', " + "'DOORS CHESTS BLOCKS MODS MEMBERS PASSWORD LIST_PERMS CROPS' " - + "from faction_id f;", + + "from faction_id f;", "insert into permissions (group_id, role, tier) " + "select f.group_id, 'MODS', " + "'DOORS CHESTS BLOCKS MEMBERS CROPS' " @@ -243,8 +207,8 @@ public void registerMigrations() { + "select f.group_id, 'MEMBERS', " + "'DOORS CHESTS' " + "from faction_id f;"); - - db.registerMigration(1, false, + + db.registerMigration(1, false, new Callable() { @Override public Boolean call() { @@ -256,7 +220,7 @@ public void run() { if (g == null) { createGroup(NameLayerPlugin.getSpecialAdminGroup(), null, null); } else { - removeAllMembers(g.getName()); + removeAllMembersLegacy(g.getName()); } } }); @@ -295,27 +259,27 @@ public void run() { "group_id varchar(255) not null," + "sub_group_id varchar(255) not null," + "unique key (group_id, sub_group_id)) charset=latin1;"); - - db.registerMigration(3, false, + + db.registerMigration(3, false, "create table if not exists toggleAutoAccept(" + "uuid varchar(36) not null," + "primary key key_uuid(uuid));"); - db.registerMigration(4, false, + db.registerMigration(4, false, "alter table faction_id add index `faction_id_index` (group_name);"); - db.registerMigration(5, false, + db.registerMigration(5, false, "alter table faction_member add index `faction_member_index` (group_id);"); db.registerMigration(6, false, - "create table if not exists default_group(" + + "create table if not exists default_group(" + "uuid varchar(36) NOT NULL," + "defaultgroup varchar(255) NOT NULL,"+ "primary key key_uuid(uuid))"); db.registerMigration(7, false, - "create table if not exists group_invitation(" + + "create table if not exists group_invitation(" + "uuid varchar(36) NOT NULL," + "groupName varchar(255) NOT NULL,"+ "role varchar(10) NOT NULL default 'MEMBERS'," + @@ -353,9 +317,9 @@ public Boolean call() { } catch (SQLException e) { logger.log(Level.SEVERE, "Failed to get old permissions, things might get a little wonky now.", e); } - + int maxBatch = 100, count = 0, regadd = 0; - + for (Object[] spool : unspool) { int groupId = (int) spool[0]; String role = (String) spool[1]; @@ -370,11 +334,11 @@ public Boolean call() { if (id == null) { //unknown perm, so we register it id = ++maximumId; // prefix mutator! - + permReg.setInt(1, maximumId); permReg.setString(2, p); permReg.addBatch(); // defer insert. - + permIds.put(p, id); regadd ++; } @@ -383,7 +347,7 @@ public Boolean call() { permInit.setInt(3, id); permInit.addBatch(); count ++; - + if (count > maxBatch) { permInit.executeBatch(); // TODO process warnings / errors @@ -396,7 +360,7 @@ public Boolean call() { permInit.executeBatch(); // TODO process warnings / errors } - + if (regadd > 0) { permReg.executeBatch(); // TODO process warnings / errors @@ -414,9 +378,9 @@ public Boolean call() { "alter table faction drop column group_type"); - db.registerMigration(12, false, + db.registerMigration(12, false, "UPDATE faction SET group_name=REPLACE(group_name,'|','');"); - + db.registerMigration(13, false, "drop procedure if exists deletegroupfromtable;", "create definer=current_user procedure deletegroupfromtable(" + @@ -473,16 +437,16 @@ public Boolean call() { + "where fi.group_id = fii.group_id;" + "end;", "drop procedure if exists createGroup;", - "create definer=current_user procedure createGroup(" + + "create definer=current_user procedure createGroup(" + "in group_name varchar(255), " + "in founder varchar(36), " + "in password varchar(255), " + "in discipline_flags int(11)) " + "sql security invoker " + "begin" + - " if (select (count(*) = 0) from faction_id q where q.group_name = group_name) is true then" + + " if (select (count(*) = 0) from faction_id q where q.group_name = group_name) is true then" + " insert into faction_id(group_name) values (group_name); " + - " insert into faction(group_name, founder, password, discipline_flags) values (group_name, founder, password, discipline_flags);" + + " insert into faction(group_name, founder, password, discipline_flags) values (group_name, founder, password, discipline_flags);" + " insert into faction_member (member_name, role, group_id) select founder, 'OWNER', f.group_id from faction_id f where f.group_name = group_name; " + " select f.group_id from faction_id f where f.group_name = group_name; " + " end if; " + @@ -493,8 +457,61 @@ public Boolean call() { "DELETE FROM permissionByGroup " + "WHERE role='" + PlayerType.NOT_BLACKLISTED +"' " + "AND perm_id=(SELECT perm_id FROM permissionIdMapping WHERE name='BASTION_PLACE');"); + + db.registerMigration(15, false, + "ALTER TABLE faction ADD COLUMN id INT NOT NULL FIRST", + "UPDATE faction, faction_id SET faction.id = faction_id.group_id WHERE faction.group_name = faction_id.group_name", + "ALTER TABLE faction DROP PRIMARY KEY", + "ALTER TABLE faction ADD CONSTRAINT UNIQUE KEY (group_name)", + "ALTER TABLE faction ADD PRIMARY KEY (id)", + "ALTER TABLE faction MODIFY id INT NOT NULL AUTO_INCREMENT", + "DROP TABLE faction_id", + "DROP TABLE subgroup", // don't use old values from subgroup as it has been disabled anyway + "ALTER TABLE faction ADD COLUMN (parent_id INT)", + // TODO: ON DELETE SET NULL or ON DELETE CASCADE? If the parent group is deleted, should the child group be unlinked or deleted too? + "ALTER TABLE faction ADD CONSTRAINT FOREIGN KEY (parent_id) REFERENCES faction (id) ON DELETE SET NULL ON UPDATE RESTRICT", + + "drop procedure if exists deletegroupfromtable;", + "create definer=current_user procedure deletegroupfromtable(" + + "in groupId int," + + "in specialAdminGroup int" + + ") sql security invoker begin " + + "delete fm.* from faction_member fm " + + "where fm.group_id = groupId;" + + "delete b.* from blacklist b " + + "where b.group_id = groupId;" + + "delete p.* from permissions p " + + "where p.group_id = groupId;" + + "delete from faction where id = groupId;" + + "end;", + + "drop procedure if exists createGroup;", + "create definer=current_user procedure createGroup(" + + "in group_name varchar(255), " + + "in founder varchar(36), " + + "in password varchar(255), " + + "in discipline_flags int(11)) " + + "sql security invoker " + + "begin" + + "insert into faction(group_name, founder, password, discipline_flags) values (group_name, founder, password, discipline_flags);" + + "insert into faction_member (member_name, role, group_id) select founder, 'OWNER', LAST_INSERT_ID(); " + + "select LAST_INSERT_ID(); " + + "end;", + + "drop procedure if exists mergeintogroup;", + "create definer=current_user procedure mergeintogroup(" + + "in groupName int, in tomerge int) " + + "sql security invoker begin " + + "update ignore faction_member fm " // move all members from group From to To + + "set fm.group_id = groupName " + + "where fm.group_id = tomerge;" + + "DELETE fm.* from faction_member fm " // Remove those "overlap" members left behind by IGNORE + + "where fm.group_id = tomerge;" + + "UPDATE faction SET parent_id = groupName WHERE parent_id = tomerge;" + + "delete from faction where id = tomerge;" + // Remove "faction" record of From + "end;"); } - + public int createGroup(String group, UUID owner, String password){ int ret = -1; try (Connection connection = db.getConnection(); @@ -506,7 +523,7 @@ public int createGroup(String group, UUID owner, String password){ createGroup.setString(3, password); createGroup.setInt(4, 0); try (ResultSet set = createGroup.executeQuery();) { - ret = set.next() ? set.getInt("f.group_id") : -1; + ret = set.next() ? set.getInt(1) : -1; logger.log(Level.INFO, "Created group {0} w/ id {1} for {2}", new Object[] {group, ret, own}); } catch (SQLException e) { logger.log(Level.WARNING, "Problem creating group " + group, e); @@ -516,10 +533,10 @@ public int createGroup(String group, UUID owner, String password){ logger.log(Level.WARNING, "Problem setting up query to create group " + group, e); ret = -1; } - + return ret; } - + public Group getGroup(String groupName){ String name = null; UUID owner = null; @@ -529,13 +546,13 @@ public Group getGroup(String groupName){ Timestamp timeStamp = null; try (Connection connection = db.getConnection(); PreparedStatement getGroup = connection.prepareStatement(GroupManagerDao.getGroup)){ - + getGroup.setString(1, groupName); try (ResultSet set = getGroup.executeQuery()){ if (!set.next()) { return null; } - + name = set.getString(1); String uuid = set.getString(2); owner = (uuid != null) ? UUID.fromString(uuid) : null; @@ -557,11 +574,11 @@ public Group getGroup(String groupName){ } catch (Exception e) { logger.log(Level.WARNING, "Problem retrieving group " + groupName, e); } - + // other group IDs cached via the constructor. return g; } - + public Group getGroup(int groupId){ String name = null; UUID owner = null; @@ -603,7 +620,7 @@ public Group getGroup(int groupId){ return g; } - + public List getGroupNames(UUID uuid){ List groups = new ArrayList(); try (Connection connection = db.getConnection(); @@ -621,26 +638,7 @@ public List getGroupNames(UUID uuid){ } return groups; } - - public List getGroupNames(UUID uuid, String role){ - List groups = new ArrayList(); - try (Connection connection = db.getConnection(); - PreparedStatement getGroupNameFromRole = connection.prepareStatement(GroupManagerDao.getGroupNameFromRole)){ - getGroupNameFromRole.setString(1, uuid.toString()); - getGroupNameFromRole.setString(2, role); - try (ResultSet set = getGroupNameFromRole.executeQuery();) { - while(set.next()) { - groups.add(set.getString(1)); - } - } catch (SQLException e) { - logger.log(Level.WARNING, "Problem getting player " + uuid + " groups by role " + role, e); - } - } catch (SQLException e) { - logger.log(Level.WARNING, "Problem preparing to get player " + uuid + " groups by role " + role, e); - } - return groups; - } - + public PlayerType getPlayerType(int groupid, UUID uuid){ PlayerType ptype = null; try (Connection connection = db.getConnection(); @@ -659,7 +657,7 @@ public PlayerType getPlayerType(int groupid, UUID uuid){ } return ptype; } - + public void updateTimestampAsync(final String group){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @@ -667,10 +665,10 @@ public void updateTimestampAsync(final String group){ public void run() { updateTimestamp(group); } - + }); } - + public void updateTimestamp(String group){ try (Connection connection = db.getConnection(); PreparedStatement updateLastTimestamp = connection.prepareStatement(GroupManagerDao.updateLastTimestamp)){ @@ -680,58 +678,57 @@ public void updateTimestamp(String group){ logger.log(Level.WARNING, "Problem updating timestamp for group " + group, e); } } - - public void deleteGroupAsync(final String groupName){ + + public void deleteGroupAsync(final int groupId){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @Override public void run() { - deleteGroup(groupName); + deleteGroup(groupId); } - + }); } - - public void deleteGroup(String groupName){ + + public void deleteGroup(int groupId){ try (Connection connection = db.getConnection(); PreparedStatement deleteGroup = connection.prepareStatement(GroupManagerDao.deleteGroup)){ - deleteGroup.setString(1, groupName); - deleteGroup.setString(2, NameLayerPlugin.getSpecialAdminGroup()); + deleteGroup.setInt(1, groupId); deleteGroup.executeUpdate(); } catch (SQLException e) { - logger.log(Level.WARNING, "Problem deleting group " + groupName, e); + logger.log(Level.WARNING, "Problem deleting group " + groupId, e); } } - - public void addMemberAsync(final UUID member, final String faction, final PlayerType role){ + + public void addMemberAsync(final UUID member, final int group, final PlayerType role){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @Override public void run() { - addMember(member,faction,role); + addMember(member,group,role); } - + }); } - - public void addMember(UUID member, String faction, PlayerType role){ + + public void addMember(UUID member, int group, PlayerType role){ try (Connection connection = db.getConnection(); PreparedStatement addMember = connection.prepareStatement(GroupManagerDao.addMember)){ - addMember.setString(1, member.toString()); - addMember.setString(2, role.name()); - addMember.setString(3, faction); + addMember.setInt(1, group); + addMember.setString(2, member.toString()); + addMember.setString(3, role.name()); addMember.executeUpdate(); } catch (SQLException e) { - logger.log(Level.WARNING, "Problem adding " + member + " as " + role.toString() - + " to group " + faction, e); - } + logger.log(Level.WARNING, "Problem adding " + member + " as " + role.toString() + + " to group " + group, e); + } } - - public List getAllMembers(String groupName, PlayerType role){ + + public List getAllMembers(int group, PlayerType role){ List members = new ArrayList(); try (Connection connection = db.getConnection(); PreparedStatement getMembers = connection.prepareStatement(GroupManagerDao.getMembers)){ - getMembers.setString(1, groupName); + getMembers.setInt(1, group); getMembers.setString(2, role.name()); try (ResultSet set = getMembers.executeQuery();) { while(set.next()){ @@ -742,159 +739,147 @@ public List getAllMembers(String groupName, PlayerType role){ members.add(UUID.fromString(uuid)); } } catch (SQLException e) { - logger.log(Level.WARNING, "Problem getting all " + role.toString() + " for group " + groupName, e); + logger.log(Level.WARNING, "Problem getting all " + role.toString() + " for group " + group, e); } } catch (SQLException e) { - logger.log(Level.WARNING, "Problem preparing to get all " + role.toString() + " for group " + groupName, e); + logger.log(Level.WARNING, "Problem preparing to get all " + role.toString() + " for group " + group, e); } return members; } - - public void removeMemberAsync(final UUID member, final String group){ + + public void removeMemberAsync(final UUID member, final int group){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @Override public void run() { removeMember(member,group); } - + }); } - - public void removeMember(UUID member, String group){ + + public void removeMember(UUID member, int group){ try (Connection connection = db.getConnection(); PreparedStatement removeMember = connection.prepareStatement(GroupManagerDao.removeMember)){ removeMember.setString(1, member.toString()); - removeMember.setString(2, group); + removeMember.setInt(2, group); removeMember.executeUpdate(); } catch (SQLException e) { logger.log(Level.WARNING, "Problem removing " + member + " from group " + group, e); } } - public void removeAllMembersAsync(final String group){ + public void removeAllMembersAsync(final int group){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @Override public void run() { removeAllMembers(group); } - + }); } - - public void removeAllMembers(String group){ + + public void removeAllMembers(int group){ try (Connection connection = db.getConnection(); PreparedStatement removeAllMembers = connection.prepareStatement(GroupManagerDao.removeAllMembers)){ + removeAllMembers.setInt(1, group); + removeAllMembers.executeUpdate(); + } catch (SQLException e) { + logger.log(Level.WARNING, "Problem removing all members from group " + group, e); + } + } + + private void removeAllMembersLegacy(String group){ + try (Connection connection = db.getConnection(); + PreparedStatement removeAllMembers = connection.prepareStatement(GroupManagerDao.removeAllMembersLegacy)){ removeAllMembers.setString(1, group); removeAllMembers.executeUpdate(); } catch (SQLException e) { logger.log(Level.WARNING, "Problem removing all members from group " + group, e); } } - - public void addSubGroupAsync(final String group, final String subGroup){ + + public void addSubGroupAsync(final int group, final int subGroup){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @Override public void run() { addSubGroup(group,subGroup); } - + }); } - - public void addSubGroup(String group, String subGroup){ - try (Connection connection = db.getConnection(); - PreparedStatement addSubGroup = connection.prepareStatement(GroupManagerDao.addSubGroup)){ - addSubGroup.setString(1, subGroup); - addSubGroup.setString(2, group); - addSubGroup.executeUpdate(); + + public void addSubGroup(int group, int subGroup){ + try (Connection connection = db.getConnection()){ + connection.setAutoCommit(false); + PreparedStatement detectCyclesStatement = connection.prepareStatement(GroupManagerDao.detectCycles); + detectCyclesStatement.setInt(1, subGroup); + detectCyclesStatement.setInt(2, group); + if (detectCyclesStatement.executeQuery().next()) { + throw new IllegalStateException("Cannot create sub group with parent " + group + " and child " + subGroup + "; would create a cycle."); + } + + PreparedStatement addSubGroupStatement = connection.prepareStatement(GroupManagerDao.addSubGroup); + addSubGroupStatement.setInt(1, group); + addSubGroupStatement.setInt(2, subGroup); + addSubGroupStatement.executeUpdate(); + connection.commit(); } catch (SQLException e) { logger.log(Level.WARNING, "Problem adding subgroup " + subGroup + " to group " + group, e); } - removeCycles(); } - - public List getSubGroups(String group){ + + public List getSubGroups(int group){ List groups = new ArrayList(); - List subgroups = Lists.newArrayList(); + List subgroups = Lists.newArrayList(); try (Connection connection = db.getConnection(); PreparedStatement getSubGroups = connection.prepareStatement(GroupManagerDao.getSubGroups)){ - getSubGroups.setString(1, group); - + getSubGroups.setInt(1, group); + try (ResultSet set = getSubGroups.executeQuery();){ while (set.next()) { - subgroups.add(set.getString(1)); + subgroups.add(set.getInt(1)); } - } + } } catch (SQLException e) { logger.log(Level.WARNING, "Problem getting subgroups for group " + group, e); } - for (String groupname : subgroups) { - Group g = null; - if (GroupManager.hasGroup(groupname)) { - g = GroupManager.getGroup(groupname); - } else { - g = getGroup(groupname); - } - + for (Integer groupid : subgroups) { + Group g = GroupManager.getGroup(groupid); + if (g != null) { groups.add(g); } } return groups; } - - public Group getSuperGroup(String group){ - String supergroup = null; - try (Connection connection = db.getConnection(); - PreparedStatement getSuperGroup = connection.prepareStatement(GroupManagerDao.getSuperGroup)){ - getSuperGroup.setString(1, group); - try (ResultSet set = getSuperGroup.executeQuery();) { - if (!set.next()) { - return null; - } - supergroup = set.getString(1); - } catch (Exception e){ - logger.log(Level.WARNING, "Problem finding or getting superGroup for group " + group, e); - return null; - } - } catch (SQLException e) { - logger.log(Level.WARNING, "Problem getting superGroup for group " + group, e); - return null; - } - if (GroupManager.hasGroup(supergroup)) { - return GroupManager.getGroup(supergroup); - } else { - return getGroup(supergroup); - } - } - - public void removeSubGroupAsync(final String group, final String subgroup){ + + public void removeSubGroupAsync(final int group, final int subgroup){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @Override public void run() { removeSubGroup(group,subgroup); } - + }); } - - public void removeSubGroup(String group, String subGroup){ + + public void removeSubGroup(int group, int subGroup){ try (Connection connection = db.getConnection(); PreparedStatement removeSubGroup = connection.prepareStatement(GroupManagerDao.removeSubGroup)){ - removeSubGroup.setString(1, group); - removeSubGroup.setString(2, subGroup); + removeSubGroup.setInt(1, group); + removeSubGroup.setInt(2, subGroup); removeSubGroup.executeUpdate(); } catch (SQLException e) { logger.log(Level.WARNING, "Removing subgroup " + subGroup + " from group " + group, e); } } - + public void addAllPermissions(int groupId, Map > perms) { try (Connection connection = db.getConnection(); PreparedStatement addPermissionById = connection.prepareStatement(GroupManagerDao.addPermissionById)){ @@ -907,7 +892,7 @@ public void addAllPermissions(int groupId, Map perms){ + + public void addPermissionAsync(final int group, final String role, final List perms){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @Override public void run() { - addPermission(gname,role,perms); + addPermission(group,role,perms); } - + }); } - public void addPermission(String groupName, String role, List perms) { + public void addPermission(int group, String role, List perms) { try (Connection connection = db.getConnection(); PreparedStatement addPermission = connection.prepareStatement(GroupManagerDao.addPermission)){ for(PermissionType perm : perms) { - addPermission.setString(1, role); - addPermission.setInt(2, perm.getId()); - addPermission.setString(3, groupName); + addPermission.setInt(1, group); + addPermission.setString(2, role); + addPermission.setInt(3, perm.getId()); addPermission.addBatch(); } int[] res = addPermission.executeBatch(); if (res == null) { logger.log(Level.WARNING, "Failed to add all permissions to group {0}, role {1}", - new Object[] {groupName, role} ); + new Object[] {group, role} ); } else { int cnt = 0; for (int r : res) cnt += r; logger.log(Level.INFO, "Added {0} of {1} permissions to group {2}, role {3}", - new Object[] {cnt, res.length, groupName, role}); + new Object[] {cnt, res.length, group, role}); } } catch (SQLException e) { logger.log(Level.WARNING, "Problem adding " + role + " with " + perms - + " to group " + groupName, e); + + " to group " + group, e); } } - - public Map> getPermissions(String group){ + + public Map> getPermissions(int group){ Map> perms = new HashMap<>(); try (Connection connection = db.getConnection(); PreparedStatement getPermission = connection.prepareStatement(GroupManagerDao.getPermission)){ - getPermission.setString(1, group); + getPermission.setInt(1, group); try (ResultSet set = getPermission.executeQuery();) { while(set.next()){ PlayerType type = PlayerType.getPlayerType(set.getString(1)); @@ -985,22 +970,22 @@ public Map> getPermissions(String group){ } return perms; } - - public void removePermissionAsync(final String group, final PlayerType ptype, final PermissionType perm){ + + public void removePermissionAsync(final int group, final PlayerType ptype, final PermissionType perm){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @Override public void run() { removePermission(group,ptype,perm); } - + }); } - - public void removePermission(String group, PlayerType pType, PermissionType perm){ + + public void removePermission(int group, PlayerType pType, PermissionType perm){ try (Connection connection = db.getConnection(); PreparedStatement removePermission = connection.prepareStatement(GroupManagerDao.removePermission)){ - removePermission.setString(1, group); + removePermission.setInt(1, group); removePermission.setString(2, pType.name()); removePermission.setInt(3, perm.getId()); removePermission.executeUpdate(); @@ -1009,7 +994,7 @@ public void removePermission(String group, PlayerType pType, PermissionType perm + " on playertype " + pType.name(), e); } } - + public void registerPermissionAsync(final PermissionType perm){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @@ -1017,10 +1002,10 @@ public void registerPermissionAsync(final PermissionType perm){ public void run() { registerPermission(perm); } - + }); } - + public void registerPermission(PermissionType perm) { try (Connection connection = db.getConnection(); PreparedStatement registerPermission = connection.prepareStatement(GroupManagerDao.registerPermission)){ @@ -1031,7 +1016,7 @@ public void registerPermission(PermissionType perm) { logger.log(Level.WARNING, "Problem register permission " + perm.getName(), e); } } - + public Map getPermissionMapping() { Map perms = new TreeMap(); try (Connection connection = db.getConnection(); @@ -1048,7 +1033,7 @@ public Map getPermissionMapping() { } return perms; } - + public void addNewDefaultPermissionAsync(final List ptypes, final PermissionType perm){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @@ -1056,10 +1041,10 @@ public void addNewDefaultPermissionAsync(final List ptypes, final P public void run() { addNewDefaultPermission(ptypes,perm); } - + }); } - + public void addNewDefaultPermission(List playerTypes, PermissionType perm) { try (Connection connection = db.getConnection(); PreparedStatement addPermissionById = connection.prepareStatement(GroupManagerDao.addDefaultPermission);) {; @@ -1067,12 +1052,12 @@ public void addNewDefaultPermission(List playerTypes, PermissionTyp addPermissionById.setString(1, pType.name()); addPermissionById.setInt(2, perm.getId()); addPermissionById.execute(); - } + } } catch (SQLException e) { logger.log(Level.WARNING, "Error initiating connection to set default perms for permission " + perm + " for player types " + playerTypes, e); } } - + public int countGroups(){ int ret = 0; try (Connection connection = db.getConnection(); @@ -1084,7 +1069,7 @@ public int countGroups(){ } return ret; } - + public int countGroups(UUID uuid){ int ret = 0; try (Connection connection = db.getConnection(); @@ -1094,47 +1079,44 @@ public int countGroups(UUID uuid){ ret = set.next() ? set.getInt("count") : 0; } catch (SQLException e) { logger.log(Level.WARNING, "Problem counting groups for " + uuid, e); - } + } } catch (SQLException e) { logger.log(Level.WARNING, "Problem setting up statement to count groups for " + uuid, e); } return ret; - + } - - public void mergeGroupAsync(final String groupname, final String tomerge){ + + public void mergeGroupAsync(final int groupname, final int tomerge){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @Override public void run() { mergeGroup(groupname,tomerge); } - + }); } - - public void mergeGroup(String groupName, String toMerge){ - try (Connection connection = db.getConnection(); - PreparedStatement mergeGroup = connection.prepareStatement(GroupManagerDao.mergeGroup);){ - mergeGroup.setString(1, groupName); - mergeGroup.setString(2, toMerge); + + public boolean mergeGroup(int group, int toMerge){ + try (Connection connection = db.getConnection()) { + connection.setAutoCommit(false); + + Bukkit.getPluginManager().callEvent(new AsyncGroupMergeEvent(group, toMerge, connection)); + + PreparedStatement mergeGroup = connection.prepareStatement(GroupManagerDao.mergeGroup); + mergeGroup.setInt(1, group); + mergeGroup.setInt(2, toMerge); mergeGroup.execute(); + + connection.commit(); + return true; } catch (SQLException e) { - logger.log(Level.WARNING, "Problem merging group " + toMerge + " into " + groupName, e); - } - removeCycles(); - } - - public void removeCycles() { - try (Connection connection = db.getConnection(); - PreparedStatement removeCycles = connection.prepareStatement(GroupManagerDao.removeCycles);) { - int removed = removeCycles.executeUpdate(); - logger.log(Level.INFO, "Removed {0} subgroup cycles", removed); - } catch (SQLException e) { - logger.log(Level.WARNING, "Failed to execute cycle removal code!"); + logger.log(Level.WARNING, "Problem merging group " + toMerge + " into " + group, e); + return false; } } - + public void updatePasswordAsync(final String groupname, final String password){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @@ -1142,10 +1124,10 @@ public void updatePasswordAsync(final String groupname, final String password){ public void run() { updatePassword(groupname,password); } - + }); } - + public void updatePassword(String groupName, String password){ try (Connection connection = db.getConnection(); PreparedStatement updatePassword = connection.prepareStatement(GroupManagerDao.updatePassword);){ @@ -1156,10 +1138,10 @@ public void updatePassword(String groupName, String password){ logger.log(Level.WARNING, "Problem updating password for group " + groupName, e); } } - + /** * Loads the uuid of all players who have autoaccept for group invites turned on - * + * * @return All Players who have auto accept turned on */ public Set loadAllAutoAccept() { @@ -1170,13 +1152,13 @@ public Set loadAllAutoAccept() { while (rs.next()) { accepts.add(UUID.fromString(rs.getString(1))); } - + } catch (SQLException e) { logger.log(Level.WARNING, "Problem loading all autoaccepts", e); } return accepts; } - + /** * Adds the uuid to the db if they should auto accept groups when invited. * @param uuid sets up this player by uuid to accept groups async @@ -1190,7 +1172,7 @@ public void run() { } }); } - + public void autoAcceptGroups(final UUID uuid){ try (Connection connection = db.getConnection(); PreparedStatement addAutoAcceptGroup = connection.prepareStatement(GroupManagerDao.addAutoAcceptGroup);){ @@ -1200,7 +1182,7 @@ public void autoAcceptGroups(final UUID uuid){ logger.log(Level.WARNING, "Problem setting autoaccept for " + uuid, e); } } - + /** * @param uuid- The UUID of the player. * @return Returns true if they should auto accept. @@ -1220,7 +1202,7 @@ public boolean shouldAutoAcceptGroups(UUID uuid){ } return false; } - + public void removeAutoAcceptGroupAsync(final UUID uuid){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @@ -1230,7 +1212,7 @@ public void run() { } }); } - + public void removeAutoAcceptGroup(final UUID uuid){ try (Connection connection = db.getConnection(); PreparedStatement removeAutoAcceptGroup = connection.prepareStatement(GroupManagerDao.removeAutoAcceptGroup);){ @@ -1240,7 +1222,7 @@ public void removeAutoAcceptGroup(final UUID uuid){ logger.log(Level.WARNING, "Problem removing autoaccept for " + uuid, e); } } - + public void setDefaultGroupAsync(final UUID uuid, final String groupname){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @@ -1248,10 +1230,10 @@ public void setDefaultGroupAsync(final UUID uuid, final String groupname){ public void run() { setDefaultGroup(uuid,groupname); } - + }); } - + public void setDefaultGroup(UUID uuid, String groupName){ try (Connection connection = db.getConnection(); PreparedStatement setDefaultGroup = connection.prepareStatement(GroupManagerDao.setDefaultGroup);){ @@ -1262,7 +1244,7 @@ public void setDefaultGroup(UUID uuid, String groupName){ logger.log(Level.WARNING, "Problem setting user " + uuid + " default group to " + groupName, e); } } - + public void changeDefaultGroupAsync(final UUID uuid, final String groupname){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @@ -1270,10 +1252,10 @@ public void changeDefaultGroupAsync(final UUID uuid, final String groupname){ public void run() { changeDefaultGroup(uuid,groupname); } - + }); } - + public void changeDefaultGroup(UUID uuid, String groupName){ try (Connection connection = db.getConnection(); PreparedStatement changeDefaultGroup = connection.prepareStatement(GroupManagerDao.changeDefaultGroup);){ @@ -1300,7 +1282,7 @@ public String getDefaultGroup(UUID uuid) { } return group; } - + public Map getAllDefaultGroups() { Map groups = null; try (Connection connection = db.getConnection(); @@ -1317,7 +1299,7 @@ public Map getAllDefaultGroups() { } return groups; } - + /** * Use this method to override the current founder of a group. * @param uuid This is the uuid of the player. @@ -1330,10 +1312,10 @@ public void setFounderAsync(final UUID uuid, final Group group){ public void run() { setFounder(uuid,group); } - + }); } - + public void setFounder(UUID uuid, Group group) { try (Connection connection = db.getConnection(); PreparedStatement updateOwner = connection.prepareStatement(GroupManagerDao.updateOwner);){ @@ -1344,7 +1326,7 @@ public void setFounder(UUID uuid, Group group) { logger.log(Level.WARNING, "Problem setting founder of group " + group.getName() + " to " + uuid, e); } } - + public void setDisciplinedAsync(final Group group, final boolean disciplined){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @@ -1352,10 +1334,10 @@ public void setDisciplinedAsync(final Group group, final boolean disciplined){ public void run() { setDisciplined(group,disciplined); } - + }); } - + public void setDisciplined(Group group, boolean disciplined) { try (Connection connection = db.getConnection(); PreparedStatement updateDisciplined = connection.prepareStatement(GroupManagerDao.updateDisciplined);){ @@ -1363,12 +1345,12 @@ public void setDisciplined(Group group, boolean disciplined) { updateDisciplined.setString(2, group.getName()); updateDisciplined.executeUpdate(); } catch (SQLException e) { - logger.log(Level.WARNING, "Problem setting disciplined of group " + group.getName() + logger.log(Level.WARNING, "Problem setting disciplined of group " + group.getName() + " to " + disciplined, e); } } - + public void addGroupInvitationAsync(final UUID uuid, final String groupName, final String role){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @@ -1376,10 +1358,10 @@ public void addGroupInvitationAsync(final UUID uuid, final String groupName, fin public void run() { addGroupInvitation(uuid,groupName,role); } - + }); } - + public void addGroupInvitation(UUID uuid, String groupName, String role){ try (Connection connection = db.getConnection(); PreparedStatement addGroupInvitation = connection.prepareStatement(GroupManagerDao.addGroupInvitation);){ @@ -1392,7 +1374,7 @@ public void addGroupInvitation(UUID uuid, String groupName, String role){ + uuid + " with role " + role, e); } } - + public void removeGroupInvitationAsync(final UUID uuid, final String groupName){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @@ -1400,10 +1382,10 @@ public void removeGroupInvitationAsync(final UUID uuid, final String groupName){ public void run() { removeGroupInvitation(uuid,groupName); } - + }); } - + public void removeGroupInvitation(UUID uuid, String groupName){ try (Connection connection = db.getConnection(); PreparedStatement removeGroupInvitation = connection.prepareStatement(GroupManagerDao.removeGroupInvitation);){ @@ -1415,12 +1397,12 @@ public void removeGroupInvitation(UUID uuid, String groupName){ + uuid, e); } } - - + + /** - * Use this method to load a specific invitation to a group without the notification. + * Use this method to load a specific invitation to a group without the notification. * @param playerUUID The uuid of the invited player. - * @param group The group the player was invited to. + * @param group The group the player was invited to. */ public void loadGroupInvitationAsync(final UUID playerUUID, final Group group){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @@ -1429,13 +1411,13 @@ public void loadGroupInvitationAsync(final UUID playerUUID, final Group group){ public void run() { loadGroupInvitation(playerUUID, group); } - + }); } - + public void loadGroupInvitation(UUID playerUUID, Group group){ if(group == null) return; - + try (Connection connection = db.getConnection(); PreparedStatement loadGroupInvitation = connection.prepareStatement(GroupManagerDao.loadGroupInvitation);){ loadGroupInvitation.setString(1, playerUUID.toString()); @@ -1453,11 +1435,11 @@ public void loadGroupInvitation(UUID playerUUID, Group group){ logger.log(Level.WARNING, "Problem loading group " + group.getName() + " invites for " + playerUUID, e); } } catch(SQLException e) { - logger.log(Level.WARNING, "Problem preparing query to load group " + group.getName() + + logger.log(Level.WARNING, "Problem preparing query to load group " + group.getName() + " invites for " + playerUUID, e); } } - + public Map getInvitesForGroup(String groupName) { Map invs = new TreeMap(); if (groupName == null) { @@ -1490,7 +1472,7 @@ public Map getInvitesForGroup(String groupName) { } return invs; } - + /** * Use this method to load all invitations to all groups. */ @@ -1515,7 +1497,7 @@ public void loadGroupsInvitations(){ if(role != null){ type = PlayerType.getPlayerType(role); } - + if(g != null){ g.addInvite(playerUUID, type, false); PlayerListener.addNotification(playerUUID, g); @@ -1525,7 +1507,7 @@ public void loadGroupsInvitations(){ logger.log(Level.WARNING, "Problem loading all group invitations", e); } } - + public void logNameChangeAsync(final UUID uuid, final String oldName, final String newName){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @@ -1533,10 +1515,10 @@ public void logNameChangeAsync(final UUID uuid, final String oldName, final Stri public void run() { logNameChange(uuid,oldName,newName); } - + }); } - + public void logNameChange(UUID uuid, String oldName, String newName) { try (Connection connection = db.getConnection(); PreparedStatement logNameChange = connection.prepareStatement(GroupManagerDao.logNameChange);){ @@ -1549,118 +1531,84 @@ public void logNameChange(UUID uuid, String oldName, String newName) { logger.log(Level.WARNING, "Exception during change.", e); } } - + public boolean hasChangedNameBefore(UUID uuid) { boolean ret = false; try (Connection connection = db.getConnection(); PreparedStatement checkForNameChange = connection.prepareStatement(GroupManagerDao.checkForNameChange);){ checkForNameChange.setString(1, uuid.toString()); - try (ResultSet set = checkForNameChange.executeQuery();) { + try (ResultSet set = checkForNameChange.executeQuery();) { ret = set.next(); } catch (SQLException e) { logger.log(Level.WARNING, "Failed to check if " + uuid + " has previously changed names", e); - } + } } catch (SQLException e) { logger.log(Level.WARNING, "Failed to check if {0} has previously changed names", uuid); logger.log(Level.WARNING, "Exception during check.", e); } return ret; } - - public void addBlackListMemberAsync(final String groupName, final UUID uuid){ + + public void addBlackListMemberAsync(final int group, final UUID uuid){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @Override public void run() { - addBlackListMember(groupName,uuid); + addBlackListMember(group,uuid); } - + }); } - - public void addBlackListMember(String groupName, UUID player) { + + public void addBlackListMember(int group, UUID player) { try (Connection connection = db.getConnection(); PreparedStatement addBlacklistMember = connection.prepareStatement(GroupManagerDao.addBlacklistMember);){ - addBlacklistMember.setString(1, player.toString()); - addBlacklistMember.setString(2, groupName); + addBlacklistMember.setInt(1, group); + addBlacklistMember.setString(2, player.toString()); addBlacklistMember.executeUpdate(); } catch(SQLException e) { - logger.log(Level.WARNING, "Unable to add black list member " + player + " to group " + groupName, e); + logger.log(Level.WARNING, "Unable to add black list member " + player + " to group " + group, e); } } - - public void removeBlackListMemberAsync(final String gname, final UUID uuid){ + + public void removeBlackListMemberAsync(final int group, final UUID uuid){ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable(){ @Override public void run() { - removeBlackListMember(gname,uuid); + removeBlackListMember(group,uuid); } - + }); } - - public void removeBlackListMember(String groupName, UUID player) { + + public void removeBlackListMember(int group, UUID player) { try (Connection connection = db.getConnection(); PreparedStatement removeBlackListMember = connection.prepareStatement(GroupManagerDao.removeBlackListMember);){ - removeBlackListMember.setString(1, groupName); + removeBlackListMember.setInt(1, group); removeBlackListMember.setString(2, player.toString()); removeBlackListMember.executeUpdate(); } catch(SQLException e) { - logger.log(Level.WARNING, "Unable to remove black list member " + player + " to group " + groupName, e); + logger.log(Level.WARNING, "Unable to remove black list member " + player + " to group " + group, e); } } - - public Set getBlackListMembers(String groupName) { + + public Set getBlackListMembers(int group) { Set uuids = new HashSet(); try (Connection connection = db.getConnection(); PreparedStatement getBlackListMembers = connection.prepareStatement(GroupManagerDao.getBlackListMembers);){ - getBlackListMembers.setString(1, groupName); + getBlackListMembers.setInt(1, group); try (ResultSet set = getBlackListMembers.executeQuery();) { while (set.next()) { uuids.add(UUID.fromString(set.getString(1))); } } catch (SQLException e) { - logger.log(Level.WARNING, "Unable to retrieve black list members for group " + groupName, e); + logger.log(Level.WARNING, "Unable to retrieve black list members for group " + group, e); } } catch (SQLException e) { - logger.log(Level.WARNING, "Unable to prepare query to retrieve black list members for group " + groupName, e); + logger.log(Level.WARNING, "Unable to prepare query to retrieve black list members for group " + group, e); } return uuids; } - /** - * Gets all the IDs for this group name, sorted by "size" in membercount. - * Ideally only one groupname/id has members and the rest are shadows, but in any case - * we arbitrarily define primacy as the one with the most members for ease of accounting - * and backwards compatibility. - * - * @param groupName the group name to get IDs for - * @return the list of IDs for this group name - */ - public List getAllIDs(String groupName) { - if (groupName == null) { - return null; - } - try (Connection connection = db.getConnection(); - PreparedStatement getGroupIDs = connection.prepareStatement(GroupManagerDao.getGroupIDs);){ - getGroupIDs.setString(1, groupName); - try (ResultSet set = getGroupIDs.executeQuery();) { - List ids = new ArrayList<>(); - - while (set.next()) { - ids.add(set.getInt(1)); - } - - return ids; - } catch (SQLException se) { - logger.log(Level.WARNING, "Unable to fully load group ID set", se); - } - } catch (SQLException se) { - logger.log(Level.WARNING, "Unable to prepare query to fully load group ID set", se); - } - return null; - } - - } diff --git a/paper/src/main/java/vg/civcraft/mc/namelayer/events/AsyncGroupMergeEvent.java b/paper/src/main/java/vg/civcraft/mc/namelayer/events/AsyncGroupMergeEvent.java new file mode 100644 index 00000000..5dc6da0c --- /dev/null +++ b/paper/src/main/java/vg/civcraft/mc/namelayer/events/AsyncGroupMergeEvent.java @@ -0,0 +1,43 @@ +package vg.civcraft.mc.namelayer.events; + +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +import java.sql.Connection; + +public class AsyncGroupMergeEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + private final Connection connection; // the connection currently running the transaction, an error will cause the whole merge to rollback + private final int beingMerged; // the group that will join into another + private final int mergingInto; // the group that is receiving the other + + public AsyncGroupMergeEvent(int group, int toBeMerged, Connection connection) { + super(true); + this.mergingInto = group; + this.beingMerged = toBeMerged; + this.connection = connection; + } + /** + * @return Returns the group to be merged. + */ + public int getToBeMerged(){ + return beingMerged; + } + /** + * @return Returns the group that will be left after the merging. + */ + public int getMergingInto(){ + return mergingInto; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/paper/src/main/java/vg/civcraft/mc/namelayer/group/BlackList.java b/paper/src/main/java/vg/civcraft/mc/namelayer/group/BlackList.java index befa7cc9..5d141fd7 100644 --- a/paper/src/main/java/vg/civcraft/mc/namelayer/group/BlackList.java +++ b/paper/src/main/java/vg/civcraft/mc/namelayer/group/BlackList.java @@ -8,34 +8,34 @@ import vg.civcraft.mc.namelayer.NameLayerPlugin; public class BlackList { - private Map> blackListsByGroupName; + private Map> blacklistsByGroup; public BlackList() { - blackListsByGroupName = new HashMap>(); + blacklistsByGroup = new HashMap<>(); } public Set getBlacklist(Group g) { - return getBlacklist(g.getName()); + return getBlacklist(g.getGroupId()); } - public Set getBlacklist(String groupName) { - Set black = blackListsByGroupName.get(groupName); + public Set getBlacklist(int group) { + Set black = blacklistsByGroup.get(group); if (black == null) { - loadBlacklistMembersFromDb(groupName); - black = blackListsByGroupName.get(groupName); + loadBlacklistMembersFromDb(group); + black = blacklistsByGroup.get(group); } return black; } public boolean isBlacklisted(Group group, UUID uuid) { - return isBlacklisted(group.getName(), uuid); + return isBlacklisted(group.getGroupId(), uuid); } - public boolean isBlacklisted(String groupName, UUID uuid) { - Set ids = blackListsByGroupName.get(groupName); + public boolean isBlacklisted(int group, UUID uuid) { + Set ids = blacklistsByGroup.get(group); if (ids == null) { - loadBlacklistMembersFromDb(groupName); - ids = blackListsByGroupName.get(groupName); + loadBlacklistMembersFromDb(group); + ids = blacklistsByGroup.get(group); } if (ids != null && ids.contains(uuid)) { return true; @@ -43,52 +43,52 @@ public boolean isBlacklisted(String groupName, UUID uuid) { return false; } - public void loadBlacklistMembersFromDb(String groupName) { - blackListsByGroupName.put(groupName, NameLayerPlugin.getGroupManagerDao().getBlackListMembers(groupName)); + public void loadBlacklistMembersFromDb(int group) { + blacklistsByGroup.put(group, NameLayerPlugin.getGroupManagerDao().getBlackListMembers(group)); } - public void initEmptyBlackList(String groupName) { - blackListsByGroupName.put(groupName, new HashSet()); + public void initEmptyBlackList(int group) { + blacklistsByGroup.put(group, new HashSet()); } public void addBlacklistMember(Group group, UUID uuid, boolean writeToDb) { - addBlacklistMember(group.getName(), uuid, writeToDb); + addBlacklistMember(group.getGroupId(), uuid, writeToDb); } - public void addBlacklistMember(String groupName, UUID uuid, boolean writeToDb) { - Set ids = blackListsByGroupName.get(groupName); + public void addBlacklistMember(int group, UUID uuid, boolean writeToDb) { + Set ids = blacklistsByGroup.get(group); if (ids == null) { - loadBlacklistMembersFromDb(groupName); - ids = blackListsByGroupName.get(groupName); + loadBlacklistMembersFromDb(group); + ids = blacklistsByGroup.get(group); } if (ids != null && !ids.contains(uuid)) { ids.add(uuid); if (writeToDb) { - NameLayerPlugin.getGroupManagerDao().addBlackListMember(groupName, uuid); + NameLayerPlugin.getGroupManagerDao().addBlackListMember(group, uuid); } } } public void removeBlacklistMember(Group group, UUID uuid, boolean writeToDb) { - removeBlacklistMember(group.getName(), uuid, writeToDb); + removeBlacklistMember(group.getGroupId(), uuid, writeToDb); } - public void removeBlacklistMember(String groupName, UUID uuid, boolean writeToDb) { - Set ids = blackListsByGroupName.get(groupName); + public void removeBlacklistMember(int group, UUID uuid, boolean writeToDb) { + Set ids = blacklistsByGroup.get(group); if (ids == null) { - loadBlacklistMembersFromDb(groupName); - ids = blackListsByGroupName.get(groupName); + loadBlacklistMembersFromDb(group); + ids = blacklistsByGroup.get(group); } if (ids != null && ids.contains(uuid)) { ids.remove(uuid); if (writeToDb) { - NameLayerPlugin.getGroupManagerDao().removeBlackListMember(groupName, uuid); + NameLayerPlugin.getGroupManagerDao().removeBlackListMember(group, uuid); } } } public void removeFromCache(String groupName) { - blackListsByGroupName.remove(groupName); + blacklistsByGroup.remove(groupName); } } diff --git a/paper/src/main/java/vg/civcraft/mc/namelayer/group/Group.java b/paper/src/main/java/vg/civcraft/mc/namelayer/group/Group.java index 403357c3..79840aff 100644 --- a/paper/src/main/java/vg/civcraft/mc/namelayer/group/Group.java +++ b/paper/src/main/java/vg/civcraft/mc/namelayer/group/Group.java @@ -26,71 +26,61 @@ public class Group { private boolean isDisciplined; // if true, prevents any interactions with this group private boolean isValid = true; // if false, then group has recently been deleted and is invalid private int id; - private Set ids = Sets.newConcurrentHashSet(); - + private Group supergroup; private Set subgroups = Sets.newConcurrentHashSet(); private Map players = Maps.newHashMap(); private Map invites = Maps.newHashMap(); private long activityTimestamp; - - public Group(String name, UUID owner, boolean disciplined, + + public Group(String name, UUID owner, boolean disciplined, String password, int id, long activityTimestamp) { if (db == null) { db = NameLayerPlugin.getGroupManagerDao(); } - + this.name = name; this.password = password; this.owner = owner; this.isDisciplined = disciplined; this.activityTimestamp = activityTimestamp; - + if (name == null) { - this.ids.add(id); this.id = id; return; } - + for (PlayerType permission : PlayerType.values()) { - List list = db.getAllMembers(name, permission); + List list = db.getAllMembers(id, permission); for (UUID uuid : list) { players.put(uuid, permission); } } - - // This returns list of ids w/ id holding largest # of players at top. - List allIds = db.getAllIDs(name); - if (allIds != null && allIds.size() > 0) { - this.ids.addAll(allIds); - this.id = allIds.get(0); // default "root" id is the one with the players. - } else { - this.ids.add(id); - this.id = id; // otherwise just use what we're given - } - + + this.id = id; + // only get subgroups, supergroups will set themselves - for (Group subgroup : GroupManager.getSubGroups(name)) { + for (Group subgroup : GroupManager.getSubGroups(id)) { link(this, subgroup, false); } } - + public long getActivityTimeStamp() { return activityTimestamp; } - + public void updateActivityTimeStamp() { this.activityTimestamp = System.currentTimeMillis(); db.updateTimestampAsync(name); } - + public void prepareForDeletion() { unlink(supergroup, this); for (Group subgroup : subgroups) { unlink(this, subgroup); } } - + /** * Returns all the uuids of the members in this group. * @return Returns all the uuids. @@ -98,7 +88,7 @@ public void prepareForDeletion() { public List getAllMembers() { return Lists.newArrayList(players.keySet()); } - + /** * Returns all the UUIDS of a group's PlayerType. * @param type- The PlayerType of a group that you want the UUIDs of. @@ -113,18 +103,18 @@ public List getAllMembers(PlayerType type) { } return uuids; } - + /** * Gives the uuids of the members whose name starts with the given * String, this is not case-sensitive - * + * * @param prefix start of the players name * @return list of all players whose name starts with the given string */ public List getMembersByName(String prefix) { List uuids = Lists.newArrayList(); List members = getAllMembers(); - + prefix = prefix.toLowerCase(); for (UUID member : members) { String name = NameAPI.getCurrentName(member); @@ -134,10 +124,10 @@ public List getMembersByName(String prefix) { } return uuids; } - + /** * Gives the uuids of players who are in this group and whos name is - * within the given range. + * within the given range. * @param lowerLimit lexicographically lowest acceptable name * @param upperLimit lexicographically highest acceptable name * @return list of uuids of all players in the group whose name is within the given range @@ -145,17 +135,17 @@ public List getMembersByName(String prefix) { public List getMembersInNameRange(String lowerLimit, String upperLimit) { List uuids = Lists.newArrayList(); List members = getAllMembers(); - + for (UUID member : members) { String name = NameAPI.getCurrentName(member); - if (name.compareToIgnoreCase(lowerLimit) >= 0 + if (name.compareToIgnoreCase(lowerLimit) >= 0 && name.compareToIgnoreCase(upperLimit) <= 0) { uuids.add(member); } } return uuids; } - + /** * Gives a list of the members of this group, excluding the inherited members. * @return List of UUIDs of the current players in this group @@ -163,10 +153,10 @@ public List getMembersInNameRange(String lowerLimit, String upperLimit) { public List getCurrentMembers() { return Lists.newArrayList(players.keySet()); } - + public List getCurrentMembers(PlayerType rank) { List uuids = Lists.newArrayList(); - + for (Map.Entry entry : players.entrySet()) { if (entry.getValue() == rank) { uuids.add(entry.getKey()); @@ -174,14 +164,14 @@ public List getCurrentMembers(PlayerType rank) { } return uuids; } - + /** * @return Returns the SubGroups in this group. */ public List getSubgroups() { return Lists.newArrayList(subgroups); } - + /** * Checks if a sub group is on a group. * @param group- The SubGroup. @@ -190,21 +180,21 @@ public List getSubgroups() { public boolean hasSubGroup(Group group){ return subgroups.contains(group); } - + /** * @return Returns the SubGroup for this group if there is one, null otherwise. */ public Group getSuperGroup() { return supergroup; } - + /** * @return Returns if this group has a super group or not. */ public boolean hasSuperGroup() { return supergroup != null; } - + /** * Checks if the given Group is a supergroup of this group and this * group's supergroups. @@ -219,7 +209,7 @@ public boolean hasSuperGroup(Group group) { } return supergroup.hasSuperGroup(group); } - + /** * Adds the player to be allowed to join a group into a specific PlayerType. * @param uuid- The UUID of the player. @@ -228,12 +218,12 @@ public boolean hasSuperGroup(Group group) { public void addInvite(UUID uuid, PlayerType type){ addInvite(uuid, type, true); } - + /** * Adds the player to be allowed to join a group into a specific PlayerType. * @param uuid- The UUID of the player. * @param type- The PlayerType they will be joining. - * @param saveToDB - save the invitation to the DB. + * @param saveToDB - save the invitation to the DB. */ public void addInvite(UUID uuid, PlayerType type, boolean saveToDB){ invites.put(uuid, type); @@ -241,7 +231,7 @@ public void addInvite(UUID uuid, PlayerType type, boolean saveToDB){ db.addGroupInvitation(uuid, name, type.name()); } } - + /** * Get's the PlayerType of an invited Player. * @param uuid- The UUID of the player. @@ -253,7 +243,7 @@ public PlayerType getInvite(UUID uuid) { } return invites.get(uuid); } - + /** * Removes the invite of a Player * @param uuid - The UUID of the player. @@ -261,11 +251,11 @@ public PlayerType getInvite(UUID uuid) { public void removeInvite(UUID uuid){ removeInvite(uuid, true); } - + /** * Removes the invite of a Player * @param uuid- The UUID of the player. - * @param saveToDB - remove the invitation from the DB. + * @param saveToDB - remove the invitation from the DB. */ public void removeInvite(UUID uuid, boolean saveToDB){ invites.remove(uuid); @@ -297,14 +287,14 @@ public boolean isMember(UUID uuid, PlayerType type) { public boolean isCurrentMember(UUID uuid) { return players.containsKey(uuid); } - + public boolean isCurrentMember(UUID uuid, PlayerType rank) { if (players.containsKey(uuid)) { return players.get(uuid).equals(rank); } return false; } - + /** * @param uuid- The UUID of the player. * @return Returns the PlayerType of a UUID. @@ -319,7 +309,7 @@ public PlayerType getPlayerType(UUID uuid) { } return PlayerType.NOT_BLACKLISTED; } - + public PlayerType getCurrentRank(UUID uuid) { return players.get(uuid); } @@ -327,14 +317,14 @@ public PlayerType getCurrentRank(UUID uuid) { /** * Adds a member to a group. * @param uuid- The uuid of the player. - * @param type- The PlayerType to add. If a preexisting PlayerType is found, + * @param type- The PlayerType to add. If a preexisting PlayerType is found, * it will be overwritten. */ - + public void addMember(UUID uuid, PlayerType type){ addMember(uuid,type,true); } - + public void addMember(UUID uuid, PlayerType type, boolean savetodb) { if (type == PlayerType.NOT_BLACKLISTED) { return; @@ -342,9 +332,9 @@ public void addMember(UUID uuid, PlayerType type, boolean savetodb) { if (savetodb) { // TODO: Make this atomic. UPDATE, don't remove and add! (Use INSERT ... UPDATE ON DUPLICATE / FAILURE semantic) if (isMember(uuid, type)){ - db.removeMember(uuid, name); + db.removeMember(uuid, id); } - db.addMember(uuid, name, type); + db.addMember(uuid, id, type); } players.put(uuid, type); } @@ -356,62 +346,62 @@ public void addMember(UUID uuid, PlayerType type, boolean savetodb) { public void removeMember(UUID uuid){ removeMember(uuid,true); } - + public void removeMember(UUID uuid, boolean savetodb) { if (savetodb){ - db.removeMember(uuid, name); + db.removeMember(uuid, id); } players.remove(uuid); } - + public void removeAllMembers() { removeAllMembers(true); } - + public void removeAllMembers(boolean savetodb) { if (savetodb) { - db.removeAllMembers(this.name); + db.removeAllMembers(this.id); } players.clear(); } /** - * + * * @param supergroup the base group * @param subgroup the group to link under it - * @param saveToDb - add link to the DB. + * @param saveToDb - add link to the DB. * @return true if linking succeeded, false otherwise. */ public static boolean link(Group supergroup, Group subgroup, boolean saveToDb) { if (supergroup == null || subgroup == null) { return false; } - + if (supergroup.equals(subgroup)) { return false; } - + if (supergroup.hasSuperGroup(subgroup)) { return false; } - + if (subgroup.hasSuperGroup()) { unlink(subgroup.supergroup, subgroup); } subgroup.supergroup = supergroup; - + if (!supergroup.hasSubGroup(subgroup)) { supergroup.subgroups.add(subgroup); } - if (saveToDb) { - db.addSubGroup(supergroup.getName(), subgroup.getName()); + if (saveToDb) { + db.addSubGroup(supergroup.getGroupId(), subgroup.getGroupId()); } - + return true; } - + /** - * + * * @param supergroup the main group * @param subgroup the sub group to unlink * @return true if unlink succeeded, false otherwise @@ -420,25 +410,25 @@ public static boolean unlink(Group supergroup, Group subgroup){ return unlink(supergroup,subgroup, true); } public static boolean unlink(Group supergroup, Group subgroup, boolean savetodb) { - if (supergroup == null || subgroup == null) { + if (supergroup == null || subgroup == null) { return false; } - + if (subgroup.hasSuperGroup() && subgroup.supergroup.equals(supergroup)) { subgroup.supergroup = null; } - + if (supergroup.hasSubGroup(subgroup)) { supergroup.subgroups.remove(subgroup); - } - + } + if (savetodb){ - db.removeSubGroup(supergroup.getName(), subgroup.getName()); + db.removeSubGroup(supergroup.getGroupId(), subgroup.getGroupId()); } - + return true; } - + public static boolean areLinked(Group supergroup, Group subgroup) { if (supergroup == null || subgroup == null) { return false; @@ -460,11 +450,11 @@ public static boolean areLinked(Group supergroup, Group subgroup) { } return false; } - + /** * Sets the default group for a player * @param uuid- The UUID of the player. - * + * */ public void setDefaultGroup(UUID uuid) { NameLayerPlugin.getDefaultGroupHandler().setDefaultGroup(uuid, this); @@ -473,9 +463,9 @@ public void setDefaultGroup(UUID uuid) { public void changeDefaultGroup(UUID uuid) { NameLayerPlugin.getDefaultGroupHandler().setDefaultGroup(uuid, this); } - + // == GETTERS ========================================================================= // - + /** * @return Returns the group name. */ @@ -494,7 +484,7 @@ public void changeDefaultGroup(UUID uuid) { * @return The UUID of the owner of the group. */ public UUID getOwner() { return owner; } - + /** * @param uuid the uuid of owner * @return true if the UUID belongs to the owner of the group, false otherwise. @@ -508,29 +498,15 @@ public void changeDefaultGroup(UUID uuid) { /** * Gets the id for a group. *

- * Note: + * Note: * Keep in mind though if you are trying to get a group_id from a GroupCreateEvent event * it will not be accurate. You must have a delay for 1 tick for it to work correctly. - *

- * Also calling the GroupManager.getGroup(int) will return a group that either has that - * group id or the object associated with that id. As such if a group is previously called - * and which didn't have the same id as the one called now you could get a different group id. - * Example would be System.out.println(GroupManager.getGroup(1).getGroupId()) and that - * could equal something like 2. * @return the group id for a group. */ public int getGroupId() { return id; } - - /** - * Addresses issue above somewhat. Allows implementations that need the whole list of Ids - * associated with this groupname to get them. - * - * @return list of ids paired with this group name. - */ - public List getGroupIds() { return new ArrayList(this.ids); } // == SETTERS ========================================================================= // - + /** * Sets the password for a group. Set the parameter as null to remove the password. * @param password- The password of the group. @@ -552,14 +528,14 @@ public void setPassword(String password, boolean savetodb) { public void setOwner(UUID uuid){ setOwner(uuid,true); } - + public void setOwner(UUID uuid, boolean savetodb) { this.owner = uuid; if (savetodb){ db.setFounder(uuid, this); } } - + public void setDisciplined(boolean value){ setDisciplined(value, true); } @@ -573,36 +549,9 @@ public void setDisciplined(boolean value, boolean savetodb) { public void setValid(boolean valid) { this.isValid = valid; } - // acts as replace - public void setGroupId(int id) { - this.ids.remove(this.id); - this.id = id; - if (!ids.contains(this.id)){ - this.ids.add(this.id); - } - } - - /** - * Updates/replaces the group id list with a new one. Clears the old one, adds these, - * and ensures that the "main" id is added to the list as well. - * - * @param ids the list of IDs to replace - */ - public void setGroupIds(List ids) { - this.ids.clear(); - if (ids != null) { - this.ids.addAll(ids); - } - if (!ids.contains(this.id)){ - this.ids.add(this.id); - } - } - - @Override public boolean equals(Object obj) { - if (!(obj instanceof Group)) + if (!(obj instanceof Group g)) return false; - Group g = (Group) obj; - return g.getName().equals(this.getName()); // If they have the same name they are equal. + return g.getGroupId() == this.getGroupId(); } } diff --git a/paper/src/main/java/vg/civcraft/mc/namelayer/gui/AdminFunctionsGUI.java b/paper/src/main/java/vg/civcraft/mc/namelayer/gui/AdminFunctionsGUI.java index af9c66b3..658e8182 100644 --- a/paper/src/main/java/vg/civcraft/mc/namelayer/gui/AdminFunctionsGUI.java +++ b/paper/src/main/java/vg/civcraft/mc/namelayer/gui/AdminFunctionsGUI.java @@ -239,7 +239,7 @@ public void clicked(Player p) { } NameLayerPlugin.log(Level.INFO, p.getName() + " deleted " + g.getName() + " via the gui"); - if (gm.deleteGroup(g.getName())) { + if (gm.deleteGroup(g.getGroupId())) { p.sendMessage(ChatColor.GREEN + g.getName() + " was successfully deleted."); } else { diff --git a/paper/src/main/java/vg/civcraft/mc/namelayer/permission/GroupPermission.java b/paper/src/main/java/vg/civcraft/mc/namelayer/permission/GroupPermission.java index 6d9ee822..1d6963bf 100644 --- a/paper/src/main/java/vg/civcraft/mc/namelayer/permission/GroupPermission.java +++ b/paper/src/main/java/vg/civcraft/mc/namelayer/permission/GroupPermission.java @@ -21,7 +21,7 @@ public GroupPermission(Group group){ } private void loadPermsforGroup(){ - perms = db.getPermissions(group.getName()); + perms = db.getPermissions(group.getGroupId()); //to save ourselves from trouble later, we ensure that every perm type has at least an empty list for(PlayerType pType : PlayerType.values()) { perms.computeIfAbsent(pType, k -> new ArrayList<>()); @@ -79,7 +79,7 @@ public boolean addPermission(PlayerType pType, PermissionType permType, boolean } playerPerms.add(permType); if (savetodb) { - db.addPermission(group.getName(), pType.name(), Collections.singletonList(permType)); + db.addPermission(group.getGroupId(), pType.name(), Collections.singletonList(permType)); } return true; } @@ -101,7 +101,7 @@ public boolean removePermission(PlayerType pType, PermissionType permType, boole } playerPerms.remove(permType); if (savetodb) { - db.removePermissionAsync(group.getName(), pType, permType); + db.removePermissionAsync(group.getGroupId(), pType, permType); } return true; }