BxDolWiki.php 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup UnaCore UNA Core
  7. * @{
  8. */
  9. /**
  10. * WIKI object.
  11. *
  12. * It's possble to create different WIKI object which will different URLs, Menus and permissions.
  13. * For example it's possible to create
  14. * http://example.com/wiki/somepageshere and http://example.com/cocs/anotherpageshere
  15. *
  16. * @section wiki_create Creating the WIKI object:
  17. *
  18. *
  19. * Add record to 'sys_objects_wiki' table:
  20. *
  21. * - object: name of the WIKI object, this name will be user in URL as well,
  22. * for example, 'wiki' will have URLs like this: http://example.com/wiki/somepageshere
  23. * - title: title of the WIKI, for example, documentation, help, tutorial
  24. * - module: module name WIKI object belongs to
  25. * - allow_add_for_levels: allow to add pages and blocks for this member levels
  26. * - allow_edit_for_levels: allow to edit block for this member levels
  27. * - allow_delete_for_levels: allow to delet pages and blocks for this member levels
  28. * - allow_translate_for_levels: allow to add translations for this member levels
  29. * - override_class_name: user defined class name
  30. * - override_class_file: the location of the user defined class, leave it empty if class is located in system folders.
  31. *
  32. * Add record to 'sys_rewrite_rules' table:
  33. * - preg - regular expression which matches some URL
  34. * - service - service method to call if abbe regular expression matches
  35. * - active - active flag
  36. *
  37. * Add record to 'sys_permalinks' table:
  38. * - standard - how link should look like when permalinks are off
  39. * - permalink - how link should look like when permalinks are on,
  40. * some special server configuration may be required to make permalink to work,
  41. * such as 'mod_rewrite' and .htaccess file for Apache
  42. * - check - option name which enables/disables permalinks
  43. * - compare_by_prefix - compare by prefix
  44. */
  45. class BxDolWiki extends BxDolFactory implements iBxDolFactoryObject
  46. {
  47. protected $_sObject;
  48. protected $_aObject;
  49. protected $_sLangCateg = 'Wiki';
  50. /**
  51. * Constructor
  52. * @param $aObject array of WIKI options
  53. */
  54. protected function __construct($aObject)
  55. {
  56. parent::__construct();
  57. $this->_sObject = $aObject['object'];
  58. $this->_aObject = $aObject;
  59. $this->_oQuery = new BxDolWikiQuery($aObject);
  60. }
  61. /**
  62. * Get WIKI object instance by object URI
  63. * @param $sObject object name
  64. * @return object instance or false on error
  65. */
  66. static public function getObjectInstanceByUri($sUri, $oTemplate = false)
  67. {
  68. $aObject = BxDolWikiQuery::getWikiObjectByUri($sUri);
  69. if (!$aObject || !is_array($aObject))
  70. return false;
  71. return self::getObjectInstance($aObject['object'], $oTemplate);
  72. }
  73. /**
  74. * Get WIKI object instance by object name
  75. * @param $sObject object name
  76. * @return object instance or false on error
  77. */
  78. static public function getObjectInstance($sObject, $oTemplate = false)
  79. {
  80. if (isset($GLOBALS['bxDolClasses']['BxDolWiki!'.$sObject]))
  81. return $GLOBALS['bxDolClasses']['BxDolWiki!'.$sObject];
  82. $aObject = BxDolWikiQuery::getWikiObject($sObject);
  83. if (!$aObject || !is_array($aObject))
  84. $aObject = BxDolWikiQuery::getWikiObject('system');
  85. $sClass = empty($aObject['override_class_name']) ? 'BxDolWiki' : $aObject['override_class_name'];
  86. if (!empty($aObject['override_class_file']))
  87. require_once(BX_DIRECTORY_PATH_ROOT . $aObject['override_class_file']);
  88. $o = new $sClass($aObject, $oTemplate);
  89. return ($GLOBALS['bxDolClasses']['BxDolWiki!'.$sObject] = $o);
  90. }
  91. /**
  92. * Get object name
  93. */
  94. public function getObjectName ()
  95. {
  96. return $this->_sObject;
  97. }
  98. /**
  99. * Get wiki URi
  100. */
  101. public function getWikiUri ()
  102. {
  103. return $this->_aObject['uri'];
  104. }
  105. /**
  106. * Get WIKI block content
  107. * @param $iBlockId block ID
  108. * @param $sLang optional language name
  109. * @return block content
  110. */
  111. public function getBlockContent ($iBlockId, $sLang = false, $iRevision = false)
  112. {
  113. if (!$sLang)
  114. $sLang = bx_lang_name();
  115. $s = '';
  116. $sControls = '';
  117. $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang, $iRevision);
  118. $aWikiLatest = $this->_oQuery->getBlockContent ($iBlockId, $sLang);
  119. if ($aWikiVer) {
  120. require_once(BX_DIRECTORY_PATH_PLUGINS . "parsedown/Parsedown.php");
  121. $oParsedown = new Parsedown();
  122. $oParsedown->setSafeMode($aWikiVer['unsafe'] ? false : true);
  123. $s = $oParsedown->text($aWikiVer['content']);
  124. }
  125. if (!$aWikiVer && $aWikiLatest) {
  126. return _t('_sys_wiki_error_no_rev', $iRevision ? $iRevision : 0, $sLang);
  127. }
  128. if (!$aWikiVer && !$aWikiLatest && $this->isAllowed('edit')) {
  129. $s = _t('_sys_wiki_error_no_revs');
  130. }
  131. if ($aWikiVer || (!$aWikiVer && $this->isAllowed('edit'))) {
  132. $sControls = BxDolService::call('system', 'wiki_controls', array($this, $aWikiVer, $aWikiLatest, $iBlockId), 'TemplServiceWiki');
  133. }
  134. return $s . $sControls;
  135. }
  136. /**
  137. * Generate wiki contents - list of all wiki pages
  138. */
  139. public function getContents ($sAllExceptSpecified = '', $sOnlySpecified = '')
  140. {
  141. $aAllExceptSpecified = $sAllExceptSpecified ? explode(',', $sAllExceptSpecified) : array();
  142. $aOnlySpecified = $sOnlySpecified ? explode(',', $sOnlySpecified) : array();
  143. if (!($a = $this->_oQuery->getPages($aAllExceptSpecified, $aOnlySpecified)))
  144. return '';
  145. $aVars = array('bx_repeat:pages' => array());
  146. foreach ($a as $r) {
  147. $oPage = BxDolPage::getObjectInstance($r['object']);
  148. if (!$oPage->isVisiblePage())
  149. continue;
  150. $sUrl = $this->getPageUrl($r['uri']);
  151. $sTitle = _t($r['title']);
  152. $aVars['bx_repeat:pages'][] = array(
  153. 'url' => $sUrl,
  154. 'title' => $sTitle ? $sTitle : _t('_Empty'),
  155. );
  156. }
  157. usort($aVars['bx_repeat:pages'], function ($r1, $r2) {
  158. return strcmp($r1['title'], $r2['title']);
  159. });
  160. return BxDolTemplate::getInstance()->parseHtmlByName('wiki_contents.html', $aVars);
  161. }
  162. /**
  163. * Generate list of wiki blocks with missing translations for the given language
  164. */
  165. public function getMissingTranslations ($sLang = false)
  166. {
  167. if (!$sLang)
  168. $sLang = bx_lang_name();
  169. if (!$this->isAllowed('edit') && !$this->isAllowed('translate') || !preg_match("/^[a-z]+$/", $sLang))
  170. return _t('_sys_txt_access_denied');
  171. if (!BxDolLanguages::getInstance()->getLangId($sLang))
  172. return _t('_sys_wiki_error_no_such_lang');
  173. $a = $this->_oQuery->getBlocksWithMissingTranslations($sLang);
  174. if (!$a)
  175. return _t('_sys_wiki_no_missing_translations', $sLang);
  176. $aVars = array(
  177. 'title_title' => _t('_sys_wiki_title_title'),
  178. 'title_lang' => _t('_sys_wiki_title_lang_missing'),
  179. 'title_author' => _t('_sys_wiki_title_author', _t('_sys_wiki_orig')),
  180. 'title_content' => _t('_sys_wiki_title_content', _t('_sys_wiki_orig')),
  181. 'title_time' => _t('_sys_wiki_title_time', _t('_sys_wiki_orig')),
  182. 'bx_repeat:blocks' => array()
  183. );
  184. foreach ($a as $iBlockId) {
  185. $aWikiVerMain = $this->_oQuery->getBlockContent ($iBlockId, false);
  186. $aPage = $this->_oQuery->getPageByBlockId($iBlockId);
  187. $sUrl = $this->getPageUrl($aPage['uri']) . '#bx-page-wiki-container-' . $iBlockId;
  188. $oProfile = BxDolProfile::getInstanceMagic($aWikiVerMain['profile_id']);
  189. $aVars['bx_repeat:blocks'][] = array(
  190. 'author_url' => $oProfile->getUrl(),
  191. 'author_name' => $oProfile->getDisplayName(),
  192. 'url' => $sUrl,
  193. 'lang' => $sLang,
  194. 'title' => _t($aPage['title']),
  195. 'content' => strmaxtextlen($aWikiVerMain['content']),
  196. 'timejs' => bx_time_js($aWikiVerMain['added']),
  197. );
  198. }
  199. return BxDolTemplate::getInstance()->parseHtmlByName('wiki_translations_missing.html', $aVars);
  200. }
  201. /**
  202. * Generate list of wiki blocks with outdated translations for the given language
  203. */
  204. public function getOutdatedTranslations ($sLang = false)
  205. {
  206. if (!$sLang)
  207. $sLang = bx_lang_name();
  208. if (!$this->isAllowed('edit') && !$this->isAllowed('translate') || !preg_match("/^[a-z]+$/", $sLang))
  209. return _t('_sys_txt_access_denied');
  210. if (!BxDolLanguages::getInstance()->getLangId($sLang))
  211. return _t('_sys_wiki_error_no_such_lang');
  212. $aVars = array(
  213. 'title_title' => _t('_sys_wiki_title_title'),
  214. 'title_lang' => _t('_sys_wiki_title_lang_outated'),
  215. 'title_author' => _t('_sys_wiki_title_author', _t('_sys_wiki_orig')),
  216. 'title_content' => _t('_sys_wiki_title_content', _t('_sys_wiki_orig')),
  217. 'title_time_main' => _t('_sys_wiki_title_time', _t('_sys_wiki_orig')),
  218. 'title_time' => _t('_sys_wiki_title_time', '"'.$sLang.'"'),
  219. 'bx_repeat:blocks' => array()
  220. );
  221. $a = $this->_oQuery->getBlocksWithOutdatedTranslations($sLang);
  222. if (!$a)
  223. return _t('_sys_wiki_all_translations_up_to_date', $sLang);
  224. foreach ($a as $iBlockId) {
  225. $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang, false, false);
  226. $aWikiVerMain = $this->_oQuery->getBlockContent ($iBlockId, false);
  227. $aPage = $this->_oQuery->getPageByBlockId($iBlockId);
  228. $sUrl = $this->getPageUrl($aPage['uri']) . '#bx-page-wiki-container-' . $iBlockId;
  229. $oProfile = BxDolProfile::getInstanceMagic($aWikiVerMain['profile_id']);
  230. $aVars['bx_repeat:blocks'][] = array(
  231. 'author_url' => $oProfile->getUrl(),
  232. 'author_name' => $oProfile->getDisplayName(),
  233. 'url' => $sUrl,
  234. 'lang' => $sLang,
  235. 'title' => _t($aPage['title']),
  236. 'content' => strmaxtextlen($aWikiVerMain['content']),
  237. 'timejs_main' => bx_time_js($aWikiVerMain['added']),
  238. 'timejs' => bx_time_js($aWikiVer['added']),
  239. );
  240. }
  241. return BxDolTemplate::getInstance()->parseHtmlByName('wiki_translations_outdated.html', $aVars);
  242. }
  243. /**
  244. * Check if partucular action is allowed
  245. * @param $sType action type: add, edit, delete, translate
  246. * @param $sProfileId profile to check, if not provided then current profile is used
  247. * @return true if action is allowed, false otherwise
  248. */
  249. public function isAllowed ($sType, $iProfileId = false)
  250. {
  251. if ('translate' == $sType) {
  252. $aLangs = BxDolLanguages::getInstance()->getLanguages(false, true);
  253. if (count($aLangs) < 2)
  254. return false;
  255. }
  256. if (isAdmin())
  257. return true;
  258. $aTypes = array(
  259. 'add' => 'allow_add_for_levels',
  260. 'add-page' => 'allow_add_for_levels',
  261. 'edit' => 'allow_edit_for_levels',
  262. 'translate' => 'allow_translate_for_levels',
  263. 'delete-version' => 'allow_delete_for_levels',
  264. 'delete-block' => 'allow_delete_for_levels',
  265. 'get-traaslation' => 'allow_translate_for_levels',
  266. 'history' => isLogged(),
  267. 'unsafe' => 'allow_unsafe_for_levels',
  268. );
  269. if (!isset($aTypes[$sType]))
  270. return false;
  271. if (true === $aTypes[$sType] || false === $aTypes[$sType])
  272. return $aTypes[$sType];
  273. if (!isset($this->_aObject[$aTypes[$sType]]))
  274. return false;
  275. $oAcl = BxDolAcl::getInstance();
  276. return $oAcl->isMemberLevelInSet($this->_aObject[$aTypes[$sType]], $iProfileId);
  277. }
  278. public function actionGetTranslation ()
  279. {
  280. $aWikiVer = $this->_oQuery->getBlockContent ((int)bx_get('block_id'), bx_get('language'), false, false);
  281. if (!$aWikiVer)
  282. return array('code' => 1, 'actions' => 'ShowMsg', 'msg' => 'no translation was found');
  283. else
  284. return array('code' => 0, 'language' => $aWikiVer['language'], 'content' => $aWikiVer['content'], 'block_id' => $aWikiVer['block_id']);
  285. }
  286. public function actionDeleteVersion ()
  287. {
  288. $iBlockId = (int)bx_get('block_id');
  289. $sLang = bx_lang_name();
  290. $oLang = BxDolLanguages::getInstance();
  291. $aVars = $this->getVarsForHistory($iBlockId, $sLang);
  292. $aVars['select_all'] = _t('_Select_all');
  293. if (!$aVars['bx_repeat:revisions'])
  294. return BxDolTemplate::getInstance()->parseHtmlByName('wiki_msg.html', array(
  295. 'close' => _t('_sys_close'),
  296. 'msg' => _t('_sys_wiki_error_no_revs'),
  297. ));
  298. $aForm = array(
  299. 'form_attrs' => array(
  300. 'name' => 'bx-wiki-del-rev',
  301. 'method' => 'post',
  302. ),
  303. 'params' => array (
  304. 'db' => array(
  305. 'submit_name' => 'do_submit',
  306. ),
  307. ),
  308. 'inputs' => array(
  309. 'block_id' => array(
  310. 'type' => 'hidden',
  311. 'name' => 'block_id',
  312. 'value' => $iBlockId,
  313. ),
  314. 'language' => array(
  315. 'type' => 'hidden',
  316. 'name' => 'language',
  317. 'value' => $sLang,
  318. ),
  319. 'revision' => array(
  320. 'type' => 'custom',
  321. 'name' => 'revision',
  322. 'caption' => '',
  323. 'content' => BxDolTemplate::getInstance()->parseHtmlByName('wiki_delete_version.html', $aVars),
  324. ),
  325. 'buttons' => array(
  326. 'type' => 'input_set',
  327. array(
  328. 'type' => 'submit',
  329. 'name' => 'do_submit',
  330. 'value' => _t('_Submit'),
  331. ),
  332. array(
  333. 'type' => 'reset',
  334. 'name' => 'close',
  335. 'value' => _t('_sys_close'),
  336. 'attrs' => array(
  337. 'onclick' => "$('.bx-popup-applied:visible').dolPopupHide();",
  338. 'class' => "bx-def-margin-sec-left",
  339. ),
  340. ),
  341. ),
  342. ),
  343. );
  344. $oForm = new BxTemplFormView ($aForm);
  345. $oForm->initChecker();
  346. if ($oForm->isSubmittedAndValid ()) {
  347. $i = $this->_oQuery->deleteRevisions ($iBlockId, $sLang, bx_get('revision'));
  348. return array('code' => 0, 'actions' => array('Reload', 'ClosePopup', 'ShowMsg'), 'block_id' => $iBlockId, 'msg' => _t('_sys_wiki_revisions_deleted', $i));
  349. }
  350. else {
  351. return BxDolTemplate::getInstance()->parseHtmlByName('wiki_form.html', array(
  352. 'form' => $oForm->getCode(),
  353. 'block_id' => $iBlockId,
  354. 'wiki_action_uri' => $this->getWikiUri(),
  355. 'action' => 'delete-version',
  356. ));
  357. }
  358. }
  359. public function actionAddPage ()
  360. {
  361. // validate page URI
  362. $sPageUri = strtolower(bx_get('page'));
  363. if (!preg_match("/^[a-z0-9_-]+$/", $sPageUri))
  364. return _t('_sys_wiki_error_incorrect_page_uri', bx_process_output($sPageUri));
  365. // check if such page exist
  366. $oPage1 = BxDolPage::getObjectInstanceByUri($sPageUri);
  367. $oPage2 = BxDolPage::getObjectInstance($this->_aObject['module'] . str_replace('-', '_', $sPageUri));
  368. if ($oPage1 || $oPage2)
  369. return _t('_sys_wiki_error_page_exists', bx_process_output($sPageUri));
  370. // get lang category where translations will be added
  371. $oLang = BxDolStudioLanguagesUtils::getInstance();
  372. $iLangCat = $oLang->getLanguageCategory($this->_sLangCateg);
  373. if (!$iLangCat)
  374. return _t('_sys_wiki_error_occured', 9);
  375. // set default values for the form
  376. $aValues = array();
  377. $aLangs = $oLang->getLanguages(false, true);
  378. foreach ($aLangs as $sKey => $sLang)
  379. $aValues[$sKey] = ucfirst($sPageUri);
  380. // init form
  381. $aForm = array(
  382. 'form_attrs' => array(
  383. 'name' => 'bx-wiki-create-page',
  384. 'method' => 'post',
  385. ),
  386. 'params' => array (
  387. 'db' => array(
  388. 'submit_name' => 'do_submit',
  389. ),
  390. ),
  391. 'inputs' => array(
  392. 'page' => array(
  393. 'type' => 'hidden',
  394. 'name' => 'page',
  395. 'value' => $sPageUri,
  396. ),
  397. 'title' => array(
  398. 'type' => 'text_translatable',
  399. 'name' => 'title',
  400. 'caption' => _t('_adm_bp_txt_page_title'),
  401. 'info' => _t('_adm_bp_dsc_page_title'),
  402. 'value' => '',
  403. 'values' => $aValues,
  404. 'required' => '1',
  405. 'db' => array (
  406. 'pass' => 'Xss',
  407. ),
  408. 'checker' => array (
  409. 'func' => 'LengthTranslatable',
  410. 'params' => array(3,100, 'title'),
  411. 'error' => _t('_adm_bp_err_page_title'),
  412. ),
  413. ),
  414. 'buttons' => array(
  415. 'type' => 'input_set',
  416. array(
  417. 'type' => 'submit',
  418. 'name' => 'do_submit',
  419. 'value' => _t('_Submit'),
  420. ),
  421. array(
  422. 'type' => 'reset',
  423. 'name' => 'close',
  424. 'value' => _t('_sys_close'),
  425. 'attrs' => array(
  426. 'onclick' => "$('.bx-popup-applied:visible').dolPopupHide();",
  427. 'class' => "bx-def-margin-sec-left",
  428. ),
  429. ),
  430. ),
  431. ),
  432. );
  433. $oForm = new BxTemplStudioFormView ($aForm);
  434. $oForm->initChecker();
  435. if ($oForm->isSubmittedAndValid ()) {
  436. // insert page
  437. $sLangKey = '_' . $this->_aObject['module'] . '_' . str_replace('-', '_', $sPageUri) . '_' . time();
  438. $sUrl = $this->getPageUrl($sPageUri, false, false);
  439. $iPageId = $this->_oQuery->insertPage ($sPageUri, $sUrl, $sLangKey);
  440. if (!$iPageId)
  441. return array('code' => 10, 'actions' => array('ShowMsg'), 'msg' => _t('_sys_wiki_error_occured', 10));
  442. // insert translations
  443. $aLangs = $oLang->getLanguages(true, true);
  444. foreach ($aLangs as $iLangId => $sLangTitle) {
  445. $sLang = $oLang->getLangName($iLangId);
  446. if (!($sVal = $oForm->getCleanValue('title-' . $sLang)))
  447. continue;
  448. $oLang->addLanguageString($sLangKey, $sVal, $iLangId, $iLangCat);
  449. }
  450. return array('code' => 0, 'url' => BxDolPermalinks::getInstance()->permalink($sUrl));
  451. }
  452. else {
  453. // display form
  454. return BxDolTemplate::getInstance()->parseHtmlByName('wiki_create_page_form.html', array(
  455. 'form' => $oForm->getCode(),
  456. 'wiki_action_uri' => $this->getWikiUri(),
  457. 'action' => 'add-page',
  458. ));
  459. }
  460. }
  461. public function actionAdd ()
  462. {
  463. $iCellId = (int)bx_get('cell_id');
  464. $sPage = bx_get('page');
  465. $oPage = BxDolPage::getObjectInstance($sPage);
  466. if (!$oPage)
  467. return array('code' => 4, 'actions' => array('ShowMsg'), 'msg' => _t('_sys_wiki_error_occured', 4));
  468. if ($this->_aObject['module'] != $oPage->getModule())
  469. return array('code' => 5, 'actions' => array('ShowMsg'), 'msg' => _t('_sys_txt_access_denied'));
  470. $iDesignBox = getParam($this->_aObject['module'] . '_design_box');
  471. $aBlock = array(
  472. 'object' => $sPage,
  473. 'cell_id' => $iCellId,
  474. 'module' => $this->_aObject['module'],
  475. 'title_system' => '',
  476. 'title' => '',
  477. 'designbox_id' => false === $iDesignBox ? 0 : $iDesignBox,
  478. 'visible_for_levels' => 2147483647,
  479. 'type' => 'wiki',
  480. 'deletable' => 1,
  481. 'copyable' => 0,
  482. 'active' => 1,
  483. );
  484. $oQueryPageBuilder = new BxDolStudioBuilderPageQuery();
  485. if (!($iBlockId = $oQueryPageBuilder->insertBlock($aBlock)))
  486. return array('code' => 6, 'actions' => array('ShowMsg'), 'msg' => _t('_sys_wiki_error_occured', 6));
  487. return array('code' => 0, 'block_id' => $iBlockId, 'cell_id' => $iCellId);
  488. }
  489. public function actionDeleteBlock ()
  490. {
  491. $iBlockId = (int)bx_get('block_id');
  492. $oQueryPageBuilder = new BxDolStudioBuilderPageQuery();
  493. if (!$oQueryPageBuilder->deleteBlocks(array('type' => 'by_id', 'value' => $iBlockId)))
  494. return array('code' => 3, 'actions' => array('ShowMsg'), 'block_id' => $iBlockId, 'msg' => _t('_sys_wiki_error_occured', 3));
  495. $this->_oQuery->deleteAllRevisions($iBlockId);
  496. return array('code' => 0, 'actions' => array('DeleteBlock', 'ShowMsg'), 'block_id' => $iBlockId, 'msg' => _t('_sys_wiki_block_deleted'));
  497. }
  498. public function actionHistory ()
  499. {
  500. $iBlockId = (int)bx_get('block_id');
  501. $sLang = bx_lang_name();
  502. $oLang = BxDolLanguages::getInstance();
  503. $aVars = $this->getVarsForHistory($iBlockId, $sLang);
  504. $aVars['language'] = $oLang->getLangTitle($oLang->getLangId($sLang));
  505. $aVars['close'] = _t('_sys_close');
  506. $aVars['msg'] = $aVars['bx_repeat:revisions'] ? '' : _t('_sys_wiki_error_no_revs');
  507. return BxDolTemplate::getInstance()->parseHtmlByName('wiki_history.html', $aVars);
  508. }
  509. public function actionTranslate ()
  510. {
  511. return $this->actionEdit (true);
  512. }
  513. public function actionEdit ($bTranslate = false)
  514. {
  515. $iBlockId = (int)bx_get('block_id');
  516. $sMainLangLabel = '';
  517. $aWikiVerMain = array();
  518. $sLangForTranslate = '';
  519. $aLangsForInput = $this->getLangsForInput ($iBlockId, $bTranslate, $sMainLangLabel, $aWikiVerMain, $sLangForTranslate);
  520. // don't allow to translate empty blocks
  521. if (!$aWikiVerMain && $bTranslate)
  522. return BxDolTemplate::getInstance()->parseHtmlByName('wiki_msg.html', array(
  523. 'close' => _t('_sys_close'),
  524. 'msg' => _t('_sys_wiki_error_no_revs'),
  525. ));
  526. // get latest revision for block with current lang
  527. if ($bTranslate) {
  528. $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLangForTranslate, false, false);
  529. }
  530. else {
  531. $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, bx_lang_name());
  532. }
  533. unset($aWikiVer['notes']); // unset notes since we need this field empty in the form
  534. if (!$aWikiVer) { // check for new block, so initialize with default values
  535. $aWikiVer = array('block_id' => $iBlockId);
  536. if ($bTranslate)
  537. $aWikiVer['language'] = $sLangForTranslate;
  538. else
  539. $aWikiVer['language'] = bx_lang_name();
  540. }
  541. // init form object
  542. $oForm = BxDolForm::getObjectInstance('sys_wiki', $bTranslate ? 'sys_wiki_translate' : 'sys_wiki_edit');
  543. if (!$oForm)
  544. return _t('_sys_wiki_error_occured', 12);
  545. if (isset($oForm->aInputs['language']))
  546. $oForm->aInputs['language']['values'] = $aLangsForInput;
  547. if (isset($oForm->aInputs['content_main']) && $sMainLangLabel) {
  548. $oForm->aInputs['content_main']['caption'] = $sMainLangLabel;
  549. $oForm->aInputs['content_main']['content'] = $aWikiVerMain ? BxDolTemplate::getInstance()->parseHtmlByName('wiki_content.html', array('content' => $aWikiVerMain['content'])) : '';
  550. }
  551. $oForm->initChecker($aWikiVer);
  552. if (!$oForm->isSubmittedAndValid()) {
  553. // display form
  554. return BxDolTemplate::getInstance()->parseHtmlByName('wiki_form.html', array(
  555. 'form' => $oForm->getCode(),
  556. 'block_id' => $iBlockId,
  557. 'wiki_action_uri' => $this->getWikiUri(),
  558. 'action' => $bTranslate ? 'translate' : 'edit',
  559. ));
  560. }
  561. else {
  562. $sLang = $oForm->getCleanValue('language');
  563. // get previous revision with priority for current language
  564. $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang);
  565. $bMainLang = $this->getFieldMainLangFlag ($oForm, $sLang, $aWikiVer);
  566. $sRev = $this->getFieldRev ($oForm, $sLang, $aWikiVer);
  567. $bUnsafe = $this->getFieldUnsafeFlag ($oForm, $sLang, $aWikiVer);
  568. // insert new revision (main lang is NOT allowed for translations)
  569. $iTime = time();
  570. if ((!$bMainLang || ($bMainLang && $this->isAllowed('edit'))) && $this->isContentChanged($iBlockId, $sLang, $oForm->getCleanValue('content'))) {
  571. $sId = $oForm->insert(array(
  572. 'added' => $iTime,
  573. 'revision' => $sRev,
  574. 'main_lang' => $bMainLang,
  575. 'profile_id' => bx_get_logged_profile_id(),
  576. 'unsafe' => $bUnsafe,
  577. ));
  578. }
  579. // process translations if available
  580. if (($sTranslations = bx_get('translations')) && ($aTranslations = json_decode($sTranslations, true))) {
  581. foreach ($aTranslations as $sLang => $sContent) {
  582. if ($sLang == $oForm->getCleanValue('language'))
  583. continue;
  584. // get previous revision with priority for current language
  585. $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang);
  586. $bMainLang = $this->getFieldMainLangFlag ($oForm, $sLang, $aWikiVer);
  587. $sRev = $this->getFieldRev ($oForm, $sLang, $aWikiVer);
  588. $bUnsafe = $this->getFieldUnsafeFlag ($oForm, $sLang, $aWikiVer);
  589. // insert new revision (main lang is NOT allowed for translations)
  590. if ((!$bMainLang || ($bMainLang && $this->isAllowed('edit'))) && $this->isContentChanged($iBlockId, $sLang, $sContent)) {
  591. $sId = $oForm->insert(array(
  592. 'added' => $iTime,
  593. 'revision' => $sRev,
  594. 'main_lang' => $bMainLang,
  595. 'profile_id' => bx_get_logged_profile_id(),
  596. 'unsafe' => $bUnsafe,
  597. 'language' => $sLang,
  598. 'content' => $sContent,
  599. ));
  600. }
  601. }
  602. }
  603. // update indexing data
  604. $this->updateBlockIndexingData($iBlockId);
  605. return array('code' => 0, 'actions' => array('Reload', 'ClosePopup'), 'block_id' => $iBlockId);
  606. }
  607. }
  608. protected function updateBlockIndexingData($iBlockId)
  609. {
  610. if (!($aLangs = $this->_oQuery->getBlockLangs ($iBlockId)))
  611. return false;
  612. $sText = '';
  613. foreach ($aLangs as $sLang) {
  614. $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang, false, false);
  615. $sText .= trim(strip_tags($aWikiVer['content'])) . ' ';
  616. }
  617. return $this->_oQuery->updateBlockIndexingData ($iBlockId, $sText);
  618. }
  619. protected function getPageUrl ($sPageUri, $bPermalink = true, $bAddRootUrl = true)
  620. {
  621. $sUrl = ($bAddRootUrl ? BX_DOL_URL_ROOT : '') . 'r.php?_q=' . $this->_aObject['uri'] . '/' . $sPageUri;
  622. return $bPermalink ? BxDolPermalinks::getInstance()->permalink($sUrl) : $sUrl;
  623. }
  624. protected function isContentChanged ($iBlockId, $sLang, $sContent)
  625. {
  626. if (!$sContent) // don't allow revisions with empty content
  627. return false;
  628. $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang, false, false);
  629. if (!$aWikiVer) // when no previous revision available
  630. return true;
  631. return $sContent != $aWikiVer['content'];
  632. }
  633. protected function getFieldRev ($oForm, $sLang, $aWikiVer) {
  634. // increase revision for particular language or start with first revision
  635. return $aWikiVer && $sLang == $aWikiVer['language'] ? $aWikiVer['revision'] + 1 : 1;
  636. }
  637. protected function getFieldMainLangFlag ($oForm, $sLang, $aWikiVer) {
  638. // detect main language flag
  639. if ($aWikiVer && $sLang == $aWikiVer['language'])
  640. return $aWikiVer['main_lang']; // when revision is increased (language matches) - copy this flag from previous revision
  641. elseif (!$aWikiVer)
  642. return 1; // when it's first revision and no translations - start as main language
  643. else
  644. return 0;
  645. }
  646. protected function getFieldUnsafeFlag ($oForm, $sLang, $aWikiVer) {
  647. if ($aWikiVer && $sLang == $aWikiVer['language'] && !$aWikiVer['unsafe'])
  648. return 0; // copy 'unsafe' from previous revision only when unsafe = 0
  649. else
  650. return $this->isAllowed('unsafe') ? 1 : 0; // in other cases - check permissions
  651. }
  652. protected function getLangsForInput ($iBlockId, $bTranslateForm, &$sMainLangLabel, &$aWikiVerMain, &$sLangForTranslate)
  653. {
  654. // get main lang update time
  655. $aWikiVerMain = $this->_oQuery->getBlockContent ($iBlockId, 'neverhood');
  656. $iUpdatedMainLang = $aWikiVerMain ? $aWikiVerMain['added'] : 0;
  657. // generate values for radio set
  658. $aLangs = BxDolLanguages::getInstance()->getLanguages(false, true);
  659. foreach ($aLangs as $sKey => $sLang) {
  660. $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sKey, false, false);
  661. $sMainLang = $aWikiVer && $aWikiVer['main_lang'] ? '★' : '';
  662. $sComment = !$aWikiVer ? _t('_sys_wiki_lang_missing') : bx_time_js($aWikiVer['added']);
  663. if (!$aWikiVer || $iUpdatedMainLang > $aWikiVer['added'])
  664. $aLangs[$sKey] = _t('_sys_wiki_lang_mask_warn', $sLang, $sMainLang, $sComment);
  665. else
  666. $aLangs[$sKey] = _t('_sys_wiki_lang_mask', $sLang, $sMainLang, $sComment);
  667. if ($bTranslateForm && !$aWikiVer['main_lang'] && !$sLangForTranslate) {
  668. $sLangForTranslate = $sKey;
  669. }
  670. if ($bTranslateForm && $aWikiVer['main_lang']) {
  671. $sMainLangLabel = $aLangs[$sKey];
  672. unset($aLangs[$sKey]);
  673. continue;
  674. }
  675. }
  676. return $aLangs;
  677. }
  678. public function getVarsForHistory ($iBlockId, $sLang)
  679. {
  680. $a = $this->_oQuery->getBlockHistory($iBlockId, $sLang);
  681. $aVars = array(
  682. 'bx_repeat:revisions' => array()
  683. );
  684. foreach ($a as $r) {
  685. $oProfile = BxDolProfile::getInstanceMagic($r['profile_id']);
  686. list($sPageLink, $aPageParams) = bx_get_base_url_popup(array($r['block_id'].'rev' => $r['revision']));
  687. $r['author_url'] = $oProfile->getUrl();
  688. $r['author_name'] = $oProfile->getDisplayName();
  689. $r['timejs'] = bx_time_js($r['added']);
  690. $r['rev_url'] = BxDolPermalinks::getInstance()->permalink(bx_append_url_params($sPageLink, $aPageParams));
  691. $aVars['bx_repeat:revisions'][] = $r;
  692. }
  693. return $aVars;
  694. }
  695. }
  696. /** @} */