Cuberite
A lightweight, fast and extensible game server for Minecraft
RankManager.cpp
Go to the documentation of this file.
1 
2 // RankManager.cpp
3 
4 // Implements the cRankManager class that represents the rank manager responsible for assigning permissions and message visuals to players
5 
6 #include "Globals.h"
7 #include "RankManager.h"
8 #include "IniFile.h"
9 #include "Protocol/MojangAPI.h"
10 #include "ClientHandle.h"
11 
12 
13 
14 
15 
17 // cRankManagerIniMigrator:
18 
21 {
22 public:
23  cRankManagerIniMigrator(cRankManager & a_RankManager, cMojangAPI & a_MojangAPI) :
24  m_RankManager(a_RankManager),
25  m_MojangAPI(a_MojangAPI)
26  {
27  }
28 
29 
30 
32  bool Migrate(void)
33  {
35 
36  LOGD("Reading groups...");
37  if (!ReadGroups())
38  {
39  return false;
40  }
41  LOGD("Cleaning groups inheritance...");
43  LOGD("Creating groups...");
44  CreateGroups();
45 
46  LOGD("Reading users...");
47  if (!ReadUsers())
48  {
49  return false;
50  }
51  LOGD("Cleaning user groups...");
53  LOGD("Resolving user UUIDs...");
55 
56  LOGD("Setting ranks...");
57  SetRanks();
58 
59  LOGD("Creating defaults...");
61 
62  return true;
63  }
64 
65 protected:
66 
68  struct sGroup
69  {
74 
75  sGroup(void) {}
76 
77  sGroup(const AString & a_Name, const AString & a_Color, const AStringVector & a_Inherits, const AStringVector & a_Permissions):
78  m_Name(a_Name),
79  m_Color(a_Color),
80  m_Inherits(a_Inherits),
81  m_Permissions(a_Permissions)
82  {
83  }
84  };
85  typedef std::map<AString, sGroup> sGroupMap;
86 
87 
89  struct sUser
90  {
93 
96 
99 
100 
101  sUser(void) {}
102 
103  sUser(const AString & a_Name, const AStringVector & a_Groups):
104  m_Name(a_Name),
105  m_Groups(a_Groups)
106  {
107  }
108  };
109  typedef std::map<AString, sUser> sUserMap;
110 
111  typedef std::map<AString, AString> cStringMap;
112 
113 
116 
119 
121  sGroupMap m_Groups;
122 
124  sUserMap m_Users;
125 
133  cStringMap m_GroupsToRanks;
134 
135 
136 
138  bool ReadGroups(void)
139  {
140  // Read the file:
141  cIniFile Groups;
142  if (!Groups.ReadFile("groups.ini"))
143  {
144  return false;
145  }
146 
147  // Read all the groups into a map:
148  int NumGroups = Groups.GetNumKeys();
149  for (int i = 0; i < NumGroups; i++)
150  {
151  AString GroupName = Groups.GetKeyName(i);
152  AString lcGroupName = StrToLower(GroupName);
153  if (m_Groups.find(lcGroupName) != m_Groups.end())
154  {
155  LOGINFO("groups.ini contains a duplicate definition of group %s, ignoring the latter.", GroupName.c_str());
156  continue;
157  }
158  m_Groups[lcGroupName] = sGroup(
159  GroupName,
160  Groups.GetValue(GroupName, "Color", ""),
161  StringSplitAndTrim(Groups.GetValue(GroupName, "Inherits"), ","),
162  StringSplitAndTrim(Groups.GetValue(GroupName, "Permissions"), ",")
163  );
164  } // for i - Groups' keys
165  return true;
166  }
167 
168 
169 
172  {
173  for (sGroupMap::iterator itrG = m_Groups.begin(), endG = m_Groups.end(); itrG != endG; ++itrG)
174  {
175  AStringVector & Inherits = itrG->second.m_Inherits;
176  for (AStringVector::iterator itrI = Inherits.begin(); itrI != Inherits.end();)
177  {
178  AString lcInherits = StrToLower(*itrI);
179  if (m_Groups.find(lcInherits) != m_Groups.end())
180  {
181  // Inherited group exists, continue checking the next one
182  ++itrI;
183  continue;
184  }
185  // Inherited group doesn't exist, remove it from the list:
186  LOGWARNING("RankMigrator: Group \"%s\" inherits from a non-existent group \"%s\", this inheritance will be ignored.",
187  itrG->second.m_Name.c_str(), itrI->c_str()
188  );
189  AStringVector::iterator itrI2 = itrI;
190  ++itrI2;
191  Inherits.erase(itrI);
192  itrI = itrI2;
193  } // for itrI - Inherits[]
194  } // for itrG - m_Groups[]
195  }
196 
197 
198 
200  bool ReadUsers(void)
201  {
202  // Read the file:
203  cIniFile Users;
204  if (!Users.ReadFile("users.ini"))
205  {
206  return false;
207  }
208 
209  // Read all the users into a map:
210  int NumUsers = Users.GetNumKeys();
211  for (int i = 0; i < NumUsers; i++)
212  {
213  AString UserName = Users.GetKeyName(i);
214  AString lcUserName = StrToLower(UserName);
215  if (m_Users.find(lcUserName) != m_Users.end())
216  {
217  LOGINFO("users.ini contains a duplicate definition of user %s, ignoring the latter.", UserName.c_str());
218  continue;
219  }
220  m_Users[lcUserName] = sUser(
221  UserName,
222  StringSplitAndTrim(Users.GetValue(UserName, "Groups", ""), ",")
223  );
224  } // for i - Users' keys
225  return true;
226  }
227 
228 
229 
231  void CleanUserGroups(void)
232  {
233  for (sUserMap::iterator itrU = m_Users.begin(), endU = m_Users.end(); itrU != endU; ++itrU)
234  {
235  AStringVector & Groups = itrU->second.m_Groups;
236  for (AStringVector::iterator itrG = Groups.begin(); itrG != Groups.end();)
237  {
238  AString lcGroup = StrToLower(*itrG);
239  if (m_Groups.find(lcGroup) != m_Groups.end())
240  {
241  // Assigned group exists, continue checking the next one
242  ++itrG;
243  continue;
244  }
245  // Assigned group doesn't exist, remove it from the list:
246  LOGWARNING("RankMigrator: User \"%s\" is assigned a non-existent group \"%s\", this assignment will be ignored.",
247  itrU->second.m_Name.c_str(), itrG->c_str()
248  );
249  AStringVector::iterator itrG2 = itrG;
250  ++itrG2;
251  Groups.erase(itrG);
252  itrG = itrG2;
253  } // for itrG - Groups[]
254  } // for itrU - m_Users[]
255  }
256 
257 
258 
261  void CreateGroups(void)
262  {
263  // Create each group, with its permissions:
264  for (sGroupMap::const_iterator itr = m_Groups.begin(), end = m_Groups.end(); itr != end; ++itr)
265  {
266  m_RankManager.AddGroup(itr->second.m_Name);
267  m_RankManager.AddPermissionsToGroup(itr->second.m_Permissions, itr->second.m_Name);
268  } // for itr - m_Groups[]
269  }
270 
271 
274  void ResolveUserUUIDs(void)
275  {
276  // Resolve all PlayerNames at once (the API doesn't like single-name queries):
277  AStringVector PlayerNames;
278  for (sUserMap::const_iterator itr = m_Users.begin(), end = m_Users.end(); itr != end; ++itr)
279  {
280  PlayerNames.push_back(itr->second.m_Name);
281  }
282  m_MojangAPI.GetUUIDsFromPlayerNames(PlayerNames);
283 
284  // Assign the UUIDs back to players, remove those not resolved:
285  for (auto & User : m_Users)
286  {
287  cUUID UUID = m_MojangAPI.GetUUIDFromPlayerName(User.second.m_Name);
288  if (UUID.IsNil())
289  {
290  LOGWARNING("RankMigrator: Cannot resolve player %s to online UUID, player will be left unranked in online mode", User.second.m_Name.c_str());
291  }
292  User.second.m_UUID = UUID;
293  User.second.m_OfflineUUID = cClientHandle::GenerateOfflineUUID(User.second.m_Name);
294  }
295  }
296 
297 
298 
300  void AddGroupsToRank(const AStringVector & a_Groups, const AString & a_RankName)
301  {
302  for (AStringVector::const_iterator itr = a_Groups.begin(), end = a_Groups.end(); itr != end; ++itr)
303  {
304  // Normalize the group name:
305  sGroup & Group = m_Groups[StrToLower(*itr)];
306 
307  // Avoid loops, check if the group is already added:
308  if (m_RankManager.IsGroupInRank(Group.m_Name, a_RankName))
309  {
310  continue;
311  }
312 
313  // Add the group, and all the groups it inherits from recursively:
314  m_RankManager.AddGroupToRank(Group.m_Name, a_RankName);
315  AddGroupsToRank(Group.m_Inherits, a_RankName);
316  } // for itr - a_Groups[]
317  }
318 
319 
320 
322  void SetRanks(void)
323  {
324  for (sUserMap::const_iterator itr = m_Users.begin(), end = m_Users.end(); itr != end; ++itr)
325  {
326  // Ignore users with no groups:
327  const AStringVector & Groups = itr->second.m_Groups;
328  if (Groups.empty())
329  {
330  LOGWARNING("RankMigrator: Player %s has no groups assigned to them, skipping the player.", itr->second.m_Name.c_str());
331  continue;
332  }
333 
334  // Compose the rank name out of group names:
335  AString RankName;
336  for (AStringVector::const_iterator itrG = Groups.begin(), endG = Groups.end(); itrG != endG; ++itrG)
337  {
338  AString GroupName = m_Groups[StrToLower(*itrG)].m_Name; // Normalize group name
339  if (!RankName.empty())
340  {
341  RankName.push_back(',');
342  }
343  RankName.append(GroupName);
344  } // for itrG - Groups[]
345 
346  // Create the rank, with al its groups:
347  if (!m_RankManager.RankExists(RankName))
348  {
349  m_RankManager.AddRank(RankName, "", "", m_Groups[StrToLower(Groups[0])].m_Color);
350  AddGroupsToRank(Groups, RankName);
351  }
352 
353  // Set the rank to the user, using both the online and offline UUIDs:
354  m_RankManager.SetPlayerRank(itr->second.m_UUID, itr->second.m_Name, RankName);
355  m_RankManager.SetPlayerRank(itr->second.m_OfflineUUID, itr->second.m_Name, RankName);
356  } // for itr - m_Users[]
357  }
358 
359 
360 
363  void CreateDefaults(void)
364  {
365  if (!m_RankManager.RankExists("Default"))
366  {
367  m_RankManager.AddRank("Default", "", "", "");
368  if (!m_RankManager.IsGroupInRank("Default", "Default"))
369  {
370  m_RankManager.AddGroupToRank("Default", "Default");
371  }
372  }
373  m_RankManager.SetDefaultRank("Default");
374  }
375 };
376 
377 
378 
379 
380 
382 // cRankManager:
383 
385  m_DB("Ranks.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE),
386  m_IsInitialized(false),
387  m_MojangAPI(nullptr)
388 {
389 }
390 
391 
392 
393 
394 
396 {
397  if (m_MojangAPI != nullptr)
398  {
399  m_MojangAPI->SetRankManager(nullptr);
400  }
401 }
402 
403 
404 
405 
406 
408 {
409  ASSERT(!m_IsInitialized); // Calling Initialize for the second time?
410 
411  // Create the DB tables, if they don't exist:
412  m_DB.exec("CREATE TABLE IF NOT EXISTS Rank (RankID INTEGER PRIMARY KEY, Name, MsgPrefix, MsgSuffix, MsgNameColorCode)");
413  m_DB.exec("CREATE TABLE IF NOT EXISTS PlayerRank (PlayerUUID, PlayerName, RankID INTEGER)");
414  m_DB.exec("CREATE TABLE IF NOT EXISTS PermGroup (PermGroupID INTEGER PRIMARY KEY, Name)");
415  m_DB.exec("CREATE TABLE IF NOT EXISTS RankPermGroup (RankID INTEGER, PermGroupID INTEGER)");
416  m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionItem (PermGroupID INTEGER, Permission)");
417  m_DB.exec("CREATE TABLE IF NOT EXISTS RestrictionItem (PermGroupID INTEGER, Permission)");
418  m_DB.exec("CREATE TABLE IF NOT EXISTS DefaultRank (RankID INTEGER)");
419 
420  m_IsInitialized = true;
421 
422  a_MojangAPI.SetRankManager(this);
423 
424  // Check if tables empty, migrate from ini files then
425  if (AreDBTablesEmpty())
426  {
427  LOGINFO("There are no ranks, migrating old-style INI files to new DB ranks...");
428  LOGINFO("(This might take a while)");
429  cRankManagerIniMigrator Migrator(*this, a_MojangAPI);
430  if (Migrator.Migrate())
431  {
432  LOGINFO("Ranks migrated.");
433  // The default rank has been set by the migrator
434  return;
435  }
436 
437  // Migration failed. Add some defaults
438  LOGINFO("Rank migration failed, creating default ranks...");
439  CreateDefaults();
440  LOGINFO("Default ranks created.");
441  }
442 
443  // Load the default rank:
444  try
445  {
446  SQLite::Statement stmt(m_DB,
447  "SELECT Rank.Name FROM Rank "
448  "LEFT JOIN DefaultRank ON Rank.RankID = DefaultRank.RankID"
449  );
450  if (stmt.executeStep())
451  {
452  m_DefaultRank = stmt.getColumn(0).getText();
453  }
454  }
455  catch (const SQLite::Exception & ex)
456  {
457  LOGWARNING("%s: Cannot load default rank: %s", __FUNCTION__, ex.what());
458  return;
459  }
460 
461  // If the default rank cannot be loaded, use the first rank:
462  if (m_DefaultRank.empty())
463  {
465  }
466 }
467 
468 
469 
470 
471 
473 {
475  cCSLock Lock(m_CS);
476 
477  try
478  {
479  SQLite::Statement stmt(m_DB, "SELECT Rank.Name FROM Rank LEFT JOIN PlayerRank ON Rank.RankID = PlayerRank.RankID WHERE PlayerRank.PlayerUUID = ?");
480  stmt.bind(1, a_PlayerUUID.ToShortString());
481  // executeStep returns false on no data
482  if (!stmt.executeStep())
483  {
484  // No data returned from the DB
485  return AString();
486  }
487  return stmt.getColumn(0).getText();
488  }
489  catch (const SQLite::Exception & ex)
490  {
491  LOGWARNING("%s: Cannot get player rank name: %s", __FUNCTION__, ex.what());
492  }
493  return AString();
494 }
495 
496 
497 
498 
499 
501 {
503  cCSLock Lock(m_CS);
504 
505  try
506  {
507  // Prepare the DB statement:
508  SQLite::Statement stmt(m_DB, "SELECT PlayerName FROM PlayerRank WHERE PlayerUUID = ?");
509  stmt.bind(1, a_PlayerUUID.ToShortString());
510 
511  if (stmt.executeStep())
512  {
513  return stmt.getColumn(0).getText();
514  }
515  }
516  catch (SQLite::Exception & ex)
517  {
518  LOGWARNING("%s: Cannot get player name: %s", __FUNCTION__, ex.what());
519  }
520  return AString();
521 }
522 
523 
524 
525 
526 
528 {
530  cCSLock Lock(m_CS);
531 
532  AStringVector res;
533  try
534  {
535  // Prepare the DB statement:
536  SQLite::Statement stmt(m_DB,
537  "SELECT PermGroup.Name FROM PermGroup "
538  "LEFT JOIN RankPermGroup ON PermGroup.PermGroupID = RankPermGroup.PermGroupID "
539  "LEFT JOIN PlayerRank ON PlayerRank.RankID = RankPermGroup.RankID "
540  "WHERE PlayerRank.PlayerUUID = ?"
541  );
542  stmt.bind(1, a_PlayerUUID.ToShortString());
543 
544  // Execute and get results:
545  while (stmt.executeStep())
546  {
547  res.push_back(stmt.getColumn(0).getText());
548  }
549  }
550  catch (const SQLite::Exception & ex)
551  {
552  LOGWARNING("%s: Cannot get player groups: %s", __FUNCTION__, ex.what());
553  }
554  return res;
555 }
556 
557 
558 
559 
560 
562 {
563  AString Rank = GetPlayerRankName(a_PlayerUUID);
564  if (Rank.empty())
565  {
566  Rank = m_DefaultRank;
567  }
568  return GetRankPermissions(Rank);
569 }
570 
571 
572 
573 
574 
576 {
577  AString Rank = GetPlayerRankName(a_PlayerUUID);
578  if (Rank.empty())
579  {
580  Rank = m_DefaultRank;
581  }
582  return GetRankRestrictions(Rank);
583 }
584 
585 
586 
587 
588 
590 {
592  cCSLock Lock(m_CS);
593 
594  AStringVector res;
595  try
596  {
597  SQLite::Statement stmt(m_DB,
598  "SELECT PermGroup.Name FROM PermGroup "
599  "LEFT JOIN RankPermGroup ON RankPermGroup.PermGroupID = PermGroup.PermGroupID "
600  "LEFT JOIN Rank ON Rank.RankID = RankPermGroup.RankID "
601  "WHERE Rank.Name = ?"
602  );
603  stmt.bind(1, a_RankName);
604  while (stmt.executeStep())
605  {
606  res.push_back(stmt.getColumn(0).getText());
607  }
608  }
609  catch (const SQLite::Exception & ex)
610  {
611  LOGWARNING("%s: Failed to get rank groups from DB: %s", __FUNCTION__, ex.what());
612  }
613  return res;
614 }
615 
616 
617 
618 
619 
621 {
623  cCSLock Lock(m_CS);
624 
625  AStringVector res;
626  try
627  {
628  SQLite::Statement stmt(m_DB,
629  "SELECT PermissionItem.Permission FROM PermissionItem "
630  "LEFT JOIN PermGroup ON PermGroup.PermGroupID = PermissionItem.PermGroupID "
631  "WHERE PermGroup.Name = ?"
632  );
633  stmt.bind(1, a_GroupName);
634  while (stmt.executeStep())
635  {
636  res.push_back(stmt.getColumn(0).getText());
637  }
638  }
639  catch (const SQLite::Exception & ex)
640  {
641  LOGWARNING("%s: Failed to get group permissions from DB: %s", __FUNCTION__, ex.what());
642  }
643  return res;
644 }
645 
646 
647 
648 
649 
651 {
653  cCSLock Lock(m_CS);
654 
655  AStringVector res;
656  try
657  {
658  SQLite::Statement stmt(m_DB,
659  "SELECT RestrictionItem.Permission FROM RestrictionItem "
660  "LEFT JOIN PermGroup ON PermGroup.PermGroupID = RestrictionItem.PermGroupID "
661  "WHERE PermGroup.Name = ?"
662  );
663  stmt.bind(1, a_GroupName);
664  while (stmt.executeStep())
665  {
666  res.push_back(stmt.getColumn(0).getText());
667  }
668  }
669  catch (const SQLite::Exception & ex)
670  {
671  LOGWARNING("%s: Failed to get group restrictions from DB: %s", __FUNCTION__, ex.what());
672  }
673  return res;
674 }
675 
676 
677 
678 
679 
681 {
683  cCSLock Lock(m_CS);
684 
685  AStringVector res;
686  try
687  {
688  SQLite::Statement stmt(m_DB,
689  "SELECT PermissionItem.Permission FROM PermissionItem "
690  "LEFT JOIN RankPermGroup ON RankPermGroup.PermGroupID = PermissionItem.PermGroupID "
691  "LEFT JOIN Rank ON Rank.RankID = RankPermGroup.RankID "
692  "WHERE Rank.Name = ?"
693  );
694  stmt.bind(1, a_RankName);
695  while (stmt.executeStep())
696  {
697  res.push_back(stmt.getColumn(0).getText());
698  }
699  }
700  catch (const SQLite::Exception & ex)
701  {
702  LOGWARNING("%s: Failed to get rank permissions from DB: %s", __FUNCTION__, ex.what());
703  }
704  return res;
705 }
706 
707 
708 
709 
710 
712 {
714  cCSLock Lock(m_CS);
715 
716  AStringVector res;
717  try
718  {
719  SQLite::Statement stmt(m_DB,
720  "SELECT RestrictionItem.Permission FROM RestrictionItem "
721  "LEFT JOIN RankPermGroup ON RankPermGroup.PermGroupID = RestrictionItem.PermGroupID "
722  "LEFT JOIN Rank ON Rank.RankID = RankPermGroup.RankID "
723  "WHERE Rank.Name = ?"
724  );
725  stmt.bind(1, a_RankName);
726  while (stmt.executeStep())
727  {
728  res.push_back(stmt.getColumn(0).getText());
729  }
730  }
731  catch (const SQLite::Exception & ex)
732  {
733  LOGWARNING("%s: Failed to get rank restrictions from DB: %s", __FUNCTION__, ex.what());
734  }
735  return res;
736 }
737 
738 
739 
740 
741 
742 std::vector<cUUID> cRankManager::GetAllPlayerUUIDs(void)
743 {
745  cCSLock Lock(m_CS);
746 
747  cUUID tempUUID;
748  std::vector<cUUID> res;
749  try
750  {
751  SQLite::Statement stmt(m_DB, "SELECT PlayerUUID FROM PlayerRank ORDER BY PlayerName COLLATE NOCASE");
752  while (stmt.executeStep())
753  {
754  if (!tempUUID.FromString(stmt.getColumn(0).getText()))
755  {
756  // Invalid UUID, ignore
757  continue;
758  }
759  res.push_back(tempUUID);
760  }
761  }
762  catch (const SQLite::Exception & ex)
763  {
764  LOGWARNING("%s: Failed to get players from DB: %s", __FUNCTION__, ex.what());
765  }
766  return res;
767 }
768 
769 
770 
771 
772 
774 {
776  cCSLock Lock(m_CS);
777 
778  AStringVector res;
779  try
780  {
781  SQLite::Statement stmt(m_DB, "SELECT Name FROM Rank");
782  while (stmt.executeStep())
783  {
784  res.push_back(stmt.getColumn(0).getText());
785  }
786  }
787  catch (const SQLite::Exception & ex)
788  {
789  LOGWARNING("%s: Failed to get ranks from DB: %s", __FUNCTION__, ex.what());
790  }
791  return res;
792 }
793 
794 
795 
796 
797 
799 {
801  cCSLock Lock(m_CS);
802 
803  AStringVector res;
804  try
805  {
806  SQLite::Statement stmt(m_DB, "SELECT Name FROM PermGroup");
807  while (stmt.executeStep())
808  {
809  res.push_back(stmt.getColumn(0).getText());
810  }
811  }
812  catch (const SQLite::Exception & ex)
813  {
814  LOGWARNING("%s: Failed to get groups from DB: %s", __FUNCTION__, ex.what());
815  }
816  return res;
817 }
818 
819 
820 
821 
822 
824 {
826  cCSLock Lock(m_CS);
827 
828  AStringVector res;
829  try
830  {
831  SQLite::Statement stmt(m_DB, "SELECT DISTINCT(Permission) FROM PermissionItem");
832  while (stmt.executeStep())
833  {
834  res.push_back(stmt.getColumn(0).getText());
835  }
836  }
837  catch (const SQLite::Exception & ex)
838  {
839  LOGWARNING("%s: Failed to get permissions from DB: %s", __FUNCTION__, ex.what());
840  }
841  return res;
842 }
843 
844 
845 
846 
847 
849 {
851  cCSLock Lock(m_CS);
852 
853  AStringVector res;
854  try
855  {
856  SQLite::Statement stmt(m_DB, "SELECT DISTINCT(Permission) FROM RestrictionItem");
857  while (stmt.executeStep())
858  {
859  res.push_back(stmt.getColumn(0).getText());
860  }
861  }
862  catch (const SQLite::Exception & ex)
863  {
864  LOGWARNING("%s: Failed to get restrictions from DB: %s", __FUNCTION__, ex.what());
865  }
866  return res;
867 }
868 
869 
870 
871 
872 
874 {
875  AStringVector Permissions = GetAllPermissions();
876  AStringVector Restrictions = GetAllRestrictions();
877  for (auto & restriction: Restrictions)
878  {
879  Permissions.push_back(restriction);
880  }
881  return Permissions;
882 }
883 
884 
885 
886 
887 
889  const cUUID & a_PlayerUUID,
890  AString & a_MsgPrefix,
891  AString & a_MsgSuffix,
892  AString & a_MsgNameColorCode
893 )
894 {
895  AString Rank = GetPlayerRankName(a_PlayerUUID);
896  if (Rank.empty())
897  {
898  // Rank not found, return failure:
899  a_MsgPrefix.clear();
900  a_MsgSuffix.clear();
901  a_MsgNameColorCode.clear();
902  return false;
903  }
904  return GetRankVisuals(Rank, a_MsgPrefix, a_MsgSuffix, a_MsgNameColorCode);
905 }
906 
907 
908 
909 
910 
912  const AString & a_RankName,
913  const AString & a_MsgPrefix,
914  const AString & a_MsgSuffix,
915  const AString & a_MsgNameColorCode
916 )
917 {
919  cCSLock Lock(m_CS);
920 
921  try
922  {
923  // Check if such a rank name is already used:
924  {
925  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM Rank WHERE Name = ?");
926  stmt.bind(1, a_RankName);
927  if (stmt.executeStep())
928  {
929  if (stmt.getColumn(0).getInt() > 0)
930  {
931  // Rank already exists, do nothing:
932  return;
933  }
934  }
935  }
936 
937  // Insert a new rank:
938  SQLite::Statement stmt(m_DB, "INSERT INTO Rank (Name, MsgPrefix, MsgSuffix, MsgNameColorCode) VALUES (?, ?, ?, ?)");
939  stmt.bind(1, a_RankName);
940  stmt.bind(2, a_MsgPrefix);
941  stmt.bind(3, a_MsgSuffix);
942  stmt.bind(4, a_MsgNameColorCode);
943  if (stmt.exec() <= 0)
944  {
945  LOGWARNING("%s: Failed to add a new rank \"%s\".", __FUNCTION__, a_RankName.c_str());
946  return;
947  }
948  }
949  catch (const SQLite::Exception & ex)
950  {
951  LOGWARNING("%s: Failed to add a new rank \"%s\": %s", __FUNCTION__, a_RankName.c_str(), ex.what());
952  }
953 }
954 
955 
956 
957 
958 
959 void cRankManager::AddGroup(const AString & a_GroupName)
960 {
962  cCSLock Lock(m_CS);
963 
964  try
965  {
966  // Check if such a group name is already used:
967  {
968  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermGroup WHERE Name = ?");
969  stmt.bind(1, a_GroupName);
970  if (stmt.executeStep())
971  {
972  if (stmt.getColumn(0).getInt() > 0)
973  {
974  // Group already exists, do nothing:
975  return;
976  }
977  }
978  }
979 
980  // Insert a new group:
981  SQLite::Statement stmt(m_DB, "INSERT INTO PermGroup (Name) VALUES (?)");
982  stmt.bind(1, a_GroupName);
983  if (stmt.exec() <= 0)
984  {
985  LOGWARNING("%s: Failed to add a new group \"%s\".", __FUNCTION__, a_GroupName.c_str());
986  return;
987  }
988  }
989  catch (const SQLite::Exception & ex)
990  {
991  LOGWARNING("%s: Failed to add a new group \"%s\": %s", __FUNCTION__, a_GroupName.c_str(), ex.what());
992  }
993 }
994 
995 
996 
997 
998 
999 void cRankManager::AddGroups(const AStringVector & a_GroupNames)
1000 {
1002  cCSLock Lock(m_CS);
1003 
1004  try
1005  {
1006  for (AStringVector::const_iterator itr = a_GroupNames.begin(), end = a_GroupNames.end(); itr != end; ++itr)
1007  {
1008  // Check if such the group name is already used:
1009  {
1010  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermGroup WHERE Name = ?");
1011  stmt.bind(1, *itr);
1012  if (stmt.executeStep())
1013  {
1014  if (stmt.getColumn(0).getInt() > 0)
1015  {
1016  // Group already exists, do nothing:
1017  return;
1018  }
1019  }
1020  }
1021 
1022  // Insert a new group:
1023  SQLite::Statement stmt(m_DB, "INSERT INTO PermGroup (Name) VALUES (?)");
1024  stmt.bind(1, *itr);
1025  if (stmt.exec() <= 0)
1026  {
1027  LOGWARNING("%s: Failed to add a new group \"%s\".", __FUNCTION__, itr->c_str());
1028  return;
1029  }
1030  } // for itr - a_GroupNames[]
1031  }
1032  catch (const SQLite::Exception & ex)
1033  {
1034  LOGWARNING("%s: Failed to add new groups: %s", __FUNCTION__, ex.what());
1035  }
1036 }
1037 
1038 
1039 
1040 
1041 
1042 bool cRankManager::AddGroupToRank(const AString & a_GroupName, const AString & a_RankName)
1043 {
1045  cCSLock Lock(m_CS);
1046 
1047  try
1048  {
1049  // Get the group's ID:
1050  int GroupID;
1051  {
1052  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1053  stmt.bind(1, a_GroupName);
1054  if (!stmt.executeStep())
1055  {
1056  LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str());
1057  return false;
1058  }
1059  GroupID = stmt.getColumn(0);
1060  }
1061 
1062  // Get the rank's ID:
1063  int RankID;
1064  {
1065  SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?");
1066  stmt.bind(1, a_RankName);
1067  if (!stmt.executeStep())
1068  {
1069  LOGWARNING("%s: No such rank (%s), aborting.", __FUNCTION__, a_RankName.c_str());
1070  return false;
1071  }
1072  RankID = stmt.getColumn(0);
1073  }
1074 
1075  // Check if the group is already there:
1076  {
1077  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM RankPermGroup WHERE RankID = ? AND PermGroupID = ?");
1078  stmt.bind(1, RankID);
1079  stmt.bind(2, GroupID);
1080  if (!stmt.executeStep())
1081  {
1082  LOGWARNING("%s: Failed to check binding between rank %s and group %s, aborting.", __FUNCTION__, a_RankName.c_str(), a_GroupName.c_str());
1083  return false;
1084  }
1085  if (stmt.getColumn(0).getInt() > 0)
1086  {
1087  LOGD("%s: Group %s already present in rank %s, skipping and returning success.",
1088  __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str()
1089  );
1090  return true;
1091  }
1092  }
1093 
1094  // Add the group:
1095  {
1096  SQLite::Statement stmt(m_DB, "INSERT INTO RankPermGroup (RankID, PermGroupID) VALUES (?, ?)");
1097  stmt.bind(1, RankID);
1098  stmt.bind(2, GroupID);
1099  if (stmt.exec() <= 0)
1100  {
1101  LOGWARNING("%s: Failed to add group %s to rank %s, aborting.", __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str());
1102  return false;
1103  }
1104  }
1105 
1106  // Adding succeeded:
1107  return true;
1108  }
1109  catch (const SQLite::Exception & ex)
1110  {
1111  LOGWARNING("%s: Failed to add group %s to rank %s: %s", __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str(), ex.what());
1112  }
1113  return false;
1114 }
1115 
1116 
1117 
1118 
1119 
1120 bool cRankManager::AddPermissionToGroup(const AString & a_Permission, const AString & a_GroupName)
1121 {
1123  cCSLock Lock(m_CS);
1124 
1125  try
1126  {
1127  // Get the group's ID:
1128  int GroupID;
1129  {
1130  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1131  stmt.bind(1, a_GroupName);
1132  if (!stmt.executeStep())
1133  {
1134  LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str());
1135  return false;
1136  }
1137  GroupID = stmt.getColumn(0).getInt();
1138  }
1139 
1140  // Check if the permission is already present:
1141  {
1142  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermissionItem WHERE PermGroupID = ? AND Permission = ?");
1143  stmt.bind(1, GroupID);
1144  stmt.bind(2, a_Permission);
1145  if (!stmt.executeStep())
1146  {
1147  LOGWARNING("%s: Failed to check binding between permission %s and group %s, aborting.", __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str());
1148  return false;
1149  }
1150  if (stmt.getColumn(0).getInt() > 0)
1151  {
1152  LOGD("%s: Permission %s is already present in group %s, skipping and returning success.",
1153  __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str()
1154  );
1155  return true;
1156  }
1157  }
1158 
1159  // Add the permission:
1160  {
1161  SQLite::Statement stmt(m_DB, "INSERT INTO PermissionItem (Permission, PermGroupID) VALUES (?, ?)");
1162  stmt.bind(1, a_Permission);
1163  stmt.bind(2, GroupID);
1164  if (stmt.exec() <= 0)
1165  {
1166  LOGWARNING("%s: Failed to add permission %s to group %s, aborting.", __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str());
1167  return false;
1168  }
1169  }
1170 
1171  // Adding succeeded:
1172  return true;
1173  }
1174  catch (const SQLite::Exception & ex)
1175  {
1176  LOGWARNING("%s: Failed to add permission %s to group %s: %s",
1177  __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str(), ex.what()
1178  );
1179  }
1180  return false;
1181 }
1182 
1183 
1184 
1185 
1186 
1187 bool cRankManager::AddRestrictionToGroup(const AString & a_Restriction, const AString & a_GroupName)
1188 {
1190  cCSLock Lock(m_CS);
1191 
1192  try
1193  {
1194  // Get the group's ID:
1195  int GroupID;
1196  {
1197  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1198  stmt.bind(1, a_GroupName);
1199  if (!stmt.executeStep())
1200  {
1201  LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str());
1202  return false;
1203  }
1204  GroupID = stmt.getColumn(0).getInt();
1205  }
1206 
1207  // Check if the restriction is already present:
1208  {
1209  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM RestrictionItem WHERE PermGroupID = ? AND Permission = ?");
1210  stmt.bind(1, GroupID);
1211  stmt.bind(2, a_Restriction);
1212  if (!stmt.executeStep())
1213  {
1214  LOGWARNING("%s: Failed to check binding between restriction %s and group %s, aborting.", __FUNCTION__, a_Restriction.c_str(), a_GroupName.c_str());
1215  return false;
1216  }
1217  if (stmt.getColumn(0).getInt() > 0)
1218  {
1219  LOGD("%s: Restriction %s is already present in group %s, skipping and returning success.",
1220  __FUNCTION__, a_Restriction.c_str(), a_GroupName.c_str()
1221  );
1222  return true;
1223  }
1224  }
1225 
1226  // Add the restriction:
1227  {
1228  SQLite::Statement stmt(m_DB, "INSERT INTO RestrictionItem (Permission, PermGroupID) VALUES (?, ?)");
1229  stmt.bind(1, a_Restriction);
1230  stmt.bind(2, GroupID);
1231  if (stmt.exec() <= 0)
1232  {
1233  LOGWARNING("%s: Failed to add restriction %s to group %s, aborting.", __FUNCTION__, a_Restriction.c_str(), a_GroupName.c_str());
1234  return false;
1235  }
1236  }
1237 
1238  // Adding succeeded:
1239  return true;
1240  }
1241  catch (const SQLite::Exception & ex)
1242  {
1243  LOGWARNING("%s: Failed to add restriction %s to group %s: %s",
1244  __FUNCTION__, a_Restriction.c_str(), a_GroupName.c_str(), ex.what()
1245  );
1246  }
1247  return false;
1248 }
1249 
1250 
1251 
1252 
1253 
1254 bool cRankManager::AddPermissionsToGroup(const AStringVector & a_Permissions, const AString & a_GroupName)
1255 {
1257  cCSLock Lock(m_CS);
1258 
1259  try
1260  {
1261  // Get the group's ID:
1262  int GroupID;
1263  {
1264  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1265  stmt.bind(1, a_GroupName);
1266  if (!stmt.executeStep())
1267  {
1268  LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str());
1269  return false;
1270  }
1271  GroupID = stmt.getColumn(0).getInt();
1272  }
1273 
1274  for (AStringVector::const_iterator itr = a_Permissions.begin(), end = a_Permissions.end(); itr != end; ++itr)
1275  {
1276  // Check if the permission is already present:
1277  {
1278  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermissionItem WHERE PermGroupID = ? AND Permission = ?");
1279  stmt.bind(1, GroupID);
1280  stmt.bind(2, *itr);
1281  if (!stmt.executeStep())
1282  {
1283  LOGWARNING("%s: Failed to check binding between permission %s and group %s, aborting.", __FUNCTION__, itr->c_str(), a_GroupName.c_str());
1284  return false;
1285  }
1286  if (stmt.getColumn(0).getInt() > 0)
1287  {
1288  LOGD("%s: Permission %s is already present in group %s, skipping and returning success.",
1289  __FUNCTION__, itr->c_str(), a_GroupName.c_str()
1290  );
1291  continue;
1292  }
1293  }
1294 
1295  // Add the permission:
1296  {
1297  SQLite::Statement stmt(m_DB, "INSERT INTO PermissionItem (Permission, PermGroupID) VALUES (?, ?)");
1298  stmt.bind(1, *itr);
1299  stmt.bind(2, GroupID);
1300  if (stmt.exec() <= 0)
1301  {
1302  LOGWARNING("%s: Failed to add permission %s to group %s, skipping.", __FUNCTION__, itr->c_str(), a_GroupName.c_str());
1303  continue;
1304  }
1305  }
1306  } // for itr - a_Permissions[]
1307 
1308  // Adding succeeded:
1309  return true;
1310  }
1311  catch (const SQLite::Exception & ex)
1312  {
1313  LOGWARNING("%s: Failed to add permissions to group %s: %s",
1314  __FUNCTION__, a_GroupName.c_str(), ex.what()
1315  );
1316  }
1317  return false;
1318 }
1319 
1320 
1321 
1322 
1323 
1324 bool cRankManager::AddRestrictionsToGroup(const AStringVector & a_Restrictions, const AString & a_GroupName)
1325 {
1327  cCSLock Lock(m_CS);
1328 
1329  try
1330  {
1331  // Get the group's ID:
1332  int GroupID;
1333  {
1334  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1335  stmt.bind(1, a_GroupName);
1336  if (!stmt.executeStep())
1337  {
1338  LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str());
1339  return false;
1340  }
1341  GroupID = stmt.getColumn(0).getInt();
1342  }
1343 
1344  for (auto itr = a_Restrictions.cbegin(), end = a_Restrictions.cend(); itr != end; ++itr)
1345  {
1346  // Check if the restriction is already present:
1347  {
1348  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM RestrictionItem WHERE PermGroupID = ? AND Permission = ?");
1349  stmt.bind(1, GroupID);
1350  stmt.bind(2, *itr);
1351  if (!stmt.executeStep())
1352  {
1353  LOGWARNING("%s: Failed to check binding between restriction %s and group %s, aborting.", __FUNCTION__, itr->c_str(), a_GroupName.c_str());
1354  return false;
1355  }
1356  if (stmt.getColumn(0).getInt() > 0)
1357  {
1358  LOGD("%s: Restriction %s is already present in group %s, skipping and returning success.",
1359  __FUNCTION__, itr->c_str(), a_GroupName.c_str()
1360  );
1361  continue;
1362  }
1363  }
1364 
1365  // Add the permission:
1366  {
1367  SQLite::Statement stmt(m_DB, "INSERT INTO RestrictionItem (Permission, PermGroupID) VALUES (?, ?)");
1368  stmt.bind(1, *itr);
1369  stmt.bind(2, GroupID);
1370  if (stmt.exec() <= 0)
1371  {
1372  LOGWARNING("%s: Failed to add restriction %s to group %s, skipping.", __FUNCTION__, itr->c_str(), a_GroupName.c_str());
1373  continue;
1374  }
1375  }
1376  } // for itr - a_Restrictions[]
1377 
1378  // Adding succeeded:
1379  return true;
1380  }
1381  catch (const SQLite::Exception & ex)
1382  {
1383  LOGWARNING("%s: Failed to add restrictions to group %s: %s",
1384  __FUNCTION__, a_GroupName.c_str(), ex.what()
1385  );
1386  }
1387  return false;
1388 }
1389 
1390 
1391 
1392 
1393 
1394 void cRankManager::RemoveRank(const AString & a_RankName, const AString & a_ReplacementRankName)
1395 {
1397  cCSLock Lock(m_CS);
1398 
1399  // Check if the default rank is being removed with a proper replacement:
1400  if ((a_RankName == m_DefaultRank) && !RankExists(a_ReplacementRankName))
1401  {
1402  LOGWARNING("%s: Cannot remove rank %s, it is the default rank and the replacement rank doesn't exist.", __FUNCTION__, a_RankName.c_str());
1403  return;
1404  }
1405 
1406  AStringVector res;
1407  try
1408  {
1409  // Get the RankID for the rank being removed:
1410  int RemoveRankID;
1411  {
1412  SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?");
1413  stmt.bind(1, a_RankName);
1414  if (!stmt.executeStep())
1415  {
1416  LOGINFO("%s: Rank %s was not found. Skipping.", __FUNCTION__, a_RankName.c_str());
1417  return;
1418  }
1419  RemoveRankID = stmt.getColumn(0).getInt();
1420  }
1421 
1422  // Get the RankID for the replacement rank:
1423  int ReplacementRankID = -1;
1424  {
1425  SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?");
1426  stmt.bind(1, a_ReplacementRankName);
1427  if (stmt.executeStep())
1428  {
1429  ReplacementRankID = stmt.getColumn(0).getInt();
1430  }
1431  }
1432 
1433  // Remove the rank's bindings to groups:
1434  {
1435  SQLite::Statement stmt(m_DB, "DELETE FROM RankPermGroup WHERE RankID = ?");
1436  stmt.bind(1, RemoveRankID);
1437  stmt.exec();
1438  }
1439 
1440  // Adjust players:
1441  if (ReplacementRankID == -1)
1442  {
1443  // No replacement, just delete all the players that have the rank:
1444  SQLite::Statement stmt(m_DB, "DELETE FROM PlayerRank WHERE RankID = ?");
1445  stmt.bind(1, RemoveRankID);
1446  stmt.exec();
1447  }
1448  else
1449  {
1450  // Replacement available, change all the player records:
1451  SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET RankID = ? WHERE RankID = ?");
1452  stmt.bind(1, ReplacementRankID);
1453  stmt.bind(2, RemoveRankID);
1454  stmt.exec();
1455  }
1456 
1457  // Remove the rank from the DB:
1458  {
1459  SQLite::Statement stmt(m_DB, "DELETE FROM Rank WHERE RankID = ?");
1460  stmt.bind(1, RemoveRankID);
1461  stmt.exec();
1462  }
1463 
1464  // Update the default rank, if it was the one being removed:
1465  if (a_RankName == m_DefaultRank)
1466  {
1467  m_DefaultRank = a_RankName;
1468  }
1469  }
1470  catch (const SQLite::Exception & ex)
1471  {
1472  LOGWARNING("%s: Failed to remove rank from DB: %s", __FUNCTION__, ex.what());
1473  }
1474 }
1475 
1476 
1477 
1478 
1479 
1480 void cRankManager::RemoveGroup(const AString & a_GroupName)
1481 {
1483  cCSLock Lock(m_CS);
1484 
1485  try
1486  {
1487  // Get the ID of the group:
1488  int GroupID;
1489  {
1490  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1491  stmt.bind(1, a_GroupName);
1492  if (!stmt.executeStep())
1493  {
1494  LOGINFO("%s: Group %s was not found, skipping.", __FUNCTION__, a_GroupName.c_str());
1495  return;
1496  }
1497  GroupID = stmt.getColumn(0).getInt();
1498  }
1499 
1500  // Remove all permissions from the group:
1501  {
1502  SQLite::Statement stmt(m_DB, "DELETE FROM PermissionItem WHERE PermGroupID = ?");
1503  stmt.bind(1, GroupID);
1504  stmt.exec();
1505  }
1506 
1507  // Remove the group from all ranks that contain it:
1508  {
1509  SQLite::Statement stmt(m_DB, "DELETE FROM RankPermGroup WHERE PermGroupID = ?");
1510  stmt.bind(1, GroupID);
1511  stmt.exec();
1512  }
1513 
1514  // Remove the group itself:
1515  {
1516  SQLite::Statement stmt(m_DB, "DELETE FROM PermGroup WHERE PermGroupID = ?");
1517  stmt.bind(1, GroupID);
1518  stmt.exec();
1519  }
1520  }
1521  catch (const SQLite::Exception & ex)
1522  {
1523  LOGWARNING("%s: Failed to remove group %s from DB: %s", __FUNCTION__, a_GroupName.c_str(), ex.what());
1524  }
1525 }
1526 
1527 
1528 
1529 
1530 
1531 void cRankManager::RemoveGroupFromRank(const AString & a_GroupName, const AString & a_RankName)
1532 {
1534  cCSLock Lock(m_CS);
1535 
1536  try
1537  {
1538  // Get the IDs of the group and the rank:
1539  int GroupID, RankID;
1540  {
1541  SQLite::Statement stmt(m_DB,
1542  "SELECT PermGroup.PermGroupID, Rank.RankID FROM PermGroup "
1543  "LEFT JOIN RankPermGroup ON RankPermGroup.PermGroupID = PermGroup.PermGroupID "
1544  "LEFT JOIN Rank ON Rank.RankID = RankPermGroup.RankID "
1545  "WHERE PermGroup.Name = ? AND Rank.Name = ?"
1546  );
1547  stmt.bind(1, a_GroupName);
1548  stmt.bind(2, a_RankName);
1549  if (!stmt.executeStep())
1550  {
1551  LOGINFO("%s: Group %s was not found in rank %s, skipping.", __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str());
1552  return;
1553  }
1554  GroupID = stmt.getColumn(0).getInt();
1555  RankID = stmt.getColumn(1).getInt();
1556  }
1557 
1558  // Remove the group from all ranks that contain it:
1559  {
1560  SQLite::Statement stmt(m_DB, "DELETE FROM RankPermGroup WHERE PermGroupID = ?");
1561  stmt.bind(1, GroupID);
1562  stmt.exec();
1563  }
1564 
1565  // Remove the group-to-rank binding:
1566  {
1567  SQLite::Statement stmt(m_DB, "DELETE FROM RankPermGroup WHERE PermGroupID = ? AND RankID = ?");
1568  stmt.bind(1, GroupID);
1569  stmt.bind(1, RankID);
1570  stmt.exec();
1571  }
1572  }
1573  catch (const SQLite::Exception & ex)
1574  {
1575  LOGWARNING("%s: Failed to remove group %s from rank %s in the DB: %s", __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str(), ex.what());
1576  }
1577 }
1578 
1579 
1580 
1581 
1582 
1583 void cRankManager::RemovePermissionFromGroup(const AString & a_Permission, const AString & a_GroupName)
1584 {
1586  cCSLock Lock(m_CS);
1587 
1588  try
1589  {
1590  // Get the ID of the group:
1591  int GroupID;
1592  {
1593  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1594  stmt.bind(1, a_GroupName);
1595  if (!stmt.executeStep())
1596  {
1597  LOGINFO("%s: Group %s was not found, skipping.", __FUNCTION__, a_GroupName.c_str());
1598  return;
1599  }
1600  GroupID = stmt.getColumn(0).getInt();
1601  }
1602 
1603  // Remove the permission from the group:
1604  {
1605  SQLite::Statement stmt(m_DB, "DELETE FROM PermissionItem WHERE PermGroupID = ? AND Permission = ?");
1606  stmt.bind(1, GroupID);
1607  stmt.bind(2, a_Permission);
1608  stmt.exec();
1609  }
1610  }
1611  catch (const SQLite::Exception & ex)
1612  {
1613  LOGWARNING("%s: Failed to remove permission %s from group %s in DB: %s",
1614  __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str(), ex.what()
1615  );
1616  }
1617 }
1618 
1619 
1620 
1621 
1622 
1623 void cRankManager::RemoveRestrictionFromGroup(const AString & a_Restriction, const AString & a_GroupName)
1624 {
1626  cCSLock Lock(m_CS);
1627 
1628  try
1629  {
1630  // Get the ID of the group:
1631  int GroupID;
1632  {
1633  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1634  stmt.bind(1, a_GroupName);
1635  if (!stmt.executeStep())
1636  {
1637  LOGINFO("%s: Group %s was not found, skipping.", __FUNCTION__, a_GroupName.c_str());
1638  return;
1639  }
1640  GroupID = stmt.getColumn(0).getInt();
1641  }
1642 
1643  // Remove the permission from the group:
1644  {
1645  SQLite::Statement stmt(m_DB, "DELETE FROM RestrictionItem WHERE PermGroupID = ? AND Permission = ?");
1646  stmt.bind(1, GroupID);
1647  stmt.bind(2, a_Restriction);
1648  stmt.exec();
1649  }
1650  }
1651  catch (const SQLite::Exception & ex)
1652  {
1653  LOGWARNING("%s: Failed to remove restriction %s from group %s in DB: %s",
1654  __FUNCTION__, a_Restriction.c_str(), a_GroupName.c_str(), ex.what()
1655  );
1656  }
1657 }
1658 
1659 
1660 
1661 
1662 
1663 bool cRankManager::RenameRank(const AString & a_OldName, const AString & a_NewName)
1664 {
1666  cCSLock Lock(m_CS);
1667 
1668  try
1669  {
1670  // Check that NewName doesn't exist:
1671  {
1672  SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?");
1673  stmt.bind(1, a_NewName);
1674  if (stmt.executeStep())
1675  {
1676  LOGINFO("%s: Rank %s is already present, cannot rename %s", __FUNCTION__, a_NewName.c_str(), a_OldName.c_str());
1677  return false;
1678  }
1679  }
1680 
1681  // Rename:
1682  {
1683  SQLite::Statement stmt(m_DB, "UPDATE Rank SET Name = ? WHERE Name = ?");
1684  stmt.bind(1, a_NewName);
1685  stmt.bind(2, a_OldName);
1686  if (stmt.exec() <= 0)
1687  {
1688  LOGINFO("%s: There is no rank %s, cannot rename to %s.", __FUNCTION__, a_OldName.c_str(), a_NewName.c_str());
1689  return false;
1690  }
1691  }
1692 
1693  // Update the default rank, if it was the one being renamed:
1694  if (a_OldName == m_DefaultRank)
1695  {
1696  m_DefaultRank = a_NewName;
1697  }
1698 
1699  return true;
1700  }
1701  catch (const SQLite::Exception & ex)
1702  {
1703  LOGWARNING("%s: Failed to rename rank %s to %s in DB: %s",
1704  __FUNCTION__, a_OldName.c_str(), a_NewName.c_str(), ex.what());
1705  }
1706  return false;
1707 }
1708 
1709 
1710 
1711 
1712 
1713 bool cRankManager::RenameGroup(const AString & a_OldName, const AString & a_NewName)
1714 {
1716  cCSLock Lock(m_CS);
1717 
1718  try
1719  {
1720  // Check that NewName doesn't exist:
1721  {
1722  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1723  stmt.bind(1, a_NewName);
1724  if (stmt.executeStep())
1725  {
1726  LOGD("%s: Group %s is already present, cannot rename %s", __FUNCTION__, a_NewName.c_str(), a_OldName.c_str());
1727  return false;
1728  }
1729  }
1730 
1731  // Rename:
1732  bool res;
1733  {
1734  SQLite::Statement stmt(m_DB, "UPDATE PermGroup SET Name = ? WHERE Name = ?");
1735  stmt.bind(1, a_NewName);
1736  stmt.bind(2, a_OldName);
1737  res = (stmt.exec() > 0);
1738  }
1739 
1740  return res;
1741  }
1742  catch (const SQLite::Exception & ex)
1743  {
1744  LOGWARNING("%s: Failed to rename group %s to %s in DB: %s",
1745  __FUNCTION__, a_OldName.c_str(), a_NewName.c_str(), ex.what());
1746  }
1747  return false;
1748 }
1749 
1750 
1751 
1752 
1753 
1754 void cRankManager::SetPlayerRank(const cUUID & a_PlayerUUID, const AString & a_PlayerName, const AString & a_RankName)
1755 {
1757  cCSLock Lock(m_CS);
1758 
1759  AString StrUUID = a_PlayerUUID.ToShortString();
1760 
1761  try
1762  {
1763  // Get the rank ID:
1764  int RankID;
1765  {
1766  SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?");
1767  stmt.bind(1, a_RankName);
1768  if (!stmt.executeStep())
1769  {
1770  LOGWARNING("%s: There is no rank %s, aborting.", __FUNCTION__, a_RankName.c_str());
1771  return;
1772  }
1773  RankID = stmt.getColumn(0).getInt();
1774  }
1775 
1776  // Update the player's rank, if already in DB:
1777  {
1778  SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET RankID = ?, PlayerName = ? WHERE PlayerUUID = ?");
1779  stmt.bind(1, RankID);
1780  stmt.bind(2, a_PlayerName);
1781  stmt.bind(3, StrUUID);
1782  if (stmt.exec() > 0)
1783  {
1784  // Successfully updated the player's rank
1785  return;
1786  }
1787  }
1788 
1789  // The player is not yet in the DB, add them:
1790  SQLite::Statement stmt(m_DB, "INSERT INTO PlayerRank (RankID, PlayerUUID, PlayerName) VALUES (?, ?, ?)");
1791  stmt.bind(1, RankID);
1792  stmt.bind(2, StrUUID);
1793  stmt.bind(3, a_PlayerName);
1794  if (stmt.exec() > 0)
1795  {
1796  // Successfully added the player
1797  return;
1798  }
1799 
1800  LOGWARNING("%s: Failed to set player UUID %s to rank %s.",
1801  __FUNCTION__, StrUUID.c_str(), a_RankName.c_str()
1802  );
1803  }
1804  catch (const SQLite::Exception & ex)
1805  {
1806  LOGWARNING("%s: Failed to set player UUID %s to rank %s: %s",
1807  __FUNCTION__, StrUUID.c_str(), a_RankName.c_str(), ex.what()
1808  );
1809  }
1810 }
1811 
1812 
1813 
1814 
1815 
1816 void cRankManager::RemovePlayerRank(const cUUID & a_PlayerUUID)
1817 {
1819  cCSLock Lock(m_CS);
1820 
1821  AString StrUUID = a_PlayerUUID.ToShortString();
1822 
1823  try
1824  {
1825  SQLite::Statement stmt(m_DB, "DELETE FROM PlayerRank WHERE PlayerUUID = ?");
1826  stmt.bind(1, StrUUID);
1827  stmt.exec();
1828  }
1829  catch (const SQLite::Exception & ex)
1830  {
1831  LOGWARNING("%s: Failed to remove rank from player UUID %s: %s",
1832  __FUNCTION__, StrUUID.c_str(), ex.what()
1833  );
1834  }
1835 }
1836 
1837 
1838 
1839 
1840 
1842  const AString & a_RankName,
1843  const AString & a_MsgPrefix,
1844  const AString & a_MsgSuffix,
1845  const AString & a_MsgNameColorCode
1846 )
1847 {
1849  cCSLock Lock(m_CS);
1850 
1851  try
1852  {
1853  SQLite::Statement stmt(m_DB, "UPDATE Rank SET MsgPrefix = ?, MsgSuffix = ?, MsgNameColorCode = ? WHERE Name = ?");
1854  stmt.bind(1, a_MsgPrefix);
1855  stmt.bind(2, a_MsgSuffix);
1856  stmt.bind(3, a_MsgNameColorCode);
1857  stmt.bind(4, a_RankName);
1858  if (stmt.exec() < 1)
1859  {
1860  LOGINFO("%s: Rank %s not found, visuals not set.", __FUNCTION__, a_RankName.c_str());
1861  }
1862  }
1863  catch (const SQLite::Exception & ex)
1864  {
1865  LOGWARNING("%s: Failed to get ranks from DB: %s", __FUNCTION__, ex.what());
1866  }
1867 }
1868 
1869 
1870 
1871 
1872 
1874  const AString & a_RankName,
1875  AString & a_MsgPrefix,
1876  AString & a_MsgSuffix,
1877  AString & a_MsgNameColorCode
1878 )
1879 {
1881  cCSLock Lock(m_CS);
1882 
1883  try
1884  {
1885  SQLite::Statement stmt(m_DB, "SELECT MsgPrefix, MsgSuffix, MsgNameColorCode FROM Rank WHERE Name = ?");
1886  stmt.bind(1, a_RankName);
1887  if (!stmt.executeStep())
1888  {
1889  // Rank not found
1890  return false;
1891  }
1892  a_MsgPrefix = stmt.getColumn(0).getText();
1893  a_MsgSuffix = stmt.getColumn(1).getText();
1894  a_MsgNameColorCode = stmt.getColumn(2).getText();
1895  return true;
1896  }
1897  catch (const SQLite::Exception & ex)
1898  {
1899  LOGWARNING("%s: Failed to get ranks from DB: %s", __FUNCTION__, ex.what());
1900  }
1901  return false;
1902 }
1903 
1904 
1905 
1906 
1907 
1908 bool cRankManager::RankExists(const AString & a_RankName)
1909 {
1911  cCSLock Lock(m_CS);
1912 
1913  try
1914  {
1915  SQLite::Statement stmt(m_DB, "SELECT * FROM Rank WHERE Name = ?");
1916  stmt.bind(1, a_RankName);
1917  if (stmt.executeStep())
1918  {
1919  // The rank was found
1920  return true;
1921  }
1922  }
1923  catch (const SQLite::Exception & ex)
1924  {
1925  LOGWARNING("%s: Failed to query DB for rank %s: %s", __FUNCTION__, a_RankName.c_str(), ex.what());
1926  }
1927  return false;
1928 }
1929 
1930 
1931 
1932 
1933 
1934 bool cRankManager::GroupExists(const AString & a_GroupName)
1935 {
1937  cCSLock Lock(m_CS);
1938 
1939  try
1940  {
1941  SQLite::Statement stmt(m_DB, "SELECT * FROM PermGroup WHERE Name = ?");
1942  stmt.bind(1, a_GroupName);
1943  if (stmt.executeStep())
1944  {
1945  // The group was found
1946  return true;
1947  }
1948  }
1949  catch (const SQLite::Exception & ex)
1950  {
1951  LOGWARNING("%s: Failed to query DB for group %s: %s", __FUNCTION__, a_GroupName.c_str(), ex.what());
1952  }
1953  return false;
1954 }
1955 
1956 
1957 
1958 
1959 
1960 bool cRankManager::IsPlayerRankSet(const cUUID & a_PlayerUUID)
1961 {
1963  cCSLock Lock(m_CS);
1964 
1965  AString StrUUID = a_PlayerUUID.ToShortString();
1966 
1967  try
1968  {
1969  SQLite::Statement stmt(m_DB, "SELECT * FROM PlayerRank WHERE PlayerUUID = ?");
1970  stmt.bind(1, StrUUID);
1971  if (stmt.executeStep())
1972  {
1973  // The player UUID was found, they have a rank
1974  return true;
1975  }
1976  }
1977  catch (const SQLite::Exception & ex)
1978  {
1979  LOGWARNING("%s: Failed to query DB for player UUID %s: %s", __FUNCTION__, StrUUID.c_str(), ex.what());
1980  }
1981  return false;
1982 }
1983 
1984 
1985 
1986 
1987 
1988 bool cRankManager::IsGroupInRank(const AString & a_GroupName, const AString & a_RankName)
1989 {
1991  cCSLock Lock(m_CS);
1992 
1993  try
1994  {
1995  SQLite::Statement stmt(m_DB,
1996  "SELECT * FROM Rank "
1997  "LEFT JOIN RankPermGroup ON Rank.RankID = RankPermGroup.RankID "
1998  "LEFT JOIN PermGroup ON PermGroup.PermGroupID = RankPermGroup.PermGroupID "
1999  "WHERE Rank.Name = ? AND PermGroup.Name = ?"
2000  );
2001  stmt.bind(1, a_RankName);
2002  stmt.bind(2, a_GroupName);
2003  if (stmt.executeStep())
2004  {
2005  // The group is in the rank
2006  return true;
2007  }
2008  }
2009  catch (const SQLite::Exception & ex)
2010  {
2011  LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what());
2012  }
2013  return false;
2014 }
2015 
2016 
2017 
2018 
2019 
2020 bool cRankManager::IsPermissionInGroup(const AString & a_Permission, const AString & a_GroupName)
2021 {
2023  cCSLock Lock(m_CS);
2024 
2025  try
2026  {
2027  SQLite::Statement stmt(m_DB,
2028  "SELECT * FROM PermissionItem "
2029  "LEFT JOIN PermGroup ON PermGroup.PermGroupID = PermissionItem.PermGroupID "
2030  "WHERE PermissionItem.Permission = ? AND PermGroup.Name = ?"
2031  );
2032  stmt.bind(1, a_Permission);
2033  stmt.bind(2, a_GroupName);
2034  if (stmt.executeStep())
2035  {
2036  // The permission is in the group
2037  return true;
2038  }
2039  }
2040  catch (const SQLite::Exception & ex)
2041  {
2042  LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what());
2043  }
2044  return false;
2045 }
2046 
2047 
2048 
2049 
2050 
2051 bool cRankManager::IsRestrictionInGroup(const AString & a_Restriction, const AString & a_GroupName)
2052 {
2054  cCSLock Lock(m_CS);
2055 
2056  try
2057  {
2058  SQLite::Statement stmt(m_DB,
2059  "SELECT * FROM RestrictionItem "
2060  "LEFT JOIN PermGroup ON PermGroup.PermGroupID = RestrictionItem.PermGroupID "
2061  "WHERE RestrictionItem.Permission = ? AND PermGroup.Name = ?"
2062  );
2063  stmt.bind(1, a_Restriction);
2064  stmt.bind(2, a_GroupName);
2065  if (stmt.executeStep())
2066  {
2067  // The restriction is in the group
2068  return true;
2069  }
2070  }
2071  catch (const SQLite::Exception & ex)
2072  {
2073  LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what());
2074  }
2075  return false;
2076 }
2077 
2078 
2079 
2080 
2081 
2082 void cRankManager::NotifyNameUUID(const AString & a_PlayerName, const cUUID & a_UUID)
2083 {
2085  cCSLock Lock(m_CS);
2086 
2087  try
2088  {
2089  SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET PlayerName = ? WHERE PlayerUUID = ?");
2090  stmt.bind(1, a_PlayerName);
2091  stmt.bind(2, a_UUID.ToShortString());
2092  stmt.exec();
2093  }
2094  catch (const SQLite::Exception & ex)
2095  {
2096  LOGWARNING("%s: Failed to update DB: %s", __FUNCTION__, ex.what());
2097  }
2098 }
2099 
2100 
2101 
2102 
2103 
2104 bool cRankManager::SetDefaultRank(const AString & a_RankName)
2105 {
2107  cCSLock Lock(m_CS);
2108 
2109  try
2110  {
2111  // Find the rank's ID:
2112  int RankID = 0;
2113  {
2114  SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?");
2115  stmt.bind(1, a_RankName);
2116  if (!stmt.executeStep())
2117  {
2118  LOGINFO("%s: Cannot set rank %s as the default, it does not exist.", __FUNCTION__, a_RankName.c_str());
2119  return false;
2120  }
2121  }
2122 
2123  // Set the rank as the default:
2124  {
2125  SQLite::Statement stmt(m_DB, "UPDATE DefaultRank SET RankID = ?");
2126  stmt.bind(1, RankID);
2127  if (stmt.exec() < 1)
2128  {
2129  // Failed to update, there might be none in the DB, try inserting:
2130  SQLite::Statement stmt2(m_DB, "INSERT INTO DefaultRank (RankID) VALUES (?)");
2131  stmt2.bind(1, RankID);
2132  if (stmt2.exec() < 1)
2133  {
2134  LOGINFO("%s: Cannot update the default rank in the DB to %s.", __FUNCTION__, a_RankName.c_str());
2135  return false;
2136  }
2137  }
2138  }
2139 
2140  // Set the internal cache:
2141  m_DefaultRank = a_RankName;
2142  return true;
2143  }
2144  catch (const SQLite::Exception & ex)
2145  {
2146  LOGWARNING("%s: Failed to update DB: %s", __FUNCTION__, ex.what());
2147  return false;
2148  }
2149 }
2150 
2151 
2152 
2153 
2154 
2156 {
2158  cCSLock Lock(m_CS);
2159 
2160  try
2161  {
2162  SQLite::Statement stmt(m_DB, "DELETE FROM PlayerRank");
2163  stmt.exec();
2164  }
2165  catch (SQLite::Exception & ex)
2166  {
2167  LOGWARNING("%s: Failed to remove / clear all players: %s", __FUNCTION__, ex.what());
2168  }
2169 }
2170 
2171 
2172 
2173 
2174 
2175 bool cRankManager::UpdatePlayerName(const cUUID & a_PlayerUUID, const AString & a_NewPlayerName)
2176 {
2178  cCSLock Lock(m_CS);
2179 
2180  AString StrUUID = a_PlayerUUID.ToShortString();
2181 
2182  try
2183  {
2184  SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET PlayerName = ? WHERE PlayerUUID = ?");
2185  stmt.bind(1, a_NewPlayerName);
2186  stmt.bind(2, StrUUID);
2187  if (stmt.exec() > 0)
2188  {
2189  // The player name was changed, returns true
2190  return true;
2191  }
2192  }
2193  catch (const SQLite::Exception & ex)
2194  {
2195  LOGWARNING("%s: Failed to update player name from UUID %s: %s", __FUNCTION__, StrUUID.c_str(), ex.what());
2196  }
2197  return false;
2198 }
2199 
2200 
2201 
2202 
2203 
2205 {
2206  return (
2207  IsDBTableEmpty("Rank") &&
2208  IsDBTableEmpty("PlayerRank") &&
2209  IsDBTableEmpty("PermGroup") &&
2210  IsDBTableEmpty("RankPermGroup") &&
2211  IsDBTableEmpty("PermissionItem") &&
2212  IsDBTableEmpty("DefaultRank")
2213  );
2214 }
2215 
2216 
2217 
2218 
2219 
2220 bool cRankManager::IsDBTableEmpty(const AString & a_TableName)
2221 {
2222  try
2223  {
2224  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM " + a_TableName);
2225  return (stmt.executeStep() && (stmt.getColumn(0).getInt() == 0));
2226  }
2227  catch (const SQLite::Exception & ex)
2228  {
2229  LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what());
2230  }
2231  return false;
2232 }
2233 
2234 
2235 
2236 
2237 
2239 {
2240  // Wrap everything in a big transaction to speed things up:
2241  cMassChangeLock Lock(*this);
2242 
2243  // Create ranks:
2244  AddRank("Default", "", "", "");
2245  AddRank("VIP", "", "", "");
2246  AddRank("Operator", "", "", "");
2247  AddRank("Admin", "", "", "");
2248 
2249  // Create groups:
2250  AddGroup("Default");
2251  AddGroup("Kick");
2252  AddGroup("Teleport");
2253  AddGroup("Everything");
2254 
2255  // Add groups to ranks:
2256  AddGroupToRank("Default", "Default");
2257  AddGroupToRank("Teleport", "VIP");
2258  AddGroupToRank("Teleport", "Operator");
2259  AddGroupToRank("Kick", "Operator");
2260  AddGroupToRank("Everything", "Admin");
2261 
2262  // Add permissions to groups:
2263  AddPermissionToGroup("core.help", "Default");
2264  AddPermissionToGroup("core.build", "Default");
2265  AddPermissionToGroup("core.teleport", "Teleport");
2266  AddPermissionToGroup("core.kick", "Kick");
2267  AddPermissionToGroup("*", "Everything");
2268 
2269  // Set the default rank:
2270  SetDefaultRank("Default");
2271 }
2272 
2273 
2274 
2275 
2276 
2277 bool cRankManager::DoesColumnExist(const char * a_TableName, const char * a_ColumnName)
2278 {
2279  try
2280  {
2281  SQLite::Statement stmt(m_DB, Printf("PRAGMA table_info(%s)", a_TableName));
2282  while (stmt.executeStep()) // Iterate over all table's columns
2283  {
2284  int NumColumns = stmt.getColumnCount();
2285  for (int i = 0; i < NumColumns; i++) // Iterate over all reply's columns (table column's metadata)
2286  {
2287  auto column = stmt.getColumn(i);
2288  if (strcmp(column.getName(), "name") == 0)
2289  {
2290  if (NoCaseCompare(column.getText(), a_ColumnName) == 0)
2291  {
2292  // Colun found
2293  return true;
2294  }
2295  }
2296  } // for i - stmt.getColumns()
2297  } // while (stmt.executeStep())
2298  }
2299  catch (const SQLite::Exception & ex)
2300  {
2301  LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what());
2302  }
2303  return false;
2304 }
2305 
2306 
2307 
2308 
2309 
2310 void cRankManager::CreateColumnIfNotExists(const char * a_TableName, const char * a_ColumnName, const char * a_ColumnType)
2311 {
2312  // If the column already exists, bail out:
2313  if (DoesColumnExist(a_TableName, a_ColumnName))
2314  {
2315  return;
2316  }
2317 
2318  // Add the column:
2319  try
2320  {
2321  m_DB.exec(Printf("ALTER TABLE %s ADD COLUMN %s %s", a_TableName, a_ColumnName, a_ColumnType));
2322  }
2323  catch (const SQLite::Exception & exc)
2324  {
2325  LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, exc.what());
2326  }
2327 }
2328 
2329 
2330 
2331 
cRankManager(void)
Creates the rank manager.
void Initialize(cMojangAPI &a_MojangAPI)
Initializes the rank manager.
void ClearPlayerRanks(void)
Removes all player ranks from the database.
bool AreDBTablesEmpty(void)
Returns true if all the DB tables are empty, indicating a fresh new install.
sUserMap m_Users
List of all players read from the ini file.
void RemoveRestrictionFromGroup(const AString &a_Restriction, const AString &a_GroupName)
Removes the specified restriction from the specified group.
std::vector< cUUID > GetUUIDsFromPlayerNames(const AStringVector &a_PlayerName, bool a_UseOnlyCached=false)
Converts the player names into UUIDs.
Definition: MojangAPI.cpp:380
AStringVector GetPlayerGroups(const cUUID &a_PlayerUUID)
Returns the names of Groups that the specified player has assigned to them.
void CreateDefaults(void)
Creates a default set of ranks / groups / permissions.
void ResolveUserUUIDs(void)
Resolves the UUID of each user in m_Users.
bool IsGroupInRank(const AString &a_GroupName, const AString &a_RankName)
Returns true iff the specified rank contains the specified group.
std::map< AString, sGroup > sGroupMap
Definition: RankManager.cpp:85
bool ReadGroups(void)
Reads the groups from the "groups.ini" file into m_Groups.
AString ToShortString() const
Converts the UUID to a short form string (i.e without dashes).
Definition: UUID.cpp:133
void CreateGroups(void)
Creates groups based on m_Groups.
AStringVector GetAllRanks(void)
Returns the names of all defined ranks.
int GetNumKeys(void) const
Returns number of keys currently in the ini.
Definition: IniFile.h:112
AStringVector GetRankPermissions(const AString &a_RankName)
Returns all permissions that the specified rank has assigned to it, through all its groups...
bool FromString(const AString &a_StringUUID)
Tries to interpret the string as a short or long form UUID and assign from it.
Definition: UUID.cpp:102
void CleanUserGroups(void)
Removes non-existent groups from each user&#39;s definition.
bool m_IsInitialized
Set to true once the manager is initialized.
Definition: RankManager.h:274
bool AddRestrictionsToGroup(const AStringVector &a_Restrictions, const AString &a_GroupName)
Adds the specified restrictions to the specified group.
AString GetPlayerRankName(const cUUID &a_PlayerUUID)
Returns the name of the rank that the specified player has assigned to them.
bool AddGroupToRank(const AString &a_GroupName, const AString &a_RankName)
Adds the specified permission group to the specified rank.
AStringVector GetPlayerPermissions(const cUUID &a_PlayerUUID)
Returns the permissions that the specified player has assigned to them.
void CreateDefaults(void)
Creates the Default rank that contains the Default group, if it exists.
bool IsPermissionInGroup(const AString &a_Permission, const AString &a_GroupName)
Returns true iff the specified group contains the specified permission.
AStringVector GetPlayerRestrictions(const cUUID &a_PlayerUUID)
Returns the restrictions that the specified player has assigned to them.
void CleanGroupInheritance(void)
Removes non-existent groups from all the groups&#39; inheritance.
bool AddRestrictionToGroup(const AString &a_Restriction, const AString &a_GroupName)
Adds the specified restriction to the specified group.
bool GetRankVisuals(const AString &a_RankName, AString &a_MsgPrefix, AString &a_MsgSuffix, AString &a_MsgNameColorCode)
Returns the message visuals of an existing rank.
AStringVector GetAllGroups(void)
Returns the names of all permission groups.
void NotifyNameUUID(const AString &a_PlayerName, const cUUID &a_UUID)
Called by cMojangAPI whenever the playername-uuid pairing is discovered.
bool RankExists(const AString &a_RankName)
Returns true iff the specified rank exists in the DB.
void AddGroup(const AString &a_GroupName)
Adds a new permission group.
void RemovePermissionFromGroup(const AString &a_Permission, const AString &a_GroupName)
Removes the specified permission from the specified group.
AStringVector GetRankRestrictions(const AString &a_RankName)
Returns all restrictions that the specified rank has assigned to it, through all its groups...
bool RenameRank(const AString &a_OldName, const AString &a_NewName)
Renames the specified rank.
bool DoesColumnExist(const char *a_TableName, const char *a_ColumnName)
Returns true if the specified column exists in the specified table.
void AddRank(const AString &a_RankName, const AString &a_MsgPrefix, const AString &a_MsgSuffix, const AString &a_MsgNameColorCode)
Adds a new rank.
SQLite::Database m_DB
The database storage for all the data.
Definition: RankManager.h:265
AString GetPlayerName(const cUUID &a_PlayerUUID)
Returns the last name that the specified player has.
void RemoveRank(const AString &a_RankName, const AString &a_ReplacementRankName)
Removes the specified rank.
bool ReadFile(const AString &a_FileName, bool a_AllowExampleRedirect=true)
Reads the contents of the specified ini file If the file doesn&#39;t exist and a_AllowExampleRedirect is ...
Definition: IniFile.cpp:50
Definition: UUID.h:10
AStringVector GetGroupPermissions(const AString &a_GroupName)
Returns the permissions that the specified group has assigned to it.
void SetRankManager(cRankManager *a_RankManager)
Sets the m_RankMgr that is used for name-uuid notifications.
Definition: MojangAPI.h:84
std::vector< AString > AStringVector
Definition: StringUtils.h:14
Migrates from groups.ini and users.ini into the rankmanager DB.
Definition: RankManager.cpp:20
std::map< AString, AString > cStringMap
sGroup(const AString &a_Name, const AString &a_Color, const AStringVector &a_Inherits, const AStringVector &a_Permissions)
Definition: RankManager.cpp:77
AStringVector GetAllPermissions(void)
Returns all the distinct permissions that are stored in the DB.
bool RenameGroup(const AString &a_OldName, const AString &a_NewName)
Renames the specified group.
void CreateColumnIfNotExists(const char *a_TableName, const char *a_ColumnName, const char *a_ColumnType="")
If the specified table doesn&#39;t contain the specified column, it is added to the table.
void SetRanks(void)
Creates a rank for each player, based on the master groups they are assigned.
int NoCaseCompare(const AString &s1, const AString &s2)
Case-insensitive string comparison.
AStringVector StringSplitAndTrim(const AString &str, const AString &delim)
Split the string at any of the listed delimiters and trim each value.
bool IsPlayerRankSet(const cUUID &a_PlayerUUID)
Returns true iff the specified player has a rank assigned to them in the DB.
cMojangAPI * m_MojangAPI
The MojangAPI instance that is used for translating playernames to UUIDs.
Definition: RankManager.h:278
void LOGINFO(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:165
AStringVector GetAllRestrictions(void)
Returns all the distinct restrictions that are stored in the DB.
AString & Printf(AString &str, const char *format, fmt::ArgList args)
Output the formatted text into the string.
Definition: StringUtils.cpp:55
void RemovePlayerRank(const cUUID &a_PlayerUUID)
Removes the player&#39;s rank assignment.
#define ASSERT(x)
Definition: Globals.h:335
void LOGWARNING(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:174
bool UpdatePlayerName(const cUUID &a_PlayerUUID, const AString &a_NewPlayerName)
Updates the playername that is saved with this uuid.
bool IsRestrictionInGroup(const AString &a_Restriction, const AString &a_GroupName)
Returns true iff the specified group contains the specified restriction.
#define LOGD(...)
Definition: LoggerSimple.h:40
void SetRankVisuals(const AString &a_RankName, const AString &a_MsgPrefix, const AString &a_MsgSuffix, const AString &a_MsgNameColorCode)
Sets the message visuals of an existing rank.
Container for a group read from an INI file.
Definition: RankManager.cpp:68
sUser(const AString &a_Name, const AStringVector &a_Groups)
Container for a single user read from an INI file.
Definition: RankManager.cpp:89
AString GetKeyName(const int keyID) const
Definition: IniFile.cpp:289
bool IsDBTableEmpty(const AString &a_TableName)
Returns true iff the specified DB table is empty.
bool AddPermissionToGroup(const AString &a_Permission, const AString &a_GroupName)
Adds the specified permission to the specified permission group.
bool AddPermissionsToGroup(const AStringVector &a_Permissions, const AString &a_GroupName)
Adds the specified permissions to the specified permission group.
bool Migrate(void)
Performs the complete migration from INI files to DB.
Definition: RankManager.cpp:32
cUUID GetUUIDFromPlayerName(const AString &a_PlayerName, bool a_UseOnlyCached=false)
Converts a player name into a UUID.
Definition: MojangAPI.cpp:318
sGroupMap m_Groups
List of all groups read from the ini file.
bool GroupExists(const AString &a_GroupName)
Returns true iff the specified group exists in the DB.
cCriticalSection m_CS
The mutex protecting m_DB and m_DefaultRank against multi-threaded access.
Definition: RankManager.h:271
cUUID m_UUID
Assigned by ResolveUserUUIDs(), contains the online (Mojang) UUID of the player.
Definition: RankManager.cpp:95
void GenerateOfflineUUID(void)
Generates an UUID based on the username stored for this client, and stores it in the m_UUID member...
std::string AString
Definition: StringUtils.h:13
cMojangAPI & m_MojangAPI
The player name to UUID resolver.
std::vector< cUUID > GetAllPlayerUUIDs(void)
Returns the uuids of all defined players.
AString m_DefaultRank
The name of the default rank.
Definition: RankManager.h:268
cUUID m_OfflineUUID
Assigned by ResolveUserUUIDs(), contains the offline (generated) UUID of the player.
Definition: RankManager.cpp:98
AStringVector GetGroupRestrictions(const AString &a_GroupName)
Returns the restrictions that the specified group has assigned to it.
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
cRankManager & m_RankManager
The parent Rank manager where we will create the groups, ranks and players.
AStringVector GetRankGroups(const AString &a_RankName)
Returns the names of groups that the specified rank has assigned to it.
cStringMap m_GroupsToRanks
Maps lists of groups to rank names.
Acquire this lock to perform mass changes.
Definition: RankManager.h:30
void AddGroups(const AStringVector &a_GroupNames)
Bulk-adds groups.
cRankManagerIniMigrator(cRankManager &a_RankManager, cMojangAPI &a_MojangAPI)
Definition: RankManager.cpp:23
void RemoveGroupFromRank(const AString &a_GroupName, const AString &a_RankName)
Removes the specified group from the specified rank.
void RemoveGroup(const AString &a_GroupName)
Removes the specified group completely.
bool SetDefaultRank(const AString &a_RankName)
Sets the specified rank as the default rank.
AStringVector GetAllPermissionsRestrictions(void)
Returns all the distinct permissions and restrictions that are stored in the DB.
AString GetValue(const AString &keyname, const AString &valuename, const AString &defValue="") const override
Get the value at the specified key and value, returns defValue on failure.
Definition: IniFile.cpp:481
AString StrToLower(const AString &s)
Returns a lower-cased copy of the string.
bool IsNil() const
Returns true if this contains the "nil" UUID with all bits set to 0.
Definition: UUID.h:30
bool ReadUsers(void)
Reads the users from the "users.ini" file into m_Users.
bool GetPlayerMsgVisuals(const cUUID &a_PlayerUUID, AString &a_MsgPrefix, AString &a_MsgSuffix, AString &a_MsgNameColorCode)
Returns the message visuals (prefix, postfix, color) for the specified player.
void SetPlayerRank(const cUUID &a_PlayerUUID, const AString &a_PlayerName, const AString &a_RankName)
Sets the specified player&#39;s rank.
std::map< AString, sUser > sUserMap
void AddGroupsToRank(const AStringVector &a_Groups, const AString &a_RankName)
Adds the specified groups to the specified ranks.