BxNtfsDb.php 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  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 Notifications Notifications
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. class BxNtfsDb extends BxBaseModNotificationsDb
  12. {
  13. protected $_sTableEvt2Usr;
  14. protected $_sTableAggregator;
  15. protected $_sTableQueue;
  16. protected $_sTableRead;
  17. protected $_sTableEtemplates;
  18. /*
  19. * Constructor.
  20. */
  21. function __construct(&$oConfig)
  22. {
  23. parent::__construct($oConfig);
  24. $this->_aDeliveryTypes = array(
  25. BX_BASE_MOD_NTFS_DTYPE_SITE,
  26. BX_BASE_MOD_NTFS_DTYPE_EMAIL,
  27. BX_BASE_MOD_NTFS_DTYPE_PUSH
  28. );
  29. $this->_sTableEvt2Usr = $this->_sPrefix . 'events2users';
  30. $this->_sTableAggregator = $this->_sPrefix . 'aggregator';
  31. $this->_sTableQueue = $this->_sPrefix . 'queue';
  32. $this->_sTableRead = $this->_sPrefix . 'read';
  33. $this->_sTableEtemplates = $this->_sPrefix . 'etemplates';
  34. }
  35. public function getHandlerTypes()
  36. {
  37. return $this->getColumn("SELECT DISTINCT `alert_unit` FROM `{$this->_sTableHandlers}` WHERE `type`='insert'");
  38. }
  39. public function getHandlerActions($sUnit = '')
  40. {
  41. $aBindings = [];
  42. $sWhereClause = "";
  43. if($sUnit) {
  44. $aBindings['alert_unit'] = $sUnit;
  45. $sWhereClause .= " AND `alert_unit`=:alert_unit";
  46. }
  47. return $this->getColumn("SELECT DISTINCT `alert_action` FROM `{$this->_sTableHandlers}` WHERE `type`='insert'" . $sWhereClause, $aBindings);
  48. }
  49. public function markAsClicked($iUserId, $iEventId)
  50. {
  51. return $this->query("INSERT INTO `" . $this->_sTableEvt2Usr . "` (`user_id`, `event_id`, `clicked`) VALUES (:user_id, :event_id, 1) ON DUPLICATE KEY UPDATE `clicked`=1", [
  52. 'user_id' => $iUserId,
  53. 'event_id' => $iEventId
  54. ]);
  55. }
  56. public function markAsRead($iUserId, $iEventId)
  57. {
  58. $this->queueDeleteByProfile($iUserId, $iEventId);
  59. return $this->query("INSERT INTO `" . $this->_sTableRead . "` (`user_id`, `event_id`) VALUES (:user_id, :event_id) ON DUPLICATE KEY UPDATE `event_id`=:event_id", array(
  60. 'user_id' => $iUserId,
  61. 'event_id' => $iEventId
  62. ));
  63. }
  64. public function getLastRead($iUserId)
  65. {
  66. return (int)$this->getOne("SELECT `event_id` FROM `" . $this->_sTableRead . "` WHERE `user_id`=:user_id LIMIT 1", array(
  67. 'user_id' => (int)$iUserId
  68. ));
  69. }
  70. public function deleteEvent($aParams, $sWhereAddon = "")
  71. {
  72. $aEvents = $this->getAll("SELECT * FROM `{$this->_sTable}` WHERE " . $this->arrayToSQL($aParams, " AND ") . $sWhereAddon);
  73. if(!empty($aEvents) && is_array($aEvents))
  74. foreach($aEvents as $aEvent)
  75. $this->queueDelete(array('event_id' => $aEvent['id']));
  76. return parent::deleteEvent($aParams, $sWhereAddon);
  77. }
  78. public function getEvents($aParams, $bReturnCount = false)
  79. {
  80. /**
  81. * @hooks
  82. * @hookdef hook-bx_notifications-get_events_before 'bx_notifications', 'get_events_before' - hook to override params which are used to get events
  83. * - $unit_name - equals `bx_notifications`
  84. * - $action - equals `get_events_before`
  85. * - $object_id - not used
  86. * - $sender_id - not used
  87. * - $extra_params - array of additional params with the following array keys:
  88. * - `params` - [array] by ref, params array as key&value pairs, can be overridden in hook processing
  89. * @hook @ref hook-bx_notifications-get_events_before
  90. */
  91. bx_alert($this->_oConfig->getName(), 'get_events_before', 0, 0, [
  92. 'params' => &$aParams,
  93. 'params_ref' => &$aParams,
  94. ]);
  95. if($aParams['browse'] != 'list' || $aParams['type'] != BX_NTFS_TYPE_OBJECT_OWNER_AND_CONNECTIONS)
  96. return parent::getEvents($aParams);
  97. $bEventsGroupedDb = $this->_oConfig->isEventsGroupedDb();
  98. $bClickedIndicator = $this->_oConfig->isClickedIndicator();
  99. $bCountOnly = !empty($aParams['count_only']);
  100. $bViewerId = !empty($aParams['viewer_id']);
  101. $sSelectClauseClicked = ", 0 AS `clicked`";
  102. $sLimitClause = isset($aParams['per_page']) ? "LIMIT 0, " . ($aParams['start'] + $aParams['per_page']) : "";
  103. $sSelectClauseGrouped = $sGroupByClauseGrouped = "";
  104. if($bEventsGroupedDb) {
  105. $sSelectClauseGrouped = ", GROUP_CONCAT(`{$this->_sTable}`.`id` ORDER BY `{$this->_sTableHandlers}`.`priority` DESC SEPARATOR ',') AS `subgrouped_by_mac`";
  106. $sGroupByClauseGrouped = "`{$this->_sTable}`.`source_mac`";
  107. }
  108. //--- Get query for 'Object Owner' notifications
  109. $aParams['type'] = BX_BASE_MOD_NTFS_TYPE_OBJECT_OWNER;
  110. $sGroupByClausePo = "";
  111. list($sMethod, $sSelectClause, $sJoinClausePo, $sWhereClausePo, $sOrderClausePo) = $this->_getSqlPartsEvents($aParams);
  112. if($bClickedIndicator && $bViewerId) {
  113. $sSelectClauseClicked = ", IF(ISNULL(`{$this->_sTableEvt2Usr}`.`clicked`) OR `{$this->_sTableEvt2Usr}`.`clicked`=0, 0, 1) AS `clicked`";
  114. $sJoinClausePo .= $this->prepareAsString(" LEFT JOIN `{$this->_sTableEvt2Usr}` ON `{$this->_sTable}`.`id`=`{$this->_sTableEvt2Usr}`.`event_id` AND `{$this->_sTableEvt2Usr}`.`user_id`=?", $aParams['viewer_id']);
  115. }
  116. $sGroupByClausePo .= $sGroupByClauseGrouped;
  117. if($sGroupByClausePo)
  118. $sGroupByClausePo = " GROUP BY " . $sGroupByClausePo;
  119. $sQueryOwner = "SELECT {select}
  120. FROM `{$this->_sTable}`
  121. LEFT JOIN `{$this->_sTableHandlers}` ON `{$this->_sTable}`.`type`=`{$this->_sTableHandlers}`.`alert_unit` AND `{$this->_sTable}`.`action`=`{$this->_sTableHandlers}`.`alert_action` " . $sJoinClausePo . "
  122. WHERE 1 " . $sWhereClausePo . $sGroupByClausePo . (!$bCountOnly ? " " . $sOrderClausePo . " " . $sLimitClause : "");
  123. //--- Get query for 'Connections based' notifications
  124. $aParams['type'] = BX_BASE_MOD_NTFS_TYPE_CONNECTIONS;
  125. $sGroupByClausePc = "";
  126. list($sMethod, $sSelectClause, $sJoinClausePc, $sWhereClausePc, $sOrderClausePc) = $this->_getSqlPartsEvents($aParams);
  127. if($bClickedIndicator && $bViewerId) {
  128. $sSelectClauseClicked = ", IF(ISNULL(`{$this->_sTableEvt2Usr}`.`clicked`) OR `{$this->_sTableEvt2Usr}`.`clicked`=0, 0, 1) AS `clicked`";
  129. $sJoinClausePc .= $this->prepareAsString(" LEFT JOIN `{$this->_sTableEvt2Usr}` ON `{$this->_sTable}`.`id`=`{$this->_sTableEvt2Usr}`.`event_id` AND `{$this->_sTableEvt2Usr}`.`user_id`=?", $aParams['viewer_id']);
  130. }
  131. $sGroupByClausePc .= $sGroupByClauseGrouped;
  132. if($sGroupByClausePc)
  133. $sGroupByClausePc = " GROUP BY " . $sGroupByClausePc;
  134. $sQueryConnections = "SELECT {select}
  135. FROM `{$this->_sTable}`
  136. LEFT JOIN `{$this->_sTableHandlers}` ON `{$this->_sTable}`.`type`=`{$this->_sTableHandlers}`.`alert_unit` AND `{$this->_sTable}`.`action`=`{$this->_sTableHandlers}`.`alert_action` " . $sJoinClausePc . "
  137. WHERE 1 " . $sWhereClausePc . $sGroupByClausePc . (!$bCountOnly ? " " . $sOrderClausePc . " " . $sLimitClause : "");
  138. $sSelectClause .= $sSelectClauseClicked;
  139. $sSelectClause .= $sSelectClauseGrouped;
  140. //--- Combine both queries in one
  141. $bStartFromItem = isset($aParams['start_from_item']) && $aParams['start_from_item'] === true;
  142. $sUnionMethod = 'getColumn';
  143. $sUnionOrderClause = $sUnionLimitClause = '';
  144. if(!$bCountOnly) {
  145. $sUnionMethod = $sMethod;
  146. $sUnionOrderClause = "ORDER BY `date` DESC, `id` DESC";
  147. $sUnionLimitClause = isset($aParams['per_page']) ? "LIMIT " . (!$bStartFromItem ? $aParams['start'] : 0) . ", " . $aParams['per_page'] : "";
  148. }
  149. $aAlertParams = $aParams;
  150. unset($aAlertParams['browse']);
  151. /**
  152. * Parts:
  153. * PO - notifications related to Owner's content
  154. * PC - notifications related to Connections' content
  155. */
  156. /**
  157. * @hooks
  158. * @hookdef hook-bx_notifications-get_events 'bx_notifications', 'get_events' - hook to override events list which will be received from database
  159. * - $unit_name - equals `bx_notifications`
  160. * - $action - equals `get_events`
  161. * - $object_id - not used
  162. * - $sender_id - not used
  163. * - $extra_params - array of additional params with the following array keys:
  164. * - `browse` - [string] browsing type
  165. * - `params` - [array] browse params array as key&value pairs
  166. * - `table` - [string] datatbase table name
  167. * - `method` - [string] by ref, database class method name, @see BxDolDb, can be overridden in hook processing
  168. * - `select_clause` - [string] by ref, 'select' part of SQL query, can be overridden in hook processing
  169. * - `join_clause_po` - [string] by ref, 'join' part of Owner's SQL query, can be overridden in hook processing
  170. * - `join_clause_pc` - [string] by ref, 'join' part of Connections' SQL query, can be overridden in hook processing
  171. * - `where_clause_po` - [string] by ref, 'where' part of Owner's SQL query, can be overridden in hook processing
  172. * - `where_clause_pc` - [string] by ref, 'where' part of Connections' SQL query, can be overridden in hook processing
  173. * - `order_clause_po` - [string] by ref, 'order' part of Owner's SQL query, can be overridden in hook processing
  174. * - `order_clause_pc` - [string] by ref, 'order' part of Connections' SQL query, can be overridden in hook processing
  175. * - `order_clause` - [string] by ref, 'order' part of SQL query, can be overridden in hook processing
  176. * - `limit_clause` - [string] by ref, 'limit' part of SQL query, can be overridden in hook processing
  177. * - `query_po` - [string] by ref, Owner's SQL query, can be overridden in hook processing
  178. * - `query_pc` - [string] by ref, Connections' SQL query, can be overridden in hook processing
  179. * @hook @ref hook-bx_notifications-get_events
  180. */
  181. bx_alert($this->_oConfig->getName(), 'get_events', 0, 0, [
  182. 'browse' => $aParams['browse'],
  183. 'params' => $aAlertParams,
  184. 'table' => $this->_sTable,
  185. 'method' => &$sUnionMethod,
  186. 'select_clause' => &$sSelectClause,
  187. 'join_clause_po' => &$sJoinClausePo,
  188. 'join_clause_pc' => &$sJoinClausePc,
  189. 'where_clause_po' => &$sWhereClausePo,
  190. 'where_clause_pc' => &$sWhereClausePc,
  191. 'order_clause_po' => &$sOrderClausePo,
  192. 'order_clause_pc' => &$sOrderClausePc,
  193. 'order_clause' => &$sUnionOrderClause,
  194. 'limit_clause' => &$sUnionLimitClause,
  195. 'query_po' => &$sQueryOwner,
  196. 'query_pc' => &$sQueryConnections,
  197. 'method_ref' => &$sUnionMethod,
  198. 'select_clause_ref' => &$sSelectClause,
  199. 'join_clause_po_ref' => &$sJoinClausePo,
  200. 'join_clause_pc_ref' => &$sJoinClausePc,
  201. 'where_clause_po_ref' => &$sWhereClausePo,
  202. 'where_clause_pc_ref' => &$sWhereClausePc,
  203. 'order_clause_po_ref' => &$sOrderClausePo,
  204. 'order_clause_pc_ref' => &$sOrderClausePc,
  205. 'order_clause_ref' => &$sUnionOrderClause,
  206. 'limit_clause_ref' => &$sUnionLimitClause,
  207. 'query_po_ref' => &$sQueryOwner,
  208. 'query_pc_ref' => &$sQueryConnections,
  209. ]);
  210. if($bEventsGroupedDb)
  211. $sQuery = "SELECT *, GROUP_CONCAT(`subgrouped_by_mac` ORDER BY `priority` DESC SEPARATOR ',') AS `grouped_by_mac` FROM ((" . $sQueryOwner . ") UNION (" . $sQueryConnections . ")) AS `tu` GROUP BY `source_mac` {order} {limit}";
  212. else
  213. $sQuery = "(" . $sQueryOwner . ") UNION (" . $sQueryConnections . ") {order} {limit}";
  214. $sQuery = str_replace(['{select}', '{order}', '{limit}'], [$sSelectClause, $sUnionOrderClause, $sUnionLimitClause], $sQuery);
  215. $aEntries = $this->$sUnionMethod($sQuery);
  216. if($bCountOnly)
  217. $aEntries = (int)array_sum($aEntries);
  218. return $aEntries;
  219. }
  220. protected function _getSqlPartsEvents($aParams)
  221. {
  222. list($sMethod, $sSelectClause, $sJoinClause, $sWhereClause, $sOrderClause, $sLimitClause) = parent::_getSqlPartsEvents($aParams);
  223. switch($aParams['browse']) {
  224. case 'descriptor':
  225. $sMethod = 'getRow';
  226. $sWhereClause = "";
  227. if(isset($aParams['type']))
  228. $sWhereClause .= $this->prepareAsString("AND `" . $this->_sTable . "`.`type`=? ", $aParams['type']);
  229. if(isset($aParams['action']))
  230. $sWhereClause .= $this->prepareAsString("AND `" . $this->_sTable . "`.`action`=? ", $aParams['action']);
  231. if(isset($aParams['object_id']))
  232. $sWhereClause .= $this->prepareAsString("AND `" . $this->_sTable . "`.`object_id`=? ", $aParams['object_id']);
  233. $sLimitClause = "LIMIT 1";
  234. break;
  235. case 'first':
  236. $sWhereClause .= $this->prepareAsString("AND `" . $this->_sTable . "`.`date` <= ? ", time());
  237. break;
  238. case 'list':
  239. if(!empty($aParams['count_only'])) {
  240. $sMethod = 'getOne';
  241. $sSelectClause = 'COUNT(DISTINCT `' . $this->_sTable . '`.`id`)';
  242. }
  243. else {
  244. $sSelectClause .= ", `{$this->_sTableHandlers}`.`priority` AS `priority`";
  245. if(in_array($aParams['type'], array(BX_BASE_MOD_NTFS_TYPE_CONNECTIONS, BX_NTFS_TYPE_OBJECT_OWNER_AND_CONNECTIONS)))
  246. $sSelectClause = 'DISTINCT ' . $sSelectClause;
  247. }
  248. $sWhereClause .= $this->prepareAsString("AND `" . $this->_sTable . "`.`date` <= ? ", time());
  249. break;
  250. }
  251. return array($sMethod, $sSelectClause, $sJoinClause, $sWhereClause, $sOrderClause, $sLimitClause);
  252. }
  253. protected function _getSqlPartsEventsList($aParams)
  254. {
  255. $CNF = &$this->_oConfig->CNF;
  256. $sJoinClause = $sWhereClause = "";
  257. //--- Apply 'start from' filter
  258. $sWhereClauseStartFrom = '';
  259. if(isset($aParams['start_from_item']) && $aParams['start_from_item'] === true && $aParams['start'] != 0)
  260. $sWhereClauseStartFrom = $this->prepareAsString("AND `{$this->_sTable}`.`id`<? ", (int)$aParams['start']);
  261. //--- Apply status filter
  262. $sWhereClauseStatus = '';
  263. if(isset($aParams['active']))
  264. $sWhereClauseStatus = $this->prepareAsString("AND `{$this->_sTable}`.`active`=? ", (int)$aParams['active']);
  265. //--- Apply modules or handlers filter
  266. $sWhereClauseModules = '';
  267. if(!empty($aParams['modules']) && is_array($aParams['modules']))
  268. $sWhereClauseModules = "AND `" . $this->_sTable . "`.`type` IN (" . $this->implode_escape($aParams['modules']) . ") ";
  269. if($sWhereClauseModules == '') {
  270. $aHidden = $this->_oConfig->getHandlersHidden();
  271. $sWhereClauseModules = !empty($aHidden) && is_array($aHidden) ? "AND `" . $this->_sTableHandlers . "`.`id` NOT IN (" . $this->implode_escape($aHidden) . ") " : "";
  272. }
  273. //--- Check flag 'New'
  274. $sWhereClauseNew = '';
  275. if(!empty($aParams['new']) && !empty($aParams['owner_id']))
  276. $sWhereClauseNew = $this->prepareAsString("AND `{$this->_sTable}`.`id`>? ", $this->getLastRead((int)$aParams['owner_id']));
  277. //--- Check type
  278. $sWhereClauseSettings = $sWhereClauseType = '';
  279. if(!empty($aParams['owner_id']))
  280. switch($aParams['type']) {
  281. /*
  282. * Note. It isn't used for now and outdated.
  283. */
  284. case BX_BASE_MOD_NTFS_TYPE_OWNER:
  285. $sWhereClauseType = $this->prepareAsString("AND `{$this->_sTable}`.`owner_id`=? ", $aParams['owner_id']);
  286. break;
  287. case BX_BASE_MOD_NTFS_TYPE_OBJECT_OWNER:
  288. $sJoinClause .= $this->prepareAsString(" INNER JOIN `{$this->_sTableSettings}` ON `{$this->_sTableHandlers}`.`id`=`{$this->_sTableSettings}`.`handler_id` AND `{$this->_sTableSettings}`.`delivery`='" . BX_BASE_MOD_NTFS_DTYPE_SITE . "' AND `{$this->_sTableSettings}`.`active`='1' AND `{$this->_sTableSettings}`.`type`=?", BX_NTFS_STYPE_PERSONAL);
  289. $sJoinClauseS2U = " LEFT JOIN `{$this->_sTableSettings2Users}` ON `{$this->_sTableSettings}`.`id`=`{$this->_sTableSettings2Users}`.`setting_id` ";
  290. if(!empty($aParams['owner_id']))
  291. $sJoinClauseS2U .= $this->prepareAsString("AND `{$this->_sTableSettings2Users}`.`user_id`=? ", $aParams['owner_id']);
  292. $sJoinClause .= $sJoinClauseS2U;
  293. $sWhereClauseSettings = "AND ((ISNULL(`{$this->_sTableSettings2Users}`.`active`) AND `{$this->_sTableSettings}`.`value`='1') OR (NOT ISNULL(`{$this->_sTableSettings2Users}`.`active`) AND `{$this->_sTableSettings2Users}`.`active`='1')) ";
  294. $sWhereClauseType = $this->prepareAsString("AND `{$this->_sTable}`.`owner_id`<>`{$this->_sTable}`.`object_owner_id` AND ((`{$this->_sTable}`.`owner_id`=? AND `{$this->_sTable}`.`object_privacy_view`<0 AND `{$this->_sTable}`.`owner_id`=ABS(`{$this->_sTable}`.`object_privacy_view`)) OR `{$this->_sTable}`.`object_owner_id`=?) ", $aParams['owner_id'], $aParams['owner_id']);
  295. break;
  296. case BX_BASE_MOD_NTFS_TYPE_CONNECTIONS:
  297. $oConnection = BxDolConnection::getObjectInstance($this->_oConfig->getObject('conn_subscriptions'));
  298. $aQueryParts = $oConnection->getConnectedContentAsSQLParts($this->_sTable, 'owner_id', $aParams['owner_id']);
  299. if(empty($aQueryParts) || !is_array($aQueryParts) || empty($aQueryParts['join']))
  300. break;
  301. //--- Show notifications from connected contexts (using INNER JOIN)
  302. $sJoinClause .= " LEFT JOIN `sys_profiles` AS `tsp` ON `{$this->_sTable}`.`owner_id`=`tsp`.`id` " . $aQueryParts['join'];
  303. $sWhereClauseType = '';
  304. if(getParam($CNF['PARAM_OWN_ACTIONS']) != 'on') {
  305. //--- Don't show notifications about own posts to connected contexts
  306. $sWhereClauseType .= $this->prepareAsString("AND `{$this->_sTable}`.`object_owner_id` <> ? ", $aParams['owner_id']);
  307. //--- Don't show notifications about the other own actions performed in connected contexts
  308. $sWhereClauseType .= $this->prepareAsString("AND `{$this->_sTable}`.`author_id` <> ? ", $aParams['owner_id']);
  309. }
  310. //--- Don't show notifications about posts created before the connection was established
  311. if(!empty($aQueryParts['fields']['added']))
  312. $sWhereClauseType .= "AND `{$this->_sTable}`.`date` >= " . $aQueryParts['fields']['added'];
  313. list($aModulesProfiles, $aModulesContexts) = $this->_oConfig->getProfileBasedModules();
  314. $sJoinClause .= $this->prepareAsString(" INNER JOIN `{$this->_sTableSettings}` ON `{$this->_sTableHandlers}`.`id`=`{$this->_sTableSettings}`.`handler_id` AND `{$this->_sTableSettings}`.`delivery`='" . BX_BASE_MOD_NTFS_DTYPE_SITE . "' AND `{$this->_sTableSettings}`.`active`='1' AND ((`{$this->_sTableSettings}`.`type`=? AND `tsp`.`type` IN (" . $this->implode_escape($aModulesProfiles) . ")) || (`{$this->_sTableSettings}`.`type`=? AND `tsp`.`type` IN (" . $this->implode_escape($aModulesContexts) . ")))", BX_NTFS_STYPE_FOLLOW_MEMBER, BX_NTFS_STYPE_FOLLOW_CONTEXT);
  315. $sJoinClauseS2U = " LEFT JOIN `{$this->_sTableSettings2Users}` ON `{$this->_sTableSettings}`.`id`=`{$this->_sTableSettings2Users}`.`setting_id` ";
  316. if(!empty($aParams['owner_id']))
  317. $sJoinClauseS2U .= $this->prepareAsString("AND `{$this->_sTableSettings2Users}`.`user_id`=? ", $aParams['owner_id']);
  318. $sJoinClause .= $sJoinClauseS2U;
  319. $sWhereClauseSettings = "AND ((ISNULL(`{$this->_sTableSettings2Users}`.`active`) AND `{$this->_sTableSettings}`.`value`='1') OR (NOT ISNULL(`{$this->_sTableSettings2Users}`.`active`) AND `{$this->_sTableSettings2Users}`.`active`='1')) ";
  320. break;
  321. case BX_NTFS_TYPE_OBJECT_OWNER_AND_CONNECTIONS:
  322. /**
  323. * 'personal' notifications are taken by:
  324. * 1. 'owner_id', in case of somebody performed an action in requested profile's context
  325. * 'object_privacy_view' < 0 AND 'owner_id' == ABS('object_privacy_view'))
  326. * Currently it happens when somebody posted a Direct Timeline post in requested profile.
  327. * 2. 'object_owner_id', in case of somebody performed an action with content
  328. * owned by the requested profile.
  329. */
  330. $sWhereClauseObjectOwner = $this->prepareAsString("`{$this->_sTable}`.`owner_id` <> `{$this->_sTable}`.`object_owner_id` AND ((`{$this->_sTable}`.`owner_id`=? AND `{$this->_sTable}`.`object_privacy_view`<0 AND `{$this->_sTable}`.`owner_id`=ABS(`{$this->_sTable}`.`object_privacy_view`)) OR `{$this->_sTable}`.`object_owner_id`=?) ", $aParams['owner_id'], $aParams['owner_id']);
  331. /**
  332. * 'follow' notifications are taken by connection with `owner_id`
  333. */
  334. $sWhereClauseConnections = '0';
  335. $oConnection = BxDolConnection::getObjectInstance($this->_oConfig->getObject('conn_subscriptions'));
  336. $aQueryParts = $oConnection->getConnectedContentAsSQLPartsExt($this->_sTable, 'owner_id', $aParams['owner_id']);
  337. if(!empty($aQueryParts) && is_array($aQueryParts) && !empty($aQueryParts['join'])) {
  338. $sJoinClause .= " LEFT JOIN `sys_profiles` AS `tsp` ON `{$this->_sTable}`.`owner_id`=`tsp`.`id`";
  339. $sJoinClause .= " LEFT JOIN `" . $aQueryParts['join']['table'] . "` AS `" . $aQueryParts['join']['table_alias'] . "` ON (" . $aQueryParts['join']['condition'] . ")";
  340. //--- Show notifications from connected contexts
  341. $sWhereClauseConnections = "NOT ISNULL(`c`.`content`) ";
  342. if(getParam($CNF['PARAM_OWN_ACTIONS']) != 'on') {
  343. //--- Don't show notifications about own posts to connected contexts
  344. $sWhereClauseConnections .= $this->prepareAsString("AND `{$this->_sTable}`.`object_owner_id` <> ? ", $aParams['owner_id']);
  345. //--- Don't show notifications about the other own actions performed in connected contexts
  346. $sWhereClauseType .= $this->prepareAsString("AND `{$this->_sTable}`.`author_id` <> ? ", $aParams['owner_id']);
  347. }
  348. //--- Don't show notifications about posts created before the connection was established
  349. if(!empty($aQueryParts['fields']['added']))
  350. $sWhereClauseConnections .= "AND `{$this->_sTable}`.`date` >= `" . $aQueryParts['fields']['added']['table_alias'] . "`.`" . $aQueryParts['fields']['added']['name'] . "` ";
  351. }
  352. list($aModulesProfiles, $aModulesContexts) = $this->_oConfig->getProfileBasedModules();
  353. $sJoinClause .= $this->prepareAsString(" INNER JOIN `{$this->_sTableSettings}` ON `{$this->_sTableHandlers}`.`id`=`{$this->_sTableSettings}`.`handler_id` AND `{$this->_sTableSettings}`.`delivery`='" . BX_BASE_MOD_NTFS_DTYPE_SITE . "' AND `{$this->_sTableSettings}`.`active`='1' AND (`{$this->_sTableSettings}`.`type`=? OR ((`{$this->_sTableSettings}`.`type`=? AND `tsp`.`type` IN (" . $this->implode_escape($aModulesProfiles) . ")) || (`{$this->_sTableSettings}`.`type`=? AND `tsp`.`type` IN (" . $this->implode_escape($aModulesContexts) . "))))", BX_NTFS_STYPE_PERSONAL, BX_NTFS_STYPE_FOLLOW_MEMBER, BX_NTFS_STYPE_FOLLOW_CONTEXT);
  354. $sJoinClauseS2U = " LEFT JOIN `{$this->_sTableSettings2Users}` ON `{$this->_sTableSettings}`.`id`=`{$this->_sTableSettings2Users}`.`setting_id` ";
  355. if(!empty($aParams['owner_id']))
  356. $sJoinClauseS2U .= $this->prepareAsString("AND `{$this->_sTableSettings2Users}`.`user_id`=? ", $aParams['owner_id']);
  357. $sJoinClause .= $sJoinClauseS2U;
  358. $sWhereClauseSettings = "AND ((ISNULL(`{$this->_sTableSettings2Users}`.`active`) AND `{$this->_sTableSettings}`.`value`='1') OR (NOT ISNULL(`{$this->_sTableSettings2Users}`.`active`) AND `{$this->_sTableSettings2Users}`.`active`='1')) ";
  359. $sWhereClauseType = "AND ((" . $sWhereClauseObjectOwner . ") OR (" . $sWhereClauseConnections . ")) ";
  360. break;
  361. }
  362. $aAlertParams = $aParams;
  363. unset($aAlertParams['type'], $aAlertParams['owner_id']);
  364. /**
  365. * @hooks
  366. * @hookdef hook-bx_notifications-get_list_by_type 'bx_notifications', 'get_list_by_type' - hook to override SQL query parts which are used to get events list
  367. * - $unit_name - equals `bx_notifications`
  368. * - $action - equals `get_list_by_type`
  369. * - $object_id - not used
  370. * - $sender_id - not used
  371. * - $extra_params - array of additional params with the following array keys:
  372. * - `type` - [string] a type of events list
  373. * - `owner_id` - [int] owner profile id
  374. * - `params` - [array] browse params array as key&value pairs
  375. * - `table` - [string] datatbase table name
  376. * - `join_clause` - [string] by ref, 'join' part of SQL query, can be overridden in hook processing
  377. * - `where_clause` - [string] by ref, 'where' part of SQL query, can be overridden in hook processing
  378. * - `where_clause_start_from` - [string] by ref, 'start_from' condition in 'where' part of SQL query, can be overridden in hook processing
  379. * - `where_clause_status` - [string] by ref, 'status' condition in 'where' part of SQL query, can be overridden in hook processing
  380. * - `where_clause_modules` - [string] by ref, 'modules' condition in 'where' part of SQL query, can be overridden in hook processing
  381. * - `where_clause_new` - [string] by ref, 'new' condition in 'where' part of SQL query, can be overridden in hook processing
  382. * - `where_clause_settings` - [string] by ref, 'settings' conditions in 'where' part of SQL query, can be overridden in hook processing
  383. * - `where_clause_type` - [string] by ref, 'type' condition in 'where' part of SQL query, can be overridden in hook processing
  384. * @hook @ref hook-bx_notifications-get_list_by_type
  385. */
  386. bx_alert($this->_oConfig->getName(), 'get_list_by_type', 0, 0, [
  387. 'type' => $aParams['type'],
  388. 'owner_id' => $aParams['owner_id'],
  389. 'params' => $aAlertParams,
  390. 'table' => $this->_sTable,
  391. 'join_clause' => &$sJoinClause,
  392. 'where_clause' => &$sWhereClause,
  393. 'where_clause_start_from' => &$sWhereClauseStartFrom,
  394. 'where_clause_status' => &$sWhereClauseStatus,
  395. 'where_clause_modules' => &$sWhereClauseModules,
  396. 'where_clause_new' => &$sWhereClauseNew,
  397. 'where_clause_settings' => &$sWhereClauseSettings,
  398. 'where_clause_type' => &$sWhereClauseType,
  399. 'join_clause_ref' => &$sJoinClause,
  400. 'where_clause_ref' => &$sWhereClause,
  401. 'where_clause_start_from_ref' => &$sWhereClauseStartFrom,
  402. 'where_clause_status_ref' => &$sWhereClauseStatus,
  403. 'where_clause_modules_ref' => &$sWhereClauseModules,
  404. 'where_clause_new_ref' => &$sWhereClauseNew,
  405. 'where_clause_settings_ref' => &$sWhereClauseSettings,
  406. 'where_clause_type_ref' => &$sWhereClauseType,
  407. ]);
  408. $sWhereClause .= $sWhereClauseStartFrom;
  409. $sWhereClause .= $sWhereClauseStatus;
  410. $sWhereClause .= $sWhereClauseModules;
  411. $sWhereClause .= $sWhereClauseNew;
  412. $sWhereClause .= $sWhereClauseSettings;
  413. $sWhereClause .= $sWhereClauseType;
  414. return [$sJoinClause, $sWhereClause];
  415. }
  416. public function getEventsToProcess($iLimit = 0)
  417. {
  418. $aEvents = $this->getAll("SELECT * FROM `" . $this->_sTable . "` WHERE `id`>:id ORDER BY `id` ASC" . ($iLimit != 0 ? ' LIMIT ' . $iLimit : ''), array(
  419. 'id' => $this->_oConfig->getProcessedEvent()
  420. ));
  421. if(!empty($aEvents) && is_array($aEvents)) {
  422. $aEventEnd = end($aEvents);
  423. $this->_oConfig->setProcessedEvent($aEventEnd['id']);
  424. reset($aEvents);
  425. }
  426. return $aEvents;
  427. }
  428. public function aggregatorGetProfiles()
  429. {
  430. return $this->getColumn("SELECT DISTINCT `profile_id` FROM `" . $this->_sTableAggregator . "`");
  431. }
  432. public function aggregatorGetEvents($iProfileId, $sDeliveryType)
  433. {
  434. $sQuery = "SELECT
  435. `te`.*, GROUP_CONCAT(`te`.`id` ORDER BY `th`.`priority` DESC SEPARATOR ',') AS `grouped_by_mac`
  436. FROM `" . $this->_sTableAggregator . "` AS `ta`
  437. INNER JOIN `" . $this->_sTable . "` AS `te` ON `ta`.`event_id`=`te`.`id`
  438. INNER JOIN `" . $this->_sTableHandlers . "` AS `th` ON `te`.`type`=`th`.`alert_unit` AND `te`.`action`=`th`.`alert_action`
  439. WHERE
  440. `ta`.`profile_id`=:profile_id AND `ta`.`delivery`=:delivery
  441. GROUP BY `te`.`source_mac`";
  442. return $this->getAll($sQuery, [
  443. 'profile_id' => $iProfileId,
  444. 'delivery' => $sDeliveryType
  445. ]);
  446. }
  447. public function aggregatorAdd($aSet)
  448. {
  449. if(empty($aSet))
  450. return false;
  451. return $this->query("INSERT IGNORE INTO `" . $this->_sTableAggregator . "` SET " . $this->arrayToSQL($aSet)) !== false;
  452. }
  453. public function aggregatorDelete($iProfileId, $aEventsIds)
  454. {
  455. return (int)$this->query("DELETE FROM `" . $this->_sTableAggregator . "` WHERE `profile_id`=:profile_id AND `event_id` IN (" . $this->implode_escape($aEventsIds) . ")", [
  456. 'profile_id' => $iProfileId,
  457. ]) > 0;
  458. }
  459. public function queueGet($aParams)
  460. {
  461. $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
  462. $sSelectClause = "*";
  463. $sWhereClause = $sOrderClause = $sLimitClause = "";
  464. switch($aParams['type']) {
  465. case 'count':
  466. $aMethod['name'] = 'getOne';
  467. $sSelectClause = "COUNT(*)";
  468. break;
  469. case 'id':
  470. $aMethod['name'] = 'getRow';
  471. $aMethod['params'][1] = array(
  472. 'id' => $aParams['id']
  473. );
  474. $sWhereClause = " AND `id`=:id";
  475. break;
  476. case 'all_to_send':
  477. $aMethod['name'] = 'getAllWithKey';
  478. $aMethod['params'][1] = 'id';
  479. $aMethod['params'][2] = array(
  480. 'timeout' => $aParams['timeout']
  481. );
  482. $sWhereClause = " AND `date`+:timeout < UNIX_TIMESTAMP()";
  483. $sOrderClause = "`date` ASC";
  484. break;
  485. }
  486. $sOrderClause = !empty($sOrderClause) ? "ORDER BY " . $sOrderClause : $sOrderClause;
  487. $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : $sLimitClause;
  488. $aMethod['params'][0] = "SELECT
  489. " . $sSelectClause . "
  490. FROM `" . $this->_sTableQueue . "`
  491. WHERE 1" . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
  492. return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
  493. }
  494. public function queueAdd($aSet)
  495. {
  496. if(empty($aSet))
  497. return false;
  498. return (int)$this->query("INSERT INTO `" . $this->_sTableQueue . "` SET " . $this->arrayToSQL($aSet)) > 0;
  499. }
  500. public function queueDelete($aWhere)
  501. {
  502. if(empty($aWhere))
  503. return false;
  504. return (int)$this->query("DELETE FROM `" . $this->_sTableQueue . "` WHERE " . $this->arrayToSQL($aWhere, ' AND ')) > 0;
  505. }
  506. public function queueDeleteByProfile($iProfileId, $iEventId)
  507. {
  508. return (int)$this->query("DELETE FROM `" . $this->_sTableQueue . "` WHERE `profile_id`=:profile_id AND `event_id`<=:event_id", array(
  509. 'profile_id' => $iProfileId,
  510. 'event_id' => $iEventId
  511. )) > 0;
  512. }
  513. public function queueDeleteByIds($mixedId)
  514. {
  515. if(empty($mixedId))
  516. return false;
  517. if(!is_array($mixedId))
  518. $mixedId = array($mixedId);
  519. return (int)$this->query("DELETE FROM `" . $this->_sTableQueue . "` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
  520. }
  521. public function getEtemplates($aParams)
  522. {
  523. $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
  524. $sSelectClause = "*";
  525. $sWhereClause = $sOrderClause = $sLimitClause = "";
  526. switch($aParams['sample']) {
  527. case 'id':
  528. $aMethod['name'] = 'getRow';
  529. $aMethod['params'][1] = [
  530. 'id' => $aParams['id']
  531. ];
  532. $sWhereClause = " AND `id`=:id";
  533. break;
  534. case 'type_action':
  535. $aMethod['name'] = 'getRow';
  536. $aMethod['params'][1] = [
  537. 'type' => $aParams['type'],
  538. 'action' => $aParams['action']
  539. ];
  540. $sWhereClause = " AND `type`=:type AND `action`=:action";
  541. if(isset($aParams['active'])) {
  542. $aMethod['params'][1]['active'] = (int)$aParams['active'];
  543. $sWhereClause .= " AND `active`=:active";
  544. }
  545. break;
  546. }
  547. $sOrderClause = !empty($sOrderClause) ? "ORDER BY " . $sOrderClause : $sOrderClause;
  548. $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : $sLimitClause;
  549. $aMethod['params'][0] = "SELECT
  550. " . $sSelectClause . "
  551. FROM `" . $this->_sTableEtemplates . "`
  552. WHERE 1" . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
  553. return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
  554. }
  555. public function cleanEvents($iClearIntervalInDays)
  556. {
  557. $this->query("DELETE FROM `{$this->_sTable}` WHERE `date` < :date", array('date' => time() - $iClearIntervalInDays * 86400));
  558. }
  559. public function filterProfileIdsByModule($aIds, $mixedModule)
  560. {
  561. if(!is_array($mixedModule))
  562. $mixedModule = array($mixedModule);
  563. return $this->getColumn("SELECT `id` FROM `sys_profiles` WHERE `id` IN (" . $this->implode_escape($aIds) . ") AND `type` IN (" . $this->implode_escape($mixedModule) . ")");
  564. }
  565. }
  566. /** @} */