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 "Protocol/MojangAPI.h"
9 #include "ClientHandle.h"
10 
11 
12 
13 
14 
16 // cRankManager:
17 
19  m_DB("Ranks.sqlite", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE),
20  m_IsInitialized(false)
21 {
22 }
23 
24 
25 
26 
27 
29 {
30 }
31 
32 
33 
34 
35 
37 {
38  ASSERT(!m_IsInitialized); // Calling Initialize for the second time?
39 
40  // Create the DB tables, if they don't exist:
41  m_DB.exec("CREATE TABLE IF NOT EXISTS Rank (RankID INTEGER PRIMARY KEY, Name, MsgPrefix, MsgSuffix, MsgNameColorCode)");
42  m_DB.exec("CREATE TABLE IF NOT EXISTS PlayerRank (PlayerUUID, PlayerName, RankID INTEGER)");
43  m_DB.exec("CREATE TABLE IF NOT EXISTS PermGroup (PermGroupID INTEGER PRIMARY KEY, Name)");
44  m_DB.exec("CREATE TABLE IF NOT EXISTS RankPermGroup (RankID INTEGER, PermGroupID INTEGER)");
45  m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionItem (PermGroupID INTEGER, Permission)");
46  m_DB.exec("CREATE TABLE IF NOT EXISTS RestrictionItem (PermGroupID INTEGER, Permission)");
47  m_DB.exec("CREATE TABLE IF NOT EXISTS DefaultRank (RankID INTEGER)");
48 
49  m_IsInitialized = true;
50 
51  a_MojangAPI.SetRankManager(this);
52 
53  // If tables are empty, create default ranks
54  if (AreDBTablesEmpty())
55  {
56  LOGINFO("Creating default ranks...");
58  LOGINFO("Default ranks created.");
59  }
60 
61  // Load the default rank:
62  try
63  {
64  SQLite::Statement stmt(m_DB,
65  "SELECT Rank.Name FROM Rank "
66  "LEFT JOIN DefaultRank ON Rank.RankID = DefaultRank.RankID"
67  );
68  if (stmt.executeStep())
69  {
70  m_DefaultRank = stmt.getColumn(0).getText();
71  }
72  }
73  catch (const SQLite::Exception & ex)
74  {
75  LOGWARNING("%s: Cannot load default rank: %s", __FUNCTION__, ex.what());
76  return;
77  }
78 
79  // If the default rank cannot be loaded, use the first rank:
80  if (m_DefaultRank.empty())
81  {
83  }
84 }
85 
86 
87 
88 
89 
91 {
93  cCSLock Lock(m_CS);
94 
95  try
96  {
97  SQLite::Statement stmt(m_DB, "SELECT Rank.Name FROM Rank LEFT JOIN PlayerRank ON Rank.RankID = PlayerRank.RankID WHERE PlayerRank.PlayerUUID = ?");
98  stmt.bind(1, a_PlayerUUID.ToShortString());
99  // executeStep returns false on no data
100  if (!stmt.executeStep())
101  {
102  // No data returned from the DB
103  return AString();
104  }
105  return stmt.getColumn(0).getText();
106  }
107  catch (const SQLite::Exception & ex)
108  {
109  LOGWARNING("%s: Cannot get player rank name: %s", __FUNCTION__, ex.what());
110  }
111  return AString();
112 }
113 
114 
115 
116 
117 
119 {
121  cCSLock Lock(m_CS);
122 
123  try
124  {
125  // Prepare the DB statement:
126  SQLite::Statement stmt(m_DB, "SELECT PlayerName FROM PlayerRank WHERE PlayerUUID = ?");
127  stmt.bind(1, a_PlayerUUID.ToShortString());
128 
129  if (stmt.executeStep())
130  {
131  return stmt.getColumn(0).getText();
132  }
133  }
134  catch (SQLite::Exception & ex)
135  {
136  LOGWARNING("%s: Cannot get player name: %s", __FUNCTION__, ex.what());
137  }
138  return AString();
139 }
140 
141 
142 
143 
144 
146 {
148  cCSLock Lock(m_CS);
149 
150  AStringVector res;
151  try
152  {
153  // Prepare the DB statement:
154  SQLite::Statement stmt(m_DB,
155  "SELECT PermGroup.Name FROM PermGroup "
156  "LEFT JOIN RankPermGroup ON PermGroup.PermGroupID = RankPermGroup.PermGroupID "
157  "LEFT JOIN PlayerRank ON PlayerRank.RankID = RankPermGroup.RankID "
158  "WHERE PlayerRank.PlayerUUID = ?"
159  );
160  stmt.bind(1, a_PlayerUUID.ToShortString());
161 
162  // Execute and get results:
163  while (stmt.executeStep())
164  {
165  res.push_back(stmt.getColumn(0).getText());
166  }
167  }
168  catch (const SQLite::Exception & ex)
169  {
170  LOGWARNING("%s: Cannot get player groups: %s", __FUNCTION__, ex.what());
171  }
172  return res;
173 }
174 
175 
176 
177 
178 
180 {
181  AString Rank = GetPlayerRankName(a_PlayerUUID);
182  if (Rank.empty())
183  {
184  Rank = m_DefaultRank;
185  }
186  return GetRankPermissions(Rank);
187 }
188 
189 
190 
191 
192 
194 {
195  AString Rank = GetPlayerRankName(a_PlayerUUID);
196  if (Rank.empty())
197  {
198  Rank = m_DefaultRank;
199  }
200  return GetRankRestrictions(Rank);
201 }
202 
203 
204 
205 
206 
208 {
210  cCSLock Lock(m_CS);
211 
212  AStringVector res;
213  try
214  {
215  SQLite::Statement stmt(m_DB,
216  "SELECT PermGroup.Name FROM PermGroup "
217  "LEFT JOIN RankPermGroup ON RankPermGroup.PermGroupID = PermGroup.PermGroupID "
218  "LEFT JOIN Rank ON Rank.RankID = RankPermGroup.RankID "
219  "WHERE Rank.Name = ?"
220  );
221  stmt.bind(1, a_RankName);
222  while (stmt.executeStep())
223  {
224  res.push_back(stmt.getColumn(0).getText());
225  }
226  }
227  catch (const SQLite::Exception & ex)
228  {
229  LOGWARNING("%s: Failed to get rank groups from DB: %s", __FUNCTION__, ex.what());
230  }
231  return res;
232 }
233 
234 
235 
236 
237 
239 {
241  cCSLock Lock(m_CS);
242 
243  AStringVector res;
244  try
245  {
246  SQLite::Statement stmt(m_DB,
247  "SELECT PermissionItem.Permission FROM PermissionItem "
248  "LEFT JOIN PermGroup ON PermGroup.PermGroupID = PermissionItem.PermGroupID "
249  "WHERE PermGroup.Name = ?"
250  );
251  stmt.bind(1, a_GroupName);
252  while (stmt.executeStep())
253  {
254  res.push_back(stmt.getColumn(0).getText());
255  }
256  }
257  catch (const SQLite::Exception & ex)
258  {
259  LOGWARNING("%s: Failed to get group permissions from DB: %s", __FUNCTION__, ex.what());
260  }
261  return res;
262 }
263 
264 
265 
266 
267 
269 {
271  cCSLock Lock(m_CS);
272 
273  AStringVector res;
274  try
275  {
276  SQLite::Statement stmt(m_DB,
277  "SELECT RestrictionItem.Permission FROM RestrictionItem "
278  "LEFT JOIN PermGroup ON PermGroup.PermGroupID = RestrictionItem.PermGroupID "
279  "WHERE PermGroup.Name = ?"
280  );
281  stmt.bind(1, a_GroupName);
282  while (stmt.executeStep())
283  {
284  res.push_back(stmt.getColumn(0).getText());
285  }
286  }
287  catch (const SQLite::Exception & ex)
288  {
289  LOGWARNING("%s: Failed to get group restrictions from DB: %s", __FUNCTION__, ex.what());
290  }
291  return res;
292 }
293 
294 
295 
296 
297 
299 {
301  cCSLock Lock(m_CS);
302 
303  AStringVector res;
304  try
305  {
306  SQLite::Statement stmt(m_DB,
307  "SELECT PermissionItem.Permission FROM PermissionItem "
308  "LEFT JOIN RankPermGroup ON RankPermGroup.PermGroupID = PermissionItem.PermGroupID "
309  "LEFT JOIN Rank ON Rank.RankID = RankPermGroup.RankID "
310  "WHERE Rank.Name = ?"
311  );
312  stmt.bind(1, a_RankName);
313  while (stmt.executeStep())
314  {
315  res.push_back(stmt.getColumn(0).getText());
316  }
317  }
318  catch (const SQLite::Exception & ex)
319  {
320  LOGWARNING("%s: Failed to get rank permissions from DB: %s", __FUNCTION__, ex.what());
321  }
322  return res;
323 }
324 
325 
326 
327 
328 
330 {
332  cCSLock Lock(m_CS);
333 
334  AStringVector res;
335  try
336  {
337  SQLite::Statement stmt(m_DB,
338  "SELECT RestrictionItem.Permission FROM RestrictionItem "
339  "LEFT JOIN RankPermGroup ON RankPermGroup.PermGroupID = RestrictionItem.PermGroupID "
340  "LEFT JOIN Rank ON Rank.RankID = RankPermGroup.RankID "
341  "WHERE Rank.Name = ?"
342  );
343  stmt.bind(1, a_RankName);
344  while (stmt.executeStep())
345  {
346  res.push_back(stmt.getColumn(0).getText());
347  }
348  }
349  catch (const SQLite::Exception & ex)
350  {
351  LOGWARNING("%s: Failed to get rank restrictions from DB: %s", __FUNCTION__, ex.what());
352  }
353  return res;
354 }
355 
356 
357 
358 
359 
360 std::vector<cUUID> cRankManager::GetAllPlayerUUIDs(void)
361 {
363  cCSLock Lock(m_CS);
364 
365  cUUID tempUUID;
366  std::vector<cUUID> res;
367  try
368  {
369  SQLite::Statement stmt(m_DB, "SELECT PlayerUUID FROM PlayerRank ORDER BY PlayerName COLLATE NOCASE");
370  while (stmt.executeStep())
371  {
372  if (!tempUUID.FromString(stmt.getColumn(0).getText()))
373  {
374  // Invalid UUID, ignore
375  continue;
376  }
377  res.push_back(tempUUID);
378  }
379  }
380  catch (const SQLite::Exception & ex)
381  {
382  LOGWARNING("%s: Failed to get players from DB: %s", __FUNCTION__, ex.what());
383  }
384  return res;
385 }
386 
387 
388 
389 
390 
392 {
394  cCSLock Lock(m_CS);
395 
396  AStringVector res;
397  try
398  {
399  SQLite::Statement stmt(m_DB, "SELECT Name FROM Rank");
400  while (stmt.executeStep())
401  {
402  res.push_back(stmt.getColumn(0).getText());
403  }
404  }
405  catch (const SQLite::Exception & ex)
406  {
407  LOGWARNING("%s: Failed to get ranks from DB: %s", __FUNCTION__, ex.what());
408  }
409  return res;
410 }
411 
412 
413 
414 
415 
417 {
419  cCSLock Lock(m_CS);
420 
421  AStringVector res;
422  try
423  {
424  SQLite::Statement stmt(m_DB, "SELECT Name FROM PermGroup");
425  while (stmt.executeStep())
426  {
427  res.push_back(stmt.getColumn(0).getText());
428  }
429  }
430  catch (const SQLite::Exception & ex)
431  {
432  LOGWARNING("%s: Failed to get groups from DB: %s", __FUNCTION__, ex.what());
433  }
434  return res;
435 }
436 
437 
438 
439 
440 
442 {
444  cCSLock Lock(m_CS);
445 
446  AStringVector res;
447  try
448  {
449  SQLite::Statement stmt(m_DB, "SELECT DISTINCT(Permission) FROM PermissionItem");
450  while (stmt.executeStep())
451  {
452  res.push_back(stmt.getColumn(0).getText());
453  }
454  }
455  catch (const SQLite::Exception & ex)
456  {
457  LOGWARNING("%s: Failed to get permissions from DB: %s", __FUNCTION__, ex.what());
458  }
459  return res;
460 }
461 
462 
463 
464 
465 
467 {
469  cCSLock Lock(m_CS);
470 
471  AStringVector res;
472  try
473  {
474  SQLite::Statement stmt(m_DB, "SELECT DISTINCT(Permission) FROM RestrictionItem");
475  while (stmt.executeStep())
476  {
477  res.push_back(stmt.getColumn(0).getText());
478  }
479  }
480  catch (const SQLite::Exception & ex)
481  {
482  LOGWARNING("%s: Failed to get restrictions from DB: %s", __FUNCTION__, ex.what());
483  }
484  return res;
485 }
486 
487 
488 
489 
490 
492 {
493  AStringVector Permissions = GetAllPermissions();
494  AStringVector Restrictions = GetAllRestrictions();
495  for (auto & restriction: Restrictions)
496  {
497  Permissions.push_back(restriction);
498  }
499  return Permissions;
500 }
501 
502 
503 
504 
505 
507  const cUUID & a_PlayerUUID,
508  AString & a_MsgPrefix,
509  AString & a_MsgSuffix,
510  AString & a_MsgNameColorCode
511 )
512 {
513  AString Rank = GetPlayerRankName(a_PlayerUUID);
514  if (Rank.empty())
515  {
516  // Rank not found, return failure:
517  a_MsgPrefix.clear();
518  a_MsgSuffix.clear();
519  a_MsgNameColorCode.clear();
520  return false;
521  }
522  return GetRankVisuals(Rank, a_MsgPrefix, a_MsgSuffix, a_MsgNameColorCode);
523 }
524 
525 
526 
527 
528 
530  const AString & a_RankName,
531  const AString & a_MsgPrefix,
532  const AString & a_MsgSuffix,
533  const AString & a_MsgNameColorCode
534 )
535 {
537  cCSLock Lock(m_CS);
538 
539  try
540  {
541  // Check if such a rank name is already used:
542  {
543  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM Rank WHERE Name = ?");
544  stmt.bind(1, a_RankName);
545  if (stmt.executeStep())
546  {
547  if (stmt.getColumn(0).getInt() > 0)
548  {
549  // Rank already exists, do nothing:
550  return;
551  }
552  }
553  }
554 
555  // Insert a new rank:
556  SQLite::Statement stmt(m_DB, "INSERT INTO Rank (Name, MsgPrefix, MsgSuffix, MsgNameColorCode) VALUES (?, ?, ?, ?)");
557  stmt.bind(1, a_RankName);
558  stmt.bind(2, a_MsgPrefix);
559  stmt.bind(3, a_MsgSuffix);
560  stmt.bind(4, a_MsgNameColorCode);
561  if (stmt.exec() <= 0)
562  {
563  LOGWARNING("%s: Failed to add a new rank \"%s\".", __FUNCTION__, a_RankName.c_str());
564  return;
565  }
566  }
567  catch (const SQLite::Exception & ex)
568  {
569  LOGWARNING("%s: Failed to add a new rank \"%s\": %s", __FUNCTION__, a_RankName.c_str(), ex.what());
570  }
571 }
572 
573 
574 
575 
576 
577 void cRankManager::AddGroup(const AString & a_GroupName)
578 {
580  cCSLock Lock(m_CS);
581 
582  try
583  {
584  // Check if such a group name is already used:
585  {
586  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermGroup WHERE Name = ?");
587  stmt.bind(1, a_GroupName);
588  if (stmt.executeStep())
589  {
590  if (stmt.getColumn(0).getInt() > 0)
591  {
592  // Group already exists, do nothing:
593  return;
594  }
595  }
596  }
597 
598  // Insert a new group:
599  SQLite::Statement stmt(m_DB, "INSERT INTO PermGroup (Name) VALUES (?)");
600  stmt.bind(1, a_GroupName);
601  if (stmt.exec() <= 0)
602  {
603  LOGWARNING("%s: Failed to add a new group \"%s\".", __FUNCTION__, a_GroupName.c_str());
604  return;
605  }
606  }
607  catch (const SQLite::Exception & ex)
608  {
609  LOGWARNING("%s: Failed to add a new group \"%s\": %s", __FUNCTION__, a_GroupName.c_str(), ex.what());
610  }
611 }
612 
613 
614 
615 
616 
617 void cRankManager::AddGroups(const AStringVector & a_GroupNames)
618 {
620  cCSLock Lock(m_CS);
621 
622  try
623  {
624  for (AStringVector::const_iterator itr = a_GroupNames.begin(), end = a_GroupNames.end(); itr != end; ++itr)
625  {
626  // Check if such the group name is already used:
627  {
628  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermGroup WHERE Name = ?");
629  stmt.bind(1, *itr);
630  if (stmt.executeStep())
631  {
632  if (stmt.getColumn(0).getInt() > 0)
633  {
634  // Group already exists, do nothing:
635  return;
636  }
637  }
638  }
639 
640  // Insert a new group:
641  SQLite::Statement stmt(m_DB, "INSERT INTO PermGroup (Name) VALUES (?)");
642  stmt.bind(1, *itr);
643  if (stmt.exec() <= 0)
644  {
645  LOGWARNING("%s: Failed to add a new group \"%s\".", __FUNCTION__, itr->c_str());
646  return;
647  }
648  } // for itr - a_GroupNames[]
649  }
650  catch (const SQLite::Exception & ex)
651  {
652  LOGWARNING("%s: Failed to add new groups: %s", __FUNCTION__, ex.what());
653  }
654 }
655 
656 
657 
658 
659 
660 bool cRankManager::AddGroupToRank(const AString & a_GroupName, const AString & a_RankName)
661 {
663  cCSLock Lock(m_CS);
664 
665  try
666  {
667  // Get the group's ID:
668  int GroupID;
669  {
670  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
671  stmt.bind(1, a_GroupName);
672  if (!stmt.executeStep())
673  {
674  LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str());
675  return false;
676  }
677  GroupID = stmt.getColumn(0);
678  }
679 
680  // Get the rank's ID:
681  int RankID;
682  {
683  SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?");
684  stmt.bind(1, a_RankName);
685  if (!stmt.executeStep())
686  {
687  LOGWARNING("%s: No such rank (%s), aborting.", __FUNCTION__, a_RankName.c_str());
688  return false;
689  }
690  RankID = stmt.getColumn(0);
691  }
692 
693  // Check if the group is already there:
694  {
695  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM RankPermGroup WHERE RankID = ? AND PermGroupID = ?");
696  stmt.bind(1, RankID);
697  stmt.bind(2, GroupID);
698  if (!stmt.executeStep())
699  {
700  LOGWARNING("%s: Failed to check binding between rank %s and group %s, aborting.", __FUNCTION__, a_RankName.c_str(), a_GroupName.c_str());
701  return false;
702  }
703  if (stmt.getColumn(0).getInt() > 0)
704  {
705  LOGD("%s: Group %s already present in rank %s, skipping and returning success.",
706  __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str()
707  );
708  return true;
709  }
710  }
711 
712  // Add the group:
713  {
714  SQLite::Statement stmt(m_DB, "INSERT INTO RankPermGroup (RankID, PermGroupID) VALUES (?, ?)");
715  stmt.bind(1, RankID);
716  stmt.bind(2, GroupID);
717  if (stmt.exec() <= 0)
718  {
719  LOGWARNING("%s: Failed to add group %s to rank %s, aborting.", __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str());
720  return false;
721  }
722  }
723 
724  // Adding succeeded:
725  return true;
726  }
727  catch (const SQLite::Exception & ex)
728  {
729  LOGWARNING("%s: Failed to add group %s to rank %s: %s", __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str(), ex.what());
730  }
731  return false;
732 }
733 
734 
735 
736 
737 
738 bool cRankManager::AddPermissionToGroup(const AString & a_Permission, const AString & a_GroupName)
739 {
741  cCSLock Lock(m_CS);
742 
743  try
744  {
745  // Get the group's ID:
746  int GroupID;
747  {
748  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
749  stmt.bind(1, a_GroupName);
750  if (!stmt.executeStep())
751  {
752  LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str());
753  return false;
754  }
755  GroupID = stmt.getColumn(0).getInt();
756  }
757 
758  // Check if the permission is already present:
759  {
760  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermissionItem WHERE PermGroupID = ? AND Permission = ?");
761  stmt.bind(1, GroupID);
762  stmt.bind(2, a_Permission);
763  if (!stmt.executeStep())
764  {
765  LOGWARNING("%s: Failed to check binding between permission %s and group %s, aborting.", __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str());
766  return false;
767  }
768  if (stmt.getColumn(0).getInt() > 0)
769  {
770  LOGD("%s: Permission %s is already present in group %s, skipping and returning success.",
771  __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str()
772  );
773  return true;
774  }
775  }
776 
777  // Add the permission:
778  {
779  SQLite::Statement stmt(m_DB, "INSERT INTO PermissionItem (Permission, PermGroupID) VALUES (?, ?)");
780  stmt.bind(1, a_Permission);
781  stmt.bind(2, GroupID);
782  if (stmt.exec() <= 0)
783  {
784  LOGWARNING("%s: Failed to add permission %s to group %s, aborting.", __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str());
785  return false;
786  }
787  }
788 
789  // Adding succeeded:
790  return true;
791  }
792  catch (const SQLite::Exception & ex)
793  {
794  LOGWARNING("%s: Failed to add permission %s to group %s: %s",
795  __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str(), ex.what()
796  );
797  }
798  return false;
799 }
800 
801 
802 
803 
804 
805 bool cRankManager::AddRestrictionToGroup(const AString & a_Restriction, const AString & a_GroupName)
806 {
808  cCSLock Lock(m_CS);
809 
810  try
811  {
812  // Get the group's ID:
813  int GroupID;
814  {
815  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
816  stmt.bind(1, a_GroupName);
817  if (!stmt.executeStep())
818  {
819  LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str());
820  return false;
821  }
822  GroupID = stmt.getColumn(0).getInt();
823  }
824 
825  // Check if the restriction is already present:
826  {
827  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM RestrictionItem WHERE PermGroupID = ? AND Permission = ?");
828  stmt.bind(1, GroupID);
829  stmt.bind(2, a_Restriction);
830  if (!stmt.executeStep())
831  {
832  LOGWARNING("%s: Failed to check binding between restriction %s and group %s, aborting.", __FUNCTION__, a_Restriction.c_str(), a_GroupName.c_str());
833  return false;
834  }
835  if (stmt.getColumn(0).getInt() > 0)
836  {
837  LOGD("%s: Restriction %s is already present in group %s, skipping and returning success.",
838  __FUNCTION__, a_Restriction.c_str(), a_GroupName.c_str()
839  );
840  return true;
841  }
842  }
843 
844  // Add the restriction:
845  {
846  SQLite::Statement stmt(m_DB, "INSERT INTO RestrictionItem (Permission, PermGroupID) VALUES (?, ?)");
847  stmt.bind(1, a_Restriction);
848  stmt.bind(2, GroupID);
849  if (stmt.exec() <= 0)
850  {
851  LOGWARNING("%s: Failed to add restriction %s to group %s, aborting.", __FUNCTION__, a_Restriction.c_str(), a_GroupName.c_str());
852  return false;
853  }
854  }
855 
856  // Adding succeeded:
857  return true;
858  }
859  catch (const SQLite::Exception & ex)
860  {
861  LOGWARNING("%s: Failed to add restriction %s to group %s: %s",
862  __FUNCTION__, a_Restriction.c_str(), a_GroupName.c_str(), ex.what()
863  );
864  }
865  return false;
866 }
867 
868 
869 
870 
871 
872 bool cRankManager::AddPermissionsToGroup(const AStringVector & a_Permissions, const AString & a_GroupName)
873 {
875  cCSLock Lock(m_CS);
876 
877  try
878  {
879  // Get the group's ID:
880  int GroupID;
881  {
882  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
883  stmt.bind(1, a_GroupName);
884  if (!stmt.executeStep())
885  {
886  LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str());
887  return false;
888  }
889  GroupID = stmt.getColumn(0).getInt();
890  }
891 
892  for (AStringVector::const_iterator itr = a_Permissions.begin(), end = a_Permissions.end(); itr != end; ++itr)
893  {
894  // Check if the permission is already present:
895  {
896  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermissionItem WHERE PermGroupID = ? AND Permission = ?");
897  stmt.bind(1, GroupID);
898  stmt.bind(2, *itr);
899  if (!stmt.executeStep())
900  {
901  LOGWARNING("%s: Failed to check binding between permission %s and group %s, aborting.", __FUNCTION__, itr->c_str(), a_GroupName.c_str());
902  return false;
903  }
904  if (stmt.getColumn(0).getInt() > 0)
905  {
906  LOGD("%s: Permission %s is already present in group %s, skipping and returning success.",
907  __FUNCTION__, itr->c_str(), a_GroupName.c_str()
908  );
909  continue;
910  }
911  }
912 
913  // Add the permission:
914  {
915  SQLite::Statement stmt(m_DB, "INSERT INTO PermissionItem (Permission, PermGroupID) VALUES (?, ?)");
916  stmt.bind(1, *itr);
917  stmt.bind(2, GroupID);
918  if (stmt.exec() <= 0)
919  {
920  LOGWARNING("%s: Failed to add permission %s to group %s, skipping.", __FUNCTION__, itr->c_str(), a_GroupName.c_str());
921  continue;
922  }
923  }
924  } // for itr - a_Permissions[]
925 
926  // Adding succeeded:
927  return true;
928  }
929  catch (const SQLite::Exception & ex)
930  {
931  LOGWARNING("%s: Failed to add permissions to group %s: %s",
932  __FUNCTION__, a_GroupName.c_str(), ex.what()
933  );
934  }
935  return false;
936 }
937 
938 
939 
940 
941 
942 bool cRankManager::AddRestrictionsToGroup(const AStringVector & a_Restrictions, const AString & a_GroupName)
943 {
945  cCSLock Lock(m_CS);
946 
947  try
948  {
949  // Get the group's ID:
950  int GroupID;
951  {
952  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
953  stmt.bind(1, a_GroupName);
954  if (!stmt.executeStep())
955  {
956  LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str());
957  return false;
958  }
959  GroupID = stmt.getColumn(0).getInt();
960  }
961 
962  for (auto itr = a_Restrictions.cbegin(), end = a_Restrictions.cend(); itr != end; ++itr)
963  {
964  // Check if the restriction is already present:
965  {
966  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM RestrictionItem WHERE PermGroupID = ? AND Permission = ?");
967  stmt.bind(1, GroupID);
968  stmt.bind(2, *itr);
969  if (!stmt.executeStep())
970  {
971  LOGWARNING("%s: Failed to check binding between restriction %s and group %s, aborting.", __FUNCTION__, itr->c_str(), a_GroupName.c_str());
972  return false;
973  }
974  if (stmt.getColumn(0).getInt() > 0)
975  {
976  LOGD("%s: Restriction %s is already present in group %s, skipping and returning success.",
977  __FUNCTION__, itr->c_str(), a_GroupName.c_str()
978  );
979  continue;
980  }
981  }
982 
983  // Add the permission:
984  {
985  SQLite::Statement stmt(m_DB, "INSERT INTO RestrictionItem (Permission, PermGroupID) VALUES (?, ?)");
986  stmt.bind(1, *itr);
987  stmt.bind(2, GroupID);
988  if (stmt.exec() <= 0)
989  {
990  LOGWARNING("%s: Failed to add restriction %s to group %s, skipping.", __FUNCTION__, itr->c_str(), a_GroupName.c_str());
991  continue;
992  }
993  }
994  } // for itr - a_Restrictions[]
995 
996  // Adding succeeded:
997  return true;
998  }
999  catch (const SQLite::Exception & ex)
1000  {
1001  LOGWARNING("%s: Failed to add restrictions to group %s: %s",
1002  __FUNCTION__, a_GroupName.c_str(), ex.what()
1003  );
1004  }
1005  return false;
1006 }
1007 
1008 
1009 
1010 
1011 
1012 void cRankManager::RemoveRank(const AString & a_RankName, const AString & a_ReplacementRankName)
1013 {
1015  cCSLock Lock(m_CS);
1016 
1017  // Check if the default rank is being removed with a proper replacement:
1018  if ((a_RankName == m_DefaultRank) && !RankExists(a_ReplacementRankName))
1019  {
1020  LOGWARNING("%s: Cannot remove rank %s, it is the default rank and the replacement rank doesn't exist.", __FUNCTION__, a_RankName.c_str());
1021  return;
1022  }
1023 
1024  AStringVector res;
1025  try
1026  {
1027  // Get the RankID for the rank being removed:
1028  int RemoveRankID;
1029  {
1030  SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?");
1031  stmt.bind(1, a_RankName);
1032  if (!stmt.executeStep())
1033  {
1034  LOGINFO("%s: Rank %s was not found. Skipping.", __FUNCTION__, a_RankName.c_str());
1035  return;
1036  }
1037  RemoveRankID = stmt.getColumn(0).getInt();
1038  }
1039 
1040  // Get the RankID for the replacement rank:
1041  int ReplacementRankID = -1;
1042  {
1043  SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?");
1044  stmt.bind(1, a_ReplacementRankName);
1045  if (stmt.executeStep())
1046  {
1047  ReplacementRankID = stmt.getColumn(0).getInt();
1048  }
1049  }
1050 
1051  // Remove the rank's bindings to groups:
1052  {
1053  SQLite::Statement stmt(m_DB, "DELETE FROM RankPermGroup WHERE RankID = ?");
1054  stmt.bind(1, RemoveRankID);
1055  stmt.exec();
1056  }
1057 
1058  // Adjust players:
1059  if (ReplacementRankID == -1)
1060  {
1061  // No replacement, just delete all the players that have the rank:
1062  SQLite::Statement stmt(m_DB, "DELETE FROM PlayerRank WHERE RankID = ?");
1063  stmt.bind(1, RemoveRankID);
1064  stmt.exec();
1065  }
1066  else
1067  {
1068  // Replacement available, change all the player records:
1069  SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET RankID = ? WHERE RankID = ?");
1070  stmt.bind(1, ReplacementRankID);
1071  stmt.bind(2, RemoveRankID);
1072  stmt.exec();
1073  }
1074 
1075  // Remove the rank from the DB:
1076  {
1077  SQLite::Statement stmt(m_DB, "DELETE FROM Rank WHERE RankID = ?");
1078  stmt.bind(1, RemoveRankID);
1079  stmt.exec();
1080  }
1081 
1082  // Update the default rank, if it was the one being removed:
1083  if (a_RankName == m_DefaultRank)
1084  {
1085  m_DefaultRank = a_RankName;
1086  }
1087  }
1088  catch (const SQLite::Exception & ex)
1089  {
1090  LOGWARNING("%s: Failed to remove rank from DB: %s", __FUNCTION__, ex.what());
1091  }
1092 }
1093 
1094 
1095 
1096 
1097 
1098 void cRankManager::RemoveGroup(const AString & a_GroupName)
1099 {
1101  cCSLock Lock(m_CS);
1102 
1103  try
1104  {
1105  // Get the ID of the group:
1106  int GroupID;
1107  {
1108  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1109  stmt.bind(1, a_GroupName);
1110  if (!stmt.executeStep())
1111  {
1112  LOGINFO("%s: Group %s was not found, skipping.", __FUNCTION__, a_GroupName.c_str());
1113  return;
1114  }
1115  GroupID = stmt.getColumn(0).getInt();
1116  }
1117 
1118  // Remove all permissions from the group:
1119  {
1120  SQLite::Statement stmt(m_DB, "DELETE FROM PermissionItem WHERE PermGroupID = ?");
1121  stmt.bind(1, GroupID);
1122  stmt.exec();
1123  }
1124 
1125  // Remove the group from all ranks that contain it:
1126  {
1127  SQLite::Statement stmt(m_DB, "DELETE FROM RankPermGroup WHERE PermGroupID = ?");
1128  stmt.bind(1, GroupID);
1129  stmt.exec();
1130  }
1131 
1132  // Remove the group itself:
1133  {
1134  SQLite::Statement stmt(m_DB, "DELETE FROM PermGroup WHERE PermGroupID = ?");
1135  stmt.bind(1, GroupID);
1136  stmt.exec();
1137  }
1138  }
1139  catch (const SQLite::Exception & ex)
1140  {
1141  LOGWARNING("%s: Failed to remove group %s from DB: %s", __FUNCTION__, a_GroupName.c_str(), ex.what());
1142  }
1143 }
1144 
1145 
1146 
1147 
1148 
1149 void cRankManager::RemoveGroupFromRank(const AString & a_GroupName, const AString & a_RankName)
1150 {
1152  cCSLock Lock(m_CS);
1153 
1154  try
1155  {
1156  // Get the IDs of the group and the rank:
1157  int GroupID, RankID;
1158  {
1159  SQLite::Statement stmt(m_DB,
1160  "SELECT PermGroup.PermGroupID, Rank.RankID FROM PermGroup "
1161  "LEFT JOIN RankPermGroup ON RankPermGroup.PermGroupID = PermGroup.PermGroupID "
1162  "LEFT JOIN Rank ON Rank.RankID = RankPermGroup.RankID "
1163  "WHERE PermGroup.Name = ? AND Rank.Name = ?"
1164  );
1165  stmt.bind(1, a_GroupName);
1166  stmt.bind(2, a_RankName);
1167  if (!stmt.executeStep())
1168  {
1169  LOGINFO("%s: Group %s was not found in rank %s, skipping.", __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str());
1170  return;
1171  }
1172  GroupID = stmt.getColumn(0).getInt();
1173  RankID = stmt.getColumn(1).getInt();
1174  }
1175 
1176  // Remove the group from all ranks that contain it:
1177  {
1178  SQLite::Statement stmt(m_DB, "DELETE FROM RankPermGroup WHERE PermGroupID = ?");
1179  stmt.bind(1, GroupID);
1180  stmt.exec();
1181  }
1182 
1183  // Remove the group-to-rank binding:
1184  {
1185  SQLite::Statement stmt(m_DB, "DELETE FROM RankPermGroup WHERE PermGroupID = ? AND RankID = ?");
1186  stmt.bind(1, GroupID);
1187  stmt.bind(1, RankID);
1188  stmt.exec();
1189  }
1190  }
1191  catch (const SQLite::Exception & ex)
1192  {
1193  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());
1194  }
1195 }
1196 
1197 
1198 
1199 
1200 
1201 void cRankManager::RemovePermissionFromGroup(const AString & a_Permission, const AString & a_GroupName)
1202 {
1204  cCSLock Lock(m_CS);
1205 
1206  try
1207  {
1208  // Get the ID of the group:
1209  int GroupID;
1210  {
1211  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1212  stmt.bind(1, a_GroupName);
1213  if (!stmt.executeStep())
1214  {
1215  LOGINFO("%s: Group %s was not found, skipping.", __FUNCTION__, a_GroupName.c_str());
1216  return;
1217  }
1218  GroupID = stmt.getColumn(0).getInt();
1219  }
1220 
1221  // Remove the permission from the group:
1222  {
1223  SQLite::Statement stmt(m_DB, "DELETE FROM PermissionItem WHERE PermGroupID = ? AND Permission = ?");
1224  stmt.bind(1, GroupID);
1225  stmt.bind(2, a_Permission);
1226  stmt.exec();
1227  }
1228  }
1229  catch (const SQLite::Exception & ex)
1230  {
1231  LOGWARNING("%s: Failed to remove permission %s from group %s in DB: %s",
1232  __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str(), ex.what()
1233  );
1234  }
1235 }
1236 
1237 
1238 
1239 
1240 
1241 void cRankManager::RemoveRestrictionFromGroup(const AString & a_Restriction, const AString & a_GroupName)
1242 {
1244  cCSLock Lock(m_CS);
1245 
1246  try
1247  {
1248  // Get the ID of the group:
1249  int GroupID;
1250  {
1251  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1252  stmt.bind(1, a_GroupName);
1253  if (!stmt.executeStep())
1254  {
1255  LOGINFO("%s: Group %s was not found, skipping.", __FUNCTION__, a_GroupName.c_str());
1256  return;
1257  }
1258  GroupID = stmt.getColumn(0).getInt();
1259  }
1260 
1261  // Remove the permission from the group:
1262  {
1263  SQLite::Statement stmt(m_DB, "DELETE FROM RestrictionItem WHERE PermGroupID = ? AND Permission = ?");
1264  stmt.bind(1, GroupID);
1265  stmt.bind(2, a_Restriction);
1266  stmt.exec();
1267  }
1268  }
1269  catch (const SQLite::Exception & ex)
1270  {
1271  LOGWARNING("%s: Failed to remove restriction %s from group %s in DB: %s",
1272  __FUNCTION__, a_Restriction.c_str(), a_GroupName.c_str(), ex.what()
1273  );
1274  }
1275 }
1276 
1277 
1278 
1279 
1280 
1281 bool cRankManager::RenameRank(const AString & a_OldName, const AString & a_NewName)
1282 {
1284  cCSLock Lock(m_CS);
1285 
1286  try
1287  {
1288  // Check that NewName doesn't exist:
1289  {
1290  SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?");
1291  stmt.bind(1, a_NewName);
1292  if (stmt.executeStep())
1293  {
1294  LOGINFO("%s: Rank %s is already present, cannot rename %s", __FUNCTION__, a_NewName.c_str(), a_OldName.c_str());
1295  return false;
1296  }
1297  }
1298 
1299  // Rename:
1300  {
1301  SQLite::Statement stmt(m_DB, "UPDATE Rank SET Name = ? WHERE Name = ?");
1302  stmt.bind(1, a_NewName);
1303  stmt.bind(2, a_OldName);
1304  if (stmt.exec() <= 0)
1305  {
1306  LOGINFO("%s: There is no rank %s, cannot rename to %s.", __FUNCTION__, a_OldName.c_str(), a_NewName.c_str());
1307  return false;
1308  }
1309  }
1310 
1311  // Update the default rank, if it was the one being renamed:
1312  if (a_OldName == m_DefaultRank)
1313  {
1314  m_DefaultRank = a_NewName;
1315  }
1316 
1317  return true;
1318  }
1319  catch (const SQLite::Exception & ex)
1320  {
1321  LOGWARNING("%s: Failed to rename rank %s to %s in DB: %s",
1322  __FUNCTION__, a_OldName.c_str(), a_NewName.c_str(), ex.what());
1323  }
1324  return false;
1325 }
1326 
1327 
1328 
1329 
1330 
1331 bool cRankManager::RenameGroup(const AString & a_OldName, const AString & a_NewName)
1332 {
1334  cCSLock Lock(m_CS);
1335 
1336  try
1337  {
1338  // Check that NewName doesn't exist:
1339  {
1340  SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?");
1341  stmt.bind(1, a_NewName);
1342  if (stmt.executeStep())
1343  {
1344  LOGD("%s: Group %s is already present, cannot rename %s", __FUNCTION__, a_NewName.c_str(), a_OldName.c_str());
1345  return false;
1346  }
1347  }
1348 
1349  // Rename:
1350  bool res;
1351  {
1352  SQLite::Statement stmt(m_DB, "UPDATE PermGroup SET Name = ? WHERE Name = ?");
1353  stmt.bind(1, a_NewName);
1354  stmt.bind(2, a_OldName);
1355  res = (stmt.exec() > 0);
1356  }
1357 
1358  return res;
1359  }
1360  catch (const SQLite::Exception & ex)
1361  {
1362  LOGWARNING("%s: Failed to rename group %s to %s in DB: %s",
1363  __FUNCTION__, a_OldName.c_str(), a_NewName.c_str(), ex.what());
1364  }
1365  return false;
1366 }
1367 
1368 
1369 
1370 
1371 
1372 void cRankManager::SetPlayerRank(const cUUID & a_PlayerUUID, const AString & a_PlayerName, const AString & a_RankName)
1373 {
1375  cCSLock Lock(m_CS);
1376 
1377  AString StrUUID = a_PlayerUUID.ToShortString();
1378 
1379  try
1380  {
1381  // Get the rank ID:
1382  int RankID;
1383  {
1384  SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?");
1385  stmt.bind(1, a_RankName);
1386  if (!stmt.executeStep())
1387  {
1388  LOGWARNING("%s: There is no rank %s, aborting.", __FUNCTION__, a_RankName.c_str());
1389  return;
1390  }
1391  RankID = stmt.getColumn(0).getInt();
1392  }
1393 
1394  // Update the player's rank, if already in DB:
1395  {
1396  SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET RankID = ?, PlayerName = ? WHERE PlayerUUID = ?");
1397  stmt.bind(1, RankID);
1398  stmt.bind(2, a_PlayerName);
1399  stmt.bind(3, StrUUID);
1400  if (stmt.exec() > 0)
1401  {
1402  // Successfully updated the player's rank
1403  return;
1404  }
1405  }
1406 
1407  // The player is not yet in the DB, add them:
1408  SQLite::Statement stmt(m_DB, "INSERT INTO PlayerRank (RankID, PlayerUUID, PlayerName) VALUES (?, ?, ?)");
1409  stmt.bind(1, RankID);
1410  stmt.bind(2, StrUUID);
1411  stmt.bind(3, a_PlayerName);
1412  if (stmt.exec() > 0)
1413  {
1414  // Successfully added the player
1415  return;
1416  }
1417 
1418  LOGWARNING("%s: Failed to set player UUID %s to rank %s.",
1419  __FUNCTION__, StrUUID.c_str(), a_RankName.c_str()
1420  );
1421  }
1422  catch (const SQLite::Exception & ex)
1423  {
1424  LOGWARNING("%s: Failed to set player UUID %s to rank %s: %s",
1425  __FUNCTION__, StrUUID.c_str(), a_RankName.c_str(), ex.what()
1426  );
1427  }
1428 }
1429 
1430 
1431 
1432 
1433 
1434 void cRankManager::RemovePlayerRank(const cUUID & a_PlayerUUID)
1435 {
1437  cCSLock Lock(m_CS);
1438 
1439  AString StrUUID = a_PlayerUUID.ToShortString();
1440 
1441  try
1442  {
1443  SQLite::Statement stmt(m_DB, "DELETE FROM PlayerRank WHERE PlayerUUID = ?");
1444  stmt.bind(1, StrUUID);
1445  stmt.exec();
1446  }
1447  catch (const SQLite::Exception & ex)
1448  {
1449  LOGWARNING("%s: Failed to remove rank from player UUID %s: %s",
1450  __FUNCTION__, StrUUID.c_str(), ex.what()
1451  );
1452  }
1453 }
1454 
1455 
1456 
1457 
1458 
1460  const AString & a_RankName,
1461  const AString & a_MsgPrefix,
1462  const AString & a_MsgSuffix,
1463  const AString & a_MsgNameColorCode
1464 )
1465 {
1467  cCSLock Lock(m_CS);
1468 
1469  try
1470  {
1471  SQLite::Statement stmt(m_DB, "UPDATE Rank SET MsgPrefix = ?, MsgSuffix = ?, MsgNameColorCode = ? WHERE Name = ?");
1472  stmt.bind(1, a_MsgPrefix);
1473  stmt.bind(2, a_MsgSuffix);
1474  stmt.bind(3, a_MsgNameColorCode);
1475  stmt.bind(4, a_RankName);
1476  if (stmt.exec() < 1)
1477  {
1478  LOGINFO("%s: Rank %s not found, visuals not set.", __FUNCTION__, a_RankName.c_str());
1479  }
1480  }
1481  catch (const SQLite::Exception & ex)
1482  {
1483  LOGWARNING("%s: Failed to get ranks from DB: %s", __FUNCTION__, ex.what());
1484  }
1485 }
1486 
1487 
1488 
1489 
1490 
1492  const AString & a_RankName,
1493  AString & a_MsgPrefix,
1494  AString & a_MsgSuffix,
1495  AString & a_MsgNameColorCode
1496 )
1497 {
1499  cCSLock Lock(m_CS);
1500 
1501  try
1502  {
1503  SQLite::Statement stmt(m_DB, "SELECT MsgPrefix, MsgSuffix, MsgNameColorCode FROM Rank WHERE Name = ?");
1504  stmt.bind(1, a_RankName);
1505  if (!stmt.executeStep())
1506  {
1507  // Rank not found
1508  return false;
1509  }
1510  a_MsgPrefix = stmt.getColumn(0).getText();
1511  a_MsgSuffix = stmt.getColumn(1).getText();
1512  a_MsgNameColorCode = stmt.getColumn(2).getText();
1513  return true;
1514  }
1515  catch (const SQLite::Exception & ex)
1516  {
1517  LOGWARNING("%s: Failed to get ranks from DB: %s", __FUNCTION__, ex.what());
1518  }
1519  return false;
1520 }
1521 
1522 
1523 
1524 
1525 
1526 bool cRankManager::RankExists(const AString & a_RankName)
1527 {
1529  cCSLock Lock(m_CS);
1530 
1531  try
1532  {
1533  SQLite::Statement stmt(m_DB, "SELECT * FROM Rank WHERE Name = ?");
1534  stmt.bind(1, a_RankName);
1535  if (stmt.executeStep())
1536  {
1537  // The rank was found
1538  return true;
1539  }
1540  }
1541  catch (const SQLite::Exception & ex)
1542  {
1543  LOGWARNING("%s: Failed to query DB for rank %s: %s", __FUNCTION__, a_RankName.c_str(), ex.what());
1544  }
1545  return false;
1546 }
1547 
1548 
1549 
1550 
1551 
1552 bool cRankManager::GroupExists(const AString & a_GroupName)
1553 {
1555  cCSLock Lock(m_CS);
1556 
1557  try
1558  {
1559  SQLite::Statement stmt(m_DB, "SELECT * FROM PermGroup WHERE Name = ?");
1560  stmt.bind(1, a_GroupName);
1561  if (stmt.executeStep())
1562  {
1563  // The group was found
1564  return true;
1565  }
1566  }
1567  catch (const SQLite::Exception & ex)
1568  {
1569  LOGWARNING("%s: Failed to query DB for group %s: %s", __FUNCTION__, a_GroupName.c_str(), ex.what());
1570  }
1571  return false;
1572 }
1573 
1574 
1575 
1576 
1577 
1578 bool cRankManager::IsPlayerRankSet(const cUUID & a_PlayerUUID)
1579 {
1581  cCSLock Lock(m_CS);
1582 
1583  AString StrUUID = a_PlayerUUID.ToShortString();
1584 
1585  try
1586  {
1587  SQLite::Statement stmt(m_DB, "SELECT * FROM PlayerRank WHERE PlayerUUID = ?");
1588  stmt.bind(1, StrUUID);
1589  if (stmt.executeStep())
1590  {
1591  // The player UUID was found, they have a rank
1592  return true;
1593  }
1594  }
1595  catch (const SQLite::Exception & ex)
1596  {
1597  LOGWARNING("%s: Failed to query DB for player UUID %s: %s", __FUNCTION__, StrUUID.c_str(), ex.what());
1598  }
1599  return false;
1600 }
1601 
1602 
1603 
1604 
1605 
1606 bool cRankManager::IsGroupInRank(const AString & a_GroupName, const AString & a_RankName)
1607 {
1609  cCSLock Lock(m_CS);
1610 
1611  try
1612  {
1613  SQLite::Statement stmt(m_DB,
1614  "SELECT * FROM Rank "
1615  "LEFT JOIN RankPermGroup ON Rank.RankID = RankPermGroup.RankID "
1616  "LEFT JOIN PermGroup ON PermGroup.PermGroupID = RankPermGroup.PermGroupID "
1617  "WHERE Rank.Name = ? AND PermGroup.Name = ?"
1618  );
1619  stmt.bind(1, a_RankName);
1620  stmt.bind(2, a_GroupName);
1621  if (stmt.executeStep())
1622  {
1623  // The group is in the rank
1624  return true;
1625  }
1626  }
1627  catch (const SQLite::Exception & ex)
1628  {
1629  LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what());
1630  }
1631  return false;
1632 }
1633 
1634 
1635 
1636 
1637 
1638 bool cRankManager::IsPermissionInGroup(const AString & a_Permission, const AString & a_GroupName)
1639 {
1641  cCSLock Lock(m_CS);
1642 
1643  try
1644  {
1645  SQLite::Statement stmt(m_DB,
1646  "SELECT * FROM PermissionItem "
1647  "LEFT JOIN PermGroup ON PermGroup.PermGroupID = PermissionItem.PermGroupID "
1648  "WHERE PermissionItem.Permission = ? AND PermGroup.Name = ?"
1649  );
1650  stmt.bind(1, a_Permission);
1651  stmt.bind(2, a_GroupName);
1652  if (stmt.executeStep())
1653  {
1654  // The permission is in the group
1655  return true;
1656  }
1657  }
1658  catch (const SQLite::Exception & ex)
1659  {
1660  LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what());
1661  }
1662  return false;
1663 }
1664 
1665 
1666 
1667 
1668 
1669 bool cRankManager::IsRestrictionInGroup(const AString & a_Restriction, const AString & a_GroupName)
1670 {
1672  cCSLock Lock(m_CS);
1673 
1674  try
1675  {
1676  SQLite::Statement stmt(m_DB,
1677  "SELECT * FROM RestrictionItem "
1678  "LEFT JOIN PermGroup ON PermGroup.PermGroupID = RestrictionItem.PermGroupID "
1679  "WHERE RestrictionItem.Permission = ? AND PermGroup.Name = ?"
1680  );
1681  stmt.bind(1, a_Restriction);
1682  stmt.bind(2, a_GroupName);
1683  if (stmt.executeStep())
1684  {
1685  // The restriction is in the group
1686  return true;
1687  }
1688  }
1689  catch (const SQLite::Exception & ex)
1690  {
1691  LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what());
1692  }
1693  return false;
1694 }
1695 
1696 
1697 
1698 
1699 
1700 void cRankManager::NotifyNameUUID(const AString & a_PlayerName, const cUUID & a_UUID)
1701 {
1703  cCSLock Lock(m_CS);
1704 
1705  try
1706  {
1707  SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET PlayerName = ? WHERE PlayerUUID = ?");
1708  stmt.bind(1, a_PlayerName);
1709  stmt.bind(2, a_UUID.ToShortString());
1710  stmt.exec();
1711  }
1712  catch (const SQLite::Exception & ex)
1713  {
1714  LOGWARNING("%s: Failed to update DB: %s", __FUNCTION__, ex.what());
1715  }
1716 }
1717 
1718 
1719 
1720 
1721 
1722 bool cRankManager::SetDefaultRank(const AString & a_RankName)
1723 {
1725  cCSLock Lock(m_CS);
1726 
1727  try
1728  {
1729  // Find the rank's ID:
1730  int RankID = 0;
1731  {
1732  SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?");
1733  stmt.bind(1, a_RankName);
1734  if (!stmt.executeStep())
1735  {
1736  LOGINFO("%s: Cannot set rank %s as the default, it does not exist.", __FUNCTION__, a_RankName.c_str());
1737  return false;
1738  }
1739  }
1740 
1741  // Set the rank as the default:
1742  {
1743  SQLite::Statement stmt(m_DB, "UPDATE DefaultRank SET RankID = ?");
1744  stmt.bind(1, RankID);
1745  if (stmt.exec() < 1)
1746  {
1747  // Failed to update, there might be none in the DB, try inserting:
1748  SQLite::Statement stmt2(m_DB, "INSERT INTO DefaultRank (RankID) VALUES (?)");
1749  stmt2.bind(1, RankID);
1750  if (stmt2.exec() < 1)
1751  {
1752  LOGINFO("%s: Cannot update the default rank in the DB to %s.", __FUNCTION__, a_RankName.c_str());
1753  return false;
1754  }
1755  }
1756  }
1757 
1758  // Set the internal cache:
1759  m_DefaultRank = a_RankName;
1760  return true;
1761  }
1762  catch (const SQLite::Exception & ex)
1763  {
1764  LOGWARNING("%s: Failed to update DB: %s", __FUNCTION__, ex.what());
1765  return false;
1766  }
1767 }
1768 
1769 
1770 
1771 
1772 
1774 {
1776  cCSLock Lock(m_CS);
1777 
1778  try
1779  {
1780  SQLite::Statement stmt(m_DB, "DELETE FROM PlayerRank");
1781  stmt.exec();
1782  }
1783  catch (SQLite::Exception & ex)
1784  {
1785  LOGWARNING("%s: Failed to remove / clear all players: %s", __FUNCTION__, ex.what());
1786  }
1787 }
1788 
1789 
1790 
1791 
1792 
1793 bool cRankManager::UpdatePlayerName(const cUUID & a_PlayerUUID, const AString & a_NewPlayerName)
1794 {
1796  cCSLock Lock(m_CS);
1797 
1798  AString StrUUID = a_PlayerUUID.ToShortString();
1799 
1800  try
1801  {
1802  SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET PlayerName = ? WHERE PlayerUUID = ?");
1803  stmt.bind(1, a_NewPlayerName);
1804  stmt.bind(2, StrUUID);
1805  if (stmt.exec() > 0)
1806  {
1807  // The player name was changed, returns true
1808  return true;
1809  }
1810  }
1811  catch (const SQLite::Exception & ex)
1812  {
1813  LOGWARNING("%s: Failed to update player name from UUID %s: %s", __FUNCTION__, StrUUID.c_str(), ex.what());
1814  }
1815  return false;
1816 }
1817 
1818 
1819 
1820 
1821 
1823 {
1824  return (
1825  IsDBTableEmpty("Rank") &&
1826  IsDBTableEmpty("PlayerRank") &&
1827  IsDBTableEmpty("PermGroup") &&
1828  IsDBTableEmpty("RankPermGroup") &&
1829  IsDBTableEmpty("PermissionItem") &&
1830  IsDBTableEmpty("DefaultRank")
1831  );
1832 }
1833 
1834 
1835 
1836 
1837 
1838 bool cRankManager::IsDBTableEmpty(const AString & a_TableName)
1839 {
1840  try
1841  {
1842  SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM " + a_TableName);
1843  return (stmt.executeStep() && (stmt.getColumn(0).getInt() == 0));
1844  }
1845  catch (const SQLite::Exception & ex)
1846  {
1847  LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what());
1848  }
1849  return false;
1850 }
1851 
1852 
1853 
1854 
1855 
1857 {
1858  // Wrap everything in a big transaction to speed things up:
1859  cMassChangeLock Lock(*this);
1860 
1861  // Create ranks:
1862  AddRank("Default", "", "", "");
1863  AddRank("VIP", "", "", "");
1864  AddRank("Operator", "", "", "");
1865  AddRank("Admin", "", "", "");
1866 
1867  // Create groups:
1868  AddGroup("Default");
1869  AddGroup("Kick");
1870  AddGroup("Teleport");
1871  AddGroup("Everything");
1872 
1873  // Add groups to ranks:
1874  AddGroupToRank("Default", "Default");
1875  AddGroupToRank("Teleport", "VIP");
1876  AddGroupToRank("Teleport", "Operator");
1877  AddGroupToRank("Kick", "Operator");
1878  AddGroupToRank("Everything", "Admin");
1879 
1880  // Add permissions to groups:
1881  AddPermissionToGroup("core.help", "Default");
1882  AddPermissionToGroup("core.build", "Default");
1883  AddPermissionToGroup("core.teleport", "Teleport");
1884  AddPermissionToGroup("core.kick", "Kick");
1885  AddPermissionToGroup("*", "Everything");
1886 
1887  // Set the default rank:
1888  SetDefaultRank("Default");
1889 }
1890 
1891 
1892 
1893 
1894 
1895 bool cRankManager::DoesColumnExist(const char * a_TableName, const char * a_ColumnName)
1896 {
1897  try
1898  {
1899  SQLite::Statement stmt(m_DB, fmt::format(FMT_STRING("PRAGMA table_info({})"), a_TableName));
1900  while (stmt.executeStep()) // Iterate over all table's columns
1901  {
1902  int NumColumns = stmt.getColumnCount();
1903  for (int i = 0; i < NumColumns; i++) // Iterate over all reply's columns (table column's metadata)
1904  {
1905  auto column = stmt.getColumn(i);
1906  if (strcmp(column.getName(), "name") == 0)
1907  {
1908  if (NoCaseCompare(column.getText(), a_ColumnName) == 0)
1909  {
1910  // Colun found
1911  return true;
1912  }
1913  }
1914  } // for i - stmt.getColumns()
1915  } // while (stmt.executeStep())
1916  }
1917  catch (const SQLite::Exception & ex)
1918  {
1919  LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what());
1920  }
1921  return false;
1922 }
1923 
1924 
1925 
1926 
1927 
1928 void cRankManager::CreateColumnIfNotExists(const char * a_TableName, const char * a_ColumnName, const char * a_ColumnType)
1929 {
1930  // If the column already exists, bail out:
1931  if (DoesColumnExist(a_TableName, a_ColumnName))
1932  {
1933  return;
1934  }
1935 
1936  // Add the column:
1937  try
1938  {
1939  m_DB.exec(fmt::format(FMT_STRING("ALTER TABLE {} ADD COLUMN {} {}"), a_TableName, a_ColumnName, a_ColumnType));
1940  }
1941  catch (const SQLite::Exception & exc)
1942  {
1943  LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, exc.what());
1944  }
1945 }
1946 
1947 
1948 
1949 
#define ASSERT(x)
Definition: Globals.h:276
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
#define LOGD
Definition: LoggerSimple.h:83
void LOGINFO(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:61
int NoCaseCompare(const AString &s1, const AString &s2)
Case-insensitive string comparison.
std::vector< AString > AStringVector
Definition: StringUtils.h:12
std::string AString
Definition: StringUtils.h:11
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
void SetRankManager(cRankManager *a_RankManager)
Sets the m_RankMgr that is used for name-uuid notifications.
Definition: MojangAPI.h:79
AStringVector GetGroupPermissions(const AString &a_GroupName)
Returns the permissions that the specified group has assigned to it.
void AddGroups(const AStringVector &a_GroupNames)
Bulk-adds groups.
void AddGroup(const AString &a_GroupName)
Adds a new permission group.
AStringVector GetGroupRestrictions(const AString &a_GroupName)
Returns the restrictions that the specified group has assigned to it.
bool IsPermissionInGroup(const AString &a_Permission, const AString &a_GroupName)
Returns true iff the specified group contains the specified permission.
AStringVector GetAllPermissionsRestrictions(void)
Returns all the distinct permissions and restrictions that are stored in the DB.
void RemoveRestrictionFromGroup(const AString &a_Restriction, const AString &a_GroupName)
Removes the specified restriction from the specified group.
bool GroupExists(const AString &a_GroupName)
Returns true iff the specified group exists in the DB.
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.
bool AddGroupToRank(const AString &a_GroupName, const AString &a_RankName)
Adds the specified permission group to the specified rank.
cRankManager(void)
Creates the rank manager.
Definition: RankManager.cpp:18
bool DoesColumnExist(const char *a_TableName, const char *a_ColumnName)
Returns true if the specified column exists in the specified table.
bool RenameGroup(const AString &a_OldName, const AString &a_NewName)
Renames the specified group.
bool SetDefaultRank(const AString &a_RankName)
Sets the specified rank as the default rank.
AString m_DefaultRank
The name of the default rank.
Definition: RankManager.h:268
void RemovePlayerRank(const cUUID &a_PlayerUUID)
Removes the player's rank assignment.
bool AddPermissionToGroup(const AString &a_Permission, const AString &a_GroupName)
Adds the specified permission to the specified permission group.
bool m_IsInitialized
Set to true once the manager is initialized.
Definition: RankManager.h:274
AStringVector GetPlayerPermissions(const cUUID &a_PlayerUUID)
Returns the permissions that the specified player has assigned to them.
AStringVector GetAllGroups(void)
Returns the names of all permission groups.
void AddRank(const AString &a_RankName, const AString &a_MsgPrefix, const AString &a_MsgSuffix, const AString &a_MsgNameColorCode)
Adds a new rank.
bool GetRankVisuals(const AString &a_RankName, AString &a_MsgPrefix, AString &a_MsgSuffix, AString &a_MsgNameColorCode)
Returns the message visuals of an existing rank.
bool IsDBTableEmpty(const AString &a_TableName)
Returns true iff the specified DB table is empty.
void CreateColumnIfNotExists(const char *a_TableName, const char *a_ColumnName, const char *a_ColumnType="")
If the specified table doesn't contain the specified column, it is added to the table.
bool RankExists(const AString &a_RankName)
Returns true iff the specified rank exists in the DB.
AStringVector GetRankPermissions(const AString &a_RankName)
Returns all permissions that the specified rank has assigned to it, through all its groups.
cCriticalSection m_CS
The mutex protecting m_DB and m_DefaultRank against multi-threaded access.
Definition: RankManager.h:271
AString GetPlayerName(const cUUID &a_PlayerUUID)
Returns the last name that the specified player has.
bool IsPlayerRankSet(const cUUID &a_PlayerUUID)
Returns true iff the specified player has a rank assigned to them in the DB.
void RemovePermissionFromGroup(const AString &a_Permission, const AString &a_GroupName)
Removes the specified permission from the specified group.
void Initialize(cMojangAPI &a_MojangAPI)
Initializes the rank manager.
Definition: RankManager.cpp:36
AStringVector GetPlayerGroups(const cUUID &a_PlayerUUID)
Returns the names of Groups that the specified player has assigned to them.
AStringVector GetAllRanks(void)
Returns the names of all defined ranks.
bool AreDBTablesEmpty(void)
Returns true if all the DB tables are empty, indicating a fresh new install.
bool AddRestrictionToGroup(const AString &a_Restriction, const AString &a_GroupName)
Adds the specified restriction to the specified group.
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.
AString GetPlayerRankName(const cUUID &a_PlayerUUID)
Returns the name of the rank that the specified player has assigned to them.
Definition: RankManager.cpp:90
void RemoveGroupFromRank(const AString &a_GroupName, const AString &a_RankName)
Removes the specified group from the specified rank.
void NotifyNameUUID(const AString &a_PlayerName, const cUUID &a_UUID)
Called by cMojangAPI whenever the playername-uuid pairing is discovered.
AStringVector GetRankGroups(const AString &a_RankName)
Returns the names of groups that the specified rank has assigned to it.
void RemoveGroup(const AString &a_GroupName)
Removes the specified group completely.
void SetPlayerRank(const cUUID &a_PlayerUUID, const AString &a_PlayerName, const AString &a_RankName)
Sets the specified player's rank.
bool UpdatePlayerName(const cUUID &a_PlayerUUID, const AString &a_NewPlayerName)
Updates the playername that is saved with this uuid.
AStringVector GetAllRestrictions(void)
Returns all the distinct restrictions that are stored in the DB.
void CreateDefaults(void)
Creates a default set of ranks / groups / permissions.
AStringVector GetRankRestrictions(const AString &a_RankName)
Returns all restrictions that the specified rank has assigned to it, through all its groups.
void RemoveRank(const AString &a_RankName, const AString &a_ReplacementRankName)
Removes the specified rank.
SQLite::Database m_DB
The database storage for all the data.
Definition: RankManager.h:265
std::vector< cUUID > GetAllPlayerUUIDs(void)
Returns the uuids of all defined players.
AStringVector GetPlayerRestrictions(const cUUID &a_PlayerUUID)
Returns the restrictions that the specified player has assigned to them.
bool RenameRank(const AString &a_OldName, const AString &a_NewName)
Renames the specified rank.
bool AddPermissionsToGroup(const AStringVector &a_Permissions, const AString &a_GroupName)
Adds the specified permissions to the specified permission group.
AStringVector GetAllPermissions(void)
Returns all the distinct permissions that are stored in the DB.
void ClearPlayerRanks(void)
Removes all player ranks from the database.
bool IsGroupInRank(const AString &a_GroupName, const AString &a_RankName)
Returns true iff the specified rank contains the specified group.
bool IsRestrictionInGroup(const AString &a_Restriction, const AString &a_GroupName)
Returns true iff the specified group contains the specified restriction.
bool AddRestrictionsToGroup(const AStringVector &a_Restrictions, const AString &a_GroupName)
Adds the specified restrictions to the specified group.
Acquire this lock to perform mass changes.
Definition: RankManager.h:31
Definition: UUID.h:11
AString ToShortString() const
Converts the UUID to a short form string (i.e without dashes).
Definition: UUID.cpp:133
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