BxTasksModule.php 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669
  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 actionApplyFilter($iContextId, $iFilterId)
  55. {
  56. $this->applyFilter($iContextId, $iFilterId);
  57. return echoJson([
  58. 'content' => $this->_oTemplate->getEntries($iContextId, ['filter' => $iFilterId]),
  59. 'eval' => $this->_oConfig->getJsObject('tasks') . '.onApplyFilter(oData)'
  60. ]);
  61. }
  62. public function actionCreateFilter($iContextId)
  63. {
  64. $CNF = &$this->_oConfig->CNF;
  65. $sJsObject = $this->_oConfig->getJsObject('tasks');
  66. $iAuthorId = bx_get_logged_profile_id();
  67. $oForm = $this->_getFilterForm($iContextId);
  68. if(!$oForm)
  69. return echoJson([]);
  70. $oForm->initChecker();
  71. if($oForm->isSubmittedAndValid()) {
  72. $aValsToAdd = [
  73. 'context_id' => $iContextId,
  74. 'author' => $iAuthorId,
  75. 'added' => time()
  76. ];
  77. $sTitle = '';
  78. $aValues = [];
  79. foreach($oForm->aInputs as $sName => $aInput) {
  80. if(in_array($sName, ['save', 'title', 'controls']))
  81. continue;
  82. if(($mixedValue = $oForm->getCleanValue($sName))) {
  83. $sFltTitle = '';
  84. if(($aFltValues = $aInput['values'] ?? false) && is_array($aFltValues))
  85. $sFltTitle = ' (' . (is_array($mixedValue) ? implode(', ', array_intersect_key($aFltValues, array_flip($mixedValue))) : $aFltValues[$mixedValue]) . ')';
  86. $sTitle .= $aInput['caption'] . $sFltTitle . ' + ';
  87. $aValues[] = [
  88. 'f' => $sName,
  89. 'v' => $mixedValue
  90. ];
  91. }
  92. }
  93. if($aValues && is_array($aValues) && ($aCnds = $this->_getFilterConditions($iContextId, $aValues)))
  94. $aValsToAdd['conditions'] = json_encode($aCnds);
  95. if($oForm->getCleanValue('save') == 'on') {
  96. $aValsToAdd = array_merge($aValsToAdd, [
  97. 'title' => $oForm->getCleanValue('title') ?: $sFltTitle,
  98. 'permanent' => 1
  99. ]);
  100. }
  101. else
  102. $aValsToAdd['title'] = trim($sTitle, " +");
  103. $aRes = [];
  104. if(($iId = (int)$oForm->insert($aValsToAdd)) != 0) {
  105. $this->applyFilter($iContextId, $iId);
  106. $aRes = ['reload' => 1];
  107. }
  108. else
  109. $aRes = ['msg' => _t('_bx_tasks_txt_err_cannot_perform_action')];
  110. return echoJson($aRes);
  111. }
  112. $sContent = BxTemplFunctions::getInstance()->popupBox($this->_oConfig->getHtmlIds('filter_popup'), _t('_bx_tasks_popup_f_title_add'), $this->_oTemplate->parseHtmlByName('popup_form.html', [
  113. 'form_id' => $oForm->getId(),
  114. 'form' => $oForm->getCode(true)
  115. ]));
  116. return echoJson(['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => false]]]);
  117. }
  118. /*
  119. * Moved from popup to page
  120. *
  121. public function actionProcessContextForm($iContextId)
  122. {
  123. if(!$this->isAllowManageByContext($iContextId))
  124. return;
  125. $CNF = &$this->_oConfig->CNF;
  126. $aContext = $this->_oDb->getContexts(['sample' => 'id', 'id' => $iContextId]);
  127. $bContext = !empty($aContext) && is_array($aContext);
  128. $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_CONTEXT'], $CNF['OBJECT_FORM_CONTEXT_DISPLAY_EDIT']);
  129. $oForm->setAction(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'process_context_form/' . $iContextId . '/');
  130. $oForm->initChecker($aContext);
  131. if($oForm->isSubmittedAndValid()) {
  132. if(!$bContext)
  133. $oForm->insert(['id' => $iContextId]);
  134. else
  135. $oForm->update($iContextId);
  136. echoJson([
  137. 'eval' => $this->_oConfig->getJsObject('tasks') . '.hidePopup(oData, ' . $iContextId . ')',
  138. ]);
  139. }
  140. else {
  141. $sContent = $this->_oTemplate->parseHtmlByName('popup_form.html', [
  142. 'form_id' => $oForm->getId(),
  143. 'form' => $oForm->getCode(true)
  144. ]);
  145. if($oForm->isSubmitted())
  146. return echoJson([
  147. 'form' => $sContent,
  148. 'form_id' => $oForm->getId()
  149. ]);
  150. echo $sContent;
  151. }
  152. }
  153. */
  154. public function actionProcessTaskListForm($iContextId, $iId)
  155. {
  156. if (!$this->isAllowAdd(abs($iContextId)))
  157. return;
  158. $CNF = &$this->_oConfig->CNF;
  159. $oForm = null;
  160. $sPopupTitle = "";
  161. $aContentInfo = array();
  162. if ($iId == 0){
  163. $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_LIST_ENTRY'], $CNF['OBJECT_FORM_LIST_ENTRY_DISPLAY_ADD']);
  164. $sPopupTitle = _t('_bx_tasks_form_list_entry_display_add');
  165. }
  166. else {
  167. $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_LIST_ENTRY'], $CNF['OBJECT_FORM_LIST_ENTRY_DISPLAY_EDIT']);
  168. $aContentInfo = $this->_oDb->getList($iId);
  169. $sPopupTitle = _t('_bx_tasks_form_list_entry_display_edit');
  170. }
  171. if(!$oForm)
  172. return '';
  173. $oForm->setAction(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'process_task_list_form/' . $iContextId . '/' . $iId . '/');
  174. $oForm->initChecker($aContentInfo, []);
  175. if($oForm->isSubmittedAndValid()) {
  176. if ($iId == 0){
  177. $aValsToAdd['context_id'] = $iContextId;
  178. $iId = $oForm->insert($aValsToAdd);
  179. }
  180. else {
  181. $iId = $oForm->update($iId);
  182. }
  183. return echoJson(array(
  184. 'eval' => $this->_oConfig->getJsObject('tasks') . '.reloadData(oData, ' . $iContextId . ')',
  185. ));
  186. }
  187. else {
  188. $sContent = $this->_oTemplate->parseHtmlByName('popup_form.html', array(
  189. 'form_id' => $oForm->getId(),
  190. 'form' => $oForm->getCode(true)
  191. ));
  192. if (!$oForm->isSubmitted()) {
  193. echo $sContent;
  194. return;
  195. }
  196. return echoJson(array('form' => $sContent, 'form_id' => $oForm->getId()));
  197. }
  198. }
  199. public function actionDeleteTaskList($iContextId, $iId)
  200. {
  201. if (!$this->isAllowManageByContext($iContextId))
  202. return;
  203. $CNF = &$this->_oConfig->CNF;
  204. $aTasks = $this->_oDb->getTasks($iContextId, $iId);
  205. $this->_oDb->deleteList($iId);
  206. if (!empty($aTasks) && ($oConn = BxDolConnection::getObjectInstance($this->_oConfig->CNF['OBJECT_CONNECTION']))) {
  207. foreach ($aTasks as &$aTask)
  208. $oConn->onDeleteContent($aTask[$CNF['FIELD_ID']]);
  209. }
  210. echoJson(array(
  211. 'context_id' => $iContextId,
  212. ));
  213. }
  214. public function actionProcessTaskForm($iContextId, $iListId)
  215. {
  216. if(!$this->isAllowAdd($iContextId))
  217. return echoJson([]);
  218. $CNF = &$this->_oConfig->CNF;
  219. $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ENTRY'], $CNF['OBJECT_FORM_ENTRY_DISPLAY_ADD']);
  220. if(!$oForm)
  221. return echoJson([]);
  222. $oForm->setAction(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'process_task_form/' . $iContextId . '/' . $iListId . '/');
  223. $oForm->setContextId($iContextId);
  224. $oForm->initChecker();
  225. if($oForm->isSubmittedAndValid()) {
  226. $iContentId = $oForm->insert([$CNF['FIELD_ALLOW_VIEW_TO'] => -$iContextId, $CNF['FIELD_TASKLIST'] => $iListId]);
  227. if($iContentId)
  228. $this->onPublished($iContentId);
  229. return echoJson([
  230. 'eval' => $this->_oConfig->getJsObject('tasks') . '.reloadData(oData, ' . $iContextId . ')',
  231. ]);
  232. }
  233. else {
  234. $sContent = $this->_oTemplate->parseHtmlByName('popup_form.html', [
  235. 'form_id' => $oForm->getId(),
  236. 'form' => $oForm->getCode(true)
  237. ]);
  238. if($oForm->isSubmitted())
  239. return echoJson(['form' => $sContent, 'form_id' => $oForm->getId()]);
  240. echo $sContent;
  241. }
  242. }
  243. public function actionProcessTaskFormEditProperty($iContentId, $sProperty)
  244. {
  245. $CNF = &$this->_oConfig->CNF;
  246. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  247. if(!$this->isAllowAdd(abs($aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']])))
  248. return '';
  249. $sForm = '';
  250. if(($sKey = 'OBJECT_FORM_ENTRY_DISPLAY_EDIT_' . strtoupper($sProperty)) && !empty($CNF[$sKey]))
  251. $sForm = $CNF[$sKey];
  252. else
  253. return '';
  254. $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ENTRY'], $sForm);
  255. $oForm->setId($sForm);
  256. $oForm->setName($sForm);
  257. $oForm->setAction(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'process_task_form_edit_property/' . $iContentId . '/' . $sProperty . '/');
  258. if(!$oForm)
  259. return '';
  260. $oForm->initChecker($aContentInfo);
  261. if($oForm->isSubmittedAndValid()) {
  262. if(!$oForm->update($iContentId))
  263. return echoJson(['msg' => _t('_bx_tasks_txt_err_cannot_perform_action')]);
  264. if(($sMethod = '_onEdit' . bx_gen_method_name($sProperty)) && method_exists($this, $sMethod))
  265. $this->$sMethod($aContentInfo, $oForm);
  266. else
  267. $this->_onEditProperty($aContentInfo, $sProperty, $oForm);
  268. return echoJson([
  269. 'eval' => $this->_oConfig->getJsObject('tasks') . '.reload(oData)',
  270. ]);
  271. }
  272. else {
  273. $sContent = $this->_oTemplate->parseHtmlByName('popup_form.html', [
  274. 'form_id' => $oForm->getId(),
  275. 'form' => $oForm->getCode(true)
  276. ]);
  277. if (!$oForm->isSubmitted()) {
  278. echo $sContent;
  279. return;
  280. }
  281. return echoJson(['form' => $sContent, 'form_id' => $oForm->getId()]);
  282. }
  283. }
  284. public function actionCalendarData()
  285. {
  286. // check permissions
  287. $aSQLPart = array();
  288. $iContextId = (int)bx_get('context_id');
  289. if(!$this->isAllowView($iContextId))
  290. return;
  291. $oPrivacy = BxDolPrivacy::getObjectInstance($this->_oConfig->CNF['OBJECT_PRIVACY_VIEW']);
  292. if($iContextId) {
  293. $aSQLPart = $oPrivacy ? $oPrivacy->getContentByGroupAsSQLPart(- $iContextId) : array();
  294. }
  295. // get entries
  296. $aEntries = $this->_oDb->getEntriesByDate(bx_get('start'), bx_get('end'), bx_get('event'), $aSQLPart);
  297. header('Content-Type: application/json; charset=utf-8');
  298. echo json_encode($aEntries);
  299. }
  300. public function actionProcessTimer($sAction, $iContentId, $iProfileId)
  301. {
  302. if(!$this->_iProfileId || $this->_iProfileId != $iProfileId)
  303. return echoJson(['msg' => _t('_sys_txt_access_denied')]);
  304. $aResult = $this->serviceProcessTimer($sAction, $iContentId, $iProfileId);
  305. if($aResult['code'] == 0)
  306. $aResult = array_merge($aResult, [
  307. 'content_id' => $iContentId,
  308. 'profile_id' => $iProfileId,
  309. 'content' => $this->_oTemplate->getTimer($iContentId, $iProfileId),
  310. 'eval' => $this->_oConfig->getJsObject('timer') . '.onPerformAction' . bx_gen_method_name($sAction) . '(oData)'
  311. ]);
  312. return echoJson($aResult);
  313. }
  314. public function serviceGetSafeServices()
  315. {
  316. return array_merge(parent::serviceGetSafeServices(), [
  317. 'ProcessTimer' => '',
  318. ]);
  319. }
  320. public function serviceProcessTimer($sAction, $iContentId, $iProfileId)
  321. {
  322. $CNF = &$this->_oConfig->CNF;
  323. $aResult = ['code' => 1, 'msg' => _t('_sys_txt_error_occured')];
  324. $iNow = time();
  325. switch($sAction) {
  326. case 'start':
  327. $this->stopTimerByAuthor($iProfileId);
  328. $iTimer = false;
  329. $aTimer = $this->getTimer($iContentId, $iProfileId);
  330. if($aTimer && is_array($aTimer)) {
  331. if($this->updateTimerById($aTimer['id'], ['started' => $iNow]))
  332. $iTimer = $aTimer['id'];
  333. }
  334. else
  335. $iTimer = $this->_oDb->insertTimer(['content_id' => $iContentId, 'profile_id' => $iProfileId, 'started' => $iNow]);
  336. if($iTimer !== false)
  337. $aResult = ['code' => 0, 'id' => $iTimer];
  338. break;
  339. case 'stop':
  340. if($this->stopTimerByAuthor($iProfileId))
  341. $aResult = ['code' => 0];
  342. break;
  343. case 'resume':
  344. $this->stopTimerByAuthor($iProfileId);
  345. $aTimer = $this->getTimer($iContentId, $iProfileId);
  346. if($aTimer && is_array($aTimer) && $this->updateTimerById($aTimer['id'], ['started' => $iNow]))
  347. $aResult = ['code' => 0];
  348. break;
  349. case 'reload':
  350. $aTimer = $this->getTimer($iContentId, $iProfileId);
  351. $aResult = [
  352. 'code' => 0,
  353. 'started' => $aTimer && ($aTimer['started'] ?? 0) != 0
  354. ];
  355. break;
  356. case 'log':
  357. $aTimer = $this->getTimer($iContentId, $iProfileId);
  358. if(!$aTimer || !is_array($aTimer) || !$aTimer['duration'])
  359. break;
  360. list($iH, $iM) = $this->_oConfig->timeI2A($aTimer['duration'], true);
  361. $iNow = time();
  362. $iTrackId = $this->_oDb->insertTimeTrack([
  363. 'object_id' => $iContentId,
  364. 'author_id' => $iProfileId,
  365. 'author_nip' => $iProfileId == $this->_iProfileId ? bx_get_ip_hash(getVisitorIP()) : 0,
  366. 'value' => $this->_oConfig->timeA2I([(int)$iH, (int)$iM + 1]),
  367. 'value_date' => $iNow,
  368. 'date' => $iNow
  369. ]);
  370. if(!$iTrackId)
  371. break;
  372. $oTime = BxDolReport::getObjectInstance($CNF['OBJECT_REPORTS_TIME'], $iContentId);
  373. if(!$oTime || !$oTime->isEnabled())
  374. break;
  375. if(!$oTime->putReport($iContentId, $iProfileId, $iTrackId))
  376. break;
  377. $this->_oDb->deleteTimer([
  378. 'content_id' => $iContentId,
  379. 'profile_id' => $iProfileId
  380. ]);
  381. $aResult = ['code' => 0];
  382. break;
  383. case 'clear':
  384. if($this->_oDb->deleteTimer(['content_id' => $iContentId, 'profile_id' => $iProfileId]) !== false)
  385. $aResult = ['code' => 0];
  386. break;
  387. }
  388. return $aResult;
  389. }
  390. public function serviceManageTools($sType = 'common')
  391. {
  392. $CNF = &$this->_oConfig->CNF;
  393. $mixedResults = '';
  394. if(!($mixedResults = parent::serviceManageTools($sType)))
  395. return $mixedResults;
  396. return array_merge(parent::serviceManageTools($sType), [
  397. 'menu' => BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_MANAGE_TOOLS_SUBMENU'])
  398. ]);
  399. }
  400. public function serviceGetBlockMenuBrowse()
  401. {
  402. return $this->_oTemplate->getBlockMenuBrowse();
  403. }
  404. public function serviceGetBlockMenuContext($iProfileId)
  405. {
  406. $CNF = &$this->_oConfig->CNF;
  407. if(!$this->isAllowView($iProfileId))
  408. return '';
  409. $oMenu = BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_SUBMENU_VIEW_CONTEXT']);
  410. if(!$oMenu)
  411. return '';
  412. $oMenu->addMarkers(['profile_id' => $iProfileId]);
  413. return $oMenu->getCode();
  414. }
  415. public function serviceGetBlockContextPreValues($iContextPid = 0)
  416. {
  417. $CNF = &$this->_oConfig->CNF;
  418. if(!$this->isAllowManageByContext($iContextPid))
  419. return $this->_bIsApi ? [] : '';
  420. $bContextPid = !empty($iContextPid);
  421. $sGrid = $CNF['OBJECT_GRID_PRE_VALUES'];
  422. $oGrid = BxDolGrid::getObjectInstance($sGrid);
  423. if(!$oGrid)
  424. return $this->_bIsApi ? [] : '';
  425. if($bContextPid)
  426. $oGrid->setContextPid($iContextPid);
  427. if($this->_bIsApi)
  428. return [
  429. bx_api_get_block('grid', $oGrid->getCodeAPI())
  430. ];
  431. $this->_oTemplate->addCss(['manage_tools.css']);
  432. $this->_oTemplate->addJs(['modules/base/text/js/|manage_tools.js', 'pre_values.js']);
  433. $this->_oTemplate->addJsTranslation(['_sys_grid_search']);
  434. $aResult = [
  435. 'content' => $this->_oTemplate->getJsCode('pre_values', [
  436. 'sObjNameGrid' => $sGrid,
  437. 'sPageUrl' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink($CNF['URL_CONTEXT_VALUES'], ['profile_id' => $iContextPid])
  438. ]) . $oGrid->getCode()
  439. ];
  440. return $aResult;
  441. }
  442. public function serviceGetBlockContextAuthorize($iContextPid = 0)
  443. {
  444. $sModule = 'bx_github';
  445. $sMethod = 'get_block_authorize';
  446. if(!bx_is_srv($sModule, $sMethod))
  447. return '';
  448. $aContext = $this->_oDb->getContexts(['sample' => 'id', 'id' => $iContextPid]);
  449. if(empty($aContext) || !is_array($aContext) || empty($aContext['gh_app_id']) || empty($aContext['gh_username']) || empty($aContext['gh_repository']))
  450. return '';
  451. return bx_srv($sModule, $sMethod, [$aContext['gh_app_id']]);
  452. }
  453. public function serviceGetBlockContextSettings($iContextPid = 0)
  454. {
  455. $CNF = &$this->_oConfig->CNF;
  456. $iContextAuthorPid = 0;
  457. if(!$this->isAllowManageByContext($iContextPid) || !($iContextAuthorPid = $this->getContextAuthorId($iContextPid)))
  458. return $this->_bIsApi ? [] : '';
  459. $aContext = $this->_oDb->getContexts(['sample' => 'id', 'id' => $iContextPid]);
  460. $bContext = !empty($aContext) && is_array($aContext);
  461. $sMessageText = '';
  462. $iMessageTimer = 0;
  463. $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_CONTEXT'], $CNF['OBJECT_FORM_CONTEXT_DISPLAY_EDIT']);
  464. $oForm->setProfileId($iContextAuthorPid);
  465. $oForm->initChecker($aContext);
  466. if($oForm->isSubmittedAndValid()) {
  467. if(!$bContext)
  468. $bResult = $oForm->insert(['id' => $iContextPid]);
  469. else
  470. $bResult = $oForm->update($iContextPid) !== false;
  471. $sMessageText = '_bx_tasks_txt' . (!$bResult ? '_err_cannot' : '_msg') . '_perform_action';
  472. $iMessageTimer = $bResult ? 3 : 0;
  473. }
  474. return $this->_bIsApi ? bx_api_get_block('form', $oForm->getCodeAPI(), [
  475. 'ext' => [
  476. 'name' => $oForm->getName(),
  477. 'request' => ['url' => '/api.php?r=' . $this->MODULE . '/get_block_context_settings&profile_id=' . $iContextPid, 'immutable' => true]
  478. ]
  479. ]) : (!empty($sMessageText) ? MsgBox(_t($sMessageText), $iMessageTimer) : '') . $oForm->getCode();
  480. }
  481. public function serviceGetBlockManageTime($sType = 'common', $iContextPid = 0)
  482. {
  483. $CNF = &$this->_oConfig->CNF;
  484. $bContextPid = !empty($iContextPid);
  485. $sGrid = $CNF['OBJECT_GRID_TIME_' . ($bContextPid ? 'CONTEXT_' : '') . strtoupper($sType)];
  486. $oGrid = BxDolGrid::getObjectInstance($sGrid);
  487. if(!$oGrid)
  488. return $this->_bIsApi ? [] : '';
  489. if($bContextPid)
  490. $oGrid->setContextPid($iContextPid);
  491. if($this->_bIsApi)
  492. return [
  493. bx_api_get_block('grid', $oGrid->getCodeAPI())
  494. ];
  495. list($aCssCalendar, $aJsCalendar) = BxBaseFormView::getCssJsCalendar();
  496. $this->_oTemplate->addCss(array_merge($aCssCalendar, ['manage_tools.css', 'time.css']));
  497. $this->_oTemplate->addJs(array_merge($aJsCalendar, ['modules/base/text/js/|manage_tools.js', 'time.js']));
  498. $this->_oTemplate->addJsTranslation(['_sys_grid_search']);
  499. $aResult = [
  500. 'content' => $this->_oTemplate->getJsCode('time', [
  501. 'sObjNameGrid' => $sGrid
  502. ]) . $oGrid->getCode()
  503. ];
  504. if(!$bContextPid)
  505. $aResult['menu'] = BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_MANAGE_TOOLS_SUBMENU']);
  506. return $aResult;
  507. }
  508. public function serviceGetBlockTimers()
  509. {
  510. return $this->_oTemplate->getBlockTimers($this->_iProfileId);
  511. }
  512. /**
  513. * Data for Timeline module
  514. */
  515. public function serviceGetTimelineData()
  516. {
  517. $sModule = $this->_aModule['name'];
  518. return array(
  519. 'handlers' => array(
  520. 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' => ''),
  521. 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' => ''),
  522. 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' => ''),
  523. array('group' => $sModule . '_object', 'type' => 'update', 'alert_unit' => $sModule, 'alert_action' => 'edited'),
  524. array('group' => $sModule . '_object', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'deleted'),
  525. ),
  526. 'alerts' => array(
  527. array('unit' => $sModule, 'action' => 'added'),
  528. array('unit' => $sModule, 'action' => 'completed'),
  529. array('unit' => $sModule, 'action' => 'reopened'),
  530. array('unit' => $sModule, 'action' => 'edited'),
  531. array('unit' => $sModule, 'action' => 'deleted'),
  532. )
  533. );
  534. }
  535. /**
  536. * Entry task for Timeline module
  537. */
  538. public function serviceGetTimelinePost($aEvent, $aBrowseParams = array())
  539. {
  540. $CNF = &$this->_oConfig->CNF;
  541. $aResult = parent::serviceGetTimelinePost($aEvent, $aBrowseParams);
  542. if(empty($aResult) || !is_array($aResult) || empty($aResult['date']))
  543. return $aResult;
  544. $aContentInfo = $this->_oDb->getContentInfoById($aEvent['object_id']);
  545. if($aContentInfo[$CNF['FIELD_PUBLISHED']] > $aResult['date'])
  546. $aResult['date'] = $aContentInfo[$CNF['FIELD_PUBLISHED']];
  547. return $aResult;
  548. }
  549. public function serviceGetTimelineCompleted($aEvent, $aBrowseParams = array())
  550. {
  551. $CNF = &$this->_oConfig->CNF;
  552. $aResult = parent::serviceGetTimelinePost($aEvent, $aBrowseParams);
  553. if(empty($aResult) || !is_array($aResult) || empty($aResult['date']))
  554. return $aResult;
  555. $aContentInfo = $this->_oDb->getContentInfoById($aEvent['object_id']);
  556. if($aContentInfo[$CNF['FIELD_PUBLISHED']] > $aResult['date'])
  557. $aResult['date'] = $aContentInfo[$CNF['FIELD_PUBLISHED']];
  558. $aResult['sample_action'] = $aResult['content']['sample_action'] = _t('_bx_tasks_txt_action_completed');
  559. return $aResult;
  560. }
  561. public function serviceGetTimelineReopened($aEvent, $aBrowseParams = array())
  562. {
  563. $CNF = &$this->_oConfig->CNF;
  564. $aResult = parent::serviceGetTimelinePost($aEvent, $aBrowseParams);
  565. if(empty($aResult) || !is_array($aResult) || empty($aResult['date']))
  566. return $aResult;
  567. $aContentInfo = $this->_oDb->getContentInfoById($aEvent['object_id']);
  568. if($aContentInfo[$CNF['FIELD_PUBLISHED']] > $aResult['date'])
  569. $aResult['date'] = $aContentInfo[$CNF['FIELD_PUBLISHED']];
  570. $aResult['sample_action'] = $aResult['content']['sample_action'] = _t('_bx_tasks_txt_action_reopened');
  571. return $aResult;
  572. }
  573. public function serviceGetNotificationsData()
  574. {
  575. $sModule = $this->_aModule['name'];
  576. $sEventPrivacy = $sModule . '_allow_view_event_to';
  577. if(BxDolPrivacy::getObjectInstance($sEventPrivacy) === false)
  578. $sEventPrivacy = '';
  579. $aResult = parent::serviceGetNotificationsData();
  580. $aResult['handlers'] = array_merge($aResult['handlers'], array(
  581. 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),
  582. 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),
  583. 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),
  584. 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),
  585. array('group' => $sModule . '_assign', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'unassigned'),
  586. ));
  587. $aResult['settings'] = array_merge($aResult['settings'], array(
  588. array('group' => 'content', 'unit' => $sModule, 'action' => 'completed', 'types' => array('personal', 'follow_member', 'follow_context')),
  589. array('group' => 'content', 'unit' => $sModule, 'action' => 'reopened', 'types' => array('personal', 'follow_member', 'follow_context')),
  590. array('group' => 'content', 'unit' => $sModule, 'action' => 'expired', 'types' => array('personal')),
  591. array('group' => 'content', 'unit' => $sModule, 'action' => 'assigned', 'types' => array('personal')),
  592. ));
  593. $aResult['alerts'] = array_merge($aResult['alerts'], array(
  594. array('unit' => $sModule, 'action' => 'completed'),
  595. array('unit' => $sModule, 'action' => 'reopened'),
  596. array('unit' => $sModule, 'action' => 'expired'),
  597. array('unit' => $sModule, 'action' => 'assigned'),
  598. array('unit' => $sModule, 'action' => 'unassigned'),
  599. ));
  600. return $aResult;
  601. }
  602. public function serviceGetNotificationsCompleted($aEvent)
  603. {
  604. return $this->_serviceGetNotificationsByAction($aEvent, 'completed');
  605. }
  606. public function serviceGetNotificationsReopened($aEvent)
  607. {
  608. return $this->_serviceGetNotificationsByAction($aEvent, 'reopened');
  609. }
  610. public function serviceGetNotificationsExpired($aEvent)
  611. {
  612. return $this->_serviceGetNotificationsByAction($aEvent, 'expired');
  613. }
  614. public function serviceGetNotificationsAssigned($aEvent)
  615. {
  616. return $this->_serviceGetNotificationsByAction($aEvent, 'assigned');
  617. }
  618. protected function _serviceGetNotificationsByAction($aEvent, $sAction)
  619. {
  620. $CNF = &$this->_oConfig->CNF;
  621. $aResult = parent::serviceGetNotificationsPost($aEvent);
  622. if(empty($aResult) || !is_array($aResult))
  623. return $aResult;
  624. $aResult['entry_author'] = $aEvent['object_owner_id'];
  625. $aResult['entry_author_name'] = '';
  626. if(($oAuthor = BxDolProfile::getInstance($aResult['entry_author'])) !== false)
  627. $aResult['entry_author_name'] = $oAuthor->getDisplayName();
  628. $sLangKey = '_bx_tasks_txt_notification_' . $sAction;
  629. if((int)$aEvent['object_privacy_view'] < 0)
  630. $sLangKey .= '_in_context';
  631. $aResult['lang_key'] = _t($sLangKey);
  632. return $aResult;
  633. }
  634. public function serviceCheckAllowedManageInContext($iContextPid)
  635. {
  636. if(!$this->isAllowManageByContext($iContextPid))
  637. return false;
  638. return true;
  639. }
  640. public function serviceCheckAllowedManage($iContentId)
  641. {
  642. if(!$this->isAllowManage($iContentId))
  643. return false;
  644. return true;
  645. }
  646. public function serviceCheckAllowedComplete($iContentId)
  647. {
  648. if(!$this->serviceCheckAllowedManage($iContentId))
  649. return false;
  650. return !$this->isCompleted($iContentId);
  651. }
  652. public function serviceCheckAllowedUncomplete($iContentId)
  653. {
  654. if(!$this->serviceCheckAllowedManage($iContentId))
  655. return false;
  656. return $this->isCompleted($iContentId);
  657. }
  658. public function serviceIsCompleted($iContentId)
  659. {
  660. return $this->isCompleted($iContentId);
  661. }
  662. public function serviceIsUncompleted($iContentId)
  663. {
  664. return !$this->isCompleted($iContentId);
  665. }
  666. public function serviceIsAllowBadges($iContentId)
  667. {
  668. if (!$this->isAllowManage($iContentId))
  669. return false;
  670. if (!$this->serviceIsBadgesAvaliable())
  671. return false;
  672. return true;
  673. }
  674. public function serviceEntityAssignments($iContentId = 0, $bAsArray = false)
  675. {
  676. if(!$iContentId)
  677. $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
  678. if(!$iContentId)
  679. return false;
  680. $CNF = &$this->_oConfig->CNF;
  681. $aProfiles = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTION'])->getConnectedInitiators($iContentId);
  682. if($bAsArray)
  683. return $aProfiles;
  684. return $this->_oTemplate->entryAssignments($aProfiles);
  685. }
  686. public function serviceEntityTimer($iContentId = 0)
  687. {
  688. if(!$iContentId)
  689. $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
  690. if(!$iContentId)
  691. return false;
  692. return $this->_oTemplate->entryTimer($iContentId, $this->_iProfileId);
  693. }
  694. public function serviceCheckAllowedCommentsTask($iContentId, $sObjectComments)
  695. {
  696. $CNF = &$this->_oConfig->CNF;
  697. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  698. if($aContentInfo[$CNF['FIELD_ALLOW_COMMENTS']] == 0)
  699. return false;
  700. return parent::serviceCheckAllowedCommentsTask($iContentId, $sObjectComments);
  701. }
  702. public function serviceCheckAllowedCommentsView($iContentId, $sObjectComments)
  703. {
  704. $CNF = &$this->_oConfig->CNF;
  705. //negative id used in comments for reports
  706. if($iContentId < 0)
  707. return CHECK_ACTION_RESULT_ALLOWED;
  708. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  709. if($aContentInfo[$CNF['FIELD_ALLOW_COMMENTS']] == 0)
  710. return false;
  711. return parent::serviceCheckAllowedCommentsView($iContentId, $sObjectComments);
  712. }
  713. /**
  714. * @page service Service Calls
  715. * @section bx_tasks Tasks
  716. * @subsection bx_tasks-page_blocks Page Blocks
  717. * @subsubsection bx_tasks-calendar calendar
  718. *
  719. * @code bx_srv('bx_tasks', 'calendar', [...]); @endcode
  720. *
  721. * Shows tasks calendar baced on die date
  722. *
  723. * @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.
  724. * @param $sTemplate template to use to show calendar, or leave empty for default template, possible options: calendar.html, calendar_compact.html
  725. * @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.
  726. *
  727. * @see BxTasksModule::serviceCalendar
  728. */
  729. /**
  730. * @ref bx_tasks-calendar "calendar"
  731. */
  732. public function serviceCalendar($aData = array(), $sTemplate = 'calendar.html')
  733. {
  734. if (!$this->isAllowView($aData['context_id']))
  735. return;
  736. $o = new BxTemplCalendar(array(
  737. 'eventSources' => array (
  738. bx_append_url_params(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'calendar_data', $aData),
  739. ),
  740. ), $this->_oTemplate);
  741. return $o->display($sTemplate);
  742. }
  743. public function serviceGetCalendarEntries($iProfileId)
  744. {
  745. $CNF = &$this->_oConfig->CNF;
  746. $oConn = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTION']);
  747. $aData = $oConn->getConnectedInitiators($iProfileId);
  748. $aData2 = array(0);
  749. foreach($aData as $iProfileId2) {
  750. $oProfile = BxDolProfile::getInstance($iProfileId2);
  751. array_push($aData2, $oProfile->getContentId());
  752. }
  753. $aSQLPart['where'] = " AND " . $CNF['TABLE_ENTRIES'] . ".`" . $CNF['FIELD_ID'] . "` IN(" . implode(',', $aData2) . ")";
  754. return $this->_oDb->getEntriesByDate(bx_get('start'), bx_get('end'), null, $aSQLPart);
  755. }
  756. public function serviceBrowseHome($aParams = [])
  757. {
  758. $sContent = '';
  759. if(($iContextPid = bx_process_input(bx_get('context_pid'), BX_DATA_INT))) {
  760. $sContent = $this->serviceBrowseTasks($iContextPid);
  761. if($sContent && ($oProfile = BxDolProfile::getInstance($iContextPid)) !== false)
  762. return [
  763. 'title' => bx_replace_markers(_t('_bx_tasks_page_block_title_entries_in_context'), [
  764. 'display_name' => $oProfile->getDisplayName(),
  765. 'profile_link' => $oProfile->getUrl()
  766. ]),
  767. 'content' => $sContent
  768. ];
  769. }
  770. else
  771. $sContent = $this->serviceBrowseTasksByProfile();
  772. return $sContent ?: MsgBox(_t('_Empty'));
  773. }
  774. public function serviceBrowseContext($iProfileId = 0, $aParams = [])
  775. {
  776. if(!$iProfileId)
  777. $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
  778. if(!$iProfileId)
  779. return '';
  780. return $this->serviceBrowseTasks ($iProfileId, $aParams);
  781. }
  782. public function serviceBrowseTasks($iContextId = 0, $aParams = [])
  783. {
  784. if(!$this->isAllowView($iContextId))
  785. return '';
  786. return $this->_oTemplate->getEntriesList($iContextId, $aParams);
  787. }
  788. public function serviceBrowseTasksByProfile($iProfileId = 0, $aParams = [])
  789. {
  790. if(!$iProfileId && $this->_iProfileId)
  791. $iProfileId = $this->_iProfileId;
  792. return $this->_oTemplate->getEntriesList(0, array_merge($aParams, [
  793. 'for_profile' => $iProfileId
  794. ]));
  795. }
  796. /**
  797. * Common methods
  798. */
  799. public function getModuleTitle($sName)
  800. {
  801. $sResult = $sName;
  802. if(($_sTitle = '_' . $sName) && ($sTitle = _t($_sTitle)) && strcmp($_sTitle, $sTitle) != 0)
  803. $sResult = $sTitle;
  804. else if(($aModule = $this->_oModule->_oDb->getModuleByName($sName)) && is_array($aModule))
  805. $sResult = $aModule['title'] ?? _t('_undefined');
  806. return $sResult;
  807. }
  808. public function getAssignees()
  809. {
  810. $aResults = [];
  811. if(($oProfile = BxDolProfile::getInstance()) !== false && ($aIds = $this->_oDb->getTimeTracks(['sample' => 'assignees'])))
  812. foreach($aIds as $iId)
  813. $aResults[] = ['key' => $iId, 'value' => $oProfile->getDisplayName($iId)];
  814. return $aResults;
  815. }
  816. public function getPreLists()
  817. {
  818. $CNF = &$this->_oConfig->CNF;
  819. $aResults = [];
  820. if(($aPreLists = $this->_oDb->getPreLists(['sample' => 'all'])) && is_array($aPreLists))
  821. foreach($aPreLists as $aPreList)
  822. $aResults[$aPreList['name']] = _t($aPreList['title']);
  823. return $aResults;
  824. }
  825. public function getContexts()
  826. {
  827. $aContexts = [];
  828. $aModules = bx_srv('system', 'get_modules_by_type', ['context', ['name_as_key' => true]]);
  829. foreach($aModules as $sModule => $aModule)
  830. $aContexts[$sModule] = ($_sTitle = '_' . $sModule) && ($sTitle = _t($_sTitle)) && strcmp($_sTitle, $sTitle) != 0 ? $sTitle : $aModule['title'];
  831. return $aContexts;
  832. }
  833. public function getContextAuthorId($iContextPid)
  834. {
  835. $iContextAuthorPid = 0;
  836. if(($oContext = BxDolProfile::getInstance($iContextPid)) !== false)
  837. $iContextAuthorPid = bx_srv($oContext->getModule(), 'get_author', [$oContext->getContentId()]);
  838. return $iContextAuthorPid;
  839. }
  840. public function getContextMembers($iContextPid)
  841. {
  842. $aMembers = [];
  843. if(($oContext = BxDolProfile::getInstance($iContextPid)) !== false) {
  844. $aPids = bx_srv($oContext->getModule(), 'fans', [$oContext->getContentId(), true]);
  845. foreach($aPids as $iPid)
  846. $aMembers[$iPid] = $oContext->getDisplayName($iPid);
  847. }
  848. return $aMembers;
  849. }
  850. public function getContextEntries($iContextPid)
  851. {
  852. $CNF = &$this->_oConfig->CNF;
  853. $aEntries = [];
  854. if(($aTasks = $this->_oDb->getTasks($iContextPid)) && is_array($aTasks))
  855. foreach($aTasks as $aTask)
  856. $aEntries[$aTask[$CNF['FIELD_ID']]] = $aTask[$CNF['FIELD_TITLE']];
  857. return $aEntries;
  858. }
  859. public function getTimer($iContentId, $iProfileId)
  860. {
  861. return $this->_oDb->getTimers(['sample' => 'content_profile_ids', 'content_id' => $iContentId, 'profile_id' => $iProfileId]);
  862. }
  863. public function getTimersByAuthor($iProfileId, $bActive = false)
  864. {
  865. return $this->_oDb->getTimers(['sample' => 'profile_id', 'profile_id' => $iProfileId, 'active' => $bActive]);
  866. }
  867. public function stopTimerByAuthor($iProfileId)
  868. {
  869. $aTimer = $this->getTimersByAuthor($iProfileId, true);
  870. if(!$aTimer || !is_array($aTimer))
  871. return false;
  872. return $this->updateTimerById($aTimer['id'], [
  873. 'started' => 0,
  874. 'duration' => $aTimer['duration'] + (time() - $aTimer['started']),
  875. ]);
  876. }
  877. public function updateTimerById($iId, $aSet)
  878. {
  879. return $this->_oDb->updateTimer($aSet, ['id' => (int)$iId]) !== false;
  880. }
  881. public function onPublished($iContentId)
  882. {
  883. parent::onPublished($iContentId);
  884. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  885. if(!$aContentInfo)
  886. return;
  887. $CNF = &$this->_oConfig->CNF;
  888. if(($iContextId = (int)$aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]) < 0) {
  889. $iContextId = abs($iContextId);
  890. $mixedRepo = $this->_oDb->getContextRepository($iContextId);
  891. if($mixedRepo !== false && ($sMl = 'bx_github') && ($sMd = 'create_issue') && bx_is_srv($sMl, $sMd)) {
  892. list($sGhUsername, $sGhRepository) = $mixedRepo;
  893. $aFldLoc2Repo = [
  894. $CNF['FIELD_STICKERS'] => 'labels',
  895. $CNF['FIELD_TYPE'] => 'type',
  896. ];
  897. $aGhFields = [];
  898. foreach($aFldLoc2Repo as $sLocField => $sRepoField)
  899. if(($sLocValue = $aContentInfo[$sLocField] ?? false))
  900. switch($sLocField) {
  901. case $CNF['FIELD_STICKERS']:
  902. $aStickers = $this->getStickers($sLocValue, $iContextId);
  903. if($aStickers && is_array($aStickers)) {
  904. $aGhFields[$sRepoField] = [];
  905. foreach($aStickers as $aSticker)
  906. $aGhFields[$sRepoField][] = $aSticker['title'];
  907. }
  908. break;
  909. case $CNF['FIELD_TYPE']:
  910. $aGhFields[$sRepoField] = $this->getType($sLocValue, $iContextId);
  911. break;
  912. default:
  913. $aGhFields[$sRepoField] = $sLocValue;
  914. }
  915. $aIssue = bx_srv($sMl, $sMd, [$sGhUsername, $sGhRepository, $aContentInfo[$CNF['FIELD_TITLE']], $aContentInfo[$CNF['FIELD_TEXT']], $aGhFields]);
  916. if($aIssue && is_array($aIssue) && ($iNumber = (int)($aIssue['number'] ?? 0)) != 0 && ($sUrl = $aIssue['html_url'] ?? '') != '') {
  917. $this->_oDb->updateEntriesBy([
  918. $CNF['FIELD_GH_ISSUE'] => $iNumber,
  919. $CNF['FIELD_GH_ISSUE_URL'] => $sUrl,
  920. ], [$CNF['FIELD_ID'] => $iContentId]);
  921. $this->logActivity($iContentId, ['key' => '_bx_tasks_txt_msg_synced', 'markers' => [
  922. 'ghi_link' => $sUrl,
  923. 'ghi_number' => $iNumber
  924. ]]);
  925. }
  926. }
  927. }
  928. }
  929. public function onExpired($iContentId)
  930. {
  931. $CNF = &$this->_oConfig->CNF;
  932. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  933. if(!$aContentInfo)
  934. return;
  935. $oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTION']);
  936. if($oConnection) {
  937. $aProfileIds = $oConnection->getConnectedContent($iContentId);
  938. if(!empty($aProfileIds) && is_array($aProfileIds))
  939. foreach($aProfileIds as $iProfileId){
  940. /**
  941. * @hooks
  942. * @hookdef hook-bx_tasks-expired 'bx_tasks', 'expired' - hook on task unassigned to profile
  943. * - $unit_name - equals `bx_tasks`
  944. * - $action - equals `expired`
  945. * - $object_id - task id
  946. * - $sender_id - not used
  947. * - $extra_params - array of additional params with the following array keys:
  948. * - `object_author_id` - [int] profile_id for task's author
  949. * - `privacy_view` - [string] privacy view value
  950. * @hook @ref hook-bx_tasks-expired
  951. */
  952. bx_alert($this->getName(), 'expired', $iContentId, false, array(
  953. 'object_author_id' => $iProfileId,
  954. 'privacy_view' => $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]
  955. ));
  956. }
  957. }
  958. }
  959. public function isAllowView($iContextId)
  960. {
  961. if(!($oContext = BxDolProfile::getInstance($iContextId)) || $oContext->checkAllowedProfileView($iContextId) !== CHECK_ACTION_RESULT_ALLOWED)
  962. return false;
  963. return true;
  964. }
  965. public function isAllowAdd($iContextId)
  966. {
  967. if(!($oContext = BxDolProfile::getInstance($iContextId)) || $oContext->checkAllowedPostInProfile($iContextId) !== CHECK_ACTION_RESULT_ALLOWED)
  968. return false;
  969. return true;
  970. }
  971. public function isAllowManageByContext($iContextId)
  972. {
  973. if(isAdmin())
  974. return true;
  975. $oProfileContext = BxDolProfile::getInstance($iContextId);
  976. if(BxDolService::call($oProfileContext->getModule(), 'is_admin', array($iContextId)))
  977. return true;
  978. return false;
  979. }
  980. public function isAllowManage($mixedContent)
  981. {
  982. $CNF = &$this->_oConfig->CNF;
  983. $aContentInfo = !is_array($mixedContent) ? $this->_oDb->getContentInfoById((int)$mixedContent) : $mixedContent;
  984. if($this->checkAllowedEdit($aContentInfo) === CHECK_ACTION_RESULT_ALLOWED)
  985. return true;
  986. if($this->isAllowManageByContext(abs($aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']])))
  987. return true;
  988. if(($oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTION'])) !== false) {
  989. $iLoggedId = bx_get_logged_profile_id();
  990. $aProfileIds = $oConnection->getConnectedInitiators($aContentInfo[$CNF['FIELD_ID']]);
  991. if(!empty($aProfileIds) && is_array($aProfileIds) && in_array($iLoggedId, $aProfileIds))
  992. return true;
  993. }
  994. return false;
  995. }
  996. /**
  997. * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
  998. */
  999. public function checkAllowedManage ($aDataEntry, $isPerformAction = false)
  1000. {
  1001. return $this->isAllowManage($aDataEntry) ? CHECK_ACTION_RESULT_ALLOWED : _t('_sys_txt_access_denied');
  1002. }
  1003. public function isCompleted($iContentId)
  1004. {
  1005. $CNF = &$this->_oConfig->CNF;
  1006. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  1007. return (bool)$aContentInfo[$CNF['FIELD_COMPLETED']];
  1008. }
  1009. public function complete($iContentId, $iCompleted)
  1010. {
  1011. $CNF = &$this->_oConfig->CNF;
  1012. $iCompleted = (int)$iCompleted;
  1013. $this->_oDb->updateEntriesBy([$CNF['FIELD_COMPLETED'] => $iCompleted], [$CNF['FIELD_ID'] => (int)$iContentId]);
  1014. $sModule = $this->getName();
  1015. $sAction = !$iCompleted ? 'reopened' : 'completed';
  1016. $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
  1017. $iContentAuthor = (int)$aContentInfo[$CNF['FIELD_AUTHOR']];
  1018. /**
  1019. * @hooks
  1020. * @hookdef hook-bx_tasks-completed 'bx_tasks', 'completed' - hook on task unassigned to profile
  1021. * - $unit_name - equals `bx_tasks`
  1022. * - $action - can be `completed` or `reopened`
  1023. * - $object_id - task id
  1024. * - $sender_id - not used
  1025. * - $extra_params - array of additional params with the following array keys:
  1026. * - `object_author_id` - [int] profile_id for task's author
  1027. * - `privacy_view` - [string] privacy view value
  1028. * @hook @ref hook-bx_tasks-completed
  1029. */
  1030. bx_alert($sModule, $sAction, $iContentId, false, array(
  1031. 'object_author_id' => $iContentAuthor,
  1032. 'privacy_view' => $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]
  1033. ));
  1034. if(($oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTION'])) !== false) {
  1035. $aProfileIds = $oConnection->getConnectedContent($iContentId);
  1036. if(!empty($aProfileIds) && is_array($aProfileIds))
  1037. foreach($aProfileIds as $iProfileId) {
  1038. if($iProfileId == $iContentAuthor)
  1039. continue;
  1040. bx_alert($sModule, $sAction, $iContentId, false, array(
  1041. 'object_author_id' => $iProfileId,
  1042. 'privacy_view' => $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]
  1043. ));
  1044. }
  1045. }
  1046. $this->logActivity($iContentId, ['key' => '_bx_tasks_txt_msg_' . ($iCompleted ? '' : 'un') . 'completed']);
  1047. if(($iContextId = (int)$aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]) < 0 && ($mixedRepository = $this->_oDb->getContextRepository(abs($iContextId))) !== false) {
  1048. $sModule = 'bx_github';
  1049. $sMethod = ($iCompleted ? 'close' : 'reopen') . '_issue';
  1050. if(bx_is_srv($sModule, $sMethod) && ($iGhIssue = (int)$aContentInfo[$CNF['FIELD_GH_ISSUE']]) != 0) {
  1051. list($sGhUsername, $sGhRepository) = $mixedRepository;
  1052. bx_srv($sModule, $sMethod, [$sGhUsername, $sGhRepository, $iGhIssue]);
  1053. }
  1054. }
  1055. return true;
  1056. }
  1057. public function logActivity($iContentId, $aMessage)
  1058. {
  1059. $CNF = &$this->_oConfig->CNF;
  1060. $oCmts = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], $iContentId);
  1061. if(!$oCmts || !$oCmts->isEnabled())
  1062. return false;
  1063. if(($oAuthor = BxDolProfile::getInstance()) !== false)
  1064. $aMessage['markers'] = array_merge($aMessage['markers'] ?? [], [
  1065. 'author_link' => $oAuthor->getUrl(),
  1066. 'author_name' => $oAuthor->getDisplayName(),
  1067. ]);
  1068. return $oCmts->addAuto($aMessage);
  1069. }
  1070. public function ghUpdateIssue($mixedContent, $aGhFields = [])
  1071. {
  1072. $aContentInfo = is_array($mixedContent) ? $mixedContent : $this->_oDb->getContentInfoById((int)$mixedContent);
  1073. if(!$aContentInfo || !is_array($aContentInfo))
  1074. return false;
  1075. $CNF = &$this->_oConfig->CNF;
  1076. $iContentId = (int)$aContentInfo[$CNF['FIELD_ID']];
  1077. $iContextId = (int)$aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']];
  1078. if($iContextId >= 0)
  1079. return false;
  1080. $mixedRepo = $this->_oDb->getContextRepository(abs($iContextId));
  1081. if($mixedRepo === false)
  1082. return false;
  1083. list($sGhUsername, $sGhRepository) = $mixedRepo;
  1084. $iGhIssue = (int)$aContentInfo[$CNF['FIELD_GH_ISSUE']];
  1085. $sMl = 'bx_github';
  1086. if($aGhFields && ($sMd = 'update_issue') && bx_is_srv($sMl, $sMd))
  1087. if(bx_srv($sMl, $sMd, [$sGhUsername, $sGhRepository, $iGhIssue, $aGhFields]) !== false)
  1088. $this->logActivity($iContentId, ['key' => '_bx_tasks_txt_msg_synced', 'markers' => [
  1089. 'ghi_link' => $aContentInfo[$CNF['FIELD_GH_ISSUE_URL']],
  1090. 'ghi_number' => $iGhIssue
  1091. ]]);
  1092. return true;
  1093. }
  1094. public function getStickers($mixedValues, $iContextId = 0)
  1095. {
  1096. $CNF = &$this->_oConfig->CNF;
  1097. $aValues = is_array($mixedValues) ? $mixedValues : BxDolFormCheckerHelper::displaySet($mixedValues);
  1098. $aResults = [];
  1099. if($iContextId) {
  1100. $aStickers = $this->_oDb->getPreValues([
  1101. 'sample' => 'context_list',
  1102. 'context_id' => $iContextId,
  1103. 'list' => 'sticker'
  1104. ]);
  1105. foreach($aValues as $sValue)
  1106. if(($aSticker = $aStickers[$sValue] ?? false))
  1107. $aResults[] = [
  1108. 'title' => $aSticker['title'],
  1109. 'color' => $aSticker['color']
  1110. ];
  1111. }
  1112. if(!$aResults) {
  1113. $aStickers = BxDolForm::getDataItems($CNF['OBJECT_PRE_LIST_STICKERS']);
  1114. foreach($aValues as $sValue)
  1115. $aResults[] = [
  1116. 'title' => $aStickers[$sValue],
  1117. 'color' => ''
  1118. ];
  1119. }
  1120. return $aResults;
  1121. }
  1122. public function getType($mixedValue, $iContextId = 0)
  1123. {
  1124. $sResult = '';
  1125. if($iContextId) {
  1126. $aType = $this->_oDb->getPreValues([
  1127. 'sample' => 'context_list_value',
  1128. 'context_id' => $iContextId,
  1129. 'list' => 'type',
  1130. 'value' => $mixedValue
  1131. ]);
  1132. if($aType && is_array($aType))
  1133. $sResult = $aType['title'];
  1134. }
  1135. if(!$sResult && ($sTypeTitle = $this->_oConfig->getTypeTitle($mixedValue)) != '')
  1136. $sResult = _t($sTypeTitle);
  1137. return $sResult;
  1138. }
  1139. public function applyFilter($iContextId, $iFilterId)
  1140. {
  1141. $sCookieKey = $this->_oConfig->CNF['COOKIE_SETTING_KEY'];
  1142. $aFilters = [];
  1143. if(isset($_COOKIE[$sCookieKey]))
  1144. $aFilters = json_decode($_COOKIE[$sCookieKey], true);
  1145. if(($iFilterId = (int)$iFilterId) != 0)
  1146. $aFilters[$iContextId] = $iFilterId;
  1147. else
  1148. unset($aFilters[$iContextId]);
  1149. bx_setcookie($sCookieKey, json_encode($aFilters), time() + 60 * 60 * 24 * 365);
  1150. }
  1151. /**
  1152. * Internal methods
  1153. */
  1154. protected function _onEditProperty($aContentInfo, $sProperty, &$oForm)
  1155. {
  1156. $CNF = &$this->_oConfig->CNF;
  1157. $aPropLoc2Repo = [
  1158. $CNF['FIELD_TYPE'] => 'type',
  1159. ];
  1160. $iContentId = (int)$aContentInfo[$CNF['FIELD_ID']];
  1161. $mixedValue = $oForm->getCleanValue($CNF['FIELD_' . strtoupper($sProperty)]);
  1162. if(($sMethod = 'get' . bx_gen_method_name($sProperty) . 'Title') && method_exists($this->_oConfig, $sMethod))
  1163. $mixedValue = $this->_oConfig->$sMethod($mixedValue);
  1164. $this->logActivity($iContentId, ['key' => '_bx_tasks_txt_msg_edit_' . $sProperty, 'markers' => ['value' => $mixedValue]]);
  1165. if(($sPropRepo = $aPropLoc2Repo[$sProperty] ?? false))
  1166. $this->ghUpdateIssue($aContentInfo, [
  1167. $sPropRepo => _t($mixedValue)
  1168. ]);
  1169. }
  1170. protected function _onEditState($aContentInfo, &$oForm)
  1171. {
  1172. $CNF = &$this->_oConfig->CNF;
  1173. $iContentId = (int)$aContentInfo[$CNF['FIELD_ID']];
  1174. $iState = $oForm->getCleanValue($CNF['FIELD_STATE']);
  1175. $this->logActivity($iContentId, ['key' => '_bx_tasks_txt_msg_edit_state', 'markers' => ['value' => $this->_oConfig->getStateTitle($iState)]]);
  1176. $iCompleted = (int)$this->_oConfig->isCompleted($iState);
  1177. if($iCompleted != (int)$this->_oConfig->isCompleted($aContentInfo[$CNF['FIELD_STATE']]))
  1178. $this->complete($iContentId, $iCompleted);
  1179. }
  1180. protected function _getFilterConditions($iContextId = 0, $aItems = [])
  1181. {
  1182. $iJoins = 0;
  1183. $aResult = [
  1184. 'join' => [],
  1185. 'where' => []
  1186. ];
  1187. if(count($aItems) > 1) {
  1188. $aResult['where'] = ['grp' => true, 'o' => 'AND', 'cnds' => []];
  1189. foreach($aItems as $aItem)
  1190. if(($mixedCnd = $this->_getFilterCondition($iContextId, $aItem)) !== false) {
  1191. if(isset($mixedCnd['join'])) {
  1192. $iJoins++;
  1193. $aResult['join'][] = $mixedCnd['join'];
  1194. }
  1195. if(isset($mixedCnd['where']))
  1196. $aResult['where']['cnds'][] = $mixedCnd['where'];
  1197. }
  1198. }
  1199. else {
  1200. $mixedCnd = $this->_getFilterCondition($iContextId, reset($aItems));
  1201. if(isset($mixedCnd['join'])) {
  1202. $iJoins++;
  1203. $aResult['join'][] = $mixedCnd['join'];
  1204. }
  1205. if(isset($mixedCnd['where']))
  1206. $aResult['where'] = $mixedCnd['where'];
  1207. }
  1208. if($iJoins == 1)
  1209. $aResult['join'] = reset($aResult['join']);
  1210. else if($iJoins > 1)
  1211. $aResult['join'] = ['grp' => true, 'cnds' => $aResult['join']];
  1212. return $aResult;
  1213. }
  1214. protected function _getFilterCondition($iContextId = 0, $aItem = [])
  1215. {
  1216. $sMethod = '_getFilterCondition' . bx_gen_method_name($aItem['f']);
  1217. if(method_exists($this, $sMethod))
  1218. return $this->$sMethod($iContextId, $aItem);
  1219. $mixedV = $mixedO = false;
  1220. if(!($bArray = is_array($aItem['v'])) || count($aItem['v']) == 1) {
  1221. $mixedV = $bArray ? reset($aItem['v']) : $aItem['v'];
  1222. $mixedO = '=';
  1223. }
  1224. else {
  1225. $mixedV = $aItem['v'];
  1226. $mixedO = 'IN';
  1227. }
  1228. if(!$mixedV || !$mixedO)
  1229. return false;
  1230. return [
  1231. 'where' => ['cnd' => true, 't' => 'te', 'f' => $aItem['f'], 'v' => $mixedV, 'o' => $mixedO]
  1232. ];
  1233. }
  1234. protected function _getFilterConditionInitialMembers ($iContextId = 0, $aItem = [])
  1235. {
  1236. $CNF = &$this->_oConfig->CNF;
  1237. return [
  1238. 'join' => ['cnd' => true, 'j' => 'LEFT', 'tj' => $CNF['TABLE_ASSIGNMENTS'], 'taj' => 'ta', 'fj' => 'content', 'tam' => 'te', 'fm' => 'id'],
  1239. 'where' => ['cnd' => true, 't' => 'ta', 'f' => 'initiator', 'v' => $aItem['v'], 'o' => '=']
  1240. ];
  1241. }
  1242. protected function _getFilterForm($iContextId = 0)
  1243. {
  1244. $CNF = &$this->_oConfig->CNF;
  1245. $sJsObject = $this->_oConfig->getJsObject('tasks');
  1246. $aFieldToList = [
  1247. $CNF['FIELD_TYPE'] => $CNF['OBJECT_PRE_LIST_TYPES'],
  1248. $CNF['FIELD_PRIORITY'] => $CNF['OBJECT_PRE_LIST_PRIORITIES'],
  1249. $CNF['FIELD_ESTIMATE'] => $CNF['OBJECT_PRE_LIST_ESTIMATES'],
  1250. $CNF['FIELD_STATE'] => $CNF['OBJECT_PRE_LIST_STATES']
  1251. ];
  1252. $aForm = [
  1253. 'form_attrs' => [
  1254. 'id' => 'bx-tasks-filter-add',
  1255. 'action' => BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'create_filter/' . $iContextId,
  1256. 'method' => BX_DOL_FORM_METHOD_DEFAULT
  1257. ],
  1258. 'params' => [
  1259. 'db' => [
  1260. 'table' => $CNF['TABLE_FILTERS'],
  1261. 'key' => 'id',
  1262. 'uri' => '',
  1263. 'uri_title' => '',
  1264. 'submit_name' => 'do_apply'
  1265. ],
  1266. ],
  1267. 'inputs' => [
  1268. $CNF['FIELD_AUTHOR'] => [
  1269. 'type' => 'radio_set',
  1270. ],
  1271. $CNF['FIELD_INITIAL_MEMBERS'] => [
  1272. 'type' => 'radio_set',
  1273. ],
  1274. $CNF['FIELD_TYPE'] => [
  1275. 'type' => 'checkbox_set',
  1276. ],
  1277. $CNF['FIELD_PRIORITY'] => [
  1278. 'type' => 'checkbox_set',
  1279. ],
  1280. $CNF['FIELD_ESTIMATE'] => [
  1281. 'type' => 'checkbox_set',
  1282. ],
  1283. $CNF['FIELD_STATE'] => [
  1284. 'type' => 'checkbox_set',
  1285. ],
  1286. 'save' => [
  1287. 'type' => 'switcher',
  1288. 'name' => 'save',
  1289. 'caption' => _t('_bx_tasks_form_f_input_save'),
  1290. 'value' => 'on',
  1291. 'attrs' => [
  1292. 'onchange' => $sJsObject . '.onChangeSave(this)'
  1293. ]
  1294. ],
  1295. 'title' => [
  1296. 'type' => 'text',
  1297. 'name' => 'title',
  1298. 'caption' => _t('_bx_tasks_form_f_input_title'),
  1299. 'value' => '',
  1300. 'required' => '0',
  1301. 'tr_attrs' => [
  1302. 'class' => 'bx-tasks-ffi-hidden'
  1303. ]
  1304. ],
  1305. 'controls' => [
  1306. 'name' => 'controls',
  1307. 'type' => 'input_set',
  1308. [
  1309. 'type' => 'submit',
  1310. 'name' => 'do_apply',
  1311. 'value' => _t('_bx_tasks_form_f_input_apply'),
  1312. ], [
  1313. 'type' => 'reset',
  1314. 'name' => 'do_cancel',
  1315. 'value' => _t('_bx_tasks_form_f_input_cancel'),
  1316. 'attrs' => [
  1317. 'onclick' => "$('.bx-popup-applied:visible').dolPopupHide()",
  1318. 'class' => 'bx-def-margin-sec-left',
  1319. ],
  1320. ]
  1321. ]
  1322. ]
  1323. ];
  1324. foreach($aForm['inputs'] as $sName => $aInput) {
  1325. if(isset($aInput['name']))
  1326. continue;
  1327. $aForm['inputs'][$sName] = array_merge($aForm['inputs'][$sName], [
  1328. 'name' => $sName,
  1329. 'caption' => _t('_bx_tasks_form_f_input_' . $sName),
  1330. 'value' => '',
  1331. 'values' => []
  1332. ]);
  1333. if(($sList = $aFieldToList[$sName] ?? false) && ($aList = BxDolForm::getDataItems($sList))) {
  1334. if(isset($aList['']))
  1335. unset($aList['']);
  1336. $aForm['inputs'][$sName]['values'] = $aList;
  1337. }
  1338. }
  1339. foreach([$CNF['FIELD_AUTHOR'], $CNF['FIELD_INITIAL_MEMBERS']] as $sK)
  1340. if(isset($aForm['inputs'][$sK])) {
  1341. $aForm['inputs'][$sK]['values'][$this->_iProfileId] = _t('_bx_tasks_txt_flt_user_current');
  1342. if($iContextId && ($oContext = BxDolProfile::getInstance($iContextId)) !== false) {
  1343. $aMembers = bx_srv($oContext->getModule(), 'fans', [$oContext->getContentId(), true]);
  1344. foreach($aMembers as $iMember)
  1345. if(($iMember != $this->_iProfileId) && ($oMember = BxDolProfile::getInstance($iMember)) !== false && !($oMember instanceof BxDolProfileUndefined))
  1346. $aForm['inputs'][$sK]['values'][$iMember] = $oMember->getDisplayName();
  1347. }
  1348. }
  1349. return new BxTemplFormView($aForm);
  1350. }
  1351. }
  1352. /** @} */