BxTasksModule.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  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. * @defgroup Tasks Tasks
  6. * @ingroup UnaModules
  7. *
  8. * @{
  9. */
  10. /**
  11. * Task states
  12. */
  13. define('BX_TASKS_STATE_BACBLOG', 1);
  14. define('BX_TASKS_STATE_TODO', 2);
  15. define('BX_TASKS_STATE_IN_PROGRESS', 3);
  16. define('BX_TASKS_STATE_IN_REVIEW', 4);
  17. define('BX_TASKS_STATE_CANCELLED', 5);
  18. define('BX_TASKS_STATE_DUPLICATE', 6);
  19. define('BX_TASKS_STATE_DONE', 7);
  20. class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
  21. {
  22. function __construct(&$aModule)
  23. {
  24. parent::__construct($aModule);
  25. $CNF = &$this->_oConfig->CNF;
  26. $this->_aSearchableNamesExcept = array_merge($this->_aSearchableNamesExcept, array(
  27. $CNF['FIELD_PUBLISHED'],
  28. $CNF['FIELD_ALLOW_COMMENTS']
  29. ));
  30. }
  31. /**
  32. * Action methods
  33. */
  34. /**
  35. * Get possible recipients for start conversation form
  36. */
  37. public function actionAjaxGetInitialMembers($iContextPid)
  38. {
  39. $sTerm = bx_get('term');
  40. $sModule = $this->_oConfig->getName();
  41. $a = bx_srv('system', 'profiles_search', [$sTerm, [
  42. 'module' => $sModule,
  43. 'search_params' => ['name' => $sModule . '_initial_members', 'context_pid' => $iContextPid]
  44. ]], 'TemplServiceProfiles');
  45. header('Content-Type:text/javascript; charset=utf-8');
  46. echo(json_encode($a));
  47. }
  48. public function actionSetCompleted($iContentId, $iCompleted)
  49. {
  50. if(!$this->isAllowManage($iContentId) || !$this->complete($iContentId, $iCompleted))
  51. return echoJson(['code' => 1]);
  52. return echoJson(['code' => 0, 'reload' => 1]);
  53. }
  54. public function actionSetFilterValue($iListId, $sValue)
  55. {
  56. $CNF = &$this->_oConfig->CNF;
  57. $aTmp = array();
  58. if (isset($_COOKIE[$CNF['COOKIE_SETTING_KEY']]))
  59. $aTmp = json_decode($_COOKIE[$CNF['COOKIE_SETTING_KEY']], true);
  60. if ($sValue != '')
  61. $aTmp[$iListId] = $sValue;
  62. else
  63. unset($aTmp[$iListId]);
  64. bx_setcookie($CNF['COOKIE_SETTING_KEY'], json_encode($aTmp), time() + 60*60*24*365);
  65. }
  66. public function actionProcessTaskListForm($iContextId, $iId)
  67. {
  68. if (!$this->isAllowAdd(-$iContextId))
  69. return;
  70. $CNF = &$this->_oConfig->CNF;
  71. $oForm = null;
  72. $sPopupTitle = "";
  73. $aContentInfo = array();
  74. if ($iId == 0){
  75. $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_LIST_ENTRY'], $CNF['OBJECT_FORM_LIST_ENTRY_DISPLAY_ADD']);
  76. $sPopupTitle = _t('_bx_tasks_form_list_entry_display_add');
  77. }
  78. else {
  79. $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_LIST_ENTRY'], $CNF['OBJECT_FORM_LIST_ENTRY_DISPLAY_EDIT']);
  80. $aContentInfo = $this->_oDb->getList($iId);
  81. $sPopupTitle = _t('_bx_tasks_form_list_entry_display_edit');
  82. }
  83. $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'process_task_list_form/' . $iContextId . '/' . $iId . '/';
  84. if (!$oForm)
  85. return '';
  86. $oForm->initChecker($aContentInfo, array());
  87. if($oForm->isSubmittedAndValid()) {
  88. if ($iId == 0){
  89. $aValsToAdd['context_id'] = $iContextId;
  90. $iId = $oForm->insert($aValsToAdd);
  91. }
  92. else {
  93. $iId = $oForm->update($iId);
  94. }
  95. return echoJson(array(
  96. 'eval' => $this->_oConfig->getJsObject('tasks') . '.reloadData(oData, ' . $iContextId . ')',
  97. ));
  98. }
  99. else {
  100. $sContent = $this->_oTemplate->parseHtmlByName('popup_form.html', array(
  101. 'form_id' => $oForm->getId(),
  102. 'form' => $oForm->getCode(true)
  103. ));
  104. if (!$oForm->isSubmitted()) {
  105. echo $sContent;
  106. return;
  107. }
  108. return echoJson(array('form' => $sContent, 'form_id' => $oForm->getId()));
  109. }
  110. }
  111. public function actionDeleteTaskList($iId, $iContextId)
  112. {
  113. if (!$this->isAllowManageByContext($iContextId))
  114. return;
  115. $CNF = &$this->_oConfig->CNF;
  116. $aTasks = $this->_oDb->getTasks($iContextId, $iId);
  117. $this->_oDb->deleteList($iId);
  118. if (!empty($aTasks) && ($oConn = BxDolConnection::getObjectInstance($this->_oConfig->CNF['OBJECT_CONNECTION']))) {
  119. foreach ($aTasks as &$aTask)
  120. $oConn->onDeleteContent($aTask[$CNF['FIELD_ID']]);
  121. }
  122. echoJson(array(
  123. 'context_id' => $iContextId,
  124. ));
  125. }
  126. public function actionProcessTaskForm($iContextId, $iListId)
  127. {
  128. $_iContextId = abs($iContextId);
  129. if(!$this->isAllowAdd($_iContextId))
  130. return echoJson([]);
  131. $CNF = &$this->_oConfig->CNF;
  132. $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ENTRY'], $CNF['OBJECT_FORM_ENTRY_DISPLAY_ADD']);
  133. if(!$oForm)
  134. return echoJson([]);
  135. $oForm->setAction(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'process_task_form/' . $iContextId . '/' . $iListId . '/');
  136. $oForm->setContextId($_iContextId);
  137. $oForm->initChecker();
  138. if($oForm->isSubmittedAndValid()) {
  139. $iContentId = $oForm->insert([$CNF['FIELD_ALLOW_VIEW_TO'] => $iContextId, $CNF['FIELD_TASKLIST'] => $iListId]);
  140. if($iContentId)
  141. $this->onPublished($iContentId);
  142. return echoJson([
  143. 'eval' => $this->_oConfig->getJsObject('tasks') . '.reloadData(oData, ' . $iContextId . ')',
  144. ]);
  145. }
  146. else {
  147. $sContent = $this->_oTemplate->parseHtmlByName('popup_form.html', [
  148. 'form_id' => $oForm->getId(),
  149. 'form' => $oForm->getCode(true)
  150. ]);
  151. if($oForm->isSubmitted())
  152. return echoJson(['form' => $sContent, 'form_id' => $oForm->getId()]);
  153. echo $sContent;
  154. }
  155. }
  156. public function actionProcessTaskFormEditProperty($iContentId, $sProperty)
  157. {
  158. $CNF = &$this->_oConfig->CNF;
  159. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  160. if(!$this->isAllowAdd(abs($aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']])))
  161. return '';
  162. $sForm = '';
  163. if(($sKey = 'OBJECT_FORM_ENTRY_DISPLAY_EDIT_' . strtoupper($sProperty)) && !empty($CNF[$sKey]))
  164. $sForm = $CNF[$sKey];
  165. else
  166. return '';
  167. $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ENTRY'], $sForm);
  168. $oForm->setId($sForm);
  169. $oForm->setName($sForm);
  170. $oForm->setAction(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'process_task_form_edit_property/' . $iContentId . '/' . $sProperty . '/');
  171. if(!$oForm)
  172. return '';
  173. $oForm->initChecker($aContentInfo);
  174. if($oForm->isSubmittedAndValid()) {
  175. if(!$oForm->update($iContentId))
  176. return echoJson(['msg' => _t('_bx_tasks_txt_err_cannot_perform_action')]);
  177. if(($sMethod = '_onEdit' . bx_gen_method_name($sProperty)) && method_exists($this, $sMethod))
  178. $this->$sMethod($aContentInfo, $oForm);
  179. else
  180. $this->_onEditProperty($aContentInfo, $sProperty, $oForm);
  181. return echoJson([
  182. 'eval' => $this->_oConfig->getJsObject('tasks') . '.reload(oData)',
  183. ]);
  184. }
  185. else {
  186. $sContent = $this->_oTemplate->parseHtmlByName('popup_form.html', [
  187. 'form_id' => $oForm->getId(),
  188. 'form' => $oForm->getCode(true)
  189. ]);
  190. if (!$oForm->isSubmitted()) {
  191. echo $sContent;
  192. return;
  193. }
  194. return echoJson(['form' => $sContent, 'form_id' => $oForm->getId()]);
  195. }
  196. }
  197. public function actionCalendarData()
  198. {
  199. // check permissions
  200. $aSQLPart = array();
  201. $iContextId = (int)bx_get('context_id');
  202. if(!$this->isAllowView($iContextId))
  203. return;
  204. $oPrivacy = BxDolPrivacy::getObjectInstance($this->_oConfig->CNF['OBJECT_PRIVACY_VIEW']);
  205. if($iContextId) {
  206. $aSQLPart = $oPrivacy ? $oPrivacy->getContentByGroupAsSQLPart(- $iContextId) : array();
  207. }
  208. // get entries
  209. $aEntries = $this->_oDb->getEntriesByDate(bx_get('start'), bx_get('end'), bx_get('event'), $aSQLPart);
  210. header('Content-Type: application/json; charset=utf-8');
  211. echo json_encode($aEntries);
  212. }
  213. public function serviceGetBlockMenuContext($iProfileId)
  214. {
  215. $CNF = &$this->_oConfig->CNF;
  216. $oMenu = BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_SUBMENU_VIEW_CONTEXT']);
  217. if(!$oMenu)
  218. return '';
  219. $oMenu->addMarkers(['profile_id' => $iProfileId]);
  220. return $oMenu->getCode();
  221. }
  222. public function serviceGetBlockManageTimeContext($iContextPid)
  223. {
  224. $CNF = &$this->_oConfig->CNF;
  225. return $this->_getBlockManageTimeContext($CNF['OBJECT_GRID_TIME'], $iContextPid);
  226. }
  227. public function serviceGetBlockAdministrateTimeContext($iContextPid)
  228. {
  229. $CNF = &$this->_oConfig->CNF;
  230. return $this->_getBlockManageTimeContext($CNF['OBJECT_GRID_TIME_ADMINISTRATION'], $iContextPid);
  231. }
  232. protected function _getBlockManageTimeContext($sGridObject, $iContextPid)
  233. {
  234. $oGrid = BxDolGrid::getObjectInstance($sGridObject);
  235. if(!$oGrid)
  236. return $this->_bIsApi ? [] : '';
  237. $oGrid->setContextPid($iContextPid);
  238. if($this->_bIsApi)
  239. return [
  240. bx_api_get_block('grid', $oGrid->getCodeAPI())
  241. ];
  242. list($aCssCalendar, $aJsCalendar) = BxBaseFormView::getCssJsCalendar();
  243. $this->_oTemplate->addCss(array_merge($aCssCalendar, ['manage_tools.css', 'time.css']));
  244. $this->_oTemplate->addJs(array_merge($aJsCalendar, ['modules/base/text/js/|manage_tools.js', 'time.js']));
  245. $this->_oTemplate->addJsTranslation(['_sys_grid_search']);
  246. return $this->_oTemplate->getJsCode('time', [
  247. 'sObjNameGrid' => $sGridObject
  248. ]) . $oGrid->getCode();
  249. }
  250. /**
  251. * Data for Timeline module
  252. */
  253. public function serviceGetTimelineData()
  254. {
  255. $sModule = $this->_aModule['name'];
  256. return array(
  257. 'handlers' => array(
  258. array('group' => $sModule . '_object', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'added', 'module_name' => $sModule, 'module_method' => 'get_timeline_post', 'module_class' => 'Module', 'groupable' => 0, 'group_by' => ''),
  259. array('group' => $sModule . '_completed', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'completed', 'module_name' => $sModule, 'module_method' => 'get_timeline_completed', 'module_class' => 'Module', 'groupable' => 0, 'group_by' => ''),
  260. array('group' => $sModule . '_reopened', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'reopened', 'module_name' => $sModule, 'module_method' => 'get_timeline_reopened', 'module_class' => 'Module', 'groupable' => 0, 'group_by' => ''),
  261. array('group' => $sModule . '_object', 'type' => 'update', 'alert_unit' => $sModule, 'alert_action' => 'edited'),
  262. array('group' => $sModule . '_object', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'deleted'),
  263. ),
  264. 'alerts' => array(
  265. array('unit' => $sModule, 'action' => 'added'),
  266. array('unit' => $sModule, 'action' => 'completed'),
  267. array('unit' => $sModule, 'action' => 'reopened'),
  268. array('unit' => $sModule, 'action' => 'edited'),
  269. array('unit' => $sModule, 'action' => 'deleted'),
  270. )
  271. );
  272. }
  273. /**
  274. * Entry task for Timeline module
  275. */
  276. public function serviceGetTimelinePost($aEvent, $aBrowseParams = array())
  277. {
  278. $CNF = &$this->_oConfig->CNF;
  279. $aResult = parent::serviceGetTimelinePost($aEvent, $aBrowseParams);
  280. if(empty($aResult) || !is_array($aResult) || empty($aResult['date']))
  281. return $aResult;
  282. $aContentInfo = $this->_oDb->getContentInfoById($aEvent['object_id']);
  283. if($aContentInfo[$CNF['FIELD_PUBLISHED']] > $aResult['date'])
  284. $aResult['date'] = $aContentInfo[$CNF['FIELD_PUBLISHED']];
  285. return $aResult;
  286. }
  287. public function serviceGetTimelineCompleted($aEvent, $aBrowseParams = array())
  288. {
  289. $CNF = &$this->_oConfig->CNF;
  290. $aResult = parent::serviceGetTimelinePost($aEvent, $aBrowseParams);
  291. if(empty($aResult) || !is_array($aResult) || empty($aResult['date']))
  292. return $aResult;
  293. $aContentInfo = $this->_oDb->getContentInfoById($aEvent['object_id']);
  294. if($aContentInfo[$CNF['FIELD_PUBLISHED']] > $aResult['date'])
  295. $aResult['date'] = $aContentInfo[$CNF['FIELD_PUBLISHED']];
  296. $aResult['sample_action'] = $aResult['content']['sample_action'] = _t('_bx_tasks_txt_action_completed');
  297. return $aResult;
  298. }
  299. public function serviceGetTimelineReopened($aEvent, $aBrowseParams = array())
  300. {
  301. $CNF = &$this->_oConfig->CNF;
  302. $aResult = parent::serviceGetTimelinePost($aEvent, $aBrowseParams);
  303. if(empty($aResult) || !is_array($aResult) || empty($aResult['date']))
  304. return $aResult;
  305. $aContentInfo = $this->_oDb->getContentInfoById($aEvent['object_id']);
  306. if($aContentInfo[$CNF['FIELD_PUBLISHED']] > $aResult['date'])
  307. $aResult['date'] = $aContentInfo[$CNF['FIELD_PUBLISHED']];
  308. $aResult['sample_action'] = $aResult['content']['sample_action'] = _t('_bx_tasks_txt_action_reopened');
  309. return $aResult;
  310. }
  311. public function serviceGetNotificationsData()
  312. {
  313. $sModule = $this->_aModule['name'];
  314. $sEventPrivacy = $sModule . '_allow_view_event_to';
  315. if(BxDolPrivacy::getObjectInstance($sEventPrivacy) === false)
  316. $sEventPrivacy = '';
  317. $aResult = parent::serviceGetNotificationsData();
  318. $aResult['handlers'] = array_merge($aResult['handlers'], array(
  319. array('group' => $sModule . '_completed', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'completed', 'module_name' => $sModule, 'module_method' => 'get_notifications_completed', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
  320. array('group' => $sModule . '_reopened', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'reopened', 'module_name' => $sModule, 'module_method' => 'get_notifications_reopened', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
  321. array('group' => $sModule . '_expired', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'expired', 'module_name' => $sModule, 'module_method' => 'get_notifications_expired', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
  322. array('group' => $sModule . '_assign', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'assigned', 'module_name' => $sModule, 'module_method' => 'get_notifications_assigned', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
  323. array('group' => $sModule . '_assign', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'unassigned'),
  324. ));
  325. $aResult['settings'] = array_merge($aResult['settings'], array(
  326. array('group' => 'content', 'unit' => $sModule, 'action' => 'completed', 'types' => array('personal', 'follow_member', 'follow_context')),
  327. array('group' => 'content', 'unit' => $sModule, 'action' => 'reopened', 'types' => array('personal', 'follow_member', 'follow_context')),
  328. array('group' => 'content', 'unit' => $sModule, 'action' => 'expired', 'types' => array('personal')),
  329. array('group' => 'content', 'unit' => $sModule, 'action' => 'assigned', 'types' => array('personal')),
  330. ));
  331. $aResult['alerts'] = array_merge($aResult['alerts'], array(
  332. array('unit' => $sModule, 'action' => 'completed'),
  333. array('unit' => $sModule, 'action' => 'reopened'),
  334. array('unit' => $sModule, 'action' => 'expired'),
  335. array('unit' => $sModule, 'action' => 'assigned'),
  336. array('unit' => $sModule, 'action' => 'unassigned'),
  337. ));
  338. return $aResult;
  339. }
  340. public function serviceGetNotificationsCompleted($aEvent)
  341. {
  342. return $this->_serviceGetNotificationsByAction($aEvent, 'completed');
  343. }
  344. public function serviceGetNotificationsReopened($aEvent)
  345. {
  346. return $this->_serviceGetNotificationsByAction($aEvent, 'reopened');
  347. }
  348. public function serviceGetNotificationsExpired($aEvent)
  349. {
  350. return $this->_serviceGetNotificationsByAction($aEvent, 'expired');
  351. }
  352. public function serviceGetNotificationsAssigned($aEvent)
  353. {
  354. return $this->_serviceGetNotificationsByAction($aEvent, 'assigned');
  355. }
  356. protected function _serviceGetNotificationsByAction($aEvent, $sAction)
  357. {
  358. $CNF = &$this->_oConfig->CNF;
  359. $aResult = parent::serviceGetNotificationsPost($aEvent);
  360. if(empty($aResult) || !is_array($aResult))
  361. return $aResult;
  362. $aResult['entry_author'] = $aEvent['object_owner_id'];
  363. $aResult['entry_author_name'] = '';
  364. if(($oAuthor = BxDolProfile::getInstance($aResult['entry_author'])) !== false)
  365. $aResult['entry_author_name'] = $oAuthor->getDisplayName();
  366. $sLangKey = '_bx_tasks_txt_notification_' . $sAction;
  367. if((int)$aEvent['object_privacy_view'] < 0)
  368. $sLangKey .= '_in_context';
  369. $aResult['lang_key'] = _t($sLangKey);
  370. return $aResult;
  371. }
  372. public function serviceCheckAllowedManageInContext($iContextPid)
  373. {
  374. if(!$this->isAllowManageByContext($iContextPid))
  375. return false;
  376. return true;
  377. }
  378. public function serviceCheckAllowedManage($iContentId)
  379. {
  380. if(!$this->isAllowManage($iContentId))
  381. return false;
  382. return true;
  383. }
  384. public function serviceCheckAllowedComplete($iContentId)
  385. {
  386. if(!$this->serviceCheckAllowedManage($iContentId))
  387. return false;
  388. return !$this->isCompleted($iContentId);
  389. }
  390. public function serviceCheckAllowedUncomplete($iContentId)
  391. {
  392. if(!$this->serviceCheckAllowedManage($iContentId))
  393. return false;
  394. return $this->isCompleted($iContentId);
  395. }
  396. public function serviceIsCompleted($iContentId)
  397. {
  398. return $this->isCompleted($iContentId);
  399. }
  400. public function serviceIsUncompleted($iContentId)
  401. {
  402. return !$this->isCompleted($iContentId);
  403. }
  404. public function serviceIsAllowBadges($iContentId)
  405. {
  406. if (!$this->isAllowManage($iContentId))
  407. return false;
  408. if (!$this->serviceIsBadgesAvaliable())
  409. return false;
  410. return true;
  411. }
  412. public function serviceEntityAssignments($iContentId = 0, $bAsArray = false)
  413. {
  414. if(!$iContentId)
  415. $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
  416. if(!$iContentId)
  417. return false;
  418. $CNF = &$this->_oConfig->CNF;
  419. $aProfiles = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTION'])->getConnectedInitiators($iContentId);
  420. if($bAsArray)
  421. return $aProfiles;
  422. return $this->_oTemplate->entryAssignments($aProfiles);
  423. }
  424. public function serviceCheckAllowedCommentsTask($iContentId, $sObjectComments)
  425. {
  426. $CNF = &$this->_oConfig->CNF;
  427. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  428. if ($aContentInfo[$CNF['FIELD_ALLOW_COMMENTS']] == 0)
  429. return false;
  430. return parent::serviceCheckAllowedCommentsTask($iContentId, $sObjectComments);
  431. }
  432. public function serviceCheckAllowedCommentsView($iContentId, $sObjectComments)
  433. {
  434. $CNF = &$this->_oConfig->CNF;
  435. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  436. if ($aContentInfo[$CNF['FIELD_ALLOW_COMMENTS']] == 0)
  437. return false;
  438. return parent::serviceCheckAllowedCommentsView($iContentId, $sObjectComments);
  439. }
  440. /**
  441. * @page service Service Calls
  442. * @section bx_tasks Tasks
  443. * @subsection bx_tasks-page_blocks Page Blocks
  444. * @subsubsection bx_tasks-calendar calendar
  445. *
  446. * @code bx_srv('bx_tasks', 'calendar', [...]); @endcode
  447. *
  448. * Shows tasks calendar baced on die date
  449. *
  450. * @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.
  451. * @param $sTemplate template to use to show calendar, or leave empty for default template, possible options: calendar.html, calendar_compact.html
  452. * @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.
  453. *
  454. * @see BxTasksModule::serviceCalendar
  455. */
  456. /**
  457. * @ref bx_tasks-calendar "calendar"
  458. */
  459. public function serviceCalendar($aData = array(), $sTemplate = 'calendar.html')
  460. {
  461. if (!$this->isAllowView($aData['context_id']))
  462. return;
  463. $o = new BxTemplCalendar(array(
  464. 'eventSources' => array (
  465. bx_append_url_params(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'calendar_data', $aData),
  466. ),
  467. ), $this->_oTemplate);
  468. return $o->display($sTemplate);
  469. }
  470. public function serviceGetCalendarEntries($iProfileId)
  471. {
  472. $CNF = &$this->_oConfig->CNF;
  473. $oConn = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTION']);
  474. $aData = $oConn->getConnectedInitiators($iProfileId);
  475. $aData2 = array(0);
  476. foreach($aData as $iProfileId2) {
  477. $oProfile = BxDolProfile::getInstance($iProfileId2);
  478. array_push($aData2, $oProfile->getContentId());
  479. }
  480. $aSQLPart['where'] = " AND " . $CNF['TABLE_ENTRIES'] . ".`" . $CNF['FIELD_ID'] . "` IN(" . implode(',', $aData2) . ")";
  481. return $this->_oDb->getEntriesByDate(bx_get('start'), bx_get('end'), null, $aSQLPart);
  482. }
  483. public function serviceBrowseContext ($iProfileId = 0, $aParams = array())
  484. {
  485. if(!$iProfileId)
  486. $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
  487. if(!$iProfileId)
  488. return '';
  489. return $this->serviceBrowseTasks (-$iProfileId, $aParams);
  490. }
  491. public function serviceBrowseTasks ($iContextId = 0, $aParams = array())
  492. {
  493. $_iContextId = abs($iContextId);
  494. if(!$this->isAllowView($_iContextId))
  495. return;
  496. if(!($oProfileContext = BxDolProfile::getInstance($_iContextId)) || $oProfileContext->checkAllowedProfileView($_iContextId) !== CHECK_ACTION_RESULT_ALLOWED)
  497. return false;
  498. return $this->_oTemplate->getEntriesList($iContextId);
  499. }
  500. /**
  501. * Common methods
  502. */
  503. public function onExpired($iContentId)
  504. {
  505. $CNF = &$this->_oConfig->CNF;
  506. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  507. if(!$aContentInfo)
  508. return;
  509. $oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTION']);
  510. if($oConnection) {
  511. $aProfileIds = $oConnection->getConnectedContent($iContentId);
  512. if(!empty($aProfileIds) && is_array($aProfileIds))
  513. foreach($aProfileIds as $iProfileId){
  514. /**
  515. * @hooks
  516. * @hookdef hook-bx_tasks-expired 'bx_tasks', 'expired' - hook on task unassigned to profile
  517. * - $unit_name - equals `bx_tasks`
  518. * - $action - equals `expired`
  519. * - $object_id - task id
  520. * - $sender_id - not used
  521. * - $extra_params - array of additional params with the following array keys:
  522. * - `object_author_id` - [int] profile_id for task's author
  523. * - `privacy_view` - [string] privacy view value
  524. * @hook @ref hook-bx_tasks-expired
  525. */
  526. bx_alert($this->getName(), 'expired', $iContentId, false, array(
  527. 'object_author_id' => $iProfileId,
  528. 'privacy_view' => $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]
  529. ));
  530. }
  531. }
  532. }
  533. public function isAllowView($iContextId)
  534. {
  535. if(!($oContext = BxDolProfile::getInstance($iContextId)) || $oContext->checkAllowedProfileView($iContextId) !== CHECK_ACTION_RESULT_ALLOWED)
  536. return false;
  537. return true;
  538. }
  539. public function isAllowAdd($iContextId)
  540. {
  541. if(!($oContext = BxDolProfile::getInstance($iContextId)) || $oContext->checkAllowedPostInProfile($iContextId) !== CHECK_ACTION_RESULT_ALLOWED)
  542. return false;
  543. return true;
  544. }
  545. public function isAllowManageByContext($iContextId)
  546. {
  547. if(isAdmin())
  548. return true;
  549. $oProfileContext = BxDolProfile::getInstance($iContextId);
  550. if(BxDolService::call($oProfileContext->getModule(), 'is_admin', array($iContextId)))
  551. return true;
  552. return false;
  553. }
  554. public function isAllowManage($mixedContent)
  555. {
  556. $CNF = &$this->_oConfig->CNF;
  557. $aContentInfo = !is_array($mixedContent) ? $this->_oDb->getContentInfoById((int)$mixedContent) : $mixedContent;
  558. if($this->checkAllowedEdit($aContentInfo) === CHECK_ACTION_RESULT_ALLOWED)
  559. return true;
  560. if($this->isAllowManageByContext(abs($aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']])))
  561. return true;
  562. if(($oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTION'])) !== false) {
  563. $iLoggedId = bx_get_logged_profile_id();
  564. $aProfileIds = $oConnection->getConnectedInitiators($aContentInfo[$CNF['FIELD_ID']]);
  565. if(!empty($aProfileIds) && is_array($aProfileIds) && in_array($iLoggedId, $aProfileIds))
  566. return true;
  567. }
  568. return false;
  569. }
  570. /**
  571. * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
  572. */
  573. public function checkAllowedManage ($aDataEntry, $isPerformAction = false)
  574. {
  575. return $this->isAllowManage($aDataEntry) ? CHECK_ACTION_RESULT_ALLOWED : _t('_sys_txt_access_denied');
  576. }
  577. public function isCompleted($iContentId)
  578. {
  579. $CNF = &$this->_oConfig->CNF;
  580. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  581. return (bool)$aContentInfo[$CNF['FIELD_COMPLETED']];
  582. }
  583. public function complete($iContentId, $iCompleted)
  584. {
  585. $CNF = &$this->_oConfig->CNF;
  586. $iCompleted = (int)$iCompleted;
  587. $this->_oDb->updateEntriesBy([$CNF['FIELD_COMPLETED'] => $iCompleted], [$CNF['FIELD_ID'] => (int)$iContentId]);
  588. $sModule = $this->getName();
  589. $sAction = !$iCompleted ? 'reopened' : 'completed';
  590. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  591. $iContentAuthor = (int)$aContentInfo[$CNF['FIELD_AUTHOR']];
  592. /**
  593. * @hooks
  594. * @hookdef hook-bx_tasks-completed 'bx_tasks', 'completed' - hook on task unassigned to profile
  595. * - $unit_name - equals `bx_tasks`
  596. * - $action - can be `completed` or `reopened`
  597. * - $object_id - task id
  598. * - $sender_id - not used
  599. * - $extra_params - array of additional params with the following array keys:
  600. * - `object_author_id` - [int] profile_id for task's author
  601. * - `privacy_view` - [string] privacy view value
  602. * @hook @ref hook-bx_tasks-completed
  603. */
  604. bx_alert($sModule, $sAction, $iContentId, false, array(
  605. 'object_author_id' => $iContentAuthor,
  606. 'privacy_view' => $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]
  607. ));
  608. if(($oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTION'])) !== false) {
  609. $aProfileIds = $oConnection->getConnectedContent($iContentId);
  610. if(!empty($aProfileIds) && is_array($aProfileIds))
  611. foreach($aProfileIds as $iProfileId) {
  612. if($iProfileId == $iContentAuthor)
  613. continue;
  614. bx_alert($sModule, $sAction, $iContentId, false, array(
  615. 'object_author_id' => $iProfileId,
  616. 'privacy_view' => $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]
  617. ));
  618. }
  619. }
  620. $this->logActivity($iContentId, ['key' => '_bx_tasks_txt_msg_' . ($iCompleted ? '' : 'un') . 'completed']);
  621. return true;
  622. }
  623. public function logActivity($iContentId, $aMessage)
  624. {
  625. $CNF = &$this->_oConfig->CNF;
  626. $oCmts = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], $iContentId);
  627. if(!$oCmts || !$oCmts->isEnabled())
  628. return false;
  629. if(($oAuthor = BxDolProfile::getInstance()) !== false)
  630. $aMessage['markers'] = array_merge($aMessage['markers'] ?? [], [
  631. 'author_link' => $oAuthor->getUrl(),
  632. 'author_name' => $oAuthor->getDisplayName(),
  633. ]);
  634. return $oCmts->addAuto($aMessage);
  635. }
  636. /**
  637. * Internal methods
  638. */
  639. protected function _onEditProperty($aContentInfo, $sProperty, &$oForm)
  640. {
  641. $CNF = &$this->_oConfig->CNF;
  642. $iContentId = (int)$aContentInfo[$CNF['FIELD_ID']];
  643. $mixedValue = $oForm->getCleanValue($CNF['FIELD_' . strtoupper($sProperty)]);
  644. if(($sMethod = 'get' . bx_gen_method_name($sProperty) . 'Title') && method_exists($this->_oConfig, $sMethod))
  645. $mixedValue = $this->_oConfig->$sMethod($mixedValue);
  646. $this->logActivity($iContentId, ['key' => '_bx_tasks_txt_msg_edit_' . $sProperty, 'markers' => ['value' => $mixedValue]]);
  647. }
  648. protected function _onEditState($aContentInfo, &$oForm)
  649. {
  650. $CNF = &$this->_oConfig->CNF;
  651. $iContentId = (int)$aContentInfo[$CNF['FIELD_ID']];
  652. $iState = $oForm->getCleanValue($CNF['FIELD_STATE']);
  653. $this->logActivity($iContentId, ['key' => '_bx_tasks_txt_msg_edit_state', 'markers' => ['value' => $this->_oConfig->getStateTitle($iState)]]);
  654. $iCompleted = (int)$this->_oConfig->isCompleted($iState);
  655. if($iCompleted != (int)$this->_oConfig->isCompleted($aContentInfo[$CNF['FIELD_STATE']]))
  656. $this->complete($iContentId, $iCompleted);
  657. }
  658. }
  659. /** @} */