BxDolStudioDashboardQuery.php 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup UnaStudio UNA Studio
  7. * @{
  8. */
  9. class BxDolStudioDashboardQuery extends BxDolStudioPageQuery
  10. {
  11. function __construct()
  12. {
  13. parent::__construct();
  14. }
  15. /**
  16. * A module's storage use split by where its files live: its objects on the Local engine and those on any remote engine.
  17. * @return array ['local' => ['size' => bytes, 'objects' => count], 'remote' => ['size' => bytes, 'objects' => count]]
  18. */
  19. function getModuleStorageSizes($sModule)
  20. {
  21. $aResult = array('local' => array('size' => 0, 'objects' => 0), 'remote' => array('size' => 0, 'objects' => 0));
  22. $sSql = "SELECT IF(`engine` = 'Local', 'local', 'remote') AS `scope`, SUM(`current_size`) AS `size`, COUNT(*) AS `objects` FROM `sys_objects_storage` WHERE `object` LIKE " . $this->escape($sModule . '%') . " GROUP BY `scope`";
  23. foreach($this->getAll($sSql) as $aRow)
  24. $aResult[$aRow['scope']] = array('size' => (int)$aRow['size'], 'objects' => (int)$aRow['objects']);
  25. return $aResult;
  26. }
  27. /**
  28. * The storage objects under a name prefix, each with its engine and counters (the dashboard splits the system module's by hand).
  29. */
  30. function getStorageObjects($sPrefix)
  31. {
  32. return $this->getAll("SELECT `object`, `engine`, `current_size`, `current_number` FROM `sys_objects_storage` WHERE `object` LIKE " . $this->escape($sPrefix . '%') . " ORDER BY `object`");
  33. }
  34. /**
  35. * Users block (BxBaseStudioDashboard::serviceGetBlockUsers): every account.
  36. */
  37. function getAccountsCount()
  38. {
  39. return (int)$this->getOne("SELECT COUNT(*) FROM `sys_accounts`");
  40. }
  41. /**
  42. * Accounts seen since a moment: their last activity or login is at or after it.
  43. */
  44. function getAccountsActiveCount($iSince)
  45. {
  46. return (int)$this->getOne("SELECT COUNT(*) FROM `sys_accounts` WHERE `active` >= :since_active OR `logged` >= :since_logged", ['since_active' => (int)$iSince, 'since_logged' => (int)$iSince]);
  47. }
  48. /**
  49. * Accounts online now: with a session touched within the online window, the way BxDolAccountQuery::isOnline counts one.
  50. */
  51. function getAccountsOnlineCount()
  52. {
  53. return (int)$this->getOne("SELECT COUNT(DISTINCT `ta`.`id`) FROM `sys_accounts` AS `ta` INNER JOIN `sys_sessions` AS `ts` ON `ta`.`id` = `ts`.`user_id` WHERE `ts`.`date` > (UNIX_TIMESTAMP() - 60 * :minutes)", ['minutes' => (int)getParam('sys_account_online_time')]);
  54. }
  55. /**
  56. * Profiles of a type whose account is online now, the way getAccountsOnlineCount counts an account.
  57. */
  58. function getProfilesOnlineCount($sType)
  59. {
  60. return (int)$this->getOne("SELECT COUNT(DISTINCT `tp`.`id`) FROM `sys_profiles` AS `tp` INNER JOIN `sys_sessions` AS `ts` ON `tp`.`account_id` = `ts`.`user_id` WHERE `tp`.`type` = :type AND `ts`.`date` > (UNIX_TIMESTAMP() - 60 * :minutes)", ['type' => $sType, 'minutes' => (int)getParam('sys_account_online_time')]);
  61. }
  62. /**
  63. * Every active profile with the permission level it holds, the way BxDolAclQuery::getLevelCurrent resolves it: its latest membership
  64. * that has started and not expired, else Standard; and since when (the membership's start, else the account's creation). A pending or
  65. * suspended profile is on its status' pseudo level, so it is left out. Shared by the level queries below as a derived table.
  66. */
  67. protected function getLevelMembersSql()
  68. {
  69. bx_import('BxDolAcl');
  70. return "SELECT `tp`.`id`, `tp`.`account_id`, COALESCE(`tm`.`IDLevel`, " . (int)MEMBERSHIP_ID_STANDARD . ") AS `level`, COALESCE(UNIX_TIMESTAMP(`tm`.`DateStarts`), `ta`.`added`) AS `since`
  71. FROM `sys_profiles` AS `tp`
  72. INNER JOIN `sys_accounts` AS `ta` ON `ta`.`id` = `tp`.`account_id`
  73. LEFT JOIN `sys_acl_levels_members` AS `tm` ON `tm`.`IDMember` = `tp`.`id` AND `tm`.`DateStarts` = (SELECT MAX(`tm2`.`DateStarts`) FROM `sys_acl_levels_members` AS `tm2` WHERE `tm2`.`IDMember` = `tp`.`id` AND `tm2`.`DateStarts` <= NOW() AND (`tm2`.`DateExpires` IS NULL OR `tm2`.`DateExpires` > NOW()))
  74. WHERE `tp`.`type` <> 'system' AND `tp`.`status` = 'active'";
  75. }
  76. /**
  77. * The permission levels a profile can hold, in their order: the active ones without the pseudo levels of not being logged in, having no
  78. * profile, or an unconfirmed, pending or suspended one.
  79. * @return array of ['ID', 'Name' (a language key), 'Icon']
  80. */
  81. function getLevels()
  82. {
  83. bx_import('BxDolAcl');
  84. $aPseudo = [MEMBERSHIP_ID_NON_MEMBER, MEMBERSHIP_ID_ACCOUNT, MEMBERSHIP_ID_UNCONFIRMED, MEMBERSHIP_ID_PENDING, MEMBERSHIP_ID_SUSPENDED];
  85. return $this->getAll("SELECT `ID`, `Name`, `Icon` FROM `sys_acl_levels` WHERE `Active` = 'yes' AND `ID` NOT IN (" . implode(',', array_map('intval', $aPseudo)) . ") ORDER BY `Order` ASC, `ID` ASC");
  86. }
  87. /**
  88. * Current members per level.
  89. * @return array level id => count
  90. */
  91. function getLevelsMembersCount()
  92. {
  93. return $this->getPairs("SELECT `level`, COUNT(*) AS `count` FROM (" . $this->getLevelMembersSql() . ") AS `t` GROUP BY `level`", 'level', 'count');
  94. }
  95. /**
  96. * A level's current members by when they joined it, counted per calendar bucket like getAccountsAddedBy.
  97. * @return array bucket => count
  98. */
  99. function getLevelMembersSinceBy($iLevel, $sFormat, $iSince)
  100. {
  101. return $this->getPairs("SELECT FROM_UNIXTIME(`since`, :format) AS `bucket`, COUNT(*) AS `count` FROM (" . $this->getLevelMembersSql() . ") AS `t` WHERE `level` = :level AND `since` >= :since GROUP BY `bucket` ORDER BY `bucket`", 'bucket', 'count', ['format' => $sFormat, 'level' => (int)$iLevel, 'since' => (int)$iSince]);
  102. }
  103. /**
  104. * A level's current members whose account is online now, the way getAccountsOnlineCount counts an account.
  105. */
  106. function getLevelOnlineCount($iLevel)
  107. {
  108. return (int)$this->getOne("SELECT COUNT(DISTINCT `t`.`id`) FROM (" . $this->getLevelMembersSql() . ") AS `t` INNER JOIN `sys_sessions` AS `ts` ON `ts`.`user_id` = `t`.`account_id` WHERE `t`.`level` = :level AND `ts`.`date` > (UNIX_TIMESTAMP() - 60 * :minutes)", ['level' => (int)$iLevel, 'minutes' => (int)getParam('sys_account_online_time')]);
  109. }
  110. /**
  111. * When the first account was added; 0 without accounts.
  112. */
  113. function getAccountsFirstAdded()
  114. {
  115. return (int)$this->getOne("SELECT MIN(`added`) FROM `sys_accounts` WHERE `added` > 0");
  116. }
  117. /**
  118. * Accounts added since a moment, counted per calendar bucket named by a MySQL date format ('%Y-%m-%d' days, '%Y-%m' months, '%Y' years).
  119. * @return array bucket => count
  120. */
  121. function getAccountsAddedBy($sFormat, $iSince)
  122. {
  123. return $this->getPairs("SELECT FROM_UNIXTIME(`added`, :format) AS `bucket`, COUNT(*) AS `count` FROM `sys_accounts` WHERE `added` >= :since GROUP BY `bucket` ORDER BY `bucket`", 'bucket', 'count', ['format' => $sFormat, 'since' => (int)$iSince]);
  124. }
  125. /**
  126. * Accounts last seen (their latest activity or login) since a moment, counted per calendar bucket like getAccountsAddedBy.
  127. * @return array bucket => count
  128. */
  129. function getAccountsSeenBy($sFormat, $iSince)
  130. {
  131. return $this->getPairs("SELECT FROM_UNIXTIME(GREATEST(`active`, `logged`), :format) AS `bucket`, COUNT(*) AS `count` FROM `sys_accounts` WHERE GREATEST(`active`, `logged`) >= :since GROUP BY `bucket` ORDER BY `bucket`", 'bucket', 'count', ['format' => $sFormat, 'since' => (int)$iSince]);
  132. }
  133. /**
  134. * Rows of a module's content table (a profile type's profiles) added since a moment, counted per calendar bucket like getAccountsAddedBy.
  135. * @return array bucket => count
  136. */
  137. function getEntriesAddedBy($sTable, $sField, $sFormat, $iSince)
  138. {
  139. $sTable = preg_replace('/[^a-zA-Z0-9_]/', '', $sTable);
  140. $sField = preg_replace('/[^a-zA-Z0-9_]/', '', $sField);
  141. return $this->getPairs("SELECT FROM_UNIXTIME(`" . $sField . "`, :format) AS `bucket`, COUNT(*) AS `count` FROM `" . $sTable . "` WHERE `" . $sField . "` >= :since GROUP BY `bucket` ORDER BY `bucket`", 'bucket', 'count', ['format' => $sFormat, 'since' => (int)$iSince]);
  142. }
  143. /**
  144. * Profiles per type (the module that owns them), the system's own left out, with how many of them are active.
  145. * @return array of ['type', 'total', 'active']
  146. */
  147. function getProfilesByType()
  148. {
  149. return $this->getAll("SELECT `type`, COUNT(*) AS `total`, SUM(`status` = 'active') AS `active` FROM `sys_profiles` WHERE `type` <> 'system' GROUP BY `type` ORDER BY `total` DESC, `type` ASC");
  150. }
  151. /**
  152. * Whether remote storage is in use: some storage object lives on a remote engine, or new objects would (the default engine option).
  153. */
  154. function isRemoteStorageUsed()
  155. {
  156. if(getParam('sys_storage_default') != 'Local')
  157. return true;
  158. return (int)$this->getOne("SELECT COUNT(*) FROM `sys_objects_storage` WHERE `engine` <> 'Local'") > 0;
  159. }
  160. }
  161. /** @} */