BxEventsModule.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  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 Events Events
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. /**
  12. * Events profiles module.
  13. */
  14. class BxEventsModule extends BxBaseModGroupsModule implements iBxDolCalendarService
  15. {
  16. function __construct(&$aModule)
  17. {
  18. parent::__construct($aModule);
  19. $CNF = &$this->_oConfig->CNF;
  20. $this->_aSearchableNamesExcept = array_merge($this->_aSearchableNamesExcept, array(
  21. $CNF['FIELD_TIMEZONE'],
  22. $CNF['FIELD_JOIN_CONFIRMATION'],
  23. $CNF['FIELD_REMINDER']
  24. ));
  25. }
  26. public function actionCalendarData()
  27. {
  28. // check permissions
  29. $aSQLPart = array();
  30. $iContentId = (int)bx_get('event');
  31. $iContextId = (int)bx_get('context_id');
  32. if ($iContentId) {
  33. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  34. if (CHECK_ACTION_RESULT_ALLOWED !== $this->checkAllowedView($aContentInfo)) {
  35. $this->_oTemplate->displayAccessDenied();
  36. exit;
  37. }
  38. $aSQLPart = array();
  39. }
  40. else {
  41. $oPrivacy = BxDolPrivacy::getObjectInstance($this->_oConfig->CNF['OBJECT_PRIVACY_VIEW']);
  42. if($iContextId){
  43. if (!$this->serviceIsEnableForContext($iContextId)){
  44. exit;
  45. }
  46. else{
  47. $aSQLPart = $oPrivacy ? $oPrivacy->getContentByGroupAsSQLPart(- $iContextId) : array();
  48. }
  49. }
  50. else{
  51. $aSQLPart = $oPrivacy ? $oPrivacy->getContentPublicAsSQLPart(0, $oPrivacy->getPartiallyVisiblePrivacyGroups()) : array();
  52. }
  53. }
  54. // get entries
  55. $aEntries = $this->_oDb->getEntriesByDate(bx_get('start'), bx_get('end'), bx_get('event'), $aSQLPart);
  56. header('Content-Type: application/json; charset=utf-8');
  57. echo json_encode($aEntries);
  58. }
  59. public function serviceGetCalendarEntries($iProfileId)
  60. {
  61. $CNF = &$this->_oConfig->CNF;
  62. $oConn = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS']);
  63. $aData = $oConn->getConnectedContent($iProfileId);
  64. $aData2 = array(0);
  65. foreach($aData as $iProfileId2){
  66. $oProfile = BxDolProfile::getInstance($iProfileId2);
  67. array_push($aData2, $oProfile->getContentId());
  68. }
  69. $aSQLPart['where'] = " AND `bx_events_data`.`id` IN(" . implode(',', $aData2) . ")";
  70. return $this->_oDb->getEntriesByDate(bx_get('start'), bx_get('end'), null, $aSQLPart);
  71. }
  72. public function serviceGetSafeServices()
  73. {
  74. $a = parent::serviceGetSafeServices();
  75. return array_merge($a, array (
  76. 'BrowsePastProfiles' => '',
  77. 'Calendar' => '',
  78. ));
  79. }
  80. /**
  81. * @page service Service Calls
  82. * @section bx_events Events
  83. * @subsection bx_events-browse Browse
  84. * @subsubsection bx_events-browse_upcoming_profiles browse_upcoming_profiles
  85. *
  86. * @code bx_srv('bx_events', 'browse_upcoming_profiles', [...]); @endcode
  87. *
  88. * Browse upcoming events
  89. *
  90. * @param $bDisplayEmptyMsg show "empty" message or not if nothing found
  91. * @param $bAjaxPaginate use AJAX paginate or not
  92. *
  93. * @see BxEventsModule::serviceBrowseUpcomingProfiles
  94. */
  95. /**
  96. * @ref bx_events-browse_upcoming_profiles "browse_upcoming_profiles"
  97. */
  98. public function serviceBrowseUpcomingProfiles ($aParams = false)
  99. {
  100. $bDisplayEmptyMsg = false;
  101. if(isset($aParams['empty_message'])) {
  102. $bDisplayEmptyMsg = (bool)$aParams['empty_message'];
  103. unset($aParams['empty_message']);
  104. }
  105. $bAjaxPaginate = true;
  106. if(isset($aParams['ajax_paginate'])) {
  107. $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
  108. unset($aParams['ajax_paginate']);
  109. }
  110. return $this->_serviceBrowse ('upcoming', $aParams, BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
  111. }
  112. /**
  113. * @page service Service Calls
  114. * @section bx_events Events
  115. * @subsection bx_events-browse Browse
  116. * @subsubsection bx_events-browse_upcoming_connected_profiles browse_upcoming_connected_profiles
  117. *
  118. * @code bx_srv('bx_events', 'browse_upcoming_connected_profiles', [...]); @endcode
  119. *
  120. * Browse upcoming connected (followed) events
  121. *
  122. * @param $bDisplayEmptyMsg show "empty" message or not if nothing found
  123. * @param $bAjaxPaginate use AJAX paginate or not
  124. *
  125. * @see BxEventsModule::serviceBrowseUpcomingConnectedProfiles
  126. */
  127. /**
  128. * @ref bx_events-browse_upcoming_connected_profiles "browse_upcoming_connected_profiles"
  129. */
  130. public function serviceBrowseUpcomingConnectedProfiles ($aParams = false)
  131. {
  132. if(!is_array($aParams) || empty($aParams['object']) || empty($aParams['profile']))
  133. return '';
  134. $bDisplayEmptyMsg = false;
  135. if(isset($aParams['empty_message'])) {
  136. $bDisplayEmptyMsg = (bool)$aParams['empty_message'];
  137. unset($aParams['empty_message']);
  138. }
  139. $bAjaxPaginate = true;
  140. if(isset($aParams['ajax_paginate'])) {
  141. $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
  142. unset($aParams['ajax_paginate']);
  143. }
  144. $aDefaults = array(
  145. 'type' => 'content',
  146. 'mutual' => false,
  147. 'profile2' => 0
  148. );
  149. return $this->_serviceBrowse ('upcoming_connected', array_merge($aDefaults, $aParams), BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
  150. }
  151. /**
  152. * @page service Service Calls
  153. * @section bx_events Events
  154. * @subsection bx_events-browse Browse
  155. * @subsubsection bx_events-browse_past_profiles browse_past_profiles
  156. *
  157. * @code bx_srv('bx_events', 'browse_past_profiles', [...]); @endcode
  158. *
  159. * Browse past events
  160. *
  161. * @param $bDisplayEmptyMsg show "empty" message or not if nothing found
  162. * @param $bAjaxPaginate use AJAX paginate or not
  163. *
  164. * @see BxEventsModule::serviceBrowsePastProfiles
  165. */
  166. /**
  167. * @ref bx_events-browse_past_profiles "browse_past_profiles"
  168. */
  169. public function serviceBrowsePastProfiles ($bDisplayEmptyMsg = false, $bAjaxPaginate = true)
  170. {
  171. return $this->_serviceBrowse ('past', false, BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
  172. }
  173. /**
  174. * @page service Service Calls
  175. * @section bx_events Events
  176. * @subsection bx_events-browse Browse
  177. * @subsubsection bx_events-browse_past_profiles browse_past_profiles_by_params
  178. *
  179. * @code bx_srv('bx_events', 'browse_past_profiles_by_params', [...]); @endcode
  180. *
  181. * Browse past events
  182. *
  183. * @param $aParams array with all parameters
  184. *
  185. * @see BxEventsModule::serviceBrowsePastProfilesByParams
  186. */
  187. /**
  188. * @ref bx_events-browse_past_profiles_by_params "browse_past_profiles_by_params"
  189. */
  190. public function serviceBrowsePastProfilesByParams ($aParams)
  191. {
  192. $bDisplayEmptyMsg = false;
  193. if(isset($aParams['empty_message'])) {
  194. $bDisplayEmptyMsg = (bool)$aParams['empty_message'];
  195. unset($aParams['empty_message']);
  196. }
  197. $bAjaxPaginate = true;
  198. if(isset($aParams['ajax_paginate'])) {
  199. $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
  200. unset($aParams['ajax_paginate']);
  201. }
  202. return $this->_serviceBrowse ('past', $aParams, BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
  203. }
  204. /**
  205. * @page service Service Calls
  206. * @section bx_events Events
  207. * @subsection bx_events-page_blocks Page Blocks
  208. * @subsubsection bx_events-calendar calendar
  209. *
  210. * @code bx_srv('bx_events', 'calendar', [...]); @endcode
  211. *
  212. * Shows event or events calendar
  213. *
  214. * @param $aData additional data to point which events to show, leave empty to show all events, specify event's ID in 'event' array key to show calendar for one event only, specify context's ID in 'context_id' array key to show calendar for one context events only. If only one event is specified then it will show calendar only if it's repeating event.
  215. * @param $sTemplate template to use to show calendar, or leave empty for default template, possible options: calendar.html, calendar_compact.html
  216. * @return HTML string with calendar to display on the site, all necessary CSS and JS files are automatically added to the HEAD section of the site HTML. On error empty string is returned.
  217. *
  218. * @see BxEventsModule::serviceCalendar
  219. */
  220. /**
  221. * @ref bx_events-calendar "calendar"
  222. */
  223. public function serviceCalendar($aData = array(), $sTemplate = 'calendar.html')
  224. {
  225. if (isset($aData['event'])) {
  226. $aContentInfo = $this->_oDb->getContentInfoById ((int)$aData['event']);
  227. if ('' == $aContentInfo['repeat_stop']) // don't display calendar for non repeating events
  228. return '';
  229. }
  230. if (isset($aData['context_id'])) {
  231. if (!$this->serviceIsEnableForContext($aData['context_id'])){
  232. return '';
  233. }
  234. }
  235. $o = new BxTemplCalendar(array(
  236. 'eventSources' => array (
  237. bx_append_url_params(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'calendar_data', $aData),
  238. ),
  239. ), $this->_oTemplate);
  240. return $o->display($sTemplate);
  241. }
  242. /**
  243. * @page service Service Calls
  244. * @section bx_events Events
  245. * @subsection bx_events-other Other
  246. * @subsubsection bx_events-process_reminders process_reminders
  247. *
  248. * @code bx_srv('bx_events', 'process_reminders'); @endcode
  249. *
  250. * Send remiders to event's participants.
  251. *
  252. * It must be processed once every hour for the proper processing.
  253. * @return nothing
  254. *
  255. * @see BxEventsModule::serviceProcessReminders
  256. */
  257. /**
  258. * @ref bx_events-process_reminders "process_reminders"
  259. */
  260. public function serviceProcessReminders()
  261. {
  262. $iNow = time();
  263. // get all events for today and tomorrow, since the max reminder is 24 hours
  264. $aEntries = $this->_oDb->getEntriesByDate('@' . time(), '@' . (time() + 86400));
  265. foreach ($aEntries as $a) {
  266. if (!$a['reminder'])
  267. continue;
  268. $iTimestamp = $a['start_utc'] - (3600 * $a['reminder']);
  269. if ($iNow > ($iTimestamp - 3600) && $iNow < $iTimestamp)
  270. $this->sendReminders($a);
  271. }
  272. }
  273. /**
  274. * @page service Service Calls
  275. * @section bx_events Events
  276. * @subsection bx_events-internal Internal
  277. * @subsubsection bx_events-get_timeline_post get_timeline_post
  278. *
  279. * @code bx_srv('bx_events', 'get_timeline_post', [...]); @endcode
  280. *
  281. * Get Timeline post. It's needed for Timeline module.
  282. *
  283. * @param $aEvent timeline event array from Timeline module
  284. * @return array in special format which is needed specifically for Timeline module to display the data.
  285. *
  286. * @see BxEventsModule::serviceGetTimelinePost
  287. */
  288. /**
  289. * @ref bx_events-get_timeline_post "get_timeline_post"
  290. */
  291. public function serviceGetTimelinePost($aEvent, $aBrowseParams = array())
  292. {
  293. $a = parent::serviceGetTimelinePost($aEvent, $aBrowseParams);
  294. if($a === false)
  295. return false;
  296. $aContentInfo = $this->_oDb->getContentInfoById($aEvent['object_id']);
  297. if(empty($aContentInfo) || !is_array($aContentInfo))
  298. return $a;
  299. $CNF = $this->_oConfig->CNF;
  300. $oDateStart = date_create('@' . $aContentInfo['date_start']);
  301. $oDateStart->setTimezone(new DateTimeZone($aContentInfo['timezone'] ? $aContentInfo['timezone'] : 'UTC'));
  302. $oDateEnd = date_create('@' . ($aContentInfo['date_start'] > $aContentInfo['repeat_stop'] ? $aContentInfo['date_start'] : $aContentInfo['repeat_stop']));
  303. $oDateEnd->setTimezone(new DateTimeZone($aContentInfo['timezone'] ? $aContentInfo['timezone'] : 'UTC'));
  304. $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS']);
  305. $sLocationString = $oMetatags ? $oMetatags->locationsString($aContentInfo[$CNF['FIELD_ID']], false) : false;
  306. $a['content']['raw'] = $this->_oTemplate->parseHtmlByName('timeline_post.html', array(
  307. 'title' => $a['content']['title'],
  308. 'title_attr' => bx_html_attribute($a['content']['title']),
  309. 'url' => $a['content']['url'],
  310. 'date' => strftime(getParam('bx_events_short_date_format'), $oDateStart->getTimestamp()) . ($oDateStart->format('ymd') == $oDateEnd->format('ymd') ? '' : ' - ' . strftime(getParam('bx_events_short_date_format'), $oDateEnd->getTimestamp())),
  311. 'date_c' => $oDateStart->format('c'),
  312. 'bx_if:location' => array(
  313. 'condition' => !!$sLocationString,
  314. 'content' => array('location' => $sLocationString),
  315. ),
  316. ));
  317. $a['content']['title'] = '';
  318. $a['content']['text'] = '';
  319. return $a;
  320. }
  321. public function actionIntervals()
  322. {
  323. $sAction = bx_get('a');
  324. $sMethodName = 'subaction' . ucfirst($sAction);
  325. if (!method_exists($this, $sMethodName)) {
  326. $this->_oTemplate->pageNotFound();
  327. return;
  328. }
  329. $this->$sMethodName();
  330. }
  331. public function subactionRestore($iContentId = 0)
  332. {
  333. if (!$iContentId)
  334. $iContentId = (int)bx_get('c');
  335. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  336. if (
  337. ($aContentInfo && CHECK_ACTION_RESULT_ALLOWED !== $this->checkAllowedEdit ($aContentInfo))
  338. ||
  339. (!$aContentInfo && CHECK_ACTION_RESULT_ALLOWED !== $this->checkAllowedAdd ())
  340. ) {
  341. $this->_oTemplate->displayAccessDenied();
  342. exit;
  343. }
  344. $a = $this->_oDb->getIntervals($iContentId);
  345. foreach ($a as $iIntervalId => $r) {
  346. $a[$iIntervalId]['file_id'] = $r['interval_id'];
  347. $a[$iIntervalId]['repeat_stop'] = bx_process_output ($r['repeat_stop'], BX_DATA_DATE_TS);
  348. }
  349. if ('json' == bx_get('f')) {
  350. header('Content-type: text/html; charset=utf-8');
  351. echo json_encode($a);
  352. }
  353. }
  354. public function subactionDelete()
  355. {
  356. header('Content-type: text/html; charset=utf-8');
  357. $iIntervalId = (int)bx_get('id');
  358. if (!($aContentInfo = $this->_oDb->getContentInfoByIntervalId($iIntervalId))) {
  359. echo _t('_sys_request_page_not_found_cpt');
  360. }
  361. elseif (CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $this->checkAllowedEdit ($aContentInfo))) {
  362. echo $sMsg;
  363. }
  364. elseif (!$this->_oDb->deleteIntervalById($iIntervalId)) {
  365. echo _t('_sys_txt_error_occured');
  366. }
  367. else {
  368. echo 'ok';
  369. }
  370. }
  371. /**
  372. * Send reminder to event's paritcipants
  373. * @param $aContentInfo content info
  374. * @return number of sent reminders
  375. */
  376. protected function sendReminders($aContentInfo)
  377. {
  378. $CNF = $this->_oConfig->CNF;
  379. $oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS']);
  380. if (!$oConnection)
  381. return false;
  382. $oGroupProfile = BxDolProfile::getInstanceByContentAndType($aContentInfo[$CNF['FIELD_ID']], $this->getName());
  383. if (!$oGroupProfile)
  384. return false;
  385. $aParticipants = $oConnection->getConnectedInitiators($oGroupProfile->id(), true);
  386. if (!$aParticipants)
  387. return true;
  388. $oDateBegin = new DateTime();
  389. $oDateBegin->setTimestamp($aContentInfo['start_utc']);
  390. $oDateBegin->setTimezone(new DateTimeZone($aContentInfo['timezone'] ? $aContentInfo['timezone'] : 'UTC'));
  391. $sEntryBegin = $oDateBegin->format('r');
  392. $sEntryBeginShort = $oDateBegin->format(getParam('bx_events_short_date_format'));
  393. $oDateBegin->setTimezone(new DateTimeZone('UTC'));
  394. $sEntryBeginUTC = $oDateBegin->format('c');
  395. $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS']);
  396. $sLocationString = $oMetatags->locationsString($aContentInfo[$CNF['FIELD_ID']], false);
  397. $iCounter = 0;
  398. foreach ($aParticipants as $iProfileId) {
  399. $b = sendMailTemplate($CNF['EMAIL_REMINDER'], 0, $iProfileId, array(
  400. 'EntryUrl' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]),
  401. 'EntryTitle' => $aContentInfo['title'],
  402. 'EntryBegin' => $sEntryBegin,
  403. 'EntryBeginShort' => $sEntryBeginShort,
  404. 'EntryBeginUTC' => $sEntryBeginUTC,
  405. 'EntryLocation' => $sLocationString,
  406. ), BX_EMAIL_NOTIFY);
  407. $iCounter += $b ? 1 : 0;
  408. }
  409. return $iCounter;
  410. }
  411. }
  412. /** @} */