AntonLV 4 лет назад
Родитель
Сommit
a10489b435
100 измененных файлов с 19552 добавлено и 1 удалено
  1. 51 0
      modules/boonex/acl/updates/13.0.0_13.0.1/install/config.php
  2. 13 0
      modules/boonex/acl/updates/13.0.0_13.0.1/install/installer.php
  3. 144 0
      modules/boonex/acl/updates/13.0.0_13.0.1/source/classes/BxAclConfig.php
  4. 70 0
      modules/boonex/acl/updates/13.0.0_13.0.1/source/install/config.php
  5. 51 0
      modules/boonex/ads/updates/13.0.4_13.0.5/install/config.php
  6. 13 0
      modules/boonex/ads/updates/13.0.4_13.0.5/install/installer.php
  7. 333 0
      modules/boonex/ads/updates/13.0.4_13.0.5/source/classes/BxAdsConfig.php
  8. 300 0
      modules/boonex/ads/updates/13.0.4_13.0.5/source/classes/BxAdsGridCategories.php
  9. 2078 0
      modules/boonex/ads/updates/13.0.4_13.0.5/source/classes/BxAdsModule.php
  10. 151 0
      modules/boonex/ads/updates/13.0.4_13.0.5/source/install/config.php
  11. 51 0
      modules/boonex/albums/updates/13.0.2_13.0.3/install/config.php
  12. 13 0
      modules/boonex/albums/updates/13.0.2_13.0.3/install/installer.php
  13. 1041 0
      modules/boonex/albums/updates/13.0.2_13.0.3/source/classes/BxAlbumsModule.php
  14. 143 0
      modules/boonex/albums/updates/13.0.2_13.0.3/source/install/config.php
  15. 242 0
      modules/boonex/albums/updates/13.0.2_13.0.3/source/template/css/main.css
  16. 68 0
      modules/boonex/albums/updates/13.0.2_13.0.3/source/template/photoswipe.html
  17. 51 0
      modules/boonex/attendant/updates/13.0.2_13.0.3/install/config.php
  18. 13 0
      modules/boonex/attendant/updates/13.0.2_13.0.3/install/installer.php
  19. 256 0
      modules/boonex/attendant/updates/13.0.2_13.0.3/source/classes/BxAttendantModule.php
  20. 121 0
      modules/boonex/attendant/updates/13.0.2_13.0.3/source/classes/BxAttendantTemplate.php
  21. 77 0
      modules/boonex/attendant/updates/13.0.2_13.0.3/source/install/config.php
  22. 51 0
      modules/boonex/channels/updates/13.0.2_13.0.3/install/config.php
  23. 13 0
      modules/boonex/channels/updates/13.0.2_13.0.3/install/installer.php
  24. 4 0
      modules/boonex/channels/updates/13.0.2_13.0.3/install/langs/en.xml
  25. 13 0
      modules/boonex/channels/updates/13.0.2_13.0.3/install/sql/enable.sql
  26. 189 0
      modules/boonex/channels/updates/13.0.2_13.0.3/source/classes/BxCnlConfig.php
  27. 563 0
      modules/boonex/channels/updates/13.0.2_13.0.3/source/classes/BxCnlModule.php
  28. 153 0
      modules/boonex/channels/updates/13.0.2_13.0.3/source/install/config.php
  29. 250 0
      modules/boonex/channels/updates/13.0.2_13.0.3/source/install/langs/en.xml
  30. 428 0
      modules/boonex/channels/updates/13.0.2_13.0.3/source/install/sql/enable.sql
  31. 3 0
      modules/boonex/channels/updates/13.0.2_13.0.3/source/template/my_channels.html
  32. 51 0
      modules/boonex/convos/updates/13.0.2_13.0.3/install/config.php
  33. 13 0
      modules/boonex/convos/updates/13.0.2_13.0.3/install/installer.php
  34. 570 0
      modules/boonex/convos/updates/13.0.2_13.0.3/source/classes/BxCnvModule.php
  35. 262 0
      modules/boonex/convos/updates/13.0.2_13.0.3/source/classes/BxCnvTemplate.php
  36. 104 0
      modules/boonex/convos/updates/13.0.2_13.0.3/source/install/config.php
  37. 51 0
      modules/boonex/courses/updates/13.0.2_13.0.3/install/config.php
  38. 13 0
      modules/boonex/courses/updates/13.0.2_13.0.3/install/installer.php
  39. 4 0
      modules/boonex/courses/updates/13.0.2_13.0.3/install/langs/en.xml
  40. 7 0
      modules/boonex/courses/updates/13.0.2_13.0.3/install/sql/enable.sql
  41. 152 0
      modules/boonex/courses/updates/13.0.2_13.0.3/source/install/config.php
  42. 451 0
      modules/boonex/courses/updates/13.0.2_13.0.3/source/install/langs/en.xml
  43. 681 0
      modules/boonex/courses/updates/13.0.2_13.0.3/source/install/sql/enable.sql
  44. 16 0
      modules/boonex/courses/updates/13.0.2_13.0.3/source/js/invite_popup.js
  45. 51 0
      modules/boonex/developer/updates/13.0.2_13.0.3/install/config.php
  46. 13 0
      modules/boonex/developer/updates/13.0.2_13.0.3/install/installer.php
  47. 144 0
      modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevFormsDisplays.php
  48. 755 0
      modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevFormsField.php
  49. 190 0
      modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevFormsForms.php
  50. 166 0
      modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevFormsPreLists.php
  51. 125 0
      modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevFormsSearchForms.php
  52. 137 0
      modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevFunctions.php
  53. 175 0
      modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevNavigationMenus.php
  54. 113 0
      modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevNavigationSets.php
  55. 69 0
      modules/boonex/developer/updates/13.0.2_13.0.3/source/install/config.php
  56. 51 0
      modules/boonex/donations/updates/13.0.2_13.0.3/install/config.php
  57. 13 0
      modules/boonex/donations/updates/13.0.2_13.0.3/install/installer.php
  58. 6 0
      modules/boonex/donations/updates/13.0.2_13.0.3/install/sql/enable.sql
  59. 154 0
      modules/boonex/donations/updates/13.0.2_13.0.3/source/classes/BxDonationsConfig.php
  60. 71 0
      modules/boonex/donations/updates/13.0.2_13.0.3/source/install/config.php
  61. 114 0
      modules/boonex/donations/updates/13.0.2_13.0.3/source/install/sql/enable.sql
  62. 51 0
      modules/boonex/events/updates/13.0.4_13.0.5/install/config.php
  63. 13 0
      modules/boonex/events/updates/13.0.4_13.0.5/install/installer.php
  64. 10 0
      modules/boonex/events/updates/13.0.4_13.0.5/install/langs/en.xml
  65. 15 0
      modules/boonex/events/updates/13.0.4_13.0.5/install/sql/enable.sql
  66. 302 0
      modules/boonex/events/updates/13.0.4_13.0.5/source/classes/BxEventsConfig.php
  67. 190 0
      modules/boonex/events/updates/13.0.4_13.0.5/source/classes/BxEventsDb.php
  68. 345 0
      modules/boonex/events/updates/13.0.4_13.0.5/source/classes/BxEventsFormEntry.php
  69. 572 0
      modules/boonex/events/updates/13.0.4_13.0.5/source/classes/BxEventsModule.php
  70. 152 0
      modules/boonex/events/updates/13.0.4_13.0.5/source/install/config.php
  71. 591 0
      modules/boonex/events/updates/13.0.4_13.0.5/source/install/langs/en.xml
  72. 734 0
      modules/boonex/events/updates/13.0.4_13.0.5/source/install/sql/enable.sql
  73. 16 0
      modules/boonex/events/updates/13.0.4_13.0.5/source/js/invite_popup.js
  74. 3 1
      modules/boonex/files/template/unit_live_search.html
  75. 51 0
      modules/boonex/files/updates/13.0.4_13.0.5/install/config.php
  76. 13 0
      modules/boonex/files/updates/13.0.4_13.0.5/install/installer.php
  77. 609 0
      modules/boonex/files/updates/13.0.4_13.0.5/source/classes/BxFilesModule.php
  78. 135 0
      modules/boonex/files/updates/13.0.4_13.0.5/source/install/config.php
  79. 16 0
      modules/boonex/files/updates/13.0.4_13.0.5/source/template/unit_live_search.html
  80. 51 0
      modules/boonex/forum/updates/13.0.5_13.0.6/install/config.php
  81. 13 0
      modules/boonex/forum/updates/13.0.5_13.0.6/install/installer.php
  82. 23 0
      modules/boonex/forum/updates/13.0.5_13.0.6/install/langs/en.xml
  83. 34 0
      modules/boonex/forum/updates/13.0.5_13.0.6/install/sql/enable.sql
  84. 703 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/classes/BxForumGrid.php
  85. 1059 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/classes/BxForumModule.php
  86. 223 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/classes/BxForumSearchResult.php
  87. 266 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/classes/BxForumTemplate.php
  88. 149 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/install/config.php
  89. 451 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/install/langs/en.xml
  90. 628 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/install/sql/enable.sql
  91. 54 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/js/carusel.js
  92. 12 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/template/comment_attachments.html
  93. 115 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/template/css/carusel.css
  94. 3 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/template/entry-preview-private.html
  95. 27 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/template/unaca.html
  96. 30 0
      modules/boonex/forum/updates/13.0.5_13.0.6/source/template/unit_gallery.html
  97. 51 0
      modules/boonex/groups/updates/13.0.3_13.0.4/install/config.php
  98. 13 0
      modules/boonex/groups/updates/13.0.3_13.0.4/install/installer.php
  99. 8 0
      modules/boonex/groups/updates/13.0.3_13.0.4/install/sql/enable.sql
  100. 152 0
      modules/boonex/groups/updates/13.0.3_13.0.4/source/install/config.php

+ 51 - 0
modules/boonex/acl/updates/13.0.0_13.0.1/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Paid Levels',
+    'version_from' => '13.0.0',
+    'version_to' => '13.0.1',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/acl/updates/update_13.0.0_13.0.1/',
+    'home_uri' => 'acl_update_1300_1301',
+
+    'module_dir' => 'boonex/acl/',
+    'module_uri' => 'acl',
+
+    'db_prefix' => 'bx_acl_',
+    'class_prefix' => 'BxAcl',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Paid Levels',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/acl/updates/13.0.0_13.0.1/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxAclUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 144 - 0
modules/boonex/acl/updates/13.0.0_13.0.1/source/classes/BxAclConfig.php

@@ -0,0 +1,144 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    PaidLevels Paid Levels
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxAclConfig extends BxBaseModGeneralConfig
+{
+    protected $_oDb;
+    protected $_aHtmlIds;
+    protected $_aCurrency;
+    protected $_iOwner;
+
+    protected $_iExpireNotificationDays;
+    protected $_bExpireNotifyOnce;
+    protected $_iRemoveExpiredFor;
+
+    /**
+     * Constructor
+     */
+    public function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->CNF = array (
+            // database tables
+            'TABLE_PRICES' => $aModule['db_prefix'] . 'level_prices',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_LEVEL_ID' => 'level_id',
+            'FIELD_NAME' => 'name',
+
+            // page URIs
+            'URL_ADMINISTRATION' => 'page.php?i=acl-administration',
+            'URL_VIEW' => 'page.php?i=acl-view',
+
+            // some params
+            'PARAM_RECURRING_RESERVE' => 'bx_acl_recurring_reserve',
+            'PARAM_RECURRING_PRIORITIZE' => 'bx_acl_recurring_prioritize',
+
+            // objects 
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_acl_administration',
+            'OBJECT_GRID_VIEW' => 'bx_acl_view',
+            'OBJECT_FORM_PRICE' => 'bx_acl_price',
+            'OBJECT_FORM_PRICE_DISPLAY_ADD' => 'bx_acl_price_add',
+            'OBJECT_FORM_PRICE_DISPLAY_EDIT' => 'bx_acl_price_edit',
+            'OBJECT_FORM_PRELISTS_PERIOD_UNITS' => 'bx_acl_period_units',
+        );
+
+        $this->_aGridObjects = array(
+            'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION'],
+            'view' => $this->CNF['OBJECT_GRID_VIEW'],
+        );
+
+        $this->_aPrefixes = array(
+            'style' => 'bx-acl',
+            'option' => 'bx_acl_',
+        );
+
+        $this->_aJsClasses = array(
+            'main' => 'BxAclMain',
+            'form' => 'BxAclForm',
+            'administration' => 'BxAclAdministration',
+        );
+        $this->_aJsObjects = array(
+            'main' => 'oAclMain',
+            'form' => 'oAclForm',
+            'administration' => 'oAclAdministration',
+        );
+
+        $sHtmlPrefix = str_replace('_', '-', $this->_sName);
+        $this->_aHtmlIds = array(
+            'popup_price' => $sHtmlPrefix . '-popup-price'
+        );
+
+        $oPayments = BxDolPayments::getInstance();
+        $this->_iOwner = (int)$oPayments->getOption('site_admin');
+        $this->_aCurrency = array(
+            'code' => $oPayments->getOption('default_currency_code'),
+            'sign' => $oPayments->getOption('default_currency_sign')
+        );
+
+        $this->_bExpireNotifyOnce = true;
+        $this->_iExpireNotificationDays = 1;
+        $this->_iRemoveExpiredFor = 30;
+    }
+
+    public function init(&$oDb)
+    {
+        $this->_oDb = &$oDb;
+
+        $sOptionPrefix = $this->getPrefix('option');
+
+        $this->_iExpireNotificationDays = (int)getParam($sOptionPrefix . 'expire_notification_days');
+        $this->_bExpireNotifyOnce = getParam($sOptionPrefix . 'expire_notify_once') == 'on';
+        $this->_iRemoveExpiredFor = (int)getParam($sOptionPrefix . 'remove_expired_for');
+    }
+
+    public function getExpireNotificationDays()
+    {
+        return $this->_iExpireNotificationDays;
+    }
+
+    public function isExpireNotifyOnce()
+    {
+        return $this->_bExpireNotifyOnce;
+    }
+
+    public function getRemoveExpiredFor()
+    {
+        return $this->_iRemoveExpiredFor;
+    }
+
+    public function getHtmlIds($sKey = '')
+    {
+        if(empty($sKey))
+            return $this->_aHtmlIds;
+
+        return isset($this->_aHtmlIds[$sKey]) ? $this->_aHtmlIds[$sKey] : '';
+    }
+
+    public function getOwner()
+    {
+    	return $this->_iOwner;
+    }
+
+    public function getCurrency()
+    {
+    	return $this->_aCurrency;
+    }
+
+    public function getPriceName($sName)
+    {
+        return uriGenerate($sName, $this->CNF['TABLE_PRICES'], $this->CNF['FIELD_NAME'], ['lowercase' => false]);
+    }
+}
+
+/** @} */

+ 70 - 0
modules/boonex/acl/updates/13.0.0_13.0.1/source/install/config.php

@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    PaidLevels Paid Levels
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_acl',
+    'title' => 'Paid Levels',
+    'note' => 'Paid Levels module.',
+    'version' => '13.0.1',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/acl/',
+    'home_uri' => 'acl',
+
+    'db_prefix' => 'bx_acl_',
+    'class_prefix' => 'BxAcl',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Paid Levels',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 51 - 0
modules/boonex/ads/updates/13.0.4_13.0.5/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Ads',
+    'version_from' => '13.0.4',
+    'version_to' => '13.0.5',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/ads/updates/update_13.0.4_13.0.5/',
+    'home_uri' => 'ads_update_1304_1305',
+
+    'module_dir' => 'boonex/ads/',
+    'module_uri' => 'ads',
+
+    'db_prefix' => 'bx_ads_',
+    'class_prefix' => 'BxAds',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Ads',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/ads/updates/13.0.4_13.0.5/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxAdsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 333 - 0
modules/boonex/ads/updates/13.0.4_13.0.5/source/classes/BxAdsConfig.php

@@ -0,0 +1,333 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Ads Ads
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+bx_import('BxDolInformer');
+
+class BxAdsConfig extends BxBaseModTextConfig
+{
+    protected $_oDb;
+
+    protected $_aCurrency;
+
+    protected $_bAuction;
+
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $aMenuItems2Methods = array (
+            'approve' => 'checkAllowedApprove',
+            'edit-ad' => 'checkAllowedEdit',
+            'delete-ad' => 'checkAllowedDelete',
+        );
+
+        $this->CNF = array_merge($this->CNF, array (
+
+            // module icon
+            'ICON' => 'ad col-green2',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'entries',
+            'TABLE_ENTRIES_FULLTEXT' => 'title_text',
+            'TABLE_CATEGORIES' => $aModule['db_prefix'] . 'categories',
+            'TABLE_CATEGORIES_TYPES' => $aModule['db_prefix'] . 'categories_types',
+            'TABLE_INTERESTED_TRACK' => $aModule['db_prefix'] . 'interested_track',
+            'TABLE_LICENSES' => $aModule['db_prefix'] . 'licenses',
+            'TABLE_LICENSES_DELETED' => $aModule['db_prefix'] . 'licenses_deleted',
+            'TABLE_OFFERS' => $aModule['db_prefix'] . 'offers',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => 'author',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => 'changed',
+            'FIELD_SOLD' => 'sold',
+            'FIELD_SHIPPED' => 'shipped',
+            'FIELD_RECEIVED' => 'received',
+            'FIELD_TITLE' => 'title',
+            'FIELD_NAME' => 'name',
+            'FIELD_TEXT' => 'text',
+            'FIELD_TEXT_ID' => 'ad-text',
+            'FIELD_CATEGORY' => 'category',
+            'FIELD_CATEGORY_VIEW' => 'category_view',
+            'FIELD_CATEGORY_SELECT' => 'category_select',
+            'FIELD_PRICE' => 'price',
+            'FIELD_PRICE_SINGLE' => 'price',
+            'FIELD_AUCTION' => 'auction',
+            'FIELD_QUANTITY' => 'quantity',
+            'FIELD_YEAR' => 'year',
+            'FIELD_NOTES_PURCHASED' => 'notes_purchased',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_CF' => 'cf',
+            'FIELD_COVER' => 'covers',
+            'FIELD_PHOTO' => 'pictures',
+            'FIELD_VIDEO' => 'videos',
+            'FIELD_FILE' => 'files',
+            'FIELD_POLL' => 'polls',
+            'FIELD_THUMB' => 'thumb',
+            'FIELD_ATTACHMENTS' => 'attachments',
+            'FIELD_VIEWS' => 'views',
+            'FIELD_COMMENTS' => 'comments',
+            'FIELD_STATUS' => 'status',
+            'FIELD_STATUS_ADMIN' => 'status_admin',
+            'FIELD_LOCATION' => 'location',
+            'FIELD_LOCATION_PREFIX' => 'location',
+            'FIELD_LABELS' => 'labels',
+            'FIELD_ANONYMOUS' => 'anonymous',
+            'FIELDS_WITH_KEYWORDS' => 'auto', // can be 'auto', array of fields or comma separated string of field names, works only when OBJECT_METATAGS is specified
+            'FIELDS_DELAYED_PROCESSING' => 'videos', // can be array of fields or comma separated string of field names
+
+            'FIELD_OFR_ID' => 'id',
+            'FIELD_OFR_CONTENT' => 'content_id',
+            'FIELD_OFR_AUTHOR' => 'author_id',
+            'FIELD_OFR_ADDED' => 'added',
+            'FIELD_OFR_CHANGED' => 'changed',
+            'FIELD_OFR_AMOUNT' => 'amount',
+            'FIELD_OFR_QUANTITY' => 'quantity',
+            'FIELD_OFR_STATUS' => 'status',
+
+            // page URIs
+            'URI_VIEW_ENTRY' => 'view-ad',
+            'URI_VIEW_ENTRY_OFFERS' => 'view-ad-offers',
+            'URI_AUTHOR_ENTRIES' => 'ads-author',
+            'URI_ENTRIES_BY_CONTEXT' => 'ads-context',
+            'URI_ADD_ENTRY' => 'create-ad',
+            'URI_EDIT_ENTRY' => 'edit-ad',
+            'URI_MANAGE_COMMON' => 'ads-manage',
+
+            'URL_HOME' => 'page.php?i=ads-home',
+            'URL_POPULAR' => 'page.php?i=ads-popular',
+            'URL_UPDATED' => 'page.php?i=ads-updated',
+            'URL_CATEGORIES' => 'page.php?i=ads-categories',
+            'URL_MANAGE_COMMON' => 'page.php?i=ads-manage',
+            'URL_MANAGE_ADMINISTRATION' => 'page.php?i=ads-administration',
+            'URL_LICENSES_COMMON' => 'page.php?i=ads-licenses',
+            'URL_LICENSES_ADMINISTRATION' => 'page.php?i=ads-licenses-administration',
+
+            'GET_PARAM_CATEGORY' => 'category',
+
+            // some params
+            'PARAM_AUTO_APPROVE' => 'bx_ads_enable_auto_approve',
+            'PARAM_CHARS_SUMMARY' => 'bx_ads_summary_chars',
+            'PARAM_CHARS_SUMMARY_PLAIN' => 'bx_ads_plain_summary_chars',
+            'PARAM_NUM_RSS' => 'bx_ads_rss_num',
+            'PARAM_SEARCHABLE_FIELDS' => 'bx_ads_searchable_fields',
+            'PARAM_PER_PAGE_BROWSE_SHOWCASE' => 'bx_ads_per_page_browse_showcase',
+            'PARAM_LIFETIME' => 'bx_ads_lifetime',
+            'PARAM_LIFETIME_OFFERS' => 'bx_ads_offer_lifetime',
+            'PARAM_USE_IIN' => 'bx_ads_internal_interested_notification',
+            'PARAM_CATEGORY_LEVEL_MAX' => 1,
+            'PARAM_USE_AUCTION' => 'bx_ads_enable_auction',
+
+            // objects
+            'OBJECT_STORAGE' => 'bx_ads_covers',
+            'OBJECT_STORAGE_FILES' => 'bx_ads_files',
+            'OBJECT_STORAGE_PHOTOS' => 'bx_ads_photos',
+            'OBJECT_STORAGE_VIDEOS' => 'bx_ads_videos',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW' => 'bx_ads_preview',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => 'bx_ads_gallery',
+            'OBJECT_IMAGES_TRANSCODER_COVER' => 'bx_ads_cover',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW_FILES' => 'bx_ads_preview_files',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY_FILES' => 'bx_ads_gallery_files',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW_PHOTOS' => 'bx_ads_preview_photos',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY_PHOTOS' => 'bx_ads_gallery_photos',
+            'OBJECT_IMAGES_TRANSCODER_VIEW_PHOTOS' => 'bx_ads_view_photos',
+            'OBJECT_VIDEOS_TRANSCODERS' => array(
+                'poster' => 'bx_ads_videos_poster', 
+            	'poster_preview' => 'bx_ads_videos_poster_preview',
+            	'mp4' => 'bx_ads_videos_mp4', 
+            	'mp4_hd' => 'bx_ads_videos_mp4_hd'
+            ),
+            'OBJECT_VIDEO_TRANSCODER_HEIGHT' => '480px',
+            'OBJECT_REPORTS' => 'bx_ads',
+            'OBJECT_VIEWS' => 'bx_ads',
+            'OBJECT_VOTES' => 'bx_ads',
+            'OBJECT_REACTIONS' => 'bx_ads_reactions',
+            'OBJECT_SCORES' => 'bx_ads',
+            'OBJECT_FAVORITES' => 'bx_ads',
+            'OBJECT_FEATURED' => 'bx_ads',
+            'OBJECT_METATAGS' => 'bx_ads',
+            'OBJECT_COMMENTS' => 'bx_ads',
+            'OBJECT_NOTES' => 'bx_ads_notes',
+            'OBJECT_REVIEWS' => 'bx_ads_reviews',
+            'OBJECT_CATEGORY' => '',
+            'OBJECT_PRIVACY_VIEW' => 'bx_ads_allow_view_to',
+            'OBJECT_FORM_CATEGORY' => 'bx_ads_category',
+            'OBJECT_FORM_CATEGORY_DISPLAY_ADD' => 'bx_ads_category_add',
+            'OBJECT_FORM_CATEGORY_DISPLAY_EDIT' => 'bx_ads_category_edit',
+            'OBJECT_FORM_CATEGORY_DISPLAY_DELETE' => 'bx_ads_category_delete',
+            'OBJECT_FORM_ENTRY' => 'bx_ads',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => '',
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_ads_entry_add',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => '',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_ads_entry_delete',
+            'OBJECT_FORM_POLL' => 'bx_ads_poll',
+            'OBJECT_FORM_POLL_DISPLAY_ADD' => 'bx_ads_poll_add',
+            'OBJECT_FORM_OFFER' => 'bx_ads_offer',
+            'OBJECT_FORM_OFFER_DISPLAY_ADD' => 'bx_ads_offer_add',
+            'OBJECT_FORM_OFFER_DISPLAY_VIEW' => 'bx_ads_offer_view',
+            'OBJECT_MENU_ENTRY_ATTACHMENTS' => 'bx_ads_entry_attachments', // attachments menu in create/edit forms
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_ads_view', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL' => 'bx_ads_view_actions', // all actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_ads_my', // actions menu on my entries page
+            'OBJECT_MENU_SUBMENU' => 'bx_ads_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => 'bx_ads_view_submenu', // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'ads-home', // first item in view entry submenu from main module submenu
+            'OBJECT_MENU_SNIPPET_META' => 'bx_ads_snippet_meta', // menu for snippet meta info
+            'OBJECT_MENU_MANAGE_TOOLS' => 'bx_ads_menu_manage_tools', //manage menu in content administration tools
+            'OBJECT_MENU_LICENSES' => 'bx_ads_licenses_submenu',
+            'OBJECT_GRID_CATEGORIES' => 'bx_ads_categories',
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_ads_administration',
+            'OBJECT_GRID_COMMON' => 'bx_ads_common',
+            'OBJECT_GRID_LICENSES_ADMINISTRATION' => 'bx_ads_licenses_administration',
+            'OBJECT_GRID_LICENSES' => 'bx_ads_licenses',
+            'OBJECT_GRID_OFFERS' => 'bx_ads_offers',
+            'OBJECT_GRID_OFFERS_ALL' => 'bx_ads_offers_all',
+            'OBJECT_UPLOADERS' => array('bx_ads_simple', 'bx_ads_html5'),
+
+            // menu items which visibility depends on custom visibility checking
+            'MENU_ITEM_TO_METHOD' => array (
+                'bx_ads_my' => array (
+                    'create-ad' => 'checkAllowedAdd',
+                ),
+                'bx_ads_view' => $aMenuItems2Methods,
+            ),
+
+            // informer messages
+            'INFORMERS' => array (
+                'approving' => array (
+                    'name' => 'bx-ads-approving',
+                    'map' => array (
+                        'pending' => array('msg' => '_bx_ads_txt_msg_status_pending', 'type' => BX_INFORMER_ALERT),
+                        'hidden' => array('msg' => '_bx_ads_txt_msg_status_hidden', 'type' => BX_INFORMER_ERROR),
+                    ),
+                ),
+                'processing' => array (
+                    'name' => 'bx-ads-processing',
+                    'map' => array (
+                        'awaiting' => array('msg' => '_bx_ads_txt_processing_awaiting', 'type' => BX_INFORMER_ALERT),
+                        'failed' => array('msg' => '_bx_ads_txt_processing_failed', 'type' => BX_INFORMER_ERROR)
+                    ),
+                ),
+                'auction' => array (
+                    'name' => 'bx-ads-auction',
+                    'map' => array (
+                        'offer' => array('msg' => '_bx_ads_txt_msg_auction_offer', 'type' => BX_INFORMER_INFO),
+                        'sold' => array('msg' => '_bx_ads_txt_msg_auction_sold', 'type' => BX_INFORMER_INFO)
+                    ),
+                )
+            ),
+
+            // email templates
+            'ETEMPLATE_INTERESTED' => 'bx_ads_interested',
+            'ETEMPLATE_PURCHASED' => 'bx_ads_purchased',
+            'ETEMPLATE_SHIPPED' => 'bx_ads_shipped',
+            'ETEMPLATE_RECEIVED' => 'bx_ads_received',
+            'ETEMPLATE_OFFER_ADDED' => 'bx_ads_offer_added',
+            'ETEMPLATE_OFFER_ACCEPTED' => 'bx_ads_offer_accepted',
+            'ETEMPLATE_OFFER_DECLINED' => 'bx_ads_offer_declined',
+            'ETEMPLATE_OFFER_CANCELED' => 'bx_ads_offer_canceled',
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_ads_txt_sample_single',
+            	'txt_sample_single_with_article' => '_bx_ads_txt_sample_single_with_article',
+            	'txt_sample_comment_single' => '_bx_ads_txt_sample_comment_single',
+            	'txt_sample_vote_single' => '_bx_ads_txt_sample_vote_single',
+                'txt_sample_reaction_single' => '_bx_ads_txt_sample_reaction_single',
+                'txt_sample_score_up_single' => '_bx_ads_txt_sample_score_up_single',
+                'txt_sample_score_down_single' => '_bx_ads_txt_sample_score_down_single',
+                'txt_sample_interest_single' => '_bx_ads_txt_sample_interest_single',
+                'form_field_author' => '_bx_ads_form_entry_input_author',
+            	'grid_action_err_delete' => '_bx_ads_grid_action_err_delete',
+            	'grid_txt_account_manager' => '_bx_ads_grid_txt_account_manager',
+                'filter_item_active' => '_bx_ads_grid_filter_item_title_adm_active',
+            	'filter_item_hidden' => '_bx_ads_grid_filter_item_title_adm_hidden',
+                'filter_item_pending' => '_bx_ads_grid_filter_item_title_adm_pending',
+            	'filter_item_select_one_filter1' => '_bx_ads_grid_filter_item_title_adm_select_one_filter1',
+                'filter_item_select_one_filter2' => '_bx_ads_grid_filter_item_title_adm_select_one_filter2',
+            	'menu_item_manage_my' => '_bx_ads_menu_item_title_manage_my',
+            	'menu_item_manage_all' => '_bx_ads_menu_item_title_manage_all',
+                'txt_all_entries_by' => '_bx_ads_txt_all_entries_by',
+                'txt_all_entries_in' => '_bx_ads_txt_all_entries_in',
+                'txt_all_entries_by_author' => '_bx_ads_page_title_browse_by_author',
+                'txt_all_entries_by_context' => '_bx_ads_page_title_browse_by_context',
+                'txt_err_cannot_perform_action' => '_bx_ads_txt_err_cannot_perform_action',
+                'txt_poll_form_answers_add' => '_bx_ads_form_poll_input_answers_add',
+                'txt_poll_menu_view_answers' => '_bx_ads_txt_poll_view_answers',
+                'txt_poll_menu_view_results' => '_bx_ads_txt_poll_view_results',
+                'txt_poll_answer_vote_do_by' => '_bx_ads_txt_poll_answer_vote_do_by',
+                'txt_poll_answer_vote_counter' => '_bx_ads_txt_poll_answer_vote_counter',
+                'txt_poll_answer_vote_percent' => '_bx_ads_txt_poll_answer_vote_percent',
+                'txt_display_add' => '_bx_ads_txt_display_title_add',
+                'txt_display_edit' => '_bx_ads_txt_display_title_edit',
+                'txt_display_view' => '_bx_ads_txt_display_title_view',
+            ),
+        ));
+        
+        $this->_aJsClasses = array_merge($this->_aJsClasses, array(
+            'manage_tools' => 'BxAdsManageTools',
+            'studio' => 'BxAdsStudio',
+            'entry' => 'BxAdsEntry',
+            'form' => 'BxAdsForm',
+        ));
+
+        $this->_aJsObjects = array_merge($this->_aJsObjects, array(
+            'manage_tools' => 'oBxAdsManageTools',
+            'studio' => 'oBxAdsStudio',
+            'entry' => 'oBxAdsEntry',
+            'form' => 'oBxAdsForm',
+        ));
+
+        $this->_aGridObjects = array(
+            'categories' => $this->CNF['OBJECT_GRID_CATEGORIES'],
+            'common' => $this->CNF['OBJECT_GRID_COMMON'],
+            'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION'],
+        );
+
+        $sPrefix = str_replace('_', '-', $this->_sName);
+        $this->_aHtmlIds = array(
+            'offer_popup' =>  $sPrefix . '-offer-popup',
+        );
+
+        $oPayments = BxDolPayments::getInstance();
+        $this->_aCurrency = array(
+            'code' => $oPayments->getOption('default_currency_code'),
+            'sign' => $oPayments->getOption('default_currency_sign')
+        );
+
+        $this->_bAttachmentsInTimeline = true;
+    }
+
+    public function init(&$oDb)
+    {
+        $this->_oDb = &$oDb;
+        
+        $this->_bAuction = getParam($this->CNF['PARAM_USE_AUCTION']) == 'on';
+    }
+
+    public function isAuction()
+    {
+        return $this->_bAuction;
+    }
+
+    public function getCurrency()
+    {
+    	return $this->_aCurrency;
+    }
+
+    public function getEntryName($sName)
+    {
+        return uriGenerate($sName, $this->CNF['TABLE_ENTRIES'], $this->CNF['FIELD_NAME'], ['lowercase' => false]);
+    }
+}
+
+/** @} */

+ 300 - 0
modules/boonex/ads/updates/13.0.4_13.0.5/source/classes/BxAdsGridCategories.php

@@ -0,0 +1,300 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Ads Ads
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+class BxAdsGridCategories extends BxTemplGrid
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_sBaseUrl;
+
+    protected $_iParentId;
+    protected $_aParentInfo;
+    
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+        
+        $this->_sModule = 'bx_ads';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        $this->_sBaseUrl = bx_append_url_params(BX_DOL_URL_STUDIO . 'module.php', array(
+            'name' => $this->_sModule, 
+            'page' => 'categories'
+        ));
+
+        $this->_iParentId = bx_get('parent_id') !== false ? (int)bx_get('parent_id') : 0;
+        $this->_aQueryAppend['parent_id'] = $this->_iParentId;
+
+        if(!empty($this->_iParentId)) 
+            $this->_aParentInfo = $this->_oModule->_oDb->getCategories(array('type' => 'id', 'id' => $this->_iParentId));
+    }
+
+    public function performActionAdd()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $sAction = 'add';
+
+        $oForm = $this->_getFormObject($sAction);
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+            $aValsToAdd = array('active' => 1);
+
+            $iParentId = (int)$oForm->getCleanValue('parent_id');
+            if($iParentId != 0) {
+                $aParentInfo = $this->_oModule->_oDb->getCategories(array('type' => 'id', 'id' => $iParentId));
+
+                $aValsToAdd['level'] = $aParentInfo['level'] + 1;
+                $aValsToAdd['order'] = $this->_oModule->_oDb->getCategories(array('type' => 'parent_id_order', 'parent_id' => $iParentId)) + 1;
+            }
+            else {
+                $aValsToAdd['level'] = 0;
+                $aValsToAdd['order'] = $this->_oModule->_oDb->getCategories(array('type' => 'parent_id_order', 'parent_id' => 0)) + 1;
+            }
+
+            $oLanguage = BxDolStudioLanguagesUtils::getInstance();
+            $aLanguages = $oLanguage->getLanguagesExt();
+            $sLanguageCurrent = $oLanguage->getCurrentLangName(false);
+
+            $sTitle = BxDolForm::getSubmittedValue('title-' . $sLanguageCurrent, $oForm->aFormAttrs['method']);
+            $sName = uriGenerate(strtolower($sTitle), $CNF['TABLE_CATEGORIES'], 'name', ['empty' => 'cat', 'divider' => '_']);
+
+            $aValsToAdd['name'] = $sName;
+            BxDolForm::setSubmittedValue('title', '_bx_ads_cat_' . $sName, $oForm->aFormAttrs['method']);
+            BxDolForm::setSubmittedValue('text', '_bx_ads_cat_' . $sName, $oForm->aFormAttrs['method']);
+
+            if($oForm->getCleanValue('type_clone') == 'on') {
+                $sTypeNewTitle = BxDolForm::getSubmittedValue('type_title-' . $sLanguageCurrent, $oForm->aFormAttrs['method']);
+                if(empty($sTypeNewTitle))
+                    $sTypeNewTitle = $sTitle;
+
+                $sTypeNewName = uriGenerate(strtolower($sTypeNewTitle), $CNF['TABLE_CATEGORIES_TYPES'], 'name', ['empty' => 'cat_type', 'divider' => '_']);
+
+                $iType = (int)$oForm->getCleanValue('type');
+                $aType = $this->_oModule->_oDb->getCategoryTypes(array('type' => 'id', 'id' => $iType));
+
+                $aTypeNew = array('name' => $sTypeNewName, 'title' => '_bx_ads_cat_type_' . $sTypeNewName);
+                foreach($aLanguages as $sLanguage => $aLanguage) {
+                    $sTypeNewTitleLang = bx_process_input(BxDolForm::getSubmittedValue('type_title-' . $sLanguage, $oForm->aFormAttrs['method']));
+                    if(!empty($sTypeNewTitleLang))
+                        $sTypeNewKeys[$aTypeNew['title']][$aLanguage['id']] = $sTypeNewTitleLang;
+                }
+
+                $bDisplayCloned = true;
+                $aDisplayTypes = array('add', 'edit', 'view');
+                foreach($aDisplayTypes as $sDisplayType) {
+                    $sDisplay = 'display_' . $sDisplayType;
+                    if(empty($aType[$sDisplay])) {
+                        $aTypeNew[$sDisplay] = '';
+                        continue;
+                    }
+
+                    $sDisplayNewName = 'bx_ads_entry_' . $sTypeNewName . '_' . $sDisplayType;
+                    $sDisplayNewTitle = '_bx_ads_form_display_' . $sTypeNewName . '_' . $sDisplayType;
+
+                    if(!$this->_oModule->_oDb->cloneDisplay($aType[$sDisplay], $sDisplayNewName, $sDisplayNewTitle)) {
+                        $bDisplayCloned = false;
+                        break;
+                    }
+
+                    $aTypeNew[$sDisplay] = $sDisplayNewName;
+                    $sTypeNewKeys[$sDisplayNewTitle] = _t($CNF['T']['txt_display_' . $sDisplayType], $sTypeNewTitle);
+                }
+
+                if($bDisplayCloned && ($iTypeNewId = $this->_oModule->_oDb->insertCategoryType($aTypeNew)) !== 0) {
+                    BxDolForm::setSubmittedValue('type', $iTypeNewId, $oForm->aFormAttrs['method']);
+
+                    foreach($sTypeNewKeys as $sKey => $mixedString)
+                        $oLanguage->addLanguageString($sKey, $mixedString, 0, 0, false);
+                    $oLanguage->compileLanguage();
+                }
+            }
+
+            unset($oForm->aInputs['type_clone'], $oForm->aInputs['type_title']);
+
+            $iId = (int)$oForm->insert($aValsToAdd);
+            if($iId != 0)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_ads_grid_action_err_add_category'));
+
+            echoJson($aRes);
+        }
+        else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox($this->_sModule . '-category-add-popup', _t('_bx_ads_grid_popup_title_add'), $this->_oModule->_oTemplate->parseHtmlByName('category_form.html', array(
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+    
+    public function performActionEdit()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $sAction = 'edit';
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $iId = (int)bx_get('id');
+            if(!$iId)
+                return false;
+
+            $aIds = array($iId);
+        }
+
+        $iId = $aIds[0];
+
+        $aCategory = $this->_oModule->_oDb->getCategories(array('type' => 'id', 'id' => $iId));
+        if(empty($aCategory) || !is_array($aCategory))
+            return echoJson(array());
+
+        $oForm = $this->_getFormObject($sAction, $aCategory);
+        $oForm->initChecker($aCategory);
+
+        if($oForm->isSubmittedAndValid()) {
+            $aValsToAdd = array('active' => 1);
+
+            $iParentId = (int)$oForm->getCleanValue('parent_id');
+            if($iParentId != 0) {
+                $aParentInfo = $this->_oModule->_oDb->getCategories(array('type' => 'id', 'id' => $iParentId));
+
+                $aValsToAdd['level'] = $aParentInfo['level'] + 1;
+                $aValsToAdd['order'] = $this->_oModule->_oDb->getCategories(array('type' => 'parent_id_order', 'parent_id' => $iParentId)) + 1;
+            }
+            else {
+                $aValsToAdd['level'] = 0;
+                $aValsToAdd['order'] = $this->_oModule->_oDb->getCategories(array('type' => 'parent_id_order', 'parent_id' => 0)) + 1;
+            }
+                
+            $iId = (int)$oForm->update($iId, $aValsToAdd);
+            if($iId != 0)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_ads_grid_action_err_edit_category'));
+
+            echoJson($aRes);
+        }
+        else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox($this->_sModule . '-category-edit-popup', _t('_bx_ads_grid_popup_title_edit', _t($aCategory['title'])), $this->_oModule->_oTemplate->parseHtmlByName('category_form.html', array(
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+
+    protected function _getFormObject($sAction, $aCategory = array())
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_CATEGORY'], $CNF['OBJECT_FORM_CATEGORY_DISPLAY_' . strtoupper($sAction)]);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction . '&parent_id=' . $this->_iParentId;
+        if(!empty($aCategory['id']))
+            $oForm->aFormAttrs['action'] .= '&id=' . $aCategory['id'];
+
+        if(isset($oForm->aInputs['parent_id'])) {
+            if(empty($this->_iParentId)) {
+                $oForm->aInputs['parent_id']['values'][] = array('key' => 0, 'value' => _t('_bx_ads_form_category_input_parent_id_empty'));
+
+                $aCategories = $this->_oModule->_oDb->getCategories(array('type' => 'parent_id', 'parent_id' => $this->_iParentId));
+                foreach($aCategories as $aCategory)
+                    $oForm->aInputs['parent_id']['values'][] = array(
+                        'key' => $aCategory['id'], 
+                        'value' => _t($aCategory['title'])
+                    );
+            }
+            else {
+                $oForm->aInputs['parent_id']['type'] = 'hidden';
+                $oForm->aInputs['parent_id']['value'] = $this->_iParentId;
+            }
+        }
+        
+        return $oForm;
+    }
+
+    protected function _getActionBack($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(empty($this->_iParentId))
+            return '';
+
+        $sUrl = bx_append_url_params($this->_sBaseUrl, array('parent_id' => $this->_aParentInfo['parent_id']));
+
+    	$a['attr'] = array_merge($a['attr'], array(
+            "onclick" => "window.open('" . $sUrl . "','_self');"
+    	));
+
+    	return $this->_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getCellIcon ($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = $this->_oTemplate->getIcon($mixedValue, array('class' => 'bx-def-border'));
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+    
+    protected function _getCellSubcategories ($mixedValue, $sKey, $aField, $aRow)
+    {
+        $sContent = _t('_bx_ads_grid_column_value_subcategories', $this->_oModule->_oDb->getCategories(array('type' => 'parent_id_count', 'parent_id' => $aRow['id'])));
+
+        $mixedValue = $this->_oTemplate->parseLink(bx_append_url_params($this->_sBaseUrl, array('parent_id' => $aRow['id'])), $sContent, array(
+            'title' => _t('_bx_ads_grid_column_info_subcategories')
+        ));
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+        $this->_oModule->_oTemplate->addStudioJs(array('jquery.form.min.js', 'studio.js'));
+
+        $oForm = new BxTemplStudioFormView(array());
+        $oForm->addCssJs();
+    }
+
+    protected function _isVisibleGrid ($a)
+    {
+        return isAdmin();
+    }
+
+    protected function _delete ($mixedId)
+    {
+        $sTable = $this->_aOptions['table'];
+        $sFieldId = $this->_aOptions['field_id'];
+        $aCategory = $this->_oModule->_oDb->getRow("SELECT * FROM `" . $sTable . "` WHERE `" . $sFieldId . "`=:id", array('id' => $mixedId));
+        if(!empty($aCategory['title'])) {
+            $oLanguage = BxDolStudioLanguagesUtils::getInstance();
+            $oLanguage->deleteLanguageString($aCategory['title']);
+            $oLanguage->deleteLanguageString($aCategory['text']);
+        }
+
+        return parent::_delete($mixedId);
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `parent_id`=?", $this->_iParentId);
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+}
+
+/** @} */

+ 2078 - 0
modules/boonex/ads/updates/13.0.4_13.0.5/source/classes/BxAdsModule.php

@@ -0,0 +1,2078 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Ads Ads
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define('BX_ADS_STATUS_OFFER', 'offer');
+define('BX_ADS_STATUS_SOLD', 'sold');
+
+define('BX_ADS_OFFER_STATUS_ACCEPTED', 'accepted');
+define('BX_ADS_OFFER_STATUS_AWAITING', 'awaiting');
+define('BX_ADS_OFFER_STATUS_DECLINED', 'declined');
+define('BX_ADS_OFFER_STATUS_CANCELED', 'canceled');
+
+/**
+ * Ads module
+ */
+class BxAdsModule extends BxBaseModTextModule
+{
+    protected $_aOfferStatuses;
+
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_oConfig->init($this->_oDb);
+
+        $CNF = &$this->_oConfig->CNF;
+
+        $this->_aSearchableNamesExcept = array_merge($this->_aSearchableNamesExcept, array(
+            $CNF['FIELD_CATEGORY_VIEW'],
+            $CNF['FIELD_CATEGORY_SELECT']
+        ));
+
+        $this->_aOfferStatuses = array(
+            BX_ADS_OFFER_STATUS_ACCEPTED,
+            BX_ADS_OFFER_STATUS_AWAITING,
+            BX_ADS_OFFER_STATUS_DECLINED
+        );
+    }
+
+    public function actionGetCategoryForm()
+    {
+        if(bx_get('category') === false)
+            return echoJson(array());
+
+        return echoJson(array(
+            'content' => $this->serviceGetCreatePostForm(array(
+                'absolute_action_url' => true,
+                'dynamic_mode' => true
+            ))
+        ));
+    }
+
+    public function actionCheckName()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iId = (int)bx_get($CNF['FIELD_ID']);
+    	$sTitle = bx_process_input(bx_get($CNF['FIELD_TITLE']));
+
+    	echoJson($this->serviceCheckName($sTitle, $iId));
+    }
+
+    public function actionInterested()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return echoJson(array());
+
+        $iViewer = bx_get_logged_profile_id();        
+        $oViewer = BxDolProfile::getInstance($iViewer);
+        if(!$oViewer)
+            return echoJson(array());
+
+        $iContentAuthor = (int)$aContentInfo[$CNF['FIELD_AUTHOR']];
+        if($iContentAuthor == $iViewer)
+            return echoJson(array('msg' => _t('_bx_ads_txt_err_your_own')));
+
+        if($this->_oDb->isInterested($iContentId, $iViewer))
+            return echoJson(array('msg' => _t('_bx_ads_txt_err_duplicate')));
+
+        $iInterestId = $this->_oDb->insertInterested(array('entry_id' => $iContentId, 'profile_id' => $iViewer));
+        if(!$iInterestId)
+            return echoJson(array('msg' => _t('_bx_ads_txt_err_cannot_perform_action')));
+
+        bx_alert($this->getName(), 'doInterest', $iContentId, $iViewer, array(
+            'subobject_id' => $iInterestId, 
+            'subobject_author_id' => $iViewer, 
+
+            'object_author_id' => $iContentAuthor
+        ));
+
+        if(getParam($CNF['PARAM_USE_IIN']) == 'on')
+            sendMailTemplate($CNF['ETEMPLATE_INTERESTED'], 0, $iContentAuthor, array(
+                'viewer_name' => $oViewer->getDisplayName(),
+                'viewer_url' => $oViewer->getUrl(),
+                'ad_name' => $aContentInfo[$CNF['FIELD_TITLE']],
+                'ad_url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php', array(
+                    'i' => $CNF['URI_VIEW_ENTRY'], 
+                    $CNF['FIELD_ID'] => $iContentId
+                ))
+            ));
+
+        return echoJson(array('msg' => _t('_bx_ads_txt_msg_author_notified')));
+    }
+
+    public function actionShow()
+    {
+        return echoJson($this->_actionChangeStatus(BX_BASE_MOD_TEXT_STATUS_ACTIVE));
+    }
+
+    public function actionHide()
+    {
+        return echoJson($this->_actionChangeStatus(BX_BASE_MOD_TEXT_STATUS_HIDDEN));
+    }
+
+    public function actionMakeOffer()
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $sJsObject = $this->_oConfig->getJsObject('entry');
+
+        $iAuthorId = bx_get_logged_profile_id();
+        $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        if(empty($iAuthorId))
+            return echoJson(array('code' => 1, 'eval' => 'window.open("' . BxDolPermalinks::getInstance()->permalink('page.php?i=login') . '", "_self");'));
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return echoJson(array());
+
+        if(($mixedCheck = $this->checkAllowedMakeOffer($aContentInfo)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return echoJson(array('code' => 2, 'msg' => $mixedCheck));
+
+        $aOffer = $this->_oDb->getOffersBy(array(
+            'type' => 'content_and_author_ids', 
+            'content_id' => $iContentId, 
+            'author_id' => $iAuthorId, 
+            'status' => BX_ADS_OFFER_STATUS_AWAITING
+        ));
+
+        if(!empty($aOffer) && is_array($aOffer))
+            return echoJson(array('code' => 3, 'msg' => _t('_bx_ads_txt_err_duplicate')));
+
+        $aOffer = $this->_oDb->getOffersBy(array(
+            'type' => 'content_and_author_ids', 
+            'content_id' => $iContentId, 
+            'author_id' => $iAuthorId, 
+            'status' => BX_ADS_OFFER_STATUS_ACCEPTED
+        ));
+
+        if(!empty($aOffer) && is_array($aOffer))
+            return echoJson(array('code' => 4, 'msg' => _t('_bx_ads_txt_err_offer_accepted')));
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_OFFER'], $CNF['OBJECT_FORM_OFFER_DISPLAY_ADD']);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . bx_append_url_params($this->_oConfig->getBaseUri() . 'make_offer', array('id' => $iContentId));
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+            $aValToAdd = array('content_id' => $iContentId, 'author_id' => $iAuthorId);
+
+            $iId = (int)$oForm->insert($aValToAdd);
+            if($iId != 0) {
+                $this->checkAllowedMakeOffer($aContentInfo, true);
+
+                $this->onOfferAdded($iId, $aResult);
+
+                $aResult = array('code' => 0, 'msg' => _t('_bx_ads_txt_msg_offer_added'), 'eval' => $sJsObject . '.onMakeOffer(oData);', 'id' => $iId);
+            }
+            else
+                $aResult = array('code' => 5, 'msg' => _t('_bx_ads_txt_err_cannot_perform_action'));
+
+            return echoJson($aResult);
+        }
+
+        $sContent = BxTemplFunctions::getInstance()->transBox($this->_oConfig->getHtmlIds('offer_popup'), $this->_oTemplate->parseHtmlByName('offer_popup.html', array(
+            'form_id' => $oForm->getId(),
+            'form' => $oForm->getCode(true)
+        )));
+
+        return echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false, 'removeOnClose' => true))));
+    }
+
+    public function actionViewOffer()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iAuthorId = bx_get_logged_profile_id();
+        $iOfferId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        $aOffer = $this->_oDb->getOffersBy(array('type' => 'id', 'id' => $iOfferId));
+        if(empty($aOffer) || !is_array($aOffer))
+            return echoJson(array());
+        
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_OFFER'], $CNF['OBJECT_FORM_OFFER_DISPLAY_VIEW']);
+        $oForm->initChecker($aOffer);
+
+        $sContent = BxTemplFunctions::getInstance()->transBox($this->_oConfig->getHtmlIds('offer_popup'), $this->_oTemplate->parseHtmlByName('offer_popup.html', array(
+            'form_id' => $oForm->getId(),
+            'form' => $oForm->getCode(true)
+        )));
+
+        return echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => true, 'removeOnClose' => true))));
+    }
+
+    public function actionAcceptOffer()
+    {
+        $iId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        if(!$this->offerAccept($iId))
+            return echoJson(array('msg' => _t('_bx_ads_txt_err_cannot_perform_action')));
+
+        return echoJson(array('msg' => _t('_bx_ads_txt_msg_offer_accepted'), 'reload' => 1));
+    }
+
+    public function actionDeclineOffer()
+    {
+        $iId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        if(!$this->offerDecline($iId))
+            return echoJson(array('msg' => _t('_bx_ads_txt_err_cannot_perform_action')));
+
+        return echoJson(array('msg' => _t('_bx_ads_txt_msg_offer_declined'), 'reload' => 1));
+    }
+            
+    public function actionCancelOffer()
+    {
+        $iId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        if(!$this->offerCancel($iId))
+            return echoJson(array('msg' => _t('_bx_ads_txt_err_cannot_perform_action')));     
+
+        return echoJson(array('msg' => _t('_bx_ads_txt_msg_offer_canceled'), 'reload' => 1));
+    }
+    
+    public function actionPayOffer()
+    {
+        $iId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        if(($mixedResult = $this->offerPay($iId)) !== false)
+            return echoJson($mixedResult);
+
+        return echoJson(array('msg' => _t('_bx_ads_txt_err_cannot_perform_action')));     
+    }
+
+    public function actionShipped()
+    {
+        return echoJson($this->_actionMarkAs('shipped'));
+    }
+
+    public function actionReceived()
+    {
+        return echoJson($this->_actionMarkAs('received'));
+    }
+
+    public function serviceGetSafeServices()
+    {
+        $a = parent::serviceGetSafeServices();
+        return array_merge($a, array (
+            'EntityReviews' => '',
+            'EntityReviewsRating' => '',
+            'CategoriesList' => '',
+            'BrowseCategory' => '',
+        ));
+    }
+
+    public function serviceCheckName($sTitle, $iId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	if(empty($sTitle))
+            return array();
+
+        $sName = '';
+        if(!empty($iId)) {
+            $aEntry = $this->_oDb->getContentInfoById($iId); 
+            if(strcmp($sTitle, $aEntry[$CNF['FIELD_NAME']]) == 0) 
+                $sName = $sTitle;
+        }
+
+        return array(
+            'title' => $sTitle,
+            'name' => !empty($sName) ? $sName : $this->_oConfig->getEntryName($sTitle, $iId)
+    	);
+    }
+
+    public function serviceUpdateCategoriesStats($mixedContentInfo = false)
+    {
+        $aContentInfo = [];
+        if(!empty($mixedContentInfo))
+            $aContentInfo = !is_array($mixedContentInfo) ? $this->_oDb->getContentInfoById((int)$mixedContentInfo) : $mixedContentInfo;
+
+        $iCategoryId = 0;
+        if($aContentInfo && !empty($aContentInfo['category']))
+            $iCategoryId = (int)$aContentInfo['category'];
+
+        return $this->serviceUpdateCategoriesStatsByCategory($iCategoryId);
+    }
+
+    public function serviceUpdateCategoriesStatsByCategory($iCategoryId = 0)
+    {
+        $aParams = ['type' => 'collect_stats'];
+        if($iCategoryId)
+            $aParams['category_id'] = (int)$iCategoryId;
+
+        $aStats = $this->_oDb->getCategories($aParams);
+        if(empty($aStats) || !is_array($aStats))
+            return true;
+
+        $iUpdated = 0;
+        foreach($aStats as $aStat)
+            if($this->_oDb->updateCategory(array('items' => $aStat['count']), array('id' => $aStat['id'])))
+                $iUpdated++;
+
+        return count($aStats) == $iUpdated;
+    }
+
+    public function serviceGetCategoryOptions($iParentId, $bPleaseSelect = false)
+    {
+        $aValues = array();
+        if($bPleaseSelect)
+            $aValues[] = array('key' => '', 'value' => _t('_sys_please_select'));
+
+        $this->_getCategoryOptions($iParentId, $aValues);
+
+        return $aValues;
+    }
+
+    public function serviceGetSearchableFields($aInputsAdd = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aResult = parent::serviceGetSearchableFields(array_merge($aInputsAdd, $this->_getSearchableFields()));
+        unset($aResult[$CNF['FIELD_NOTES_PURCHASED']]);
+        unset($aResult[$CNF['FIELD_CATEGORY_VIEW']], $aResult[$CNF['FIELD_CATEGORY_SELECT']]);
+        unset($aResult[$CNF['FIELD_PRICE']], $aResult[$CNF['FIELD_YEAR']]);
+
+        return $aResult;
+    }
+
+    public function serviceGetSearchableFieldsExtended($aInputsAdd = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aInputsAdd = array_merge($aInputsAdd, $this->_getSearchableFields());
+
+        if(isset($aInputsAdd[$CNF['FIELD_CATEGORY']])) {
+            $aInputsAdd[$CNF['FIELD_CATEGORY']]['type'] = 'select';
+            $aInputsAdd[$CNF['FIELD_CATEGORY']]['values_src'] = BxDolService::getSerializedService($this->_oConfig->getName(), 'get_category_options', array(0));
+        }
+
+        if(isset($aInputsAdd[$CNF['FIELD_PRICE']])) {
+            $aInputsAdd[$CNF['FIELD_PRICE']]['search_type'] = 'text_range';
+            $aInputsAdd[$CNF['FIELD_PRICE']]['search_operator'] = 'between';
+        }
+
+        if(isset($aInputsAdd[$CNF['FIELD_YEAR']])) {
+            $aInputsAdd[$CNF['FIELD_YEAR']]['search_type'] = 'text_range';
+            $aInputsAdd[$CNF['FIELD_YEAR']]['search_operator'] = 'between';
+        }
+
+        return parent::serviceGetSearchableFieldsExtended($aInputsAdd);
+    }
+
+    /**
+     * Mark an ad as shipped/received by seller/bauer accordingly.
+     * @param type $sAction - shipped/received action.
+     * @param type $iContentId - an ad the action will be performed with.
+     * @param integer $iProfileSrc - profile, who performed the action.
+     * @param integer $iProfileDst - profile, the action is pointed on.
+     * @return boolean - true or a string value with error message.
+     */
+    public function serviceMarkAs($sAction, $iContentId, $iProfileSrc = 0, $iProfileDst = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iProfileSrc)
+            $iProfileSrc = bx_get_logged_profile_id();
+
+        $sTxtError = '_bx_ads_txt_err_cannot_perform_action';
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+
+        $sMethodCheck = 'checkAllowedMark' . bx_gen_method_name($sAction) . 'ForProfile';
+        if(!method_exists($this, $sMethodCheck))
+            return _t($sTxtError);
+
+        if(($mixedCheckResult = $this->$sMethodCheck($aContentInfo, false, $iProfileSrc)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return $mixedCheckResult;
+
+        if((int)$this->_oDb->updateEntriesBy(array($CNF['FIELD_' . strtoupper($sAction)] => time()), array($CNF['FIELD_ID'] => $iContentId)) == 0)
+            return _t($sTxtError);
+
+        $this->$sMethodCheck($aContentInfo, true, $iProfileSrc);
+
+        $sMethodOnResult = 'on' . bx_gen_method_name($sAction);
+        if(method_exists($this, $sMethodOnResult))
+            $this->$sMethodOnResult($aContentInfo, $iProfileSrc, $iProfileDst);        
+
+        return true;
+    }
+
+    public function serviceEntityCreate ($sParams = false)
+    {
+        if(($sDisplay = $this->getCategoryDisplay('add')) !== false) {
+            if(empty($sParams) || !is_array($sParams))
+                $sParams = array();
+
+            $sParams['display'] = $sDisplay;
+        }
+
+        return parent::serviceEntityCreate($sParams);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads 
+     * @subsection bx_ads-page_blocks Page Blocks
+     * @subsubsection bx_ads-entity_reviews entity_reviews
+     * 
+     * @code bx_srv('bx_ads', 'entity_reviews', [...]); @endcode
+     * 
+     * Get reviews for particular content
+     * @param $iContentId content ID
+     * 
+     * @see BxAdsModule::serviceEntityReviews
+     */
+    /** 
+     * @ref bx_ads-entity_reviews "entity_reviews"
+     */
+    public function serviceEntityReviews($iContentId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        if(empty($CNF['OBJECT_REVIEWS']))
+            return false;
+
+        return $this->_entityComments($CNF['OBJECT_REVIEWS'], $iContentId);
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads 
+     * @subsection bx_ads-page_blocks Page Blocks
+     * @subsubsection bx_ads-entity_reviews_rating entity_reviews_rating
+     * 
+     * @code bx_srv('bx_ads', 'entity_reviews_rating', [...]); @endcode
+     * 
+     * Get reviews rating for particular content
+     * @param $iContentId content ID
+     * 
+     * @see BxAdsModule::serviceEntityReviewsRating
+     */
+    /** 
+     * @ref bx_ads-entity_reviews_rating "entity_reviews_rating"
+     */
+    public function serviceEntityReviewsRating($iContentId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        if(empty($CNF['OBJECT_REVIEWS']))
+            return false;
+
+        if(!$iContentId)
+            $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        if(!$iContentId)
+            return false;
+
+        $oCmts = BxDolCmts::getObjectInstance($CNF['OBJECT_REVIEWS'], $iContentId);
+        if (!$oCmts || !$oCmts->isEnabled())
+            return false;
+
+        return $oCmts->getRatingBlock(array('in_designbox' => false));
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads 
+     * @subsection bx_ads-page_blocks Page Blocks
+     * @subsubsection bx_ads-categories_list categories_list
+     * 
+     * @code bx_srv('bx_ads', 'categories_list', [...]); @endcode
+     * 
+     * Get reviews rating for particular content
+     * @param $aParams additional params array, such as 'show_empty'
+     * 
+     * @see BxAdsModule::serviceCategoriesList
+     */
+    /** 
+     * @ref bx_ads-categories_list "categories_list"
+     */
+    public function serviceCategoriesList($aParams = array())
+    {
+        if(!isset($aParams['show_empty']))
+            $aParams['show_empty'] = true;
+
+        return $this->_oTemplate->categoriesList($aParams);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads 
+     * @subsection bx_ads-browse Browse
+     * @subsubsection bx_ads-browse_category browse_category
+     * 
+     * @code bx_srv('bx_ads', 'browse_category', [...]); @endcode
+     * 
+     * Get reviews rating for particular content
+     * @param $iCategoryId category ID
+     * @param $aParams additional params array, such as empty_message, ajax_paginate, etc
+     * 
+     * @see BxAdsModule::serviceBrowseCategory
+     */
+    /**
+     * @ref bx_ads-browse_category "browse_category"
+     */
+    public function serviceBrowseCategory($iCategoryId = 0, $aParams = array())
+    {
+        $sParamName = $sParamGet = 'category';
+
+        if(!$iCategoryId && bx_get($sParamGet) !== false)
+            $iCategoryId = bx_process_input(bx_get($sParamGet), BX_DATA_INT);
+
+        $bEmptyMessage = true;
+        if(isset($aParams['empty_message'])) {
+            $bEmptyMessage = (bool)$aParams['empty_message'];
+            unset($aParams['empty_message']);
+        }
+
+        $bAjaxPaginate = true;
+        if(isset($aParams['ajax_paginate'])) {
+            $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
+            unset($aParams['ajax_paginate']);
+        }
+
+        $aBlock = $this->_serviceBrowse ($sParamName, array_merge(array($sParamName => $iCategoryId), $aParams), BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+        if(!empty($aBlock['content'])) {
+            $aCategory = $this->_oDb->getCategories(array('type' => 'id', 'id' => $iCategoryId));
+            if(!empty($aCategory['title']))
+                $aBlock['title'] = _t('_bx_ads_page_block_title_entries_by_category_mask', _t($aCategory['title']));
+        }
+
+        return $aBlock;
+    }
+
+    public function serviceGetNotificationsData()
+    {
+        $sModule = $this->_aModule['name'];
+
+        $sEventPrivacy = $sModule . '_allow_view_event_to';
+        if(BxDolPrivacy::getObjectInstance($sEventPrivacy) === false)
+            $sEventPrivacy = '';
+
+        $aResult = parent::serviceGetNotificationsData();
+        $aResult['handlers'] = array_merge($aResult['handlers'], array(
+            array('group' => $sModule . '_interest', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'doInterest', 'module_name' => $sModule, 'module_method' => 'get_notifications_interest', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
+            array('group' => $sModule . '_paid', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'license_register', 'module_name' => $sModule, 'module_method' => 'get_notifications_license_register', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
+            //---> To Buyer
+            array('group' => $sModule . '_shipped', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'shipped', 'module_name' => $sModule, 'module_method' => 'get_notifications_shipped', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
+            //<---
+            array('group' => $sModule . '_received', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'received', 'module_name' => $sModule, 'module_method' => 'get_notifications_received', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
+
+            array('group' => $sModule . '_offer_added', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'offer_added', 'module_name' => $sModule, 'module_method' => 'get_notifications_offer_added', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
+            //---> To Offerer
+            array('group' => $sModule . '_offer_accepted', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'offer_accepted', 'module_name' => $sModule, 'module_method' => 'get_notifications_offer_accepted', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
+            array('group' => $sModule . '_offer_declined', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'offer_declined', 'module_name' => $sModule, 'module_method' => 'get_notifications_offer_declined', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
+            //<---
+            array('group' => $sModule . '_offer_canceled', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'offer_canceled', 'module_name' => $sModule, 'module_method' => 'get_notifications_offer_canceled', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy)
+        ));
+
+        $aResult['settings'] = array_merge($aResult['settings'], array(
+            array('group' => 'interest', 'unit' => $sModule, 'action' => 'doInterest', 'types' => array('personal')),
+
+            array('group' => 'usage', 'unit' => $sModule, 'action' => 'license_register', 'types' => array('personal')),
+            array('group' => 'usage', 'unit' => $sModule, 'action' => 'shipped', 'types' => array('personal')),
+            array('group' => 'usage', 'unit' => $sModule, 'action' => 'received', 'types' => array('personal')),
+            array('group' => 'usage', 'unit' => $sModule, 'action' => 'offer_added', 'types' => array('personal')),
+            array('group' => 'usage', 'unit' => $sModule, 'action' => 'offer_accepted', 'types' => array('personal')),
+            array('group' => 'usage', 'unit' => $sModule, 'action' => 'offer_declined', 'types' => array('personal')),
+            array('group' => 'usage', 'unit' => $sModule, 'action' => 'offer_canceled', 'types' => array('personal')),
+        ));
+
+        $aResult['alerts'] = array_merge($aResult['alerts'], array(
+            array('unit' => $sModule, 'action' => 'doInterest'),
+            array('unit' => $sModule, 'action' => 'license_register'),
+            array('unit' => $sModule, 'action' => 'shipped'),
+            array('unit' => $sModule, 'action' => 'received'),
+            array('unit' => $sModule, 'action' => 'offer_added'),
+            array('unit' => $sModule, 'action' => 'offer_accepted'),
+            array('unit' => $sModule, 'action' => 'offer_declined'),
+            array('unit' => $sModule, 'action' => 'offer_canceled'),
+        ));
+
+        return $aResult; 
+    }
+
+    public function serviceGetNotificationsInsertData($oAlert, $aHandler, $aDataItems)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aResult = [];
+        switch($oAlert->sAction) {
+            case 'license_register':
+                $aContentInfo = $this->_oDb->getContentInfoById($oAlert->aExtras['product_id']);
+                if(empty($aContentInfo) || !is_array($aContentInfo)) {
+                    $aResult = $aDataItems;
+                    break;
+                }
+
+                foreach($aDataItems as $aDataItem) {
+                    $aDataItem = array_merge($aDataItem, [
+                        'owner_id' => $oAlert->aExtras['profile_id'],
+                        'object_id' => $aContentInfo[$CNF['FIELD_ID']],
+                        'object_owner_id' => $aContentInfo[$CNF['FIELD_AUTHOR']],
+                        'object_privacy_view' => BX_DOL_PG_ALL
+                    ]);
+
+                    $aResult[] = $aDataItem;
+                }
+                break;
+
+            case 'shipped':
+                foreach($aDataItems as $aDataItem) {
+                    $aLicense = $this->_oDb->getLicense(['type' => 'entry_id', 'entry_id' => $aDataItem['object_id'], 'newest' => true]);
+                    if(!empty($aLicense) && is_array($aLicense))
+                        $aDataItem['object_owner_id'] = $aLicense['profile_id'];
+
+                    $aResult[] = $aDataItem;
+                }
+                break;
+
+            case 'offer_added':
+            case 'offer_canceled':
+                foreach($aDataItems as $aDataItem) {
+                    $aDataItem['object_owner_id'] = $oAlert->aExtras['object_author_id'];
+
+                    $aResult[] = $aDataItem;
+                }
+                break;
+
+            case 'offer_accepted':
+            case 'offer_declined':
+                foreach($aDataItems as $aDataItem) {
+                    $aDataItem['object_owner_id'] = $oAlert->aExtras['offer_author_id'];
+
+                    $aResult[] = $aDataItem;
+                }
+                break;
+
+            default:
+                $aResult = $aDataItems;
+        }
+
+        return $aResult;
+    }
+
+    public function serviceGetNotificationsInterest($aEvent)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$iContentId = (int)$aEvent['object_id'];
+    	$aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return array();
+
+        $iInterestedId = (int)$aEvent['subobject_id'];
+        $aInterestedInfo = $this->_oDb->getInterested(array('type' => 'id', 'id' => $iInterestedId));
+        if(empty($aInterestedInfo) || !is_array($aInterestedInfo))
+            return array();
+
+        $sEntryUrl = '{bx_url_root}' . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iContentId);
+
+        return array(
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $aContentInfo[$CNF['FIELD_TITLE']],
+            'entry_author' => $aContentInfo[$CNF['FIELD_AUTHOR']],
+            'subentry_sample' => $CNF['T']['txt_sample_interest_single'],
+            'subentry_url' => '',
+            'lang_key' => '_bx_ads_txt_ntfs_subobject_interested', //may be empty or not specified. In this case the default one from Notification module will be used.
+        );
+    }
+
+    public function serviceGetNotificationsLicenseRegister($aEvent)
+    {
+        return $this->_serviceGetNotificationsByEntryAndAction($aEvent, 'license_register');
+    }
+
+    public function serviceGetNotificationsShipped($aEvent)
+    {
+        $aResult = $this->_serviceGetNotificationsByEntryAndAction($aEvent, 'shipped');
+        $aResult['entry_author'] = $aEvent['object_owner_id'];
+
+        return $aResult;
+    }
+
+    public function serviceGetNotificationsReceived($aEvent)
+    {
+        return $this->_serviceGetNotificationsByEntryAndAction($aEvent, 'received');
+    }
+
+    public function serviceGetNotificationsOfferAdded($aEvent)
+    {
+        return $this->_serviceGetNotificationsByOfferAndAction($aEvent, 'offer_added');
+    }
+
+    public function serviceGetNotificationsOfferAccepted($aEvent)
+    {
+        $aResult = $this->_serviceGetNotificationsByOfferAndAction($aEvent, 'offer_accepted');
+        $aResult['entry_author'] = $aEvent['object_owner_id'];
+
+        return $aResult;
+    }
+
+    public function serviceGetNotificationsOfferDeclined($aEvent)
+    {
+        $aResult = $this->_serviceGetNotificationsByOfferAndAction($aEvent, 'offer_declined');
+        $aResult['entry_author'] = $aEvent['object_owner_id'];
+
+        return $aResult;
+    }
+
+    public function serviceGetNotificationsOfferCanceled($aEvent)
+    {
+        return $this->_serviceGetNotificationsByOfferAndAction($aEvent, 'offer_canceled');
+    }
+
+    protected function _serviceGetNotificationsByEntryAndAction($aEvent, $sAction)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$iContentId = (int)$aEvent['object_id'];
+    	$aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return array();
+
+        $sEntryUrl = '{bx_url_root}' . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iContentId);
+
+        return array(
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $aContentInfo[$CNF['FIELD_TITLE']],
+            'entry_author' => $aContentInfo[$CNF['FIELD_AUTHOR']],
+            'subentry_sample' => '',
+            'subentry_url' => '',
+            'lang_key' => '_bx_ads_txt_ntfs_object_' . $sAction, //may be empty or not specified. In this case the default one from Notification module will be used.
+        );
+    }
+
+    protected function _serviceGetNotificationsByOfferAndAction($aEvent, $sAction)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$iOfferId = (int)$aEvent['object_id'];
+    	$aOfferInfo = $this->_oDb->getOffersBy(['type' => 'id', 'id' => $iOfferId]);
+        if(empty($aOfferInfo) || !is_array($aOfferInfo))
+            return array();
+
+        $iContentId = $aOfferInfo[$CNF['FIELD_OFR_CONTENT']];
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return array();
+
+        $sEntryUrl = '{bx_url_root}' . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iContentId);
+
+        return array(
+            'object_id' => $iContentId,
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $aContentInfo[$CNF['FIELD_TITLE']],
+            'entry_author' => $aContentInfo[$CNF['FIELD_AUTHOR']],
+            'subentry_sample' => '',
+            'subentry_url' => '',
+            'lang_key' => '_bx_ads_txt_ntfs_' . $sAction, //may be empty or not specified. In this case the default one from Notification module will be used.
+        );
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-page_blocks Page Blocks
+     * @subsubsection bx_ads-block_licenses block_licenses
+     * 
+     * @code bx_srv('bx_ads', 'block_licenses', [...]); @endcode
+     * 
+     * Get page block with a list of licenses purchased by currently logged member.
+     *
+     * @return an array describing a block to display on the site or false if there is no enough input data. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxAdsModule::serviceBlockLicenses
+     */
+    /** 
+     * @ref bx_ads-block_licenses "block_licenses"
+     */
+    public function serviceBlockLicenses() 
+    {
+        return $this->_getBlockLicenses();
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-page_blocks Page Blocks
+     * @subsubsection bx_ads-block_licenses_administration block_licenses_administration
+     * 
+     * @code bx_srv('bx_ads', 'block_licenses_administration', [...]); @endcode
+     * 
+     * Get page block with a list of all licenses. It's needed for moderators/administrators.
+     *
+     * @return an array describing a block to display on the site or false if there is no enough input data. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxAdsModule::serviceBlockLicensesAdministration
+     */
+    /** 
+     * @ref bx_ads-block_licenses "block_licenses"
+     */
+    public function serviceBlockLicensesAdministration() 
+    {
+        return $this->_getBlockLicenses('administration');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-page_blocks Page Blocks
+     * @subsubsection bx_ads-block_licenses_note block_licenses_note
+     * 
+     * @code bx_srv('bx_ads', 'block_licenses_note', [...]); @endcode
+     * 
+     * Get page block with a notice for licenses usage.
+     *
+     * @return HTML string with block content to display on the site.
+     * 
+     * @see BxAdsModule::serviceBlockLicensesNote
+     */
+    /** 
+     * @ref bx_ads-block_licenses_note "block_licenses_note"
+     */
+    public function serviceBlockLicensesNote()
+    {
+        return MsgBox(_t('_bx_ads_page_block_content_licenses_note'));
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-payments Payments
+     * @subsubsection bx_ads-get_payment_data get_payment_data
+     * 
+     * @code bx_srv('bx_ads', 'get_payment_data', [...]); @endcode
+     * 
+     * Get an array with module's description. Is needed for payments processing module.
+     * 
+     * @return an array with module's description.
+     * 
+     * @see BxAdsModule::serviceGetPaymentData
+     */
+    /** 
+     * @ref bx_ads-get_payment_data "get_payment_data"
+     */
+    public function serviceGetPaymentData()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oPermalink = BxDolPermalinks::getInstance();
+
+        $aResult = $this->_aModule;
+        $aResult['url_browse_order_common'] = BX_DOL_URL_ROOT . $oPermalink->permalink($CNF['URL_LICENSES_COMMON'], array('filter' => '{order}'));
+        $aResult['url_browse_order_administration'] = BX_DOL_URL_ROOT . $oPermalink->permalink($CNF['URL_LICENSES_ADMINISTRATION'], array('filter' => '{order}'));
+
+        return $aResult;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-payments Payments
+     * @subsubsection bx_ads-get_cart_item get_cart_item
+     * 
+     * @code bx_srv('bx_ads', 'get_cart_item', [...]); @endcode
+     * 
+     * Get an array with prodict's description. Is used in Shopping Cart in payments processing module.
+     * 
+     * @param $mixedItemId product's ID or Unique Name.
+     * @return an array with prodict's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxAdsModule::serviceGetCartItem
+     */
+    /** 
+     * @ref bx_ads-get_cart_item "get_cart_item"
+     */
+    public function serviceGetCartItem($mixedItemId)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        if(!$mixedItemId)
+            return array();
+
+        if(is_numeric($mixedItemId))
+            $aItem = $this->_oDb->getContentInfoById((int)$mixedItemId);
+        else
+            $aItem = $this->_oDb->getContentInfoByName($mixedItemId);
+
+        if(empty($aItem) || !is_array($aItem))
+            return array();
+
+        $iItemId = (int)$aItem[$CNF['FIELD_ID']];
+        $fItemPrice = (float)$aItem[$CNF['FIELD_PRICE']];
+
+        if($this->isAuction($aItem)) {
+            $aOffer = $this->_oDb->getOffersBy(array(
+                'type' => 'accepted', 
+                'content_id' => $iItemId, 
+                'status' => BX_ADS_OFFER_STATUS_ACCEPTED
+            ));
+
+            if(!empty($aOffer) && is_array($aOffer))
+                $fItemPrice = (float)$aOffer[$CNF['FIELD_OFR_AMOUNT']];
+        }
+
+        return array (
+            'id' => $iItemId,
+            'author_id' => $aItem[$CNF['FIELD_AUTHOR']],
+            'name' => $aItem[$CNF['FIELD_NAME']],
+            'title' => $aItem[$CNF['FIELD_TITLE']],
+            'description' => $aItem[$CNF['FIELD_TEXT']],
+            'url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'], array('id' => $aItem[$CNF['FIELD_ID']])),
+            'price_single' => $fItemPrice,
+            'price_recurring' => '',
+            'period_recurring' => 0,
+            'period_unit_recurring' => '',
+            'trial_recurring' => ''
+        );
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-payments Payments
+     * @subsubsection bx_ads-get_cart_items get_cart_items
+     * 
+     * @code bx_srv('bx_ads', 'get_cart_items', [...]); @endcode
+     * 
+     * Get an array with prodicts' descriptions by seller. Is used in Manual Order Processing in payments processing module.
+     * 
+     * @param $iSellerId seller ID.
+     * @return an array with prodicts' descriptions. Empty array is returned if something is wrong or seller doesn't have any products.
+     * 
+     * @see BxAdsModule::serviceGetCartItems
+     */
+    /** 
+     * @ref bx_ads-get_cart_items "get_cart_items"
+     */
+    public function serviceGetCartItems($iSellerId)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        $iSellerId = (int)$iSellerId;
+        if(empty($iSellerId))
+            return array();
+
+        $aItems = $this->_oDb->getEntriesByAuthor($iSellerId);
+
+        $aResult = array();
+        foreach($aItems as $aItem) {
+            if($aItem[$CNF['FIELD_STATUS']] != BX_BASE_MOD_TEXT_STATUS_ACTIVE || empty($aItem[$CNF['FIELD_QUANTITY']]))
+                continue;
+
+            $aResult[] = array(
+                'id' => $aItem[$CNF['FIELD_ID']],
+                'author_id' => $aItem[$CNF['FIELD_AUTHOR']],
+                'name' => $aItem[$CNF['FIELD_NAME']],
+                'title' => $aItem[$CNF['FIELD_TITLE']],
+                'description' => $aItem[$CNF['FIELD_TEXT']],
+                'url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'], array('id' => $aItem[$CNF['FIELD_ID']])),
+                'price_single' => $aItem[$CNF['FIELD_PRICE_SINGLE']],
+                'price_recurring' => '',
+                'period_recurring' => 0,
+                'period_unit_recurring' => '',
+                'trial_recurring' => ''
+            );
+        }
+
+        return $aResult;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-payments Payments
+     * @subsubsection bx_ads-authorize_cart_item authorize_cart_item
+     * 
+     * @code bx_srv('bx_ads', 'authorize_cart_item', [...]); @endcode
+     * 
+     * Authorize the order to process a single time payment inside the Ads module in future. Is called with payment processing module after the order was authorized there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemId item ID.
+     * @param $iItemCount the number of purchased items.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @return an array with authorize prodict's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxAdsModule::serviceAuthorizeCartItem
+     */
+    /** 
+     * @ref bx_ads-authorize_cart_item "authorize_cart_item"
+     */
+    public function serviceAuthorizeCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$aItem = $this->serviceGetCartItem($iItemId);
+        if(empty($aItem) || !is_array($aItem))
+            return [];
+
+        $aEntry = $this->_oDb->getContentInfoById($iItemId);
+        if(empty($aEntry) || !is_array($aEntry))
+            return [];
+
+        bx_alert($this->getName(), 'order_authorize', 0, false, [
+            'product_id' => $iItemId,
+            'profile_id' => $iClientId,
+            'order' => $sOrder,
+            'count' => $iItemCount
+        ]);
+
+        return $aItem;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-payments Payments
+     * @subsubsection bx_ads-register_cart_item register_cart_item
+     * 
+     * @code bx_srv('bx_ads', 'register_cart_item', [...]); @endcode
+     * 
+     * Register a processed single time payment inside the Ads module. Is called with payment processing module after the payment was registered there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemId item ID.
+     * @param $iItemCount the number of purchased items.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @param $sLicense license number genereted with payment processing module for internal usage
+     * @return an array with purchased prodict's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxAdsModule::serviceRegisterCartItem
+     */
+    /** 
+     * @ref bx_ads-register_cart_item "register_cart_item"
+     */
+    public function serviceRegisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $sModule = $this->getName();
+
+    	$aItem = $this->serviceGetCartItem($iItemId);
+        if(empty($aItem) || !is_array($aItem))
+            return array();
+
+        $aEntry = $this->_oDb->getContentInfoById($iItemId);
+        $iEntryQnt = (int)$aEntry[$CNF['FIELD_QUANTITY']];
+        if(empty($aEntry) || !is_array($aEntry) || ($iEntryQnt - $iItemCount) < 0)
+            return array();
+
+        if(!$this->_oDb->registerLicense($iClientId, $iItemId, $iItemCount, $sOrder, $sLicense))
+            return array();
+
+        $iEntryQnt -= $iItemCount;
+        $this->_oDb->updateEntriesBy(array(
+            $CNF['FIELD_QUANTITY'] => $iEntryQnt,
+            $CNF['FIELD_STATUS'] => $iEntryQnt == 0 ? BX_ADS_STATUS_SOLD : BX_BASE_MOD_TEXT_STATUS_ACTIVE,
+            $CNF['FIELD_SOLD'] => $iEntryQnt == 0 ? time() : 0,
+        ), array($CNF['FIELD_ID'] => $iItemId));
+
+        bx_alert($sModule, 'license_register', 0, false, array(
+            'product_id' => $iItemId,
+            'profile_id' => $iClientId,
+            'order' => $sOrder,
+            'license' => $sLicense,
+            'count' => $iItemCount
+        ));
+
+        if($iEntryQnt == 0) {
+            $aParams = $this->_alertParams($aEntry);
+            bx_alert($sModule, 'sold', $iItemId, false, $aParams);
+        }
+
+        $oClient = BxDolProfile::getInstanceMagic($iClientId);
+        $oSeller = BxDolProfile::getInstanceMagic($iSellerId);
+        $sSellerUrl = $oSeller->getUrl();
+        $sSellerName = $oSeller->getDisplayName();
+
+        $sNote = $aEntry[$CNF['FIELD_NOTES_PURCHASED']];
+        if(empty($sNote))
+            $sNote = _t('_bx_ads_txt_purchased_note', $sSellerUrl, $sSellerName);
+
+        $sEmailTemplate = $CNF['ETEMPLATE_PURCHASED'];
+        $aEmailParams = [
+            'client_name' => $oClient->getDisplayName(),
+            'entry_name' => $aEntry[$CNF['FIELD_TITLE']],
+            'entry_url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'], ['id' => $aEntry[$CNF['FIELD_ID']]]),
+            'vendor_url' => $sSellerUrl,
+            'vendor_name' => $sSellerName,
+            'count' => (int)$iItemCount,
+            'license' => $sLicense,
+            'notes' => $sNote,
+        ];
+
+        $bCancel = false;
+        bx_alert($sModule, 'license_register_notif', 0, false, [
+            'entry_id' => $iItemId,
+            'order' => $sOrder,
+            'recipient_id' => &$iClientId,
+            'email_template' => &$sEmailTemplate,
+            'email_params' => &$aEmailParams,
+            'cancel' => &$bCancel
+        ]);
+
+        if(!$bCancel)
+            sendMailTemplate($sEmailTemplate, 0, $iClientId, $aEmailParams);
+
+        return $aItem;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-payments Payments
+     * @subsubsection bx_ads-authorize_subscription_item authorize_subscription_item
+     * 
+     * @code bx_srv('bx_ads', 'authorize_subscription_item', [...]); @endcode
+     * 
+     * Authorize the order to process a subscription (recurring payment) inside the Ads module in future. Is called with payment processing module after the order for subscription was authorized there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemId item ID.
+     * @param $iItemCount the number of purchased items.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @return an array with authorize prodict's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxAdsModule::serviceAuthorizeSubscriptionItem
+     */
+    /** 
+     * @ref bx_ads-authorize_subscription_item "authorize_subscription_item"
+     */
+    public function serviceAuthorizeSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder)
+    {
+        return [];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-payments Payments
+     * @subsubsection bx_ads-register_subscription_item register_subscription_item
+     * 
+     * @code bx_srv('bx_ads', 'register_subscription_item', [...]); @endcode
+     * 
+     * Register a processed subscription (recurring payment) inside the Ads module. Is called with payment processing module after the subscription was registered there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemId item ID.
+     * @param $iItemCount the number of purchased items.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @param $sLicense license number genereted with payment processing module for internal usage
+     * @return an array with subscribed prodict's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxAdsModule::serviceRegisterSubscriptionItem
+     */
+    /** 
+     * @ref bx_ads-register_subscription_item "register_subscription_item"
+     */
+    public function serviceRegisterSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        return [];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-payments Payments
+     * @subsubsection bx_ads-reregister_cart_item reregister_cart_item
+     * 
+     * @code bx_srv('bx_ads', 'reregister_cart_item', [...]); @endcode
+     * 
+     * Reregister a single time payment inside the Ads module. Is called with payment processing module after the payment was reregistered there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemIdOld old item ID.
+     * @param $iItemIdNew new item ID.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @return an array with purchased prodict's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxAdsModule::serviceReregisterCartItem
+     */
+    /** 
+     * @ref bx_ads-reregister_cart_item "reregister_cart_item"
+     */
+    public function serviceReregisterCartItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
+    {
+        return array();
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-payments Payments
+     * @subsubsection bx_ads-reregister_subscription_item reregister_subscription_item
+     * 
+     * @code bx_srv('bx_ads', 'reregister_subscription_item', [...]); @endcode
+     * 
+     * Reregister a subscription (recurring payment) inside the Ads module. Is called with payment processing module after the subscription was reregistered there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemIdOld old item ID.
+     * @param $iItemIdNew new item ID.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @return an array with subscribed prodict's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxAdsModule::serviceReregisterSubscriptionItem
+     */
+    /** 
+     * @ref bx_ads-reregister_subscription_item "reregister_subscription_item"
+     */
+    public function serviceReregisterSubscriptionItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
+    {
+        return array();
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-payments Payments
+     * @subsubsection bx_ads-unregister_cart_item unregister_cart_item
+     * 
+     * @code bx_srv('bx_ads', 'unregister_cart_item', [...]); @endcode
+     * 
+     * Unregister an earlier processed single time payment inside the Ads module. Is called with payment processing module after the payment was unregistered there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemId item ID.
+     * @param $iItemCount the number of purchased items.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @param $sLicense license number genereted with payment processing module for internal usage
+     * @return boolean value determining where the payment was unregistered or not.
+     * 
+     * @see BxAdsModule::serviceUnregisterCartItem
+     */
+    /** 
+     * @ref bx_ads-unregister_cart_item "unregister_cart_item"
+     */
+    public function serviceUnregisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        if(!$this->_oDb->unregisterLicense($iClientId, $iItemId, $sOrder, $sLicense))
+            return false;
+
+        bx_alert($this->getName(), 'license_unregister', 0, false, array(
+            'product_id' => $iItemId,
+            'profile_id' => $iClientId,
+            'order' => $sOrder,
+            'license' => $sLicense,
+            'count' => $iItemCount
+        ));
+
+    	return true;;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-payments Payments
+     * @subsubsection bx_ads-unregister_subscription_item unregister_subscription_item
+     * 
+     * @code bx_srv('bx_ads', 'unregister_subscription_item', [...]); @endcode
+     * 
+     * Unregister an earlier processed subscription (recurring payment) inside the Ads module. Is called with payment processing module after the subscription was unregistered there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemId item ID.
+     * @param $iItemCount the number of purchased items.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @param $sLicense license number genereted with payment processing module for internal usage
+     * @return boolean value determining where the subscription was unregistered or not.
+     * 
+     * @see BxAdsModule::serviceUnregisterSubscriptionItem
+     */
+    /** 
+     * @ref bx_ads-unregister_subscription_item "unregister_subscription_item"
+     */
+    public function serviceUnregisterSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+    	return true; 
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_ads Ads
+     * @subsection bx_ads-payments Payments
+     * @subsubsection bx_ads-cancel_subscription_item cancel_subscription_item
+     * 
+     * @code bx_srv('bx_ads', 'cancel_subscription_item', [...]); @endcode
+     * 
+     * Cancel an earlier processed subscription (recurring payment) inside the Ads module. Is called with payment processing module after the subscription was canceled there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemId item ID.
+     * @param $iItemCount the number of purchased items.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @return boolean value determining where the subscription was canceled or not.
+     * 
+     * @see BxAdsModule::serviceCancelSubscriptionItem
+     */
+    /** 
+     * @ref bx_ads-cancel_subscription_item "cancel_subscription_item"
+     */
+    public function serviceCancelSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder)
+    {
+    	return true;
+    }
+
+    public function serviceGetOffersCount($sStatus = '')
+    {
+        if(!$this->_oConfig->isAuction())
+            return 0;
+
+        if(empty($sStatus) || !in_array($sStatus, $this->_aOfferStatuses))
+            $sStatus = BX_ADS_OFFER_STATUS_AWAITING;
+
+        $iUserId = bx_get_logged_profile_id();
+        return $this->_oDb->getOffersBy(array('type' => 'content_author_id', 'author_id' => $iUserId, 'status' => $sStatus, 'count' => true));
+    }
+
+    public function serviceGetLiveUpdates($sStatus, $aMenuItemParent, $aMenuItemChild, $iCount = 0)
+    {
+        if(!in_array($sStatus, $this->_aOfferStatuses))
+            return false;
+
+        $iUserId = bx_get_logged_profile_id();
+        $iCountNew = $this->_oDb->getOffersBy(array('type' => 'content_author_id', 'author_id' => $iUserId, 'status' => $sStatus, 'count' => true));
+        if($iCountNew == $iCount)
+            return false;
+
+        return array(
+            'count' => $iCountNew, // required
+            'method' => 'bx_menu_show_live_update(oData)', // required
+            'data' => array(
+                'code' => BxDolTemplate::getInstance()->parseHtmlByTemplateName('menu_item_addon', array(
+                    'content' => '{count}'
+                )),
+            'mi_parent' => $aMenuItemParent,
+            'mi_child' => $aMenuItemChild
+            ),  // optional, may have some additional data to be passed in JS method provided using 'method' param above.
+    	);
+    }
+
+    public function serviceOffers()       
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$this->_oConfig->isAuction())
+            return '';
+
+        $oGrid = BxDolGrid::getObjectInstance($CNF['OBJECT_GRID_OFFERS_ALL']);
+        if(!$oGrid)
+            return '';
+
+        return $oGrid->getCode();
+    }
+
+    public function serviceEntityOffers($iContentId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$this->_oConfig->isAuction())
+            return '';
+
+        $oGrid = BxDolGrid::getObjectInstance($CNF['OBJECT_GRID_OFFERS']);
+        if(!$oGrid)
+            return '';
+
+        if(empty($iContentId) && ($_iContentId = bx_get('id')) !== false)
+            $iContentId = (int)$_iContentId;
+
+        $oGrid->setContentId($iContentId);
+        return $oGrid->getCode();
+    }
+
+    public function serviceEntityOfferAccepted($iContentId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$this->_oConfig->isAuction())
+            return '';
+
+        $iUserId = bx_get_logged_profile_id();
+
+        if(empty($iContentId) && ($_iContentId = bx_get('id')) !== false)
+            $iContentId = (int)$_iContentId;
+
+        $aContent = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContent) || !is_array($aContent) || $aContent[$CNF['FIELD_QUANTITY']] <= 0)
+            return '';
+
+        $aOffer = $this->_oDb->getOffersBy(array(
+            'type' => 'content_and_author_ids', 
+            'content_id' => $iContentId, 
+            'author_id' => $iUserId,
+            'status' => BX_ADS_OFFER_STATUS_ACCEPTED
+        ));
+
+        if(empty($aOffer) || !is_array($aOffer))
+            return '';
+
+        return $this->_oTemplate->entryOfferAccepted($iUserId, $aContent, $aOffer);
+    }
+
+    public function isEntryActive($aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if($aContentInfo[$CNF['FIELD_AUTHOR']] == bx_get_logged_profile_id() || $this->_isModerator())
+            return true;
+
+        if(isset($CNF['FIELD_STATUS']) && !in_array($aContentInfo[$CNF['FIELD_STATUS']], array(BX_BASE_MOD_TEXT_STATUS_ACTIVE, BX_ADS_STATUS_OFFER, BX_ADS_STATUS_SOLD)))
+            return false;
+
+        if(isset($CNF['FIELD_STATUS_ADMIN']) && $aContentInfo[$CNF['FIELD_STATUS_ADMIN']] != 'active')
+            return false;
+
+        return true;        
+    }
+
+    public function isAuction($aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return $this->_oConfig->isAuction() && (int)$aContentInfo[$CNF['FIELD_AUCTION']] != 0;
+    }
+
+    public function isAllowedMakeOffer($mixedContent, $isPerformAction = false)
+    {
+        return $this->checkAllowedMakeOffer($mixedContent, $isPerformAction) === CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function checkAllowedMakeOffer($mixedContent, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $sTxtError = '_sys_txt_access_denied';
+
+        $iProfileId = bx_get_logged_profile_id();
+
+        if(!is_array($mixedContent))
+            $mixedContent = $this->_oDb->getContentInfoById((int)$mixedContent);
+
+        if(empty($mixedContent) || !is_array($mixedContent))
+            return _t($sTxtError);
+
+        if(!$this->isAuction($mixedContent) || (int)$mixedContent[$CNF['FIELD_QUANTITY']] <= 0)
+            return _t($sTxtError);
+
+        if($mixedContent[$CNF['FIELD_AUTHOR']] == $iProfileId)
+            return _t($sTxtError);
+
+        $aCheck = checkActionModule($iProfileId, 'make offer', $this->getName(), $isPerformAction);
+        if($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED)
+            return $aCheck[CHECK_ACTION_MESSAGE];
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function isAllowedViewOffers($mixedContent, $isPerformAction = false)
+    {
+        return $this->checkAllowedViewOffers($mixedContent, $isPerformAction) === CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function checkAllowedViewOffers($mixedContent, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $sTxtError = '_sys_txt_access_denied';
+
+        if(!is_array($mixedContent))
+            $mixedContent = $this->_oDb->getContentInfoById((int)$mixedContent);
+
+        if(empty($mixedContent) || !is_array($mixedContent))
+            return _t($sTxtError);
+
+        if(!$this->isAuction($mixedContent))
+            return _t($sTxtError);
+
+        if($this->_isModerator())
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        if($mixedContent[$CNF['FIELD_AUTHOR']] == bx_get_logged_profile_id())
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return _t($sTxtError);
+    }
+
+    public function isAllowedMarkShipped($mixedContent, $isPerformAction = false)
+    {
+        return $this->checkAllowedMarkShipped($mixedContent, $isPerformAction) === CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function checkAllowedMarkShipped($mixedContent, $isPerformAction = false)
+    {
+        return $this->checkAllowedMarkShippedForProfile($mixedContent, $isPerformAction);
+    }
+
+    public function checkAllowedMarkShippedForProfile($mixedContent, $isPerformAction = false, $iProfileId = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $sTxtError = '_sys_txt_access_denied';
+
+        if(!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+                
+        if(!is_array($mixedContent))
+            $mixedContent = $this->_oDb->getContentInfoById((int)$mixedContent);
+
+        if(empty($mixedContent) || !is_array($mixedContent))
+            return _t($sTxtError);
+
+        if((int)$mixedContent[$CNF['FIELD_SHIPPED']] != 0 || $mixedContent[$CNF['FIELD_AUTHOR']] != $iProfileId)
+            return _t($sTxtError);
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function isAllowedMarkReceived($mixedContent, $isPerformAction = false)
+    {
+        return $this->checkAllowedMarkReceived($mixedContent, $isPerformAction) === CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function checkAllowedMarkReceived($mixedContent, $isPerformAction = false)
+    {
+        return $this->checkAllowedMarkReceivedForProfile($mixedContent, $isPerformAction);
+    }
+
+    public function checkAllowedMarkReceivedForProfile($mixedContent, $isPerformAction = false, $iProfileId = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $sTxtError = '_sys_txt_access_denied';
+
+        if(!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        if(!is_array($mixedContent))
+            $mixedContent = $this->_oDb->getContentInfoById((int)$mixedContent);
+
+        if(empty($mixedContent) || !is_array($mixedContent))
+            return _t($sTxtError);
+
+        if((int)$mixedContent[$CNF['FIELD_RECEIVED']] != 0 || !$this->_oDb->hasLicense($iProfileId, $mixedContent[$CNF['FIELD_ID']]))
+            return _t($sTxtError);
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function onPublished($iContentId)
+    {
+        $this->serviceUpdateCategoriesStats($iContentId);
+
+        parent::onPublished($iContentId);
+    }
+
+    public function onOfferAdded($iOfferId, &$aResult)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aOfferInfo = $this->_oDb->getOffersBy(array('type' => 'id', 'id' => $iOfferId));
+        if(empty($aOfferInfo) || !is_array($aOfferInfo))
+            return;
+
+        $iContentId = (int)$aOfferInfo[$CNF['FIELD_OFR_CONTENT']];
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return;
+
+        $iViewer = bx_get_logged_profile_id();        
+        $oViewer = BxDolProfile::getInstanceMagic($iViewer);
+
+        if(getParam($CNF['PARAM_USE_IIN']) == 'on')
+            sendMailTemplate($CNF['ETEMPLATE_OFFER_ADDED'], 0, $aContentInfo[$CNF['FIELD_AUTHOR']], array(
+                'viewer_name' => $oViewer->getDisplayName(),
+                'viewer_url' => $oViewer->getUrl(),
+                'entry_name' => $aContentInfo[$CNF['FIELD_TITLE']],
+                'entry_url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php', array(
+                    'i' => $CNF['URI_VIEW_ENTRY'], 
+                    $CNF['FIELD_ID'] => $iContentId
+                ))
+            ));
+
+        $aParams = $this->_alertParamsOffer($aContentInfo, $aOfferInfo);
+        $aParams['override_result'] = &$aResult;
+        bx_alert($this->getName(), 'offer_added', $iOfferId, $aOfferInfo[$CNF['FIELD_OFR_AUTHOR']], $aParams);
+    }
+
+    public function onOfferAccepted($iOfferId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aOfferInfo = $this->_oDb->getOffersBy(array('type' => 'id', 'id' => $iOfferId));
+        if(empty($aOfferInfo) || !is_array($aOfferInfo))
+            return;
+
+        $iContentId = (int)$aOfferInfo[$CNF['FIELD_OFR_CONTENT']];
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return;
+
+        if(!$this->_oDb->updateEntriesBy(array($CNF['FIELD_STATUS'] => BX_ADS_STATUS_OFFER), array($CNF['FIELD_ID'] => $iContentId)))
+            return;
+
+        $iOfferer = (int)$aOfferInfo[$CNF['FIELD_OFR_AUTHOR']];
+        $oOfferer = BxDolProfile::getInstanceMagic($iOfferer);
+
+        if(getParam($CNF['PARAM_USE_IIN']) == 'on')
+            sendMailTemplate($CNF['ETEMPLATE_OFFER_ACCEPTED'], 0, $iOfferer, array(
+                'offerer_name' => $oOfferer->getDisplayName(),
+                'offerer_url' => $oOfferer->getUrl(),
+                'entry_name' => $aContentInfo[$CNF['FIELD_TITLE']],
+                'entry_url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php', array(
+                    'i' => $CNF['URI_VIEW_ENTRY'], 
+                    $CNF['FIELD_ID'] => $iContentId
+                ))
+            ));
+
+        $aParams = $this->_alertParamsOffer($aContentInfo, $aOfferInfo);
+        bx_alert($this->getName(), 'offer_accepted', $iOfferId, $aContentInfo[$CNF['FIELD_AUTHOR']], $aParams);
+    }
+
+    public function onOfferDeclined($iOfferId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aOfferInfo = $this->_oDb->getOffersBy(array('type' => 'id', 'id' => $iOfferId));
+        if(empty($aOfferInfo) || !is_array($aOfferInfo))
+            return;
+
+        $iContentId = (int)$aOfferInfo[$CNF['FIELD_OFR_CONTENT']];
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return;
+
+        $iOfferer = (int)$aOfferInfo[$CNF['FIELD_OFR_AUTHOR']];
+        $oOfferer = BxDolProfile::getInstanceMagic($iOfferer);
+
+        if(getParam($CNF['PARAM_USE_IIN']) == 'on')
+            sendMailTemplate($CNF['ETEMPLATE_OFFER_DECLINED'], 0, $iOfferer, array(
+                'offerer_name' => $oOfferer->getDisplayName(),
+                'offerer_url' => $oOfferer->getUrl(),
+                'entry_name' => $aContentInfo[$CNF['FIELD_TITLE']],
+                'entry_url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php', array(
+                    'i' => $CNF['URI_VIEW_ENTRY'], 
+                    $CNF['FIELD_ID'] => $iContentId
+                ))
+            ));
+
+        $aParams = $this->_alertParamsOffer($aContentInfo, $aOfferInfo);
+        bx_alert($this->getName(), 'offer_declined', $iOfferId, $aContentInfo[$CNF['FIELD_AUTHOR']], $aParams);
+    }
+
+    public function onOfferCanceled($iOfferId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aOfferInfo = $this->_oDb->getOffersBy(array('type' => 'id', 'id' => $iOfferId));
+        if(empty($aOfferInfo) || !is_array($aOfferInfo))
+            return;
+
+        $iContentId = (int)$aOfferInfo[$CNF['FIELD_OFR_CONTENT']];
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return;
+
+        if(!$this->_oDb->updateEntriesBy(array($CNF['FIELD_STATUS'] => BX_BASE_MOD_TEXT_STATUS_ACTIVE), array($CNF['FIELD_ID'] => $iContentId)))
+            return;
+
+        $iOfferer = (int)$aOfferInfo[$CNF['FIELD_OFR_AUTHOR']];
+        $oOfferer = BxDolProfile::getInstanceMagic($iOfferer);
+
+        if(getParam($CNF['PARAM_USE_IIN']) == 'on')
+            sendMailTemplate($CNF['ETEMPLATE_OFFER_CANCELED'], 0, (int)$aContentInfo[$CNF['FIELD_AUTHOR']], array(
+                'offerer_name' => $oOfferer->getDisplayName(),
+                'offerer_url' => $oOfferer->getUrl(),
+                'entry_name' => $aContentInfo[$CNF['FIELD_TITLE']],
+                'entry_url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php', array(
+                    'i' => $CNF['URI_VIEW_ENTRY'], 
+                    $CNF['FIELD_ID'] => $iContentId
+                ))
+            ));
+
+        $aParams = $this->_alertParamsOffer($aContentInfo, $aOfferInfo);
+        bx_alert($this->getName(), 'offer_canceled', $iOfferId, $aOfferInfo[$CNF['FIELD_OFR_AUTHOR']], $aParams);
+    }
+
+    /**
+     * Common methods.
+     */
+    public function onShipped($mixedContent, $iProfileSrc = 0, $iProfileDst = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!is_array($mixedContent))
+            $mixedContent = $this->_oDb->getContentInfoById((int)$mixedContent);
+        $iContentId = (int)$mixedContent[$CNF['FIELD_ID']];
+
+        if(empty($iProfileSrc))
+            $iProfileSrc = (int)$mixedContent[$CNF['FIELD_AUTHOR']];
+
+        $oProfileSrc = BxDolProfile::getInstanceMagic($iProfileSrc);
+
+        $aOffer = $this->_oDb->getOffersBy(array('type' => 'accepted', 'content_id' => $iContentId));
+        $bOffer = !empty($aOffer) && is_array($aOffer);
+
+        if(empty($iProfileDst) && $bOffer)
+            $iProfileDst = (int)$aOffer[$CNF['FIELD_OFR_AUTHOR']];        
+
+        if(!empty($oProfileSrc) && !empty($iProfileDst) && getParam($CNF['PARAM_USE_IIN']) == 'on')
+            sendMailTemplate($CNF['ETEMPLATE_SHIPPED'], 0, $iProfileDst, array(
+                'vendor_name' => $oProfileSrc->getDisplayName(),
+                'vendor_url' => $oProfileSrc->getUrl(),
+                'entry_name' => $mixedContent[$CNF['FIELD_TITLE']],
+                'entry_url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php', array(
+                    'i' => $CNF['URI_VIEW_ENTRY'], 
+                    $CNF['FIELD_ID'] => $iContentId
+                ))
+            ));
+
+        $aParams = $this->_alertParams($mixedContent);
+        $aParams = array_merge($aParams, array(
+            'profile_src' => $iProfileSrc,
+            'profile_dst' => $iProfileDst,
+            'offer_id' => $bOffer ? (int)$aOffer[$CNF['FIELD_OFR_ID']] : 0,
+        ));
+
+        bx_alert($this->getName(), 'shipped', $iContentId, false, $aParams);
+    }
+
+    public function onReceived($mixedContent, $iProfileSrc = 0, $iProfileDst = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!is_array($mixedContent))
+            $mixedContent = $this->_oDb->getContentInfoById((int)$mixedContent);
+        $iContentId = (int)$mixedContent[$CNF['FIELD_ID']];
+
+        if(empty($iProfileDst))
+            $iProfileDst = (int)$mixedContent[$CNF['FIELD_AUTHOR']];
+
+        $aOffer = $this->_oDb->getOffersBy(array('type' => 'accepted', 'content_id' => $iContentId));
+        $bOffer = !empty($aOffer) && is_array($aOffer);
+
+        if(empty($iProfileSrc) && $bOffer)
+            $iProfileSrc = (int)$aOffer[$CNF['FIELD_OFR_AUTHOR']];
+        $oProfileSrc = BxDolProfile::getInstanceMagic($iProfileSrc);
+
+        if(!empty($iProfileSrc) && !empty($iProfileDst) && getParam($CNF['PARAM_USE_IIN']) == 'on')
+            sendMailTemplate($CNF['ETEMPLATE_RECEIVED'], 0, $iProfileDst, array(
+                'client_name' => $oProfileSrc->getDisplayName(),
+                'client_url' => $oProfileSrc->getUrl(),
+                'entry_name' => $mixedContent[$CNF['FIELD_TITLE']],
+                'entry_url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php', array(
+                    'i' => $CNF['URI_VIEW_ENTRY'], 
+                    $CNF['FIELD_ID'] => $iContentId
+                ))
+            ));
+
+        $aParams = $this->_alertParams($mixedContent);
+        $aParams = array_merge($aParams, array(
+            'profile_src' => $iProfileSrc,
+            'profile_dst' => $iProfileDst,
+            'offer_id' => $bOffer ? (int)$aOffer[$CNF['FIELD_OFR_ID']] : 0,
+        ));
+
+        bx_alert($this->getName(), 'received', $iContentId, false, $aParams);
+    }
+
+    public function offerAccept($iId) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$this->_oDb->updateOffer(array($CNF['FIELD_OFR_STATUS'] => BX_ADS_OFFER_STATUS_ACCEPTED), array($CNF['FIELD_OFR_ID'] => $iId)))
+            return false;
+    
+        $this->onOfferAccepted($iId);
+        return true;        
+    }
+
+    public function offerDecline($iId) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$this->_oDb->updateOffer(array($CNF['FIELD_OFR_STATUS'] => BX_ADS_OFFER_STATUS_DECLINED), array($CNF['FIELD_OFR_ID'] => $iId)))
+            return false;
+    
+        $this->onOfferDeclined($iId);
+        return true;        
+    }
+
+    public function offerCancel($iId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$this->_oDb->updateOffer(array($CNF['FIELD_OFR_STATUS'] => BX_ADS_OFFER_STATUS_CANCELED), array($CNF['FIELD_OFR_ID'] => $iId)))
+            return false;
+
+        $this->onOfferCanceled($iId);
+        return true;
+    }
+    
+    public function offerPay($iId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aOffer = $this->_oDb->getOffersBy(array('type' => 'id', 'id' => $iId));
+        if(empty($aOffer) || !is_array($aOffer))
+            return false;
+
+        $iContent = (int)$aOffer[$CNF['FIELD_OFR_CONTENT']];
+        $aContent = $this->_oDb->getContentInfoById($iContent);
+        $iContentAuthor = (int)$aContent[$CNF['FIELD_AUTHOR']];
+
+        $aReturn = array(
+            'redirect' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php', array(
+                'i' => $CNF['URI_VIEW_ENTRY'], 
+                $CNF['FIELD_ID'] => $aOffer[$CNF['FIELD_OFR_CONTENT']]
+            ))
+        );
+
+        $oPayments = BxDolPayments::getInstance();
+        $aResult = $oPayments->addToCart($iContentAuthor, $this->getName(), $iContent, $aOffer[$CNF['FIELD_OFR_QUANTITY']]);
+        if(!empty($aResult) && is_array($aResult)) {
+            if(!empty($aResult['message']))
+                $aReturn['msg'] = $aResult['message'];
+
+            if(isset($aResult['code']) && (int)$aResult['code'] == 0)
+                $aReturn['redirect'] = $oPayments->getCartUrl($iContentAuthor);
+        }
+
+        return $aReturn;
+    }
+
+    public function processMetasAdd($iContentId)
+    {
+        if(!parent::processMetasAdd($iContentId))
+            return false;
+
+        $CNF = &$this->_oConfig->CNF;
+
+        $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS']);
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+
+        $aCategoryTypes = $this->_oDb->getCategoryTypes(array('type' => 'all'));
+        foreach($aCategoryTypes as $aCategoryType)
+            $oMetatags->metaAddAuto($iContentId, $aContentInfo, $CNF, $aCategoryType['display_add']);
+
+        return true;
+    }
+
+    public function processMetasEdit($iContentId, $oForm)
+    {
+        if(!parent::processMetasEdit($iContentId, $oForm))
+            return false;
+        
+        $CNF = &$this->_oConfig->CNF;
+
+        $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS']);
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        
+        $aCategoryTypes = $this->_oDb->getCategoryTypes(array('type' => 'all'));
+        foreach($aCategoryTypes as $aCategoryType)
+            $oMetatags->metaAddAuto($iContentId, $aContentInfo, $CNF, $aCategoryType['display_edit']);
+
+        return true;
+    }
+
+    public function getCategoryDisplay($sDisplayType, $iCategory = 0)
+    {
+        if(empty($iCategory) && bx_get('category') !== false)
+            $iCategory = (int)bx_get('category');
+
+        if(empty($iCategory))
+            return false;
+
+        $aCategory = $this->_oDb->getCategories(array('type' => 'id_full', 'id' => $iCategory));
+
+        $sKey = 'type_display_' . $sDisplayType;
+        if(empty($aCategory[$sKey]))
+            return false;
+
+        return $aCategory[$sKey];
+    }
+
+
+    /**
+     * Internal methods.
+     */
+    protected function _actionMarkAs($sAction)
+    {
+        $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        if(($mixedResult = $this->serviceMarkAs($sAction, $iContentId)) !== true)
+            return array('msg' => $mixedResult); 
+
+        return array(
+            'reload' => 1
+        );
+    }
+
+    protected function _actionChangeStatus($sStatus)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+
+        if(($mixedResult = $this->checkAllowedEdit($aContentInfo)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return array('msg' => $mixedResult);
+
+        if(!$this->_oDb->updateEntriesBy(array($CNF['FIELD_STATUS'] => $sStatus), array($CNF['FIELD_ID'] => $iContentId)))
+            return array('msg' => _t('_bx_ads_txt_err_cannot_perform_action'));
+
+        $this->serviceUpdateCategoriesStats($aContentInfo);
+
+        return array(
+            'reload' => 1
+        );
+    }
+
+    protected function _serviceEntityForm ($sFormMethod, $iContentId = 0, $sDisplay = false, $sCheckFunction = false, $bErrorMsg = true)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $mixedContent = $this->_getContent($iContentId, true);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        $sDisplayType = false;
+        switch($sFormMethod) {
+            case 'editDataForm':
+                $sDisplayType = 'edit';
+                break;
+            case 'viewDataForm':
+            case 'viewDataEntry':
+                $sDisplayType = 'view';
+                break;
+        }
+
+        if($sDisplayType !== false && ($sDisplayNew = $this->getCategoryDisplay($sDisplayType, $aContentInfo[$CNF['FIELD_CATEGORY']])) !== false)
+            $sDisplay = $sDisplayNew;
+
+        return parent::_serviceEntityForm ($sFormMethod, $iContentId, $sDisplay, $sCheckFunction, $bErrorMsg);
+    }
+
+    protected function _getCategoryOptions($iParentId, &$aValues)
+    {
+        $aCategories = $this->_oDb->getCategories(array('type' => 'parent_id', 'parent_id' => $iParentId, 'active' => true));
+        foreach($aCategories as $aCategory) {
+            $aValues[] = array('key' => $aCategory['id'], 'value' => str_repeat('--', (int)$aCategory['level']) . ' ' . _t($aCategory['title']));
+
+            $this->_getCategoryOptions($aCategory['id'], $aValues);
+        }
+    }
+
+    protected function _getSearchableFields($mixedDisplayType = '')
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($mixedDisplayType))
+            $mixedDisplayType = array('add', 'edit');
+
+        $aResult = array();
+        $aDisplays = $this->_oDb->getDisplays($this->_oConfig->getName() . '_entry', $mixedDisplayType);
+        foreach($aDisplays as $aDisplay) {
+            if($aDisplay['display_name'] == $CNF['OBJECT_FORM_ENTRY_DISPLAY_ADD'])
+                continue;
+
+            $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ENTRY'], $aDisplay['display_name'], $this->_oTemplate);
+            if(!$oForm)
+                continue;
+
+            $aResult = array_merge($aResult, $oForm->aInputs);
+        }
+
+        return $aResult;
+    }
+    
+    protected function _getContentForTimelinePost($aEvent, $aContentInfo, $aBrowseParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $bDynamic = isset($aBrowseParams['dynamic_mode']) && (bool)$aBrowseParams['dynamic_mode'] === true;
+
+        $sCategory = '';
+        if(!empty($CNF['FIELD_CATEGORY']) && !empty($aContentInfo[$CNF['FIELD_CATEGORY']])) {
+            $iCategory = (int)$aContentInfo[$CNF['FIELD_CATEGORY']];
+            $aCategory = $this->_oDb->getCategories(array('type' => 'id', 'id' => $iCategory));
+            $sCategory = _t($aCategory['title']);
+            $sCategoryLink = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink($CNF['URL_CATEGORIES'], array($CNF['GET_PARAM_CATEGORY'] => $iCategory));
+        }
+
+        $sPrice = _t('_bx_ads_txt_free');
+        if(!empty($CNF['FIELD_PRICE']) && !empty($aContentInfo[$CNF['FIELD_PRICE']]))
+            $sPrice = _t_format_currency((float)$aContentInfo[$CNF['FIELD_PRICE']]);
+
+        $sInclude = $this->_oTemplate->addCss(array('timeline.css'), $bDynamic);
+
+        $aResult = parent::_getContentForTimelinePost($aEvent, $aContentInfo, $aBrowseParams);
+        $aResult['text'] = $this->_oTemplate->parseHtmlByName('timeline_post_text.html', array(
+            'category_link' => $sCategoryLink,
+            'category_title' => $sCategory,
+            'category_title_attr' => bx_html_attribute($sCategory),
+            'price' => $sPrice,
+            'text' => $aResult['text']
+        )) . ($bDynamic ? $sInclude : '');
+
+        
+        return $aResult;
+    }
+
+    protected function _getBlockLicenses($sType = '') 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sGrid = $CNF['OBJECT_GRID_LICENSES' . (!empty($sType) ? '_' . strtoupper($sType) : '')];
+        $oGrid = BxDolGrid::getObjectInstance($sGrid);
+        if(!$oGrid)
+            return '';
+
+        $this->_oDb->updateLicense(array('new' => 0), array('profile_id' => bx_get_logged_profile_id(), 'new' => 1));
+
+        $this->_oTemplate->addJs(array('licenses.js'));
+        return array(
+            'content' => $this->_oTemplate->getJsCode('licenses', array('sObjNameGrid' => $sGrid)) . $oGrid->getCode(),
+            'menu' => $CNF['OBJECT_MENU_LICENSES']
+        );
+    }
+
+    protected function _alertParamsOffer($aContentInfo, $aOfferInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aParams = array(
+            'object_id' => (int)$aContentInfo[$CNF['FIELD_ID']],
+            'object_author_id' => (int)$aContentInfo[$CNF['FIELD_AUTHOR']],
+
+            'offer_id' => (int)$aOfferInfo[$CNF['FIELD_OFR_ID']],
+            'offer_author_id' => (int)$aOfferInfo[$CNF['FIELD_OFR_AUTHOR']],
+        );
+        if(isset($aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]))
+            $aParams['privacy_view'] = $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']];
+
+        return $aParams;
+    }
+}
+
+/** @} */

+ 151 - 0
modules/boonex/ads/updates/13.0.4_13.0.5/source/install/config.php

@@ -0,0 +1,151 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Ads Ads
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_ads',
+    'title' => 'Ads',
+    'note' => 'Ads module.',
+    'version' => '13.0.5',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/ads/',
+    'home_uri' => 'ads',
+
+    'db_prefix' => 'bx_ads_',
+    'class_prefix' => 'BxAds',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Ads',
+
+    /**
+     * List of page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry',
+    ),
+    
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+        'trigger_profile_view_submenu',
+        'trigger_group_view_submenu',
+    ),
+
+    /**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+        'bx_ads_covers',
+    	'bx_ads_photos',
+        'bx_ads_videos',
+        'bx_ads_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+        'bx_ads_preview',
+        'bx_ads_gallery',
+        'bx_ads_cover',
+
+        'bx_ads_preview_photos',
+        'bx_ads_gallery_photos',
+        'bx_ads_view_photos',
+
+        'bx_ads_videos_poster',
+        'bx_ads_videos_poster_preview',
+        'bx_ads_videos_mp4',
+        'bx_ads_videos_mp4_hd',
+
+        'bx_ads_preview_files',
+        'bx_ads_gallery_files'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_ads',
+    	'bx_ads_cmts'
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+        'process_menu_triggers' => 1,
+        'process_page_triggers' => 1,
+    	'process_esearches' => 1,
+        'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'update_relations' => 1,
+        'unregister_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+        'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Relations Section
+     */
+    'relations' => array(
+    	'bx_timeline',
+    	'bx_notifications'
+    ),
+
+);
+
+/** @} */

+ 51 - 0
modules/boonex/albums/updates/13.0.2_13.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Albums',
+    'version_from' => '13.0.2',
+    'version_to' => '13.0.3',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/albums/updates/update_13.0.2_13.0.3/',
+    'home_uri' => 'albums_update_1302_1303',
+
+    'module_dir' => 'boonex/albums/',
+    'module_uri' => 'albums',
+
+    'db_prefix' => 'bx_albums_',
+    'class_prefix' => 'BxAlbums',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Albums',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/albums/updates/13.0.2_13.0.3/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxAlbumsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 1041 - 0
modules/boonex/albums/updates/13.0.2_13.0.3/source/classes/BxAlbumsModule.php

@@ -0,0 +1,1041 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Albums Albums
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+bx_import('BxDolAcl');
+
+/**
+ * Albums module
+ */
+class BxAlbumsModule extends BxBaseModTextModule
+{
+    protected $_aContexts = array('popular', 'public', 'author');
+
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+
+    public function serviceGetSafeServices()
+    {
+        $a = parent::serviceGetSafeServices();
+        return array_merge($a, array (
+            'EntityAddFiles' => '',
+            'MediaComments' => '',
+            'BrowseRecentMedia' => '',
+            'BrowseFeaturedMedia' => '',
+            'BrowsePopularMedia' => '',
+            'BrowseTopMedia' => '',
+            'BrowseFavoriteMedia' => '',
+        ));
+    }
+    
+    public function actionEmbed($iContentId, $sUnitTemplate = '', $sAddCode = '')
+    {
+        return $this->_oTemplate->getJsCode('main') . parent::actionEmbed($iContentId);
+    }
+
+    public function actionEmbedMedia($iContentId)
+    {
+        $oTemplate = BxDolTemplate::getInstance();
+        
+        $aContentInfo = $this->_oDb->getMediaInfoById($iContentId);
+        if(empty($aContentInfo))
+            $oTemplate->getEmbed(false);
+
+        if(empty($sUnitTemplate))
+            $sUnitTemplate = 'unit_media_gallery.html';
+
+        $oTemplate->getEmbed($this->_oTemplate->unit($aContentInfo, true, $sUnitTemplate));
+    }
+    
+    /**
+     * Entry actions and social sharing block
+     */
+    public function serviceEntityAllActions ($mixedContent = false, $aParams = array())
+    {
+        if(!empty($mixedContent)) {
+            if(!is_array($mixedContent))
+               $mixedContent = array((int)$mixedContent, array());
+        }
+        else {
+            $mixedContent = $this->_getContent();
+            if($mixedContent === false)
+                return false;
+        }
+        
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        $aMedias = $this->_oDb->getMediaListByContentId($iContentId);
+        if(!empty($aMedias) && is_array($aMedias)) {
+            $aMedia = array_shift($aMedias);
+            if(!empty($aMedia['file_id']))
+                $aParams = array_merge(array(
+                    'entry_thumb' => $aMedia['file_id']
+                ), $aParams);
+        }
+
+        return parent::serviceEntityAllActions(array($iContentId, $aContentInfo), $aParams);
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_albums Albums
+     * @subsection bx_albums-forms Forms
+     * @subsubsection bx_albums-entity_add_files entity_add_files
+     * 
+     * @code bx_srv('bx_albums', 'entity_add_files', [...]); @endcode
+     * 
+     * Display form for adding media to the album.
+     * @param $iContentId album content id where media will be added, if it's not provided then it's determined from 'id' GET variable
+     * @return HTML string with form, all necessary CSS and JS files are automatically added to the HEAD section of the site HTML. On error false or empty string is returned.
+     * 
+     * @see BxAlbumsModule::serviceEntityAddFiles
+     */
+    /** 
+     * @ref bx_albums-entity_add_files "entity_add_files"
+     */
+    public function serviceEntityAddFiles ($iContentId = 0)
+    {
+        return $this->_serviceEntityForm ('editDataForm', $iContentId, 'bx_albums_entry_add_images');
+    }
+
+    /**
+     * Delete file and album association, also file views, votes, comments, meta data are also deleted
+     * @param $iFileId file ID
+     * @return true on success of false on error
+     */ 
+    public function serviceDeleteFileAssociations($iFileId)
+    {        
+        $CNF = &$this->_oConfig->CNF;
+
+        if (!($aMediaInfo = $this->_oDb->getMediaInfoSimpleByFileId($iFileId))) // file is already deleted
+            return true; 
+    
+        if (!$this->_oDb->deassociateFileWithContent(0, $iFileId))
+            return false;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($aMediaInfo['content_id']);
+        $iSender = isLogged() ? bx_get_logged_profile_id() : $aMediaInfo['author'];
+        $iAuthor = isset($aContentInfo[$CNF['FIELD_AUTHOR']]) ? $aContentInfo[$CNF['FIELD_AUTHOR']] : $aMediaInfo['author'];
+        bx_alert($this->getName(), 'media_deleted', $aMediaInfo['content_id'], $iSender, array(
+            'object_author_id' => $iAuthor,
+
+            'subobject_id' => $aMediaInfo['id'],
+
+            'media_id' => $aMediaInfo['id'], 
+            'media_info' => $aMediaInfo,
+        ));
+
+        bx_alert($this->getName() . '_media', 'deleted', $aMediaInfo['id'], $iSender, array(
+            'object_id' => $aMediaInfo['content_id'],
+            'object_author_id' => $iAuthor,
+
+            'media_info' => $aMediaInfo,
+        ));        
+
+        if (!empty($CNF['OBJECT_VIEWS_MEDIA'])) {
+            $o = BxDolView::getObjectInstance($CNF['OBJECT_VIEWS_MEDIA'], $aMediaInfo['id']);
+            if ($o) $o->onObjectDelete();
+        }
+
+        if (!empty($CNF['OBJECT_VOTES_MEDIA'])) {
+            $o = BxDolVote::getObjectInstance($CNF['OBJECT_VOTES_MEDIA'], $aMediaInfo['id']);
+            if ($o) $o->onObjectDelete();
+        }
+
+        if (!empty($CNF['OBJECT_SCORES_MEDIA'])) {
+            $o = BxDolScore::getObjectInstance($CNF['OBJECT_SCORES_MEDIA'], $aMediaInfo['id']);
+            if ($o) $o->onObjectDelete();
+        }
+
+        if (!empty($CNF['OBJECT_COMMENTS_MEDIA'])) {
+            $o = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS_MEDIA'], $aMediaInfo['id']);
+            if ($o) $o->onObjectDelete();
+        }
+
+        if (!empty($CNF['OBJECT_METATAGS_MEDIA'])) {
+            $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS_MEDIA']);
+            $oMetatags->onDeleteContent($aMediaInfo['id']);
+        }
+
+        if (!empty($CNF['OBJECT_METATAGS_MEDIA_CAMERA'])) {
+            $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS_MEDIA_CAMERA']);
+            $oMetatags->onDeleteContent($aMediaInfo['id']);
+        }
+
+        BxDolPage::deleteSeoLink ($this->getName(), 'bx_albums_media', $aMediaInfo['id']);
+
+        return true;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_albums Albums
+     * @subsection bx_albums-page_blocks Page Blocks
+     * @subsubsection bx_albums-media_comments media_comments
+     * 
+     * @code bx_srv('bx_albums', 'media_comments', [...]); @endcode
+     * 
+     * Display media comments block.
+     * @param $iMediaId media ID, if it's omitted then it's taken from 'id' GET variable.
+     * @return HTML string with comments. On error false or empty string is returned.
+     * 
+     * @see BxAlbumsModule::serviceMediaComments
+     */
+    /** 
+     * @ref bx_albums-media_comments "media_comments"
+     */
+    public function serviceMediaComments ($iMediaId = 0)
+    {
+        return $this->_entityComments($this->_oConfig->CNF['OBJECT_COMMENTS_MEDIA'], $iMediaId);
+    }
+
+    /**
+     * Display media author block.
+     * @param $iMediaId media ID, if it's omitted then it's taken from 'id' GET variable.
+     * @return HTML string with block content. On error false or empty string is returned.
+     */
+    public function serviceMediaAuthor ($iMediaId = 0)
+    {
+        return $this->_serviceTemplateFunc ('mediaAuthor', $iMediaId, 'getMediaInfoById');
+    }
+
+    /**
+     * Entry actions and social sharing block
+     */
+    public function serviceMediaAllActions ($mixedContent = false, $aParams = array())
+    {
+        $iMediaId = 0;
+        $aMediaInfo = array();
+
+        $bContent = !empty($mixedContent);
+        if($bContent && is_array($mixedContent))
+            list($iMediaId, $aMediaInfo) = $mixedContent;
+        else {
+            if($bContent)
+                $iMediaId = (int)$mixedContent;
+            else
+                $iMediaId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+            if(!$iMediaId)
+                return false;
+
+            $aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        }
+
+        if(!$iMediaId || !$aMediaInfo)
+            return false;
+
+        $CNF = &$this->_oConfig->CNF;
+
+        return parent::serviceEntityAllActions (array($iMediaId, $aMediaInfo), array_merge(array(
+            'object_menu' => $CNF['OBJECT_MENU_ACTIONS_VIEW_MEDIA_ALL'],
+            'object_transcoder' => $CNF['OBJECT_IMAGES_TRANSCODER_BIG'],
+            'entry_url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_MEDIA'] . '&id=' . $iMediaId),
+            'entry_title' => $aMediaInfo['title'],
+            'entry_thumb' => $aMediaInfo['file_id']
+        ), $aParams));
+    }
+
+    /**
+     * Entry actions block
+     */
+    public function serviceMediaActions ($iContentId = 0)
+    {
+        $iContentId = $this->_getContent($iContentId, false);
+        if($iContentId === false)
+            return false;
+
+        $oMenu = BxTemplMenu::getObjectInstance($this->_oConfig->CNF['OBJECT_MENU_ACTIONS_VIEW_MEDIA']);
+        return $oMenu ? $oMenu->getCode() : false;
+    }
+
+    /**
+     * Display media social sharing buttons block.
+     * @param $iMediaId media ID, if it's omitted then it's taken from 'id' GET variable.
+     * @return HTML string with block content. On error false or empty string is returned.
+     */
+    public function serviceMediaSocialSharing ($iMediaId = 0)
+    {
+        if(!$iMediaId)
+            $iMediaId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if(!$iMediaId)
+            return false;
+
+        $aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        if(!$aMediaInfo)
+            return false;
+
+        $CNF = &$this->_oConfig->CNF;
+
+        return $this->serviceEntitySocialSharing(array($iMediaId, $aMediaInfo), array(
+            'uri' => $CNF['URI_VIEW_MEDIA'],
+            'title' => $aMediaInfo['title'],
+            'id_thumb' => $aMediaInfo['file_id'],
+            'object_transcoder' => $CNF['OBJECT_IMAGES_TRANSCODER_BIG']
+        ));
+    }
+
+    /**
+     * Display media preview block.
+     * @param $iMediaId media ID, if it's omitted then it's taken from 'id' GET variable.
+     * @param $mixedContext current context to navigate to next and previous file, possible values: popular, public, author. If omitted then value from 'context' GTE variable is taken. Default context is 'album' - when nothin is specified.
+     * @param $aParams array of additional params. 
+     * @return HTML string with block content. On error false or empty string is returned.
+     */
+    public function serviceMediaView ($iMediaId = 0, $mixedContext = false, $aParams = array())
+    {
+        if(!$iMediaId)
+            $iMediaId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if(!$iMediaId)
+            return false;
+
+        if(!$mixedContext) {
+            $mixedContext = bx_process_input(bx_get('context'));
+            if(!in_array($mixedContext, $this->_aContexts)) // when no context specified, it is assumed that it is an album context
+                $mixedContext = bx_process_input($mixedContext, BX_DATA_INT); // numeric context is reserved for future use
+        }
+        $aParams['context'] = $mixedContext;
+
+        $iAutoplay = 0;
+        if(!isset($aParams['autoplay']) && ($iAutoplay = bx_get('autoplay')) !== false)
+            $aParams['autoplay'] = (int)$iAutoplay;
+
+        return $this->_oTemplate->entryMediaView ($iMediaId, $aParams);
+    }
+
+    public function checkAllowedSetThumb ($iContentId = 0)
+    {
+        return CHECK_ACTION_RESULT_NOT_ALLOWED;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_albums Albums
+     * @subsection bx_albums-browse Browse
+     * @subsubsection bx_albums-browse_recent_media browse_recent_media
+     * 
+     * @code bx_srv('bx_albums', 'browse_recent_media', [...]); @endcode
+     * 
+     * Display block for browsing recently uploaded media files.
+     * @param $sUnitView unit view mode: gallery
+     * @param $bDisplayEmptyMsg display 'empty' message when nothing to browse, or return empty string.
+     * @param $bAjaxPaginate use AJAX or regular paginate.
+     * @return HTML string with block content. On error false or empty string is returned.
+     * 
+     * @see BxAlbumsModule::serviceBrowseRecentMedia
+     */
+    /** 
+     * @ref bx_albums-browse_recent_media "browse_recent_media"
+     */
+    public function serviceBrowseRecentMedia ($sUnitView = false, $bDisplayEmptyMsg = true, $bAjaxPaginate = true)
+    {
+        return $this->_serviceBrowse ('recent', array('unit_view' => $sUnitView), BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate, 'SearchResultMedia');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_albums Albums
+     * @subsection bx_albums-browse Browse
+     * @subsubsection bx_albums-browse_featured_media browse_featured_media
+     * 
+     * @code bx_srv('bx_albums', 'browse_featured_media', [...]); @endcode
+     * 
+     * Display featured media. 
+     * @param $sUnitView unit view mode: gallery
+     * @param $bDisplayEmptyMsg display 'empty' message when nothing to browse, or return empty string.
+     * @param $bAjaxPaginate use AJAX or regular paginate.
+     * @return HTML string with block content. On error false or empty string is returned.
+     * 
+     * @see BxAlbumsModule::serviceBrowseFeaturedMedia
+     */
+    /** 
+     * @ref bx_albums-browse_featured_media "browse_featured_media"
+     */
+    public function serviceBrowseFeaturedMedia ($sUnitView = false, $bDisplayEmptyMsg = false, $bAjaxPaginate = true)
+    {
+        return $this->_serviceBrowse ('featured', array('unit_view' => $sUnitView), BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate, 'SearchResultMedia');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_albums Albums
+     * @subsection bx_albums-browse Browse
+     * @subsubsection bx_albums-browse_popular_media browse_popular_media
+     * 
+     * @code bx_srv('bx_albums', 'browse_popular_media', [...]); @endcode
+     * 
+     * Display popular media.
+     * @param $sUnitView unit view mode: gallery
+     * @param $bDisplayEmptyMsg display 'empty' message when nothing to browse, or return empty string.
+     * @param $bAjaxPaginate use AJAX or regular paginate.
+     * @return HTML string with block content. On error false or empty string is returned.
+     * 
+     * @see BxAlbumsModule::serviceBrowsePopularMedia
+     */
+    /** 
+     * @ref bx_albums-browse_popular_media "browse_popular_media"
+     */
+    public function serviceBrowsePopularMedia ($sUnitView = false, $bDisplayEmptyMsg = true, $bAjaxPaginate = true)
+    {
+        return $this->_serviceBrowse ('popular', array('unit_view' => $sUnitView), BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate, 'SearchResultMedia');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_albums Albums
+     * @subsection bx_albums-browse Browse
+     * @subsubsection bx_albums-browse_top_media browse_top_media
+     * 
+     * @code bx_srv('bx_albums', 'browse_top_media', [...]); @endcode
+     * 
+     * Display top media.
+     * @param $sUnitView unit view mode: gallery
+     * @param $bDisplayEmptyMsg display 'empty' message when nothing to browse, or return empty string.
+     * @param $bAjaxPaginate use AJAX or regular paginate.
+     * @return HTML string with block content. On error false or empty string is returned.
+     * 
+     * @see BxAlbumsModule::serviceBrowseTopMedia
+     */
+    /** 
+     * @ref bx_albums-browse_top_media "browse_top_media"
+     */
+    public function serviceBrowseTopMedia ($sUnitView = false, $bDisplayEmptyMsg = true, $bAjaxPaginate = true)
+    {
+        return $this->_serviceBrowse ('top', array('unit_view' => $sUnitView), BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate, 'SearchResultMedia');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_albums Albums
+     * @subsection bx_albums-browse Browse
+     * @subsubsection bx_albums-browse_favorite_media browse_favorite_media
+     * 
+     * @code bx_srv('bx_albums', 'browse_favorite_media', [...]); @endcode
+     * 
+     * Display favorite media for particular profile. 
+     * @param $iProfileId profile ID, if omitted then 'profile_id' GET variable is used 
+     * @param $aParams additional params for browsing such as 'unit_view'
+     * 
+     * @see BxAlbumsModule::serviceBrowseFavoriteMedia
+     */
+    /** 
+     * @ref bx_albums-browse_favorite_media "browse_favorite_media"
+     */
+    public function serviceBrowseFavoriteMedia ($iProfileId = 0, $aParams = array())
+    {
+        $oProfile = null;
+        if((int)$iProfileId)
+            $oProfile = BxDolProfile::getInstance($iProfileId);
+        if(!$oProfile && bx_get('profile_id') !== false)
+            $oProfile = BxDolProfile:: getInstance(bx_process_input(bx_get('profile_id'), BX_DATA_INT));
+        if(!$oProfile)
+            $oProfile = BxDolProfile::getInstance();
+        if(!$oProfile)
+            return '';
+
+        $bEmptyMessage = false;
+        if(isset($aParams['empty_message'])) {
+            $bEmptyMessage = (bool)$aParams['empty_message'];
+            unset($aParams['empty_message']);
+        }
+
+        return $this->_serviceBrowse ('favorite', array_merge(array('user' => $oProfile->id()), $aParams), BX_DB_PADDING_DEF, $bEmptyMessage, true, 'SearchResultMedia');
+    }
+
+    public function serviceGetTimelineData()
+    {
+    	$sModule = $this->_aModule['name'];
+
+        $aResult = parent::serviceGetTimelineData();
+        $aResult['handlers'] = array_merge($aResult['handlers'], array(
+            array('group' => $sModule . '_object_media', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'medias_added', 'module_name' => $sModule, 'module_method' => 'get_timeline_media', 'module_class' => 'Module',  'groupable' => 0, 'group_by' => ''),
+        ));
+        $aResult['alerts'] = array_merge($aResult['alerts'], array(
+            array('unit' => $sModule, 'action' => 'medias_added')
+        ));
+
+        return $aResult;
+    }
+
+    public function serviceGetTimelineMedia($aEvent, $aBrowseParams = array())
+    {
+        if(empty($aEvent['content']))
+            return false;
+
+        $aEvent['content'] = unserialize($aEvent['content']);
+        if(empty($aEvent['content']['medias_added']) || !is_array($aEvent['content']['medias_added']))
+            return false;
+
+        $iContentId = (int)$aEvent['object_id'];
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return false;
+
+        $CNF = &$this->_oConfig->CNF;
+        
+        //--- Views
+        $oViews = isset($CNF['OBJECT_VIEWS']) ? BxDolView::getObjectInstance($CNF['OBJECT_VIEWS'], $iContentId) : null;
+
+        $aViews = array();
+        if ($oViews && $oViews->isEnabled())
+            $aViews = array(
+                'system' => $CNF['OBJECT_VIEWS'],
+                'object_id' => $iContentId,
+                'count' => $aContentInfo['views']
+            );
+
+        //--- Votes
+        $oVotes = isset($CNF['OBJECT_VOTES']) ? BxDolVote::getObjectInstance($CNF['OBJECT_VOTES'], $iContentId) : null;
+
+        $aVotes = array();
+        if ($oVotes && $oVotes->isEnabled())
+            $aVotes = array(
+                'system' => $CNF['OBJECT_VOTES'],
+                'object_id' => $iContentId,
+                'count' => $aContentInfo['votes']
+            );
+
+        //--- Scores
+        $oScores = isset($CNF['OBJECT_SCORES']) ? BxDolScore::getObjectInstance($CNF['OBJECT_SCORES'], $iContentId) : null;
+
+        $aScores = array();
+        if ($oScores && $oScores->isEnabled())
+            $aScores = array(
+                'system' => $CNF['OBJECT_SCORES'],
+                'object_id' => $iContentId,
+                'score' => $aContentInfo['score']
+            );
+
+        //--- Reports
+        $oReports = isset($CNF['OBJECT_REPORTS']) ? BxDolReport::getObjectInstance($CNF['OBJECT_REPORTS'], $aEvent['object_id']) : null;
+
+        $aReports = array();
+        if ($oReports && $oReports->isEnabled())
+            $aReports = array(
+                'system' => $CNF['OBJECT_REPORTS'],
+                'object_id' => $iContentId,
+                'count' => $aContentInfo['reports']
+            );
+
+        //--- Comments
+        $oCmts = isset($CNF['OBJECT_COMMENTS']) ? BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], $iContentId) : null;
+
+        $aComments = array();
+        if($oCmts && $oCmts->isEnabled())
+            $aComments = array(
+                'system' => $CNF['OBJECT_COMMENTS'],
+                'object_id' => $iContentId,
+                'count' => $aContentInfo['comments']
+            );
+
+        //--- Title & Description
+        $sTitle = isset($CNF['FIELD_TITLE']) && isset($aContentInfo[$CNF['FIELD_TITLE']]) ? $aContentInfo[$CNF['FIELD_TITLE']] : (isset($CNF['FIELD_TEXT']) && isset($aContentInfo[$CNF['FIELD_TEXT']]) ? strmaxtextlen($aContentInfo[$CNF['FIELD_TEXT']], 20, '...') : '');
+
+        return array(
+            '_cache' => true,
+            'owner_id' => $aEvent['owner_id'],
+            'object_owner_id' => $aContentInfo['author'],
+            'icon' => !empty($CNF['ICON']) ? $CNF['ICON'] : '',
+            'sample' => isset($CNF['T']['txt_sample_single_with_article']) ? $CNF['T']['txt_sample_single_with_article'] : $CNF['T']['txt_sample_single'],
+            'sample_wo_article' => $CNF['T']['txt_sample_single'],
+    	    'sample_action' => $CNF['T']['txt_sample_action_changed'],
+            'url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iContentId),
+            'content' => $this->_getContentForTimelineMedia($aEvent, $aContentInfo, $aBrowseParams), //a string to display or array to parse default template before displaying.
+            'date' => $aContentInfo[$CNF['FIELD_ADDED']],
+            'views' => $aViews,
+            'votes' => $aVotes,
+            'scores' => $aScores,
+            'reports' => $aReports,
+            'comments' => $aComments,
+            'title' => $sTitle, //may be empty.
+            'description' => '' //may be empty.
+        );
+    }
+
+    public function serviceGetNotificationsData()
+    {
+        $sModule = $this->_aModule['name'];
+
+        $sEventPrivacy = $sModule . '_allow_view_event_to';
+        if(BxDolPrivacy::getObjectInstance($sEventPrivacy) === false)
+                $sEventPrivacy = '';
+
+        $aResult = parent::serviceGetNotificationsData();
+        $aResult['handlers'] = array_merge($aResult['handlers'], array(
+            array('group' => $sModule . '_object_media', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'medias_added', 'module_name' => $sModule, 'module_method' => 'get_notifications_media', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
+            array('group' => $sModule . '_object_media', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'media_deleted'),
+
+            array('group' => $sModule . '_comment_media', 'type' => 'insert', 'alert_unit' => $sModule . '_media', 'alert_action' => 'commentPost', 'module_name' => $sModule, 'module_method' => 'get_notifications_comment_media', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
+            array('group' => $sModule . '_comment_media', 'type' => 'delete', 'alert_unit' => $sModule . '_media', 'alert_action' => 'commentRemoved'),
+
+            array('group' => $sModule . '_vote_media', 'type' => 'insert', 'alert_unit' => $sModule . '_media', 'alert_action' => 'doVote', 'module_name' => $sModule, 'module_method' => 'get_notifications_vote_media', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
+            array('group' => $sModule . '_vote_media', 'type' => 'delete', 'alert_unit' => $sModule . '_media', 'alert_action' => 'undoVote'),
+            
+            array('group' => $sModule . '_score_up_media', 'type' => 'insert', 'alert_unit' => $sModule . '_media', 'alert_action' => 'doVoteUp', 'module_name' => $sModule, 'module_method' => 'get_notifications_score_up_media', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
+
+            array('group' => $sModule . '_score_down_media', 'type' => 'insert', 'alert_unit' => $sModule . '_media', 'alert_action' => 'doVoteDown', 'module_name' => $sModule, 'module_method' => 'get_notifications_score_down_media', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy),
+        ));
+
+        $aResult['settings'] = array_merge($aResult['settings'], array(
+            array('group' => 'content', 'unit' => $sModule, 'action' => 'medias_added', 'types' => array('follow_member', 'follow_context')),
+            array('group' => 'comment', 'unit' => $sModule . '_media', 'action' => 'commentPost', 'types' => array('personal', 'follow_member', 'follow_context')),
+            array('group' => 'vote', 'unit' => $sModule . '_media', 'action' => 'doVote', 'types' => array('personal', 'follow_member', 'follow_context')),
+            array('group' => 'score_up', 'unit' => $sModule . '_media', 'action' => 'doVoteUp', 'types' => array('personal', 'follow_member', 'follow_context')),
+            array('group' => 'score_down', 'unit' => $sModule . '_media', 'action' => 'doVoteDown', 'types' => array('personal', 'follow_member', 'follow_context'))
+        ));
+
+        $aResult['alerts'] = array_merge($aResult['alerts'], array(
+            array('unit' => $sModule, 'action' => 'medias_added'),
+            array('unit' => $sModule, 'action' => 'media_deleted'),
+
+            array('unit' => $sModule . '_media', 'action' => 'commentPost'),
+            array('unit' => $sModule . '_media', 'action' => 'commentRemoved'),
+
+            array('unit' => $sModule . '_media', 'action' => 'doVote'),
+            array('unit' => $sModule . '_media', 'action' => 'undoVote'),
+
+            array('unit' => $sModule . '_media', 'action' => 'doVoteUp'),
+            array('unit' => $sModule . '_media', 'action' => 'doVoteDown'),
+        ));
+
+        return $aResult; 
+    }
+
+    public function serviceGetNotificationsMedia($aEvent)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        $iContentId = (int)$aEvent['object_id'];
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return array();
+
+    	$iMediaId = (int)$aEvent['subobject_id'];
+    	$aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        if(empty($aMediaInfo) || !is_array($aMediaInfo))
+            return array();
+
+        $oPermalinks = BxDolPermalinks::getInstance();
+        $sEntryUrl = '{bx_url_root}' . $oPermalinks->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iContentId);
+        $sSubentryUrl = '{bx_url_root}' . $oPermalinks->permalink('page.php?i=' . $CNF['URI_VIEW_MEDIA'] . '&id=' . $iMediaId);
+        $sEntryCaption = isset($aMediaInfo['title']) ? $aMediaInfo['title'] : _t('_bx_albums_media');
+
+        return array(
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $sEntryCaption,
+            'entry_author' => $aMediaInfo['author'],
+            'subentry_sample' => $CNF['T']['txt_media_single'],
+            'subentry_url' => $sSubentryUrl,
+            'lang_key' => '', //may be empty or not specified. In this case the default one from Notification module will be used.
+        );
+    }
+
+    public function serviceGetNotificationsCommentMedia($aEvent)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$iMediaId = (int)$aEvent['object_id'];
+    	$aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        if(empty($aMediaInfo) || !is_array($aMediaInfo))
+            return array();
+
+        $oComment = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS_MEDIA'], $iMediaId);
+        if(!$oComment || !$oComment->isEnabled())
+            return array();
+
+        $sEntryUrl = '{bx_url_root}' . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_MEDIA'] . '&id=' . $aMediaInfo['id']);
+        $sEntryCaption = isset($aMediaInfo['title']) ? $aMediaInfo['title'] : _t('_bx_albums_media');
+
+        return array(
+            'entry_sample' => $CNF['T']['txt_media_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $sEntryCaption,
+            'entry_author' => $aMediaInfo['author'],
+            'subentry_sample' => $CNF['T']['txt_media_comment_single'],
+            'subentry_url' => '{bx_url_root}' . $oComment->getViewUrl((int)$aEvent['subobject_id'], false),
+            'lang_key' => '', //may be empty or not specified. In this case the default one from Notification module will be used.
+        );
+    }
+
+    public function serviceGetNotificationsVoteMedia($aEvent)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$iMediaId = (int)$aEvent['object_id'];
+    	$aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        if(empty($aMediaInfo) || !is_array($aMediaInfo))
+            return array();
+
+        $oVote = BxDolVote::getObjectInstance($CNF['OBJECT_VOTES_MEDIA'], $iMediaId);
+        if(!$oVote || !$oVote->isEnabled())
+            return array();
+
+        $sEntryUrl = '{bx_url_root}' . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_MEDIA'] . '&id=' . $aMediaInfo['id']);
+        $sEntryCaption = isset($aMediaInfo['title']) ? $aMediaInfo['title'] : _t('_bx_albums_media');
+
+        return array(
+            'entry_sample' => $CNF['T']['txt_media_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $sEntryCaption,
+            'entry_author' => $aMediaInfo['author'],
+            'subentry_sample' => $CNF['T']['txt_media_vote_single'],
+            'subentry_url' => '',
+            'lang_key' => '', //may be empty or not specified. In this case the default one from Notification module will be used.
+        );
+    }
+
+    public function serviceGetNotificationsScoreUpMedia($aEvent)
+    {
+    	return $this->_serviceGetNotificationsScoreMedia('up', $aEvent);
+    }
+
+    public function serviceGetNotificationsScoreDownMedia($aEvent)
+    {
+    	return $this->_serviceGetNotificationsScoreMedia('down', $aEvent);
+    }
+
+    protected function _serviceGetNotificationsScoreMedia($sType, $aEvent)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$iMediaId = (int)$aEvent['object_id'];
+    	$aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        if(empty($aMediaInfo) || !is_array($aMediaInfo))
+            return array();
+
+        $oVote = BxDolScore::getObjectInstance($CNF['OBJECT_SCORES_MEDIA'], $iMediaId);
+        if(!$oVote || !$oVote->isEnabled())
+            return array();
+
+        $sEntryUrl = '{bx_url_root}' . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_MEDIA'] . '&id=' . $aMediaInfo['id']);
+        $sEntryCaption = isset($aMediaInfo['title']) ? $aMediaInfo['title'] : _t('_bx_albums_media');
+
+        return array(
+            'entry_sample' => $CNF['T']['txt_media_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $sEntryCaption,
+            'entry_author' => $aMediaInfo['author'],
+            'subentry_sample' => $CNF['T']['txt_media_score_' . $sType . '_single'],
+            'subentry_url' => '',
+            'lang_key' => '', //may be empty or not specified. In this case the default one from Notification module will be used.
+        );
+    }
+
+    public function actionEditMedia($iMediaId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iMediaId = (int)$iMediaId;
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_MEDIA'], $CNF['OBJECT_FORM_MEDIA_DISPLAY_EDIT']);
+        $oForm->initForm('edit', $iMediaId);
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($iMediaId) !== false) {
+                $aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+                if(!empty($aMediaInfo) && is_array($aMediaInfo) && !empty($CNF['OBJECT_METATAGS_MEDIA'])) {
+                    $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS_MEDIA']);
+                    if ($oMetatags->keywordsIsEnabled())
+                        $oMetatags->keywordsAdd($aMediaInfo['id'], $aMediaInfo['title']);
+                }
+
+                $aRes = array('reload' => 1);
+            }
+            else
+                $aRes = array('msg' => _t('_bx_albums_txt_err_cannot_perform_action'));
+
+            return echoJson($aRes);
+        }
+
+        $sContent = BxTemplStudioFunctions::getInstance()->transBox('bx-albums-edit-media-popup', $this->_oTemplate->parseHtmlByName('media-edit.html', array(
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true)
+        )));
+
+        echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+	
+    public function actionDeleteMedia($iMediaId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        $oUploader = BxDolUploader::getObjectInstance($CNF['OBJECT_UPLOADERS'][0], $CNF['OBJECT_STORAGE'], '');
+        $oUploader->deleteGhost($aMediaInfo['file_id'], bx_get_logged_profile_id());
+        
+        echoJson(['redirect' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aMediaInfo['content_id'])]);
+    }
+
+    public function actionMoveMedia($iMediaId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iMediaId = (int)$iMediaId;
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_MEDIA'], $CNF['OBJECT_FORM_MEDIA_DISPLAY_MOVE']);
+        $oForm->initForm('move', $iMediaId);
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($iMediaId) !== false)
+                $aRes = array('reload' => 1);
+            else
+                $aRes = array('msg' => _t('_bx_albums_txt_err_cannot_perform_action'));
+
+            return echoJson($aRes);
+        }
+
+        $sContent = BxTemplStudioFunctions::getInstance()->transBox('bx-albums-move-media-popup', $this->_oTemplate->parseHtmlByName('media-edit.html', array(
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true)
+        )));
+
+        echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+
+    public function actionGetSiblingMedia($iMediaId, $mixedContext)
+    {
+        $aSiblings = false;
+        $sErrorMsg = false;
+        if (!($aMediaInfo = $this->_oDb->getMediaInfoById((int)$iMediaId))) 
+            $sErrorMsg = _t('_sys_txt_error_occured');
+
+        if (empty($sErrorMsg) && !($aContentInfo = $this->_oDb->getContentInfoById($aMediaInfo['content_id'])))
+            $sErrorMsg = _t('_sys_txt_error_occured');
+
+        if (empty($sErrorMsg) && (CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $this->checkAllowedView($aContentInfo))))
+            $sErrorMsg = $sMsg;
+
+        if (empty($sErrorMsg)) {
+            $aSiblings = array (
+                'next' => $this->_oTemplate->getNextPrevMedia($aMediaInfo, true, $mixedContext),
+                'prev' => $this->_oTemplate->getNextPrevMedia($aMediaInfo, false, $mixedContext),
+            );
+        }
+    
+        $a = $sErrorMsg ? array('error' => $sErrorMsg) : array('next' => $aSiblings['next'], 'prev' => $aSiblings['prev']);
+
+        $s = json_encode($a);
+
+        header('Content-type: text/html; charset=utf-8');
+        echo $s;
+    }
+
+    public function actionRssMedia ()
+    {
+        $aArgs = func_get_args();
+        $this->_rss($aArgs, 'SearchResultMedia');
+    }
+
+    public function getMediaDuration($aMediaInfo) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($aMediaInfo) || !is_array($aMediaInfo))
+            return 0;
+
+        $sField = 'duration';
+        if(!empty($aMediaInfo[$sField]))
+            return (int)$aMediaInfo[$sField];
+
+        $iMedia = $aMediaInfo['id'];
+        $sMedia = BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['mp4'])->getFileUrl($iMedia);
+        if(empty($sMedia))
+            return 0;
+
+        $iDuration = (int)BxDolTranscoderVideo::getDuration($sMedia);
+        if(!empty($iDuration))
+            $this->_oDb->updateMedia(array($sField => $iDuration), array('id' => $iMedia));
+
+        return $iDuration;
+    }
+
+    protected function _buildRssParams($sMode, $aArgs)
+    {        
+        if ($aParams = parent::_buildRssParams($sMode, $aArgs))
+            return $aParams;
+
+        $sMode = bx_process_input($sMode);
+        switch ($sMode) {
+            case 'album':
+                $aParams = array('album_id' => isset($aArgs[0]) ? (int)$aArgs[0] : '');
+                break;
+        }
+
+        return $aParams;
+    }
+
+    protected function _getImagesForTimelinePostAttach($aEvent, $aContentInfo, $sUrl, $aBrowseParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW']) || empty($CNF['OBJECT_TRANSCODER_COVER']))
+            return array();
+
+        $aMediaList = $this->_oDb->getMediaListByContentId($aContentInfo[$CNF['FIELD_ID']]);
+        if(empty($aMediaList) || !is_array($aMediaList))
+            return array();
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        $oTcPoster = BxDolTranscoderVideo::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['poster']);
+        $oTranscoder = BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW']);
+        $oTranscoderCover = BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_TRANSCODER_COVER']);
+        if(!$oTranscoder || !$oTranscoderCover)
+            return array();
+
+        $aOutput = array();
+        foreach ($aMediaList as $aMedia) {
+            $aFileInfo = $oStorage->getFile($aMedia['file_id']);
+
+            $bVideo = $oTcPoster && strncmp('video/', $aFileInfo['mime_type'], 6) === 0 && $oTcPoster->isMimeTypeSupported($aFileInfo['mime_type']);
+            if($bVideo)
+                continue;
+
+            $aOutput[$aMedia['id']] = array (
+                'id' => $aMedia['id'],
+                'url' => $this->_oTemplate->getViewMediaUrl($CNF, $aMedia['id']), 
+                'src' => $oTranscoder->getFileUrl($aMedia['file_id']),
+                'src_orig' => $oTranscoderCover->getFileUrl($aMedia['file_id'])
+            );
+        }
+
+        if(empty($aOutput))
+            return array();
+
+        $iSlice = 4;
+        $iTotal = count($aOutput);
+        return array(
+            'total' => $iTotal,
+            'items' => $iTotal > $iSlice ? array_slice($aOutput, 0, $iSlice) : $aOutput
+        );
+    }
+
+    protected function _getVideosForTimelinePostAttach($aEvent, $aContentInfo, $sUrl, $aBrowseParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($CNF['OBJECT_VIDEOS_TRANSCODERS']))
+            return array();
+
+        $aMediaList = $this->_oDb->getMediaListByContentId($aContentInfo[$CNF['FIELD_ID']]);
+        if(empty($aMediaList) || !is_array($aMediaList))
+            return array();
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        $oTcPoster = BxDolTranscoderVideo::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['poster']);
+        $oTcMp4 = BxDolTranscoderVideo::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['mp4']);
+        $oTcMp4Hd = BxDolTranscoderVideo::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['mp4_hd']);
+        if(!$oTcPoster || !$oTcMp4 || !$oTcMp4Hd)
+            return array();
+
+        $aOutput = array();
+        foreach($aMediaList as $k => $aMedia) {
+            $aFileInfo = $oStorage->getFile($aMedia['file_id']);
+
+            $bVideo = $oTcPoster && strncmp('video/', $aFileInfo['mime_type'], 6) === 0 && $oTcPoster->isMimeTypeSupported($aFileInfo['mime_type']);
+            if(!$bVideo)
+                continue;
+
+            $sVideoUrl = $oStorage->getFileUrlById($aMedia['file_id']);
+            $aVideoFile = $oStorage->getFile($aMedia['file_id']);
+
+            $sVideoUrlHd = '';
+            if (!empty($aVideoFile['dimensions']) && $oTcMp4Hd->isProcessHD($aVideoFile['dimensions']))
+                $sVideoUrlHd = $oTcMp4Hd->getFileUrl($aMedia['file_id']);
+
+            $aOutput[$aMedia['id']] = array(
+                'id' => $aMedia['id'],
+                'src_poster' => $oTcPoster->getFileUrl($aMedia['file_id']),
+                'src_mp4' => $oTcMp4->getFileUrl($aMedia['file_id']),
+                'src_mp4_hd' => $sVideoUrlHd,
+                'duration' => $aFileInfo['duration'],
+            );
+        }
+
+        if(empty($aOutput))
+            return array();
+
+        $iSlice = 4;
+        $iTotal = count($aOutput);
+        return array(
+            'total' => $iTotal,
+            'items' => $iTotal > $iSlice ? array_slice($aOutput, 0, $iSlice) : $aOutput
+        );
+    }
+
+    protected function _getContentForTimelineMedia($aEvent, $aContentInfo, $aBrowseParams = array())
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        $sUrl = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]);
+        $sTitle = isset($CNF['FIELD_TITLE']) && isset($aContentInfo[$CNF['FIELD_TITLE']]) ? $aContentInfo[$CNF['FIELD_TITLE']] : (isset($CNF['FIELD_TEXT']) && isset($aContentInfo[$CNF['FIELD_TEXT']]) ? strmaxtextlen($aContentInfo[$CNF['FIELD_TEXT']], 20, '...') : '');
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        $oTcPoster = BxDolTranscoderVideo::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['poster']);
+        $oTcMp4 = BxDolTranscoderVideo::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['mp4']);
+        $oTcMp4Hd = BxDolTranscoderVideo::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['mp4_hd']);
+        $oTranscoder = BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW']);
+        $oTranscoderCover = BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_TRANSCODER_COVER']);
+
+    	//--- Image(s) and Video(s)
+        $aImages = $aVideos = array();
+        foreach($aEvent['content']['medias_added'] as $iMediaId) {
+            $aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+            if(empty($aMediaInfo) || !is_array($aMediaInfo))
+                continue;
+
+            $aFileInfo = $oStorage->getFile($aMediaInfo['file_id']);
+            $bVideo = $oTcPoster && strncmp('video/', $aFileInfo['mime_type'], 6) === 0 && $oTcPoster->isMimeTypeSupported($aFileInfo['mime_type']);
+            if($bVideo)
+                $aVideos[$iMediaId] = array(
+                    'id' => $aMediaInfo['id'],
+                    'src_poster' => $oTcPoster->getFileUrl($aMediaInfo['file_id']),
+                    'src_mp4' => $oTcMp4->getFileUrl($aMediaInfo['file_id']),
+                    'src_mp4_hd' => $oTcMp4Hd->getFileUrl($aMediaInfo['file_id']),
+                    'duration' => $aFileInfo['duration'],
+                );
+            else
+                $aImages[$iMediaId] = array(
+                    'id' => $aMediaInfo['id'],
+                    'url' => $this->_oTemplate->getViewMediaUrl($CNF, $aMediaInfo['id']), 
+                    'src' => $oTranscoder->getFileUrl($aMediaInfo['file_id']),
+                    'src_orig' => $oTranscoderCover->getFileUrl($aMediaInfo['file_id'])
+                );
+        }
+
+    	return array(
+            'sample' => isset($CNF['T']['txt_sample_single_with_article']) ? $CNF['T']['txt_sample_single_with_article'] : $CNF['T']['txt_sample_single'],
+            'sample_wo_article' => $CNF['T']['txt_sample_single'],
+            'sample_action' => isset($CNF['T']['txt_sample_action_changed']),
+            'url' => $sUrl,
+            'title' => $sTitle,
+            'text' => '',
+            'images_attach' => $aImages,
+            'videos_attach' => $aVideos
+        );
+    }
+
+    protected function _getImagesForTimelineMedia($aEvent, $aMediaInfo, $sUrl, $aBrowseParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aImages = array();
+
+        
+
+        return $aImages;
+    }
+}
+
+/** @} */

+ 143 - 0
modules/boonex/albums/updates/13.0.2_13.0.3/source/install/config.php

@@ -0,0 +1,143 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Albums Albums
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_albums',
+    'title' => 'Albums',
+    'note' => 'Photos & videos',
+    'version' => '13.0.3',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/albums/',
+    'home_uri' => 'albums',
+
+    'db_prefix' => 'bx_albums_',
+    'class_prefix' => 'BxAlbums',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Albums',
+
+    /**
+     * List of page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry',
+    ),
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+    	'trigger_profile_view_submenu',
+        'trigger_group_view_submenu',
+    ),
+
+	/**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_albums_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+        'bx_albums_preview',
+        'bx_albums_browse',
+        'bx_albums_big',
+        'bx_albums_video_poster_browse',
+        'bx_albums_video_poster_preview',
+        'bx_albums_video_poster_big',
+        'bx_albums_video_mp4',
+        'bx_albums_video_mp4_hd',
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_albums',
+    	'bx_albums_media',
+    	'bx_albums_cmts',
+        'bx_albums_media_cmts'
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+        'process_menu_triggers' => 1,
+        'process_page_triggers' => 1,
+    	'process_esearches' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+    	'unregister_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Connections Section
+     */
+    'relations' => array(
+    	'bx_timeline',
+    	'bx_notifications'
+    ),
+
+);
+
+/** @} */

+ 242 - 0
modules/boonex/albums/updates/13.0.2_13.0.3/source/template/css/main.css

@@ -0,0 +1,242 @@
+/* flexbox */
+.bx-albums-medias-wrapper {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -ms-flexbox;
+    display: flex;
+
+    /* makes all items on a row equal height */
+    -webkit-box-align: stretch;
+    -webkit-align-items: stretch;
+    -ms-flex-align: stretch;
+    align-items: stretch;
+
+    /* wrap onto the next line rather than stretching or shrinking */
+    -webkit-flex-wrap: wrap;
+    -ms-flex-wrap: wrap;
+    flex-wrap: wrap;
+
+    /* tells flexbox to start items from the left */
+    -webkit-box-pack: start;
+    -ms-flex-pack: start;
+    plex-pack: start;
+    -webkit-justify-content: flex-start;
+    justify-content: flex-start;
+}
+
+.bx-albums-medias-wrapper .bx-albums-media-wrapper {
+    -webkit-box-flex: 0;
+
+    -webkit-flex: 0 0 100%;
+    -ms-flex: 0 0 100%;
+    flex: 0 0 100%;
+
+    max-width: 100%;
+}
+
+.bx-albums-media-wrapper .bx-albums-unit-size {
+    width: 100%;
+    height: auto;
+    min-height: 10rem;
+    object-fit: cover;
+}
+	
+/* MEDIA: phone2 */
+
+.bx-media-phone2 .bx-layout-column-half .bx-albums-medias-wrapper .bx-albums-media-wrapper,
+.bx-media-phone2 .bx-layout-column-thin .bx-albums-medias-wrapper .bx-albums-media-wrapper {
+    -webkit-flex: 0 0 49.8%;
+    -ms-flex: 0 0 49.8%;
+    flex: 0 0 49.8%;
+    
+    max-width: 49.8%;
+}
+
+/* MEDIA: tablet2 */
+
+.bx-media-tablet2 #sys_search_results .bx-albums-medias-wrapper .bx-albums-media-wrapper,
+.bx-media-tablet2 .bx-layout-column-wide .bx-albums-medias-wrapper .bx-albums-media-wrapper,
+.bx-media-tablet2 .bx-layout-column-fullwidth .bx-albums-medias-wrapper .bx-albums-media-wrapper {
+    -webkit-flex: 0 0 49.8%;
+    -ms-flex: 0 0 49.8%;
+    flex: 0 0 49.8%;
+    
+    max-width: 49.8%;
+}
+
+.bx-media-tablet2 .bx-layout-column-wide .bx-albums-medias-wrapper .bx-albums-media-wrapper .bx-albums-unit-size {
+    width: 100%;
+    height: auto;
+}
+
+.bx-media-tablet2 #sys_search_results .bx-albums-medias-wrapper .bx-albums-media-wrapper .bx-albums-unit-size,
+.bx-media-tablet2 .bx-layout-column-fullwidth .bx-albums-medias-wrapper .bx-albums-media-wrapper .bx-albums-unit-size {
+    height: 18.0rem;
+}
+
+/* MEDIA: desktop */
+
+.bx-media-desktop .bx-layout-column-wide .bx-albums-medias-wrapper .bx-albums-media-wrapper {
+    -webkit-flex: 0 0 49.8%;
+    -ms-flex: 0 0 49.8%;
+    flex: 0 0 49.8%;
+    
+    max-width: 49.8%;
+}
+
+.bx-media-desktop .bx-layout-column-wide .bx-albums-medias-wrapper .bx-albums-media-wrapper .bx-albums-unit-size {
+    width: 100%;
+    height: auto;
+}
+    
+.bx-media-desktop #sys_search_results .bx-albums-medias-wrapper .bx-albums-media-wrapper,
+.bx-media-desktop .bx-layout-column-fullwidth .bx-albums-medias-wrapper .bx-albums-media-wrapper {
+    -webkit-flex: 0 0 33.25%;
+    -ms-flex: 0 0 33.25%;
+    flex: 0 0 33.25%;
+    
+    max-width: 33.25%;
+}
+
+.bx-media-desktop #sys_search_results .bx-albums-medias-wrapper .bx-albums-media-wrapper .bx-albums-unit-size,
+.bx-media-desktop .bx-layout-column-half .bx-albums-medias-wrapper .bx-albums-media-wrapper .bx-albums-unit-size,
+.bx-media-desktop .bx-layout-column-fullwidth .bx-albums-medias-wrapper .bx-albums-media-wrapper .bx-albums-unit-size {
+    height: 18.0rem;
+}
+
+.bx-search-result-block .bx-base-text-unit-gallery-wrapper {
+	display: block;
+}
+.bx-search-result-block.bx-base-text-unit-gallery-wrapper .bx-base-text-unit.bx-base-text-unit-gallery {
+	display: inline-block;
+}
+
+.bx-albums-media-thumb {
+    position: relative;    
+}
+.bx-albums-media-thumb a {
+    position: relative;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-justify-content: center;
+    justify-content: center;
+    -webkit-align-items: center;
+    align-items: center;
+}
+.bx-albums-media-play {
+    position: absolute;
+
+    width: 3rem;
+    height: 3rem;
+
+    background-color: rgba(255, 255, 255, 0.3);
+
+    text-align: center;
+    line-height: 3rem;
+    font-size: 1.5rem;
+}
+.bx-albums-media-duration {
+    position: absolute;
+    right: 10px;
+    bottom: 10px;
+
+    background-color: rgba(255, 255, 255, 0.9);
+}
+.bx-albums-media-caption {
+    white-space:nowrap;
+    overflow:hidden;
+    text-overflow:ellipsis;
+}
+.bx-albums-media-actions {
+    text-align: center;
+}
+.bx-base-text-unit-ext .bx-albums-unit-text-cont {
+    text-align: left;
+}
+.bx-albums-unit-images {
+    white-space:nowrap;
+    width:100%;
+    overflow: hidden;
+}
+
+.bx-albums-unit-image {
+    display: inline-block;
+    margin-right: 0.125rem;
+}
+
+.bx-albums-unit-image,
+.bx-albums-unit-image img {
+    height: 11.25rem;
+}
+.bx-albums-unit-image {
+    display: -webkit-inline-flex;
+    display: inline-flex;
+    -webkit-justify-content: center;
+    justify-content: center;
+    -webkit-align-items: center;
+    align-items: center;
+}
+.bx-base-text-unit-gallery .bx-albums-unit-images-cont {
+    padding: 0.125rem 0.125rem 0 0.125rem;
+}
+.bx-base-text-unit-gallery .bx-albums-unit-text-cont {
+    line-height: 150%;
+}
+.bx-base-text-unit-gallery .bx-albums-unit-text-cont .bx-base-text-unit-title {
+    text-align: left;
+}
+
+.bx-albums-media-file {
+    text-align: center;    
+}
+
+.bx-albums-media-file img,
+.bx-albums-media-file video {
+    max-width:100%;
+}
+
+.bx-albums-media-title {
+    position:relative;
+    padding-right:6rem;
+}
+
+.bx-albums-media-title h1, 
+.bx-albums-media-title h2, 
+.bx-albums-media-title p {
+    margin:0;
+}
+
+.bx-albums-media-controls {
+    position:absolute;
+    top:0;
+    right:0;
+}
+
+/*--- PhotoSwipe Styles ---*/
+.bx-albums.pswp {
+    z-index: 15000;
+}
+
+.pswp__caption .pswp__caption__center {
+    text-align: center;
+}
+
+.pswp__video {
+    position:absolute;
+    text-align: center;
+    top:0;
+    bottom:0;
+    left:0;
+    right:0;
+}
+
+.pswp__video:before {
+  content: "";
+  display: inline-block;
+  vertical-align: middle;
+  height: 100%;
+}
+
+.pswp__video video {
+    vertical-align: middle;    
+}

+ 68 - 0
modules/boonex/albums/updates/13.0.2_13.0.3/source/template/photoswipe.html

@@ -0,0 +1,68 @@
+<!-- TODO: translate -->
+
+<!-- Root element of PhotoSwipe. Must have class pswp. -->
+<div class="bx-albums pswp" tabindex="-1" role="dialog" aria-hidden="true">
+
+    <!-- Background of PhotoSwipe. 
+         It's a separate element as animating opacity is faster than rgba(). -->
+    <div class="pswp__bg"></div>
+
+    <!-- Slides wrapper with overflow:hidden. -->
+    <div class="pswp__scroll-wrap">
+
+        <!-- Container that holds slides. 
+            PhotoSwipe keeps only 3 of them in the DOM to save memory.
+            Don't modify these 3 pswp__item elements, data is added later on. -->
+        <div class="pswp__container">
+            <div class="pswp__item"></div>
+            <div class="pswp__item"></div>
+            <div class="pswp__item"></div>
+        </div>
+
+        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
+        <div class="pswp__ui pswp__ui--hidden">
+
+            <div class="pswp__top-bar">
+
+                <!--  Controls are self-explanatory. Order can be changed. -->
+
+                <div class="pswp__counter"></div>
+
+                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
+
+                <button class="pswp__button pswp__button--share" title="Share"></button>
+
+                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
+
+                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
+
+                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
+                <!-- element will get class pswp__preloader - active when preloader is running -->
+                <div class="pswp__preloader">
+                    <div class="pswp__preloader__icn">
+                      <div class="pswp__preloader__cut">
+                        <div class="pswp__preloader__donut"></div>
+                      </div>
+                    </div>
+                </div>
+            </div>
+
+            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
+                <div class="pswp__share-tooltip"></div> 
+            </div>
+
+            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
+            </button>
+
+            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
+            </button>
+
+            <div class="pswp__caption">
+                <div class="pswp__caption__center"></div>
+            </div>
+
+        </div>
+
+    </div>
+
+</div>

+ 51 - 0
modules/boonex/attendant/updates/13.0.2_13.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Attendant',
+    'version_from' => '13.0.2',
+    'version_to' => '13.0.3',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/attendant/updates/update_13.0.2_13.0.3/',
+    'home_uri' => 'attendant_update_1302_1303',
+
+    'module_dir' => 'boonex/attendant/',
+    'module_uri' => 'attendant',
+
+    'db_prefix' => 'bx_attendant_',
+    'class_prefix' => 'BxAttendant',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Attendant',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/attendant/updates/13.0.2_13.0.3/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxAttendantUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 256 - 0
modules/boonex/attendant/updates/13.0.2_13.0.3/source/classes/BxAttendantModule.php

@@ -0,0 +1,256 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Attendant Attendant
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+define('BX_ATTENDANT_ON_PROFILE_CREATION_METHOD', 'browse_recommended');
+define('BX_ATTENDANT_ON_PROFILE_CREATION_EVENT_AFTER_REGISTRATION', 'registration');
+define('BX_ATTENDANT_ON_PROFILE_CREATION_EVENT_AFTER_CONFIRMATION', 'confirmation');
+
+class BxAttendantModule extends BxDolModule
+{
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+
+    public function actionRecomendedPopup($sModule, $sEvent, $iObjectId, $bManual)
+    {
+        $sRv = '';
+        $aModules = explode(',', getParam('bx_attendant_on_profile_creation_modules'));
+        $aModuleData = array();
+        foreach($aModules as $sModuleName){
+            if(BxDolRequest::serviceExists($sModuleName, BX_ATTENDANT_ON_PROFILE_CREATION_METHOD)){
+                $aTmp = BxDolService::call($sModuleName, BX_ATTENDANT_ON_PROFILE_CREATION_METHOD, ['unit_view' => 'showcase', 'empty_message' => false, "ajax_paginate" => false]);
+
+                if (isset($aTmp['content'])){
+                    $sTmp = $aTmp['content'];
+                    $sTmp = str_replace('bx_conn_action', 'bx_attendant_conn_action', $sTmp);
+                    $aModuleData[$sModuleName] = $sTmp;
+                }
+            }
+        }
+        
+        $oSession = BxDolSession::getInstance();
+        $sFirstPage = $oSession->getValue('sys_entrance_url');
+       
+        if ($sFirstPage){
+            if (getParam('bx_attendant_redirect_to_entered_page') == 'on'){
+                echo json_encode(['redirect' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink($sFirstPage)]);  
+                exit();
+            }
+            else{
+                if(getParam('bx_attendant_suggest_entered_page') == 'on'){
+                    list($sPageLink, $aPageParams) = bx_get_base_url($sFirstPage);
+                    if (isset($aPageParams['i']) && isset($aPageParams['id'])){
+                        $oPage = BxDolPage::getObjectInstanceByURI($aPageParams['i']);
+
+                        if ($oPage){
+                            $sModuleName = $oPage->getModule();
+                            if(bx_srv('system', 'is_module_context', [$sModuleName])){
+
+                                $oModule = BxDolModule::getInstance($sModuleName);
+                                $aTmp = $oModule->serviceBrowse([
+                                    'mode' => 'recent',
+                                    'params' => [
+                                        'filter' => [
+                                            'field' => 'id',
+                                            'value' => [$aPageParams['id']],
+                                            'operator' => 'in',
+                                            'table' => 'tableSearch'
+                                        ],
+                                    ]
+                                ]);
+
+                                if (isset($aTmp['content'])){
+                                    $sTmp = $aTmp['content'];
+                                    $sTmp = str_replace('bx_conn_action', 'bx_attendant_conn_action', $sTmp);
+                                    $aModuleData[$sModuleName. '_initial_link'] = $sTmp;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        
+        $sRv = $this->_oTemplate->popup($aModuleData, $bManual);
+        
+        bx_alert('bx_attendant', 'show_popup', bx_get_logged_profile_id(), 0, ['module' => $sModule, 'event' => $sEvent, 'object_id' => $iObjectId, 'result' => &$sRv]);
+        
+        echo $sRv;
+    }
+    
+    /**
+     * Service methods
+     */
+    
+    /**
+     * @page service Service Calls
+     * @section bx_attendant Attendant
+     * @subsection bx_attendant-other Other
+     * @subsubsection bx_attendant-on-profile get_profile_modules
+     * 
+     * @code bx_srv('bx_attendant', 'get_profile_modules', [...]); @endcode
+     * 
+     * Get list of avaliable modules for on_profile_creation event
+     * 
+     * @return an array with avaliable modules. 
+     * 
+     * @see BxAttendantModule::serviceGetProfileModules
+     */
+    /** 
+     * @ref bx_attendant-get_profile_modules "get_profile_modules"
+     */
+    public function serviceGetProfileModules()
+    {
+        $aResult = array();
+        $BxDolModuleQuery = BxDolModuleQuery::getInstance();
+        $aModules = $BxDolModuleQuery->getModulesBy(array('type' => 'modules', 'active' => 1));
+        foreach($aModules as $aModule){
+            if(BxDolRequest::serviceExists($aModule['name'], BX_ATTENDANT_ON_PROFILE_CREATION_METHOD)){
+                $aResult[$aModule['name']] = $aModule['title'];
+            }
+        }
+        return $aResult;
+    }
+    
+    
+    /**
+     * @page service Service Calls
+     * @section bx_attendant Attendant
+     * @subsection bx_attendant-other Other
+     * @subsubsection bx_attendant-on-profile get_options_redirect_after_show
+     * 
+     * @code bx_srv('bx_attendant', 'get_options_redirect_after_show', [...]); @endcode
+     * 
+     * Get list avaliable redirct pages
+     * 
+     * @return an array with avaliable redirct pages. 
+     * 
+     * @see BxAttendantModule::serviceGetOptionsRedirectAfterShow
+     */
+    /** 
+     * @ref bx_attendant-get_options_redirect_after_show "get_options_redirect_after_show"
+     */
+    public function serviceGetOptionsRedirectAfterShow()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aResult = [];
+        $aChoices = ['noredirect', 'homepage', 'profile', 'custom'];
+        foreach($aChoices as $sChoice) 
+            $aResult[] = array('key' => $sChoice, 'value' => _t('_bx_attendant_option_redirect_show_' . $sChoice));
+
+        return $aResult;
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_attendant Attendant
+     * @subsection bx_attendant-other Other
+     * @subsubsection bx_attendant-on-profile get_popup_with_recommended_on_event_show
+     * 
+     * @code bx_srv('bx_attendant', 'get_popup_with_recommended_on_event_show', [...]); @endcode
+     * 
+     * Get list of events for on_profile_creation show
+     * 
+     * @return an array with avaliable events. 
+     * 
+     * @see BxAttendantModule::serviceGetPopupWithRecommendedOnEventShow
+     */
+    /** 
+     * @ref bx_attendant-get_popup_with_recommended_on_event_show "get_popup_with_recommended_on_event_show"
+     */
+    public function serviceGetPopupWithRecommendedOnEventShow()
+    {
+        $aResult = array();
+        $aChoices = array(BX_ATTENDANT_ON_PROFILE_CREATION_EVENT_AFTER_CONFIRMATION, BX_ATTENDANT_ON_PROFILE_CREATION_EVENT_AFTER_REGISTRATION);
+        foreach($aChoices as $sChoice)
+            $aResult[$sChoice] = _t('_bx_attendant_popup_event_after_' . $sChoice);
+        
+        return $aResult;
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_attendant Attendant
+     * @subsection bx_attendant-other Other
+     * @subsubsection bx_attendant-get_profile_modules handle_action_view
+     * 
+     * @code bx_srv('bx_attendant', 'handle_action_view', [...]); @endcode
+     * 
+     * Get Include for injection
+     * 
+     * @return an include code
+     * 
+     * @see BxAttendantModule::HandleActionView
+     */
+    /** 
+     * @ref bx_attendant-handle_action_view "handle_action_view"
+     */
+    public function serviceHandleActionView()
+    {
+        $sRv = $this->_oTemplate->init();
+        
+        if (!isLogged())
+            return;
+        
+        $aEvents = $this->_oDb->getEvents(array('type' => 'active_by_action_and_profile_id', 'action' => 'view', 'profile_id' => bx_get_logged_profile_id()));
+        foreach($aEvents as $aEvent){
+            //$oRv = call_user_func_array(array($this, $aEvent['method']), array($aEvent['object_id']));
+            $oRv = $this->processPopupOnEvent($aEvent);
+            if ($oRv !== false){
+                $sRv .= $oRv;
+                $this->_oDb->setEventProcessed($aEvent['id']);
+            }
+        }
+        
+        return $sRv;
+    }
+    
+    public function serviceHandleActionNonView()
+    {
+       //for some other actions fex cron - not implemented
+    }
+    
+    public function addEvent($sAction, $iObjectId, $sModule, $sEvent, $iProfileId)
+    {
+        $this->_oDb->addEvent($sAction, $iObjectId, $sModule, $sEvent, $iProfileId);
+    }
+    
+    public function initPopupByEvent($iObjectId, $sModule, $sEvent, $iProfileId)
+    {
+        $this->addEvent('view', $iObjectId, $sModule, $sEvent, $iProfileId);
+    }
+    
+    public function processPopupOnEvent($aEvent)
+    {
+        $sRv = '';
+        $sDefaultEvent = getParam('bx_attendant_on_profile_event_list');
+        $oProfile = BxDolProfile::getInstance($aEvent['profile_id']);
+        $oAccount = $oProfile ? $oProfile->getAccountObject() : null;
+        $bNeedRaiseEvent = false;
+        if ($aEvent['event'] == 'add' && $aEvent['module'] == 'profile'){
+            if (getParam('bx_attendant_on_profile_creation_modules') != '' && ($sDefaultEvent == BX_ATTENDANT_ON_PROFILE_CREATION_EVENT_AFTER_REGISTRATION || ($sDefaultEvent == BX_ATTENDANT_ON_PROFILE_CREATION_EVENT_AFTER_CONFIRMATION  && $oAccount != null &&  $oAccount->isConfirmed()))){
+                if ($oProfile->getModule() != 'system'){
+                    $bNeedRaiseEvent = true;
+                }
+            }
+        }
+        else{
+            bx_alert('bx_attendant', 'before_show_popup', bx_get_logged_profile_id(), 0, ['module' => $aEvent['module'], 'event' => $aEvent['event'], 'object_id' => $aEvent['object_id'], 'result' => &$bNeedRaiseEvent]);
+        }
+        if ($bNeedRaiseEvent)
+            return getParam('bx_attendant_on_profile_creation_modules').'<script>oBxAttendant.showPopup("' . $aEvent['module'] . '", "' . $aEvent['event'] . '", ' . $aEvent['object_id'] . ')</script>';
+        else
+            return false;
+    }
+}
+
+/** @} */

+ 121 - 0
modules/boonex/attendant/updates/13.0.2_13.0.3/source/classes/BxAttendantTemplate.php

@@ -0,0 +1,121 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Attendant Attendant
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+bx_import ('BxDolModuleTemplate');
+
+class BxAttendantTemplate extends BxBaseModGeneralTemplate
+{
+    var $sContainerId = 'oBxAttendantPopupWithRecommendedOnProfileAdd';
+    
+    function __construct(&$oConfig, &$oDb)
+    {
+        parent::__construct($oConfig, $oDb);
+    }
+    
+    public function init()
+    {
+        $this->addJs([
+                'main.js', 
+                'flickity/flickity.pkgd.min.js', 
+                'modules/base/general/js/|showcase.js'
+            ]
+        );
+        $this->addCss([
+                'main.css', 
+                BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'flickity/|flickity.css'
+            ]
+        );
+        if (isLogged())
+            return $this->getJsCode('main') . BxBaseFunctions::getInstance()->transBox($this->sContainerId, '', true, true);
+        
+        return '';
+    }
+    
+    public function popup($aModuleData, $bManual)
+    {
+        $aVars = [];
+        
+        foreach ($aModuleData as $sModuleName => $sModuleData){            
+           $aVars[] = [
+               'html' => $sModuleData, 
+               'title' => $this->getStringValueByModuleOrDefault('_bx_attendant_popup_with_recommended_title_', $sModuleName) , 
+               'description' => $this->getStringValueByModuleOrDefault('_bx_attendant_popup_with_recommended_description_', $sModuleName)
+           ];
+        }
+        
+        if ($bManual || count($aVars) >0){
+            return $this->parseHtmlByName('popup_recommended.html', [
+                    'bx_if:data' => [
+                        'condition' => count($aVars) > 0,
+                        'content' => [
+                            'bx_repeat:items' => $aVars, 
+                            'button_text' => _t('_bx_attendant_popup_with_recommended_button_text')
+                        ]
+                    ],
+                    'bx_if:nodata' => [
+                        'condition' => count($aVars) == 0,
+                        'content' => [
+                        ]
+                    ]
+                ]
+            );
+        }
+        else{
+            return '';
+        }
+    }
+    
+    public function getJsCode($sType, $aParams = array(), $bWrap = true)
+    {
+        $sRedirectUrl = '';
+        switch (getParam('bx_attendant_on_profile_after_action_url')) {
+            case 'profile':
+                $sRedirectUrl = BxDolProfile::getInstance()->getUrl();
+                break;
+
+            case 'custom':
+                $sRedirectCustom = getParam('bx_attendant_on_profile_after_action_url_custom');
+                if($sRedirectCustom) {
+                    $sRedirectUrl = BxDolPermalinks::getInstance()->permalink($sRedirectCustom);
+
+                    if (false === strpos($sRedirectUrl, 'http://') && false === strpos($sRedirectUrl, 'https://'))
+                        $sRedirectUrl = BX_DOL_URL_ROOT . $sRedirectCustom;
+                }
+                break;
+                
+            case 'homepage':
+                $sRedirectUrl =  BX_DOL_URL_ROOT;  
+                break;
+        }
+        
+        $aParams = array_merge(array(
+            'sContainerId' => $this->sContainerId,
+            'sUrlAfterShow' => $sRedirectUrl
+        ), $aParams);
+        
+        return parent::getJsCode($sType, $aParams, $bWrap);
+    }
+
+    private function getStringValueByModuleOrDefault($sKey, $sModuleName)
+    {
+        $sFullKey = $sKey . $sModuleName;
+        $sValue = _t($sFullKey);
+        if ($sValue == $sFullKey){
+            $oModule = BxDolModule::getInstance($sModuleName);
+            if ($oModule)
+                $sValue =_t($sKey . 'default', $oModule->_aModule['title']);
+        }
+        return $sValue;
+    }
+    
+}
+
+/** @} */

+ 77 - 0
modules/boonex/attendant/updates/13.0.2_13.0.3/source/install/config.php

@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Attendant Attendant
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_attendant',
+    'title' => 'Attendant',
+    'note' => 'Attendant module.',
+    'version' => '13.0.3',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/attendant/',
+    'home_uri' => 'attendant',
+
+    'db_prefix' => 'bx_attendant_',
+    'class_prefix' => 'BxAttendant',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Attendant',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 51 - 0
modules/boonex/channels/updates/13.0.2_13.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Channels',
+    'version_from' => '13.0.2',
+    'version_to' => '13.0.3',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/channels/updates/update_13.0.2_13.0.3/',
+    'home_uri' => 'channels_update_1302_1303',
+
+    'module_dir' => 'boonex/channels/',
+    'module_uri' => 'channels',
+
+    'db_prefix' => 'bx_cnl_',
+    'class_prefix' => 'BxCnl',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Channels',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/channels/updates/13.0.2_13.0.3/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxCnlUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 4 - 0
modules/boonex/channels/updates/13.0.2_13.0.3/install/langs/en.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_channels_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string_add>
+</resources>

+ 13 - 0
modules/boonex/channels/updates/13.0.2_13.0.3/install/sql/enable.sql

@@ -0,0 +1,13 @@
+SET @sName = 'bx_channels';
+
+
+-- MENUS
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_channels_submenu' AND `name`='channels-administration';
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_channels_submenu', 'bx_channels', 'channels-administration', '_bx_channels_menu_item_title_system_entries_manage', '_bx_courses_menu_item_title_entries_manage', 'page.php?i=channels-administration', '', '', '', '', 192, 1, 1, 5);
+
+UPDATE `sys_menu_items` SET `active`='0' WHERE `set_name`='bx_channels_menu_manage_tools' AND `name`='delete-with-content';
+
+
+-- GRIDS
+UPDATE `sys_grid_actions` SET `active`='0' WHERE `object`='bx_channels_administration' AND `type`='bulk' AND `name`='delete_with_content';

+ 189 - 0
modules/boonex/channels/updates/13.0.2_13.0.3/source/classes/BxCnlConfig.php

@@ -0,0 +1,189 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defdroup    Channels Channels
+ * @indroup     UnaModules
+ *
+ * @{
+ */
+
+class BxCnlConfig extends BxBaseModGroupsConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_aMenuItems2MethodsActions = array_merge($this->_aMenuItems2MethodsActions, array(
+            'view-channel-profile' => 'checkAllowedView',
+            'edit-channel-profile' => 'checkAllowedEdit',
+            'edit-channel-cover' => 'checkAllowedChangeCover',
+            'invite-to-channel' => 'checkAllowedInvite',
+            'delete-channel-profile' => 'checkAllowedDelete',
+        ));
+
+        $this->CNF = array (
+
+            // module icon
+            'ICON' => 'hashtag col-red2',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'data',
+            'TABLE_ENTRIES_FULLTEXT' => 'search_fields',
+            'TABLE_CONTENT' => $aModule['db_prefix'] . 'content',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => 'author',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => 'changed',
+            'FIELD_NAME' => 'channel_name',
+            'FIELD_TITLE' => 'channel_name',
+            'FIELD_PICTURE' => 'picture',
+            'FIELD_COVER' => 'cover',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_CF' => 'cf',
+            'FIELD_VIEWS' => 'views',
+            'FIELD_COMMENTS' => 'comments',
+            'FIELD_STATUS' => 'status',
+            'FIELD_STATUS_ADMIN' => '',
+            'FIELDS_QUICK_SEARCH' => array('channel_name'),
+            'FIELDS_WITH_KEYWORDS' => 'auto', // can be 'auto', array of fields or comma separated string of field names, works only when OBJECT_METATAGS is specified
+
+            // page URIs
+            'URI_VIEW_ENTRY' => 'view-channel-profile',
+            'URI_EDIT_ENTRY' => 'edit-channel-profile',
+            'URI_EDIT_COVER' => 'edit-channel-cover',
+            'URI_JOINED_ENTRIES' => 'channels-author',
+
+            'URL_HOME' => 'page.php?i=channels-home',
+            'URL_MANAGE_COMMON' => 'page.php?i=channels-manage',
+            'URL_MANAGE_ADMINISTRATION' => 'page.php?i=channels-administration',
+
+            'PARAM_DEFAULT_AUTHOR' => 'bx_channels_default_author',
+            'PARAM_NUM_RSS' => 'bx_channels_num_rss',
+          
+            'PARAM_SEARCHABLE_FIELDS' => 'bx_channels_searchable_fields',
+            'PARAM_PER_PAGE_BROWSE_SHOWCASE' => 'bx_channels_per_page_browse_showcase',
+            'PARAM_PER_PAGE_BROWSE_RECOMMENDED' => 'bx_channels_per_page_browse_recommended',
+
+            // objects
+            'OBJECT_STORAGE' => 'bx_channels_pics',
+            'OBJECT_STORAGE_COVER' => 'bx_channels_pics',
+            'OBJECT_IMAGES_TRANSCODER_THUMB' => 'bx_channels_thumb',
+            'OBJECT_IMAGES_TRANSCODER_ICON' => 'bx_channels_icon',
+            'OBJECT_IMAGES_TRANSCODER_AVATAR' => 'bx_channels_avatar',
+            'OBJECT_IMAGES_TRANSCODER_AVATAR_BIG' => 'bx_channels_avatar_big',
+            'OBJECT_IMAGES_TRANSCODER_PICTURE' => 'bx_channels_picture',
+            'OBJECT_IMAGES_TRANSCODER_COVER' => 'bx_channels_cover',
+            'OBJECT_IMAGES_TRANSCODER_COVER_THUMB' => 'bx_channels_cover_thumb',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => 'bx_channels_gallery',
+            'OBJECT_VIEWS' => 'bx_channels',
+            'OBJECT_VOTES' => 'bx_channels',
+            'OBJECT_SCORES' => 'bx_channels',
+            'OBJECT_FAVORITES' => 'bx_channels',
+            'OBJECT_FEATURED' => 'bx_channels',
+            'OBJECT_COMMENTS' => 'bx_channels',
+            'OBJECT_REPORTS' => 'bx_channels',
+            'OBJECT_METATAGS' => 'bx_channels',
+            'OBJECT_NOTES' => 'bx_cnl_notes',
+            'OBJECT_FORM_ENTRY' => 'bx_channel',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => 'bx_channel_view',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW_FULL' => 'bx_channel_view_full', // for "info" tab on view channel page
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_channel_add',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => 'bx_channel_edit',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT_COVER' => 'bx_channel_edit_cover',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_channel_delete',
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_channels_view_actions', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_MORE' => 'bx_channels_view_actions_more', // actions menu on view entry page for "more" popup
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL' => 'bx_channels_view_actions_all', // all actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_channels_my', // actions menu on profile entries page
+            'OBJECT_MENU_SUBMENU' => 'bx_channels_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => '',  // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'channels-home', // first item in view entry submenu from main module submenu
+            'OBJECT_MENU_SNIPPET_META' => 'bx_channels_snippet_meta', // menu for snippet meta info
+            'OBJECT_MENU_MANAGE_TOOLS' => 'bx_channels_menu_manage_tools', //manage menu in content administration tools
+            'OBJECT_PAGE_VIEW_ENTRY' => 'bx_channels_view_profile',
+            'OBJECT_PAGE_VIEW_ENTRY_CLOSED' => 'bx_channels_view_profile_closed',
+            'OBJECT_PRIVACY_VIEW' => 'bx_channels_allow_view_to',
+            'OBJECT_PRIVACY_VIEW_NOTIFICATION_EVENT' => 'bx_channels_allow_view_notification_to',
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_channels_administration',
+            'OBJECT_UPLOADERS_COVER' => array('bx_channels_cover_crop'),
+            'OBJECT_UPLOADERS_PICTURE' => array('bx_channels_picture_crop'),
+      
+
+            'TRIGGER_MENU_PROFILE_VIEW_SUBMENU' => 'trigger_group_view_submenu',
+            'TRIGGER_MENU_PROFILE_SNIPPET_META' => 'trigger_group_snippet_meta',
+            'TRIGGER_MENU_PROFILE_VIEW_ACTIONS' => 'trigger_group_view_actions',
+            'TRIGGER_PAGE_VIEW_ENTRY' => 'trigger_page_group_view_entry',
+
+            // menu items which visibility depends on custom visibility checking
+            'MENU_ITEM_TO_METHOD' => array (
+                'bx_channels_view_actions' => $this->_aMenuItems2MethodsActions,
+                'bx_channels_view_actions_more' => $this->_aMenuItems2MethodsActions,
+            ),
+
+            // informer messages
+            'INFORMERS' => array (
+                'status' => array (
+                    'name' => 'bx-channels-status-not-active',
+                    'map' => array (
+                        BX_PROFILE_STATUS_PENDING => '_bx_channels_txt_account_pending',
+                        BX_PROFILE_STATUS_SUSPENDED => '_bx_channels_txt_account_suspended',
+                    ),
+                ),
+            ),
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_channels_txt_sample_single',
+                'txt_sample_single_with_article' => '_bx_channels_txt_sample_single_with_article',
+                'txt_sample_comment_single' => '_bx_channels_txt_sample_comment_single',
+                'txt_sample_vote_single' => '_bx_channels_txt_sample_vote_single',
+                'txt_sample_score_up_single' => '_bx_channels_txt_sample_score_up_single',
+                'txt_sample_score_down_single' => '_bx_channels_txt_sample_score_down_single',
+                'txt_private_group' => '_bx_channels_txt_private_channel',
+                'txt_ntfs_timeline_post_common' => '_bx_channels_txt_ntfs_timeline_post_common',
+                'form_field_author' => '_bx_channels_form_entry_input_author',
+                'menu_item_title_befriend_sent' => '_bx_channels_menu_item_title_befriend_sent',
+                'menu_item_title_unfriend_cancel_request' => '_bx_channels_menu_item_title_unfriend_cancel_request',
+                'menu_item_title_befriend_confirm' => '_bx_channels_menu_item_title_befriend_confirm',
+                'menu_item_title_unfriend_reject_request' => '_bx_channels_menu_item_title_unfriend_reject_request',
+                'menu_item_title_befriend' => '_bx_channels_menu_item_title_befriend',
+                'menu_item_title_unfriend' => '_bx_channels_menu_item_title_unfriend',
+                'grid_action_err_delete' => '_bx_channels_grid_action_err_delete',
+                'grid_txt_account_manager' => '_bx_channels_grid_txt_account_manager',
+                'filter_item_active' => '_bx_channels_grid_filter_item_title_adm_active',
+                'filter_item_hidden' => '_bx_channels_grid_filter_item_title_adm_hidden',
+                'filter_item_pending' => '_bx_channels_grid_filter_item_title_adm_pending',
+                'filter_item_suspended' => '_bx_channels_grid_filter_item_title_adm_suspended',
+                'filter_item_select_one_filter1' => '_bx_channels_grid_filter_item_title_adm_select_one_filter1',
+                'filter_item_select_one_filter2' => '_bx_channels_grid_filter_item_title_adm_select_one_filter2',
+                'menu_item_manage_my' => '_bx_channels_menu_item_title_manage_my',
+                'menu_item_manage_all' => '_bx_channels_menu_item_title_manage_all',
+                'txt_all_entries_by_author' => '_bx_channels_page_title_browse_by_author'
+            ),
+
+        );
+
+        $this->_aJsClasses = array(
+            'manage_tools' => 'BxCnlManageTools'
+        );
+
+        $this->_aJsObjects = array(
+            'manage_tools' => 'oBxCnlManageTools'
+        );
+
+        $this->_aGridObjects = array(
+            'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION']
+        );
+    }
+
+    public function isFans()
+    {
+        return false;
+    }
+}
+
+/** @} */

+ 563 - 0
modules/boonex/channels/updates/13.0.2_13.0.3/source/classes/BxCnlModule.php

@@ -0,0 +1,563 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defdroup    Channels Channels
+ * @indroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Channels profiles module.
+ */
+
+class BxCnlModule extends BxBaseModGroupsModule
+{
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+
+    public function _modGroupsCheckAllowedSubscribeAdd(&$aDataEntry, $isPerformAction = false)
+    {
+        return parent::_modProfileCheckAllowedSubscribeAdd($aDataEntry, $isPerformAction);
+    }
+
+    /**
+     * Process Hash Tag
+     * 
+     * @param string $sHashtag - hashtag to be processed.
+     * @param string $sModuleName - module name.
+     * @param integer $iContentId - ID of the content which has the hashtag.
+     * @param integer $iAuthorId - action's author id.
+     */
+    function processHashtag($sHashtag, $sModuleName, $iContentId, $iAuthorId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        /*
+         * Note! For now metatag object name is used here as module name, because usually it's equal to module's name. This should be changed in Ticket #1596
+         * For now if module cannot be created then a channel for such tag shouldn't be created too.
+         */
+
+        $oModule = BxDolModule::getInstance($sModuleName);
+        if(empty($oModule) && $sModuleName != 'sys_cmts')
+            return;
+
+        /*
+         * Use content's author profile when Author ID wasn't provided. 
+         * Usually it happens when tags were processed with cron.
+         */
+        if(empty($iAuthorId))
+            $iAuthorId = BxDolService::call($sModuleName, 'get_author', array($iContentId));
+
+        $aCheck = checkActionModule($this->_iProfileId, 'create channel auto', $this->getName(), false);
+        $mixedCnlId = $this->_oDb->getChannelIdByName($sHashtag);
+        if(empty($mixedCnlId) && ($aCheck[CHECK_ACTION_RESULT] == CHECK_ACTION_RESULT_ALLOWED)) {
+            $iProfileId = (int)$this->_oDb->getParam($CNF['PARAM_DEFAULT_AUTHOR']);
+            if(empty($iProfileId)) {
+                $aOperators = BxDolAccountQuery::getInstance()->getOperators();
+                if(count($aOperators) > 0)
+                    $iProfileId = BxDolProfile::getInstanceByAccount(array_shift($aOperators))->id();
+            }
+
+            $aContent = $this->serviceEntityAdd($iProfileId, array($CNF['FIELD_NAME'] => $sHashtag, $CNF['FIELD_CF'] => 1));
+            checkActionModule($this->_iProfileId, 'create channel auto', $this->getName(), true);
+            if(isset($aContent['content']) && isset($aContent['content']['id']))
+                $mixedCnlId = $aContent['content']['id'];
+        }
+
+        if(empty($mixedCnlId) || (int)$this->_oDb->checkContentInChannel($iContentId, $mixedCnlId, $sModuleName, $iAuthorId) != 0)
+            return;
+
+        $iId = (int)$this->_oDb->addContentToChannel($iContentId, $mixedCnlId, $sModuleName, $iAuthorId);
+        if($iId == 0)
+            return;
+
+        $oCnlProfile = BxDolProfile::getInstanceByContentAndType($mixedCnlId, $this->_oConfig->getName());
+        if(!$oCnlProfile)
+            return;
+
+        $iCnlProfileId = $oCnlProfile->id();
+
+        bx_alert($this->_aModule['name'], 'hashtag_added', $iId, $iCnlProfileId, array(
+            'object_author_id' => $iAuthorId, 
+            'privacy_view' => -$iCnlProfileId,
+
+            'timeline_group' => array(
+                'by' => $sModuleName . '_' . $iAuthorId . '_' . $iContentId,
+                'field' => 'owner_id'
+            )
+        ));
+        $aParams = array(
+            'object_author_id' => $iAuthorId, 
+            'privacy_view' => -$iCnlProfileId, 
+            'subobject_id' => $iId,
+			'content_module' => $sModuleName,
+            'content_id' => $iContentId,
+            'content_author_id' => $iAuthorId
+        );
+        bx_alert('system', 'prepare_alert_params', 0, 0, array('unit'=> $this->_aModule['name'], 'action' => 'hashtag_added_notif', 'object_id' => $mixedCnlId, 'sender_id' => $iCnlProfileId, 'extras' => &$aParams));
+        bx_alert($this->_aModule['name'], 'hashtag_added_notif', $mixedCnlId, $iCnlProfileId, $aParams);
+    }
+    
+    function removeContentFromChannel($iContentId, $sModuleName)
+    {
+        $oDolProfileQuery = BxDolProfileQuery::getInstance();
+        
+        $aData = $this->_oDb->getDataByContent($iContentId, $sModuleName);
+        foreach ($aData as $aRow) {
+            $iProfileInfo = $oDolProfileQuery->getProfileByContentAndType($aRow['cnl_id'], $this->_aModule['name']);
+            if(is_array($iProfileInfo)){
+                bx_alert($this->_aModule['name'], 'hashtag_deleted', $aRow['id'], $iProfileInfo['id']);
+                bx_alert($this->_aModule['name'], 'hashtag_deleted_notif', $aRow['cnl_id'], $iProfileInfo['id'], array('subobject_id' => $aRow['id']));
+            }
+        }
+        
+        return $this->_oDb->removeContentFromChannel($iContentId, $sModuleName);
+    }
+
+    public function serviceGetSafeServices()
+    {
+        $a = parent::serviceGetSafeServices();
+        unset($a['GetCreatePostForm']);
+        unset($a['EntityCreate']);
+        return array_merge($a, array (
+            'EntityBreadcrumb' => '',
+            'EntityParent' => '',
+            'EntityChilds' => '',
+            'SearchResultByHashtag' => '',
+        ));
+    }
+
+    public function serviceGetWidgetNotices()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iResult = 0;
+        if(empty($this->_oDb->getParam($CNF['PARAM_DEFAULT_AUTHOR'])))
+            $iResult += 1;
+
+        return $iResult;
+    }
+
+    public function serviceGetOptionsDefaultAuthor()
+    {
+        $aResult = array(
+            array('key' => '', 'value' => _t('_Select_one'))
+        );
+
+        $aAccountsIds = BxDolAccountQuery::getInstance()->getOperators();
+        foreach($aAccountsIds as $iAccountId) {
+            $aProfilesIds = BxDolAccount::getInstance($iAccountId)->getProfilesIds();
+            foreach($aProfilesIds as $iProfileId)
+                $aResult[] = array(
+                    'key' => $iProfileId,
+                    'value' => BxDolProfile::getInstance($iProfileId)->getDisplayName()
+                );
+        }
+
+        return $aResult;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_channels Channels
+     * @subsection bx_channels-page_blocks Page Blocks
+     * @subsubsection bx_channels-entity_breadcrumb entity_breadcrumb
+     * 
+     * @code bx_srv('bx_channels', 'entity_breadcrumb', [...]); @endcode
+     * 
+     * Display channel breadcrumb
+     * @param $iContentId channel content ID
+     * 
+     * @see BxCnlModule::serviceEntityBreadcrumb
+     */
+    /** 
+     * @ref bx_channels-entity_breadcrumb "entity_breadcrumb"
+     */
+    public function serviceEntityBreadcrumb($iContentId = 0)
+    {
+    	if(!$iContentId)
+            $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if(!$iContentId)
+            return false;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(!$aContentInfo)
+            return false;
+
+        return $this->_oTemplate->entryBreadcrumb($aContentInfo);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_channels Channels
+     * @subsection bx_channels-page_blocks Page Blocks
+     * @subsubsection bx_channels-entity_parent entity_parent
+     * 
+     * @code bx_srv('bx_channels', 'entity_parent', [...]); @endcode
+     * 
+     * Display block with parent channel
+     * @param $iContentId channel content ID
+     * 
+     * @see BxCnlModule::serviceEntityParent
+     */
+    /** 
+     * @ref bx_channels-entity_parent "entity_parent"
+     */
+    public function serviceEntityParent($iContentId = 0)
+    {
+        return $this->_serviceTemplateFunc('entryParent', $iContentId);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_channels Channels
+     * @subsection bx_channels-page_blocks Page Blocks
+     * @subsubsection bx_channels-entity_childs entity_childs
+     * 
+     * @code bx_srv('bx_channels', 'entity_childs', [...]); @endcode
+     * 
+     * Display block with child channels
+     * @param $iContentId channel content ID
+     * 
+     * @see BxCnlModule::serviceEntityChilds
+     */
+    /** 
+     * @ref bx_channels-entity_childs "entity_childs"
+     */
+    public function serviceEntityChilds($iContentId = 0)
+    {
+        return $this->_serviceTemplateFunc('entryChilds', $iContentId);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_channels Channels
+     * @subsection bx_channels-page_blocks Page Blocks
+     * @subsubsection bx_channels-search_result_by_hashtag search_result_by_hashtag
+     * 
+     * @code bx_srv('bx_channels', 'search_result_by_hashtag', [...]); @endcode
+     * 
+     * Display search results by hashtag for particular channel
+     * @param $iContentId channel content ID
+     * 
+     * @see BxCnlModule::serviceSearchResultByHashtag
+     */
+    /** 
+     * @ref bx_channels-search_result_by_hashtag "search_result_by_hashtag"
+     */
+    public function serviceSearchResultByHashtag($iContentId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        $oSearch = new BxTemplSearch();
+        $oSearch->setLiveSearch(0);
+        $oSearch->setMetaType('keyword');
+        $aContentInfo = $this->_oDb->getContentInfoById(bx_get('id'));
+        $_GET['keyword'] = $aContentInfo[$CNF['FIELD_NAME']];
+        $sCode = $oSearch->response();
+        if (!$sCode)
+            $sCode = $oSearch->getEmptyResult();
+        
+        return $sCode;
+    }
+    
+    /**
+     * Data for Timeline module
+     */
+    public function serviceGetTimelineData()
+    {
+        $sModule = $this->_aModule['name'];
+
+        return array(
+            'handlers' => array(
+                array('group' => $sModule . '_hastag', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'hashtag_added', 'module_name' => $sModule, 'module_method' => 'get_timeline_post_hashtag', 'module_class' => 'Module',  'groupable' => 0, 'group_by' => ''),
+                array('group' => $sModule . '_hastag', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'hashtag_deleted')
+            ),
+            'alerts' => array(
+                array('unit' => $sModule, 'action' => 'hashtag_added'),
+                array('unit' => $sModule, 'action' => 'hashtag_deleted')
+            )
+        );
+    }
+
+    public function serviceGetTimelinePostAllowedView ($aEvent)
+    {
+        $sError = _t('_sys_txt_access_denied');
+
+        if(empty($aEvent) || !is_array($aEvent))
+            return $sError;
+
+        $aEventContent = $this->_oDb->getContentById($aEvent['object_id']);
+        
+        if ($aEventContent['module_name'] == 'sys_cmts')
+            return CHECK_ACTION_RESULT_ALLOWED;
+            
+        if(empty($aEventContent) || !is_array($aEventContent))
+            return $sError;
+
+        if(!BxDolRequest::serviceExists($aEventContent['module_name'], 'get_timeline_post_allowed_view'))
+            return $sError;
+
+        return BxDolService::call($aEventContent['module_name'], 'get_timeline_post_allowed_view', array(array('id' => $aEvent['id'], 'owner_id' => $aEventContent['author_id'], 'object_id' => $aEventContent['content_id'])));
+    }
+
+    public function serviceGetTimelinePostHashtag($aEvent, $aBrowseParams = array())
+    {
+        if(empty($aEvent) || !is_array($aEvent))
+            return false;
+        
+        $aEventContent = $this->_oDb->getContentById($aEvent['object_id']);
+        if(empty($aEventContent) || !is_array($aEventContent))
+            return false;
+       
+        $sModule = $aEventContent['module_name'];
+        $sClass = 'Module';
+        if($sModule == 'sys_cmts'){
+            $sClass = 'TemplCmtsServices';
+            $sModule = 'system';
+        }
+        
+        if(!BxDolRequest::serviceExists($sModule, 'get_timeline_post', $sClass))
+            return false;
+        /**
+         * Prepare fake event array (only mandatory parameters) to get
+         * necessary data (related to an 'original' event with hashtag/label) 
+         * from associated content module.
+         */
+        $iOwnerId = (int)$aEventContent['author_id'];
+        $iContentId = (int)$aEventContent['content_id'];
+        $mixedObjectPrivacyView = BX_DOL_PG_ALL;
+        if(BxDolRequest::serviceExists($sModule, 'get_privacy_view')) {
+            $mixedAllowViewTo = BxDolService::call($sModule, 'get_privacy_view', array($iContentId));
+            if($mixedAllowViewTo !== false)
+                $mixedObjectPrivacyView = $mixedAllowViewTo;
+            if(is_numeric($mixedAllowViewTo) && (int)$mixedAllowViewTo < 0)
+                $iOwnerId = abs($mixedAllowViewTo);
+        }
+        $aResult = BxDolService::call($sModule, 'get_timeline_post', array(array(
+            'owner_id' => $iOwnerId,
+            'object_id' => $iContentId,
+            'object_privacy_view' => $mixedObjectPrivacyView
+        ), $aBrowseParams), $sClass);
+
+        if(empty($aResult) || !is_array($aResult))
+            return $aResult;
+        
+        /**
+         * Note. The context shouldn't be changed therefore 
+         * use input event's context (owner_id) in returned results.
+         */
+        return array_merge($aResult, array(
+            'owner_id' => $aEvent['owner_id']
+        ));
+    }
+    
+    /**
+     * Data for Notifications module
+     */
+    public function serviceGetNotificationsData()
+    {      
+        $a = parent::serviceGetNotificationsData();
+
+        $sModule = $this->_aModule['name'];
+
+        $a['handlers'][] = array('group' => $sModule . '_hastag_notif', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'hashtag_added_notif', 'module_name' => $sModule, 'module_method' => 'get_notifications_post_hashtag', 'module_class' => 'Module');
+        $a['handlers'][] = array('group' => $sModule . '_hastag_notif', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'hashtag_deleted_notif');
+
+        $a['settings'][] = array('group' => 'hastag', 'unit' => $sModule, 'action' => 'hashtag_added_notif', 'types' => array('follow_context'));
+
+        $a['alerts'][] = array('unit' => $sModule, 'action' => 'hashtag_added_notif');
+        $a['alerts'][] = array('unit' => $sModule, 'action' => 'hashtag_deleted_notif');
+
+        return $a;
+    }
+
+    public function serviceGetNotificationsPostHashtag($aEvent)
+    {
+        if(empty($aEvent) || !is_array($aEvent))
+            return '';
+
+        $aContentEvent = $this->_oDb->getContentById($aEvent['subobject_id']);
+        if(empty($aContentEvent) || !is_array($aContentEvent))
+            return '';
+
+        $oModule = BxDolModule::getInstance($aContentEvent['module_name']);
+        if ($oModule) {
+            if (isset($oModule->_oConfig->CNF['OBJECT_PRIVACY_VIEW'])){
+                $oPrivacy = BxDolPrivacy::getObjectInstance($oModule->_oConfig->CNF['OBJECT_PRIVACY_VIEW']);
+                if (!$oPrivacy->check($aContentEvent['content_id']))
+                    return '';
+            }
+
+            $aRv = $oModule->serviceGetNotificationsPost(array(
+                'object_id' => $aContentEvent['content_id']
+            ));
+
+            $aRv['lang_key'] = '_bx_channels_ntfs_txt_subobject_added';
+            if(method_exists($oModule, 'serviceActAsProfile') && $oModule->serviceActAsProfile())
+                $aRv['lang_key'] = '_bx_channels_ntfs_txt_subobject_added_profile';
+
+            $aRv['entry_url'] = str_replace(BX_DOL_URL_ROOT, '{bx_url_root}', $this->serviceGetLink($aContentEvent['cnl_id']));
+            return $aRv;
+        }
+
+        return '';
+    }
+    
+    public function serviceBrowseByLevel ($iLevelId = 0, $bDisplayEmptyMsg = false)
+    {
+        return $this->_serviceBrowse ('level', array('level' => $iLevelId), BX_DB_PADDING_DEF, $bDisplayEmptyMsg);
+    }
+    
+    public function serviceBrowseFollowed($iProfileId = 0, $aParams = array())
+    {
+        return $this->_serviceBrowseWithParam ('followed_entries', 'profile_id', $iProfileId, $aParams);
+    }
+
+    public function serviceBrowseAuthor($iProfileId = 0, $aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($iProfileId))
+            $iProfileId = bx_get_logged_profile_id();
+
+        $sResult = isset($aParams['empty_message']) && (bool)$aParams['empty_message'] === true ? MsgBox(_t('_Empty')) : '';
+
+        $oConnection = BxDolConnection::getObjectInstance('sys_profiles_subscriptions');
+        if(!$oConnection)
+            return $sResult;
+
+        $aProfiles = $oConnection->getConnectedContentByType($iProfileId, $this->getName());
+
+        $aTmplVars = [];
+        foreach ($aProfiles as $iProfileId) {
+            $oProfile = BxDolProfile::getInstance($iProfileId);
+            if(!$oProfile)
+                continue;
+
+            $aTmplVars[] = [
+                'unit' => $oProfile->getUnit(0, ['template' => 'unit_wo_cover'])
+            ];
+        }
+
+        if(empty($aTmplVars) || !is_array($aTmplVars))
+            return $sResult;
+
+        return $this->_oTemplate->parseHtmlByName('my_channels.html', [
+            'bx_repeat:items' => $aTmplVars
+        ]);
+    }
+
+    public function serviceDeleteProfileFromFansAndAdmins ($iProfileId)
+    {
+        return true;
+    }
+
+    public function serviceGetFollowingChannelsNames($iProfileId)
+    {
+        if (!($oConn = BxDolConnection::getObjectInstance('sys_profiles_subscriptions')))
+            return array();
+
+        if (!($aIds = $oConn->getConnectedContent($iProfileId)))
+            return array();
+
+        $a = array();
+        foreach ($aIds as $iId) {
+            if (!($oProfile = BxDolProfile::getInstance($iId)))
+                continue;
+            if ($oProfile->getModule() != $this->getName())
+                continue;
+            $a[] = $oProfile->getDisplayName();
+        }
+        return $a;
+    }
+
+    public function checkAllowedCompose(&$aDataEntry, $isPerformAction = false)
+    {
+        return _t('_sys_txt_access_denied');
+    }
+
+    public function checkAllowedContact($aDataEntry, $isPerformAction = false)
+    {
+        return _t('_sys_txt_access_denied');
+    }
+
+    public function followLabels($sModule, $iContentId)
+    {
+        if (!getParam('bx_channels_labels_autofollow'))
+            return;
+        
+        if (!($oModuleProfiles = BxDolModule::getInstance($sModule)))
+            return;
+
+        if (!($aContentInfo = $oModuleProfiles->_oDb->getContentInfoById($iContentId)) || !($oProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $sModule)))
+            return;
+
+        $CNF = &$oModuleProfiles->_oConfig->CNF;
+        
+        if (!$oModuleProfiles->serviceActAsProfile() || !isset($CNF['FIELD_LABELS']) || empty($aContentInfo[$CNF['FIELD_ID']]))
+            return;
+
+        if (!($oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS'])) || !$oMetatags->keywordsIsEnabled() || !($aLabels = $oMetatags->keywordsGet($aContentInfo[$CNF['FIELD_ID']])))
+            return;
+
+        if (!($oConn = BxDolConnection::getObjectInstance('sys_profiles_subscriptions')))
+            return;
+
+        foreach ($aLabels as $sLabel) {
+
+            if (!($iContentIdChannel = $this->_oDb->getChannelIdByName($sLabel)))
+                continue;
+
+            if (!($oProfileChannel = BxDolProfile::getInstanceByContentAndType($iContentIdChannel, 'bx_channels')))
+                continue;
+
+            $oConn->addConnection($oProfile->id(), $oProfileChannel->id());
+        }
+    }
+
+    /** Returns profile's subscribed channels  React Jot
+     *
+     * @param int $iProfileId
+     * @param array $aParams
+     * @return array
+     */
+
+    public function serviceBrowseAuthorChannels($iProfileId = 0, $aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($iProfileId))
+            $iProfileId = bx_get_logged_profile_id();
+
+        $oConnection = BxDolConnection::getObjectInstance('sys_profiles_subscriptions');
+        $aProfile = $oConnection->getConnectedContent($iProfileId);
+        $aVars = array();
+        foreach ($aProfile as $iProfileId) {
+            $oProfile = BxDolProfile::getInstance($iProfileId);
+            if (!$oProfile || $oProfile->getModule() != $this->getName())
+                continue;
+
+            $iContentId = $oProfile->getContentId();
+            $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+
+            if (isset($aContentInfo[$CNF['FIELD_NAME']]))
+                array_push($aVars, array(
+                    'title' => $aContentInfo[$CNF['FIELD_NAME']],
+                    'link' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iContentId),
+                    'followers' => $oConnection -> getConnectedInitiatorsCount($iProfileId),
+                    'id' => $iProfileId,
+                    'icon' => $oProfile -> getThumb()
+                ));
+        }
+
+        return $aVars;
+    }
+}
+
+/** @} */

+ 153 - 0
modules/boonex/channels/updates/13.0.2_13.0.3/source/install/config.php

@@ -0,0 +1,153 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defdroup    Channels Channels
+ * @indroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_channels',
+    'title' => 'Channels',
+    'note' => 'Channels functionality.',
+    'version' => '13.0.3',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use channels in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/channels/',
+    'home_uri' => 'channels',
+
+    'db_prefix' => 'bx_cnl_',
+    'class_prefix' => 'BxCnl',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Channels',
+
+    /**
+     * Connections.
+     */
+    'connections' => array(
+        'sys_profiles_friends' => array ('type' => 'profiles'),
+        'sys_profiles_subscriptions' => array ('type' => 'profiles'),
+    ),
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+        'trigger_profile_view_submenu',
+        'trigger_group_view_submenu',
+        'trigger_group_snippet_meta',
+        'trigger_group_view_actions',
+    ),
+
+    /**
+     * Page triggers.
+     */
+    'page_triggers' => array (
+        'trigger_page_profile_view_entry',
+        'trigger_page_group_view_entry',
+    ),
+
+    /**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+        'bx_channels_pics'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+        'bx_channels_icon',
+        'bx_channels_thumb',
+        'bx_channels_avatar',
+        'bx_channels_avatar_big',
+        'bx_channels_picture',
+        'bx_channels_cover',
+        'bx_channels_cover_thumb',
+        'bx_channels_gallery'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_channels',
+        'bx_channels_cmts',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+        'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'process_connections' => 1,
+        'process_deleted_profiles' => 1,
+        'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+        'process_menu_triggers' => 1,
+        'process_page_triggers' => 1,
+        'process_esearches' => 1,
+        'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'unregister_transcoders' => 1,
+        'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+        'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Connections Section
+     */
+    'relations' => array(
+        'bx_timeline',
+        'bx_notifications',
+    ),
+);
+
+/** @} */

+ 250 - 0
modules/boonex/channels/updates/13.0.2_13.0.3/source/install/langs/en.xml

@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string name="_bx_channels"><![CDATA[Channels]]></string>
+    <string name="_bx_channels_cmts"><![CDATA[Channels' Comments]]></string>
+
+    <string name="_bx_channels_option_default_author"><![CDATA[Default author for automatically created channels]]></string>
+    <string name="_bx_channels_option_num_connections_quick"><![CDATA[Number of items in friends block]]></string>
+    <string name="_bx_channels_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+    <string name="_bx_channels_option_num_rss"><![CDATA[Number of items in RSS feed]]></string>
+    <string name="_bx_channels_option_searchable_fields"><![CDATA[Searchable fields]]></string>
+    <string name="_bx_channels_option_labels_autofollow"><![CDATA[Auto-follow channels when used as labels in profiles]]></string>
+
+	<string name="_bx_channels_form_profile"><![CDATA[Channels]]></string>
+	<string name="_bx_channels_form_profile_display_add"><![CDATA[Add Channel]]></string>
+	<string name="_bx_channels_form_profile_display_edit"><![CDATA[Edit Channel]]></string>
+	<string name="_bx_channels_form_profile_display_edit_cover"><![CDATA[Edit Cover]]></string>
+	<string name="_bx_channels_form_profile_display_delete"><![CDATA[Delete Channel]]></string>
+	<string name="_bx_channels_form_profile_display_view"><![CDATA[View Channel]]></string>
+	<string name="_bx_channels_form_profile_display_view_full"><![CDATA[Full View Channel]]></string>
+	<string name="_bx_channels_form_profile_display_invite"><![CDATA[Invite to Channel]]></string>
+	<string name="_bx_channels_form_entry_input_author"><![CDATA[Author]]></string>
+	<string name="_bx_channels_form_profile_input_sys_do_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_channels_form_profile_input_sys_allow_view_to"><![CDATA[Privacy]]></string>
+	<string name="_bx_channels_form_profile_input_allow_view_to"><![CDATA[Privacy]]></string>
+	<string name="_bx_channels_form_profile_input_allow_view_to_desc"><![CDATA[Closed - anyone can find the channel and see who's in it, only members can see posts. Secret - only members can find the channel and see posts.]]></string>
+	<string name="_bx_channels_form_profile_input_sys_initial_members"><![CDATA[Invite Members]]></string>
+	<string name="_bx_channels_form_profile_input_initial_members"><![CDATA[Invite Members]]></string>
+  	<string name="_bx_channels_form_profile_input_sys_channel_name"><![CDATA[Channel Name]]></string>
+	<string name="_bx_channels_form_profile_input_channel_name"><![CDATA[Channel Name]]></string>
+	<string name="_bx_channels_form_profile_input_channel_name_err"><![CDATA[Please, fill in this field. Channel name must be unique.]]></string>
+	<string name="_bx_channels_form_profile_input_sys_picture"><![CDATA[Channel Picture]]></string>
+	<string name="_bx_channels_form_profile_input_picture"><![CDATA[Upload New Channel Picture]]></string>
+	<string name="_bx_channels_form_profile_input_picture_err"><![CDATA[Channel picture is mandatory.]]></string>
+	<string name="_bx_channels_form_profile_input_sys_cover"><![CDATA[Cover Picture]]></string>
+	<string name="_bx_channels_form_profile_input_cover"><![CDATA[Upload New Cover Picture]]></string>
+	<string name="_bx_channels_form_profile_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+	<string name="_bx_channels_form_profile_input_delete_confirm"><![CDATA[I am sure I want to delete this channel]]></string>
+	<string name="_bx_channels_form_profile_input_delete_confirm_info"><![CDATA[This action can not be undone.]]></string>
+	<string name="_bx_channels_form_profile_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete channel.]]></string>
+	
+	<string name="_bx_channels_acl_action_delete_profile"><![CDATA[Delete Channel]]></string>
+	<string name="_bx_channels_acl_action_view_profile"><![CDATA[View Channel]]></string>
+	<string name="_bx_channels_acl_action_edit_any_profile"><![CDATA[Edit Any Channel]]></string>
+	<string name="_bx_channels_acl_action_delete_any_profile"><![CDATA[Delete Any Channel]]></string>
+  <string name="_bx_channels_acl_action_create_channel_auto"><![CDATA[Create Channel Auto]]></string>
+  <string name="_bx_channels_acl_action_create_channel_auto_info"><![CDATA[Automatically create new channel when new hashtag is mentioned by anyone with this level]]></string>
+ 
+  <string name="_bx_channels_page_title_sys_edit_profile"><![CDATA[Edit Channel]]></string>
+	<string name="_bx_channels_page_title_edit_profile"><![CDATA[Edit Channel]]></string>
+	<string name="_bx_channels_page_title_sys_edit_profile_cover"><![CDATA[Edit Channel Cover]]></string>
+	<string name="_bx_channels_page_title_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+	<string name="_bx_channels_page_title_sys_delete_profile"><![CDATA[Delete Channel]]></string>
+	<string name="_bx_channels_page_title_delete_profile"><![CDATA[Delete Channel]]></string>
+	<string name="_bx_channels_page_title_sys_view_profile_closed"><![CDATA[View Closed Channel]]></string>
+	<string name="_bx_channels_page_title_sys_view_profile"><![CDATA[View Channel]]></string>
+	<string name="_bx_channels_page_title_view_profile"><![CDATA[{display_name}]]></string>
+	<string name="_bx_channels_page_title_browse"><![CDATA[Channels]]></string>
+	<string name="_bx_channels_page_title_browse_by_author"><![CDATA[Channels of {display_name}]]></string>
+	<string name="_bx_channels_page_title_browse_featured"><![CDATA[Featured Channels]]></string>
+	<string name="_bx_channels_page_title_browse_top"><![CDATA[Top Channels]]></string>
+	<string name="_bx_channels_page_title_browse_recent"><![CDATA[New Channels]]></string>
+	<string name="_bx_channels_page_title_browse_connections"><![CDATA[{0} connections]]></string>
+	<string name="_bx_channels_page_title_browse_connections_mutual"><![CDATA[{0} and {1} mutual connections]]></string>
+	<string name="_bx_channels_page_title_sys_profile_friends"><![CDATA[Friends]]></string>
+	<string name="_bx_channels_page_title_profile_friends"><![CDATA[Friends]]></string>
+	<string name="_bx_channels_page_title_sys_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_channels_page_block_title_entry_reports"><![CDATA[Reports]]></string>
+	<string name="_bx_channels_page_title_profile_comments"><![CDATA[Comments]]></string>
+	<string name="_bx_channels_page_title_sys_profile_info"><![CDATA[Channel Info]]></string>
+	<string name="_bx_channels_page_title_profile_info"><![CDATA[Info about {display_name}]]></string>
+	<string name="_bx_channels_page_title_sys_recent"><![CDATA[New Channels]]></string>
+	<string name="_bx_channels_page_title_recent"><![CDATA[New Channels]]></string>
+	<string name="_bx_channels_page_title_sys_manage"><![CDATA[Manage Own Channels]]></string>
+	<string name="_bx_channels_page_title_sys_manage_administration"><![CDATA[Manage All Channels]]></string>
+	<string name="_bx_channels_page_title_manage"><![CDATA[Manage Channels]]></string>
+	<string name="_bx_channels_page_title_sys_top"><![CDATA[Top Channels]]></string>
+	<string name="_bx_channels_page_title_top"><![CDATA[Top Channels]]></string>
+	<string name="_bx_channels_page_title_sys_entries_search"><![CDATA[Search]]></string>
+	<string name="_bx_channels_page_title_entries_search"><![CDATA[Search]]></string>
+  <string name="_bx_channels_page_title_sys_entries_toplevel"><![CDATA[Top level]]></string>
+  <string name="_bx_channels_page_title_entries_toplevel"><![CDATA[Top level]]></string>
+  <string name="_bx_channels_page_title_sys_entries_of_author"><![CDATA[Сhannels of author]]></string>
+  <string name="_bx_channels_page_title_entries_of_author"><![CDATA[Сhannels by {display_name}]]></string>
+
+  <string name="_bx_channels_page_block_title_system_profile_subscribed_me"><![CDATA[Followers]]></string>
+  <string name="_bx_channels_page_block_title_profile_subscribed_me"><![CDATA[Followers]]></string>
+  <string name="_bx_channels_page_block_title_sys_entries_actions"><![CDATA[Channels actions]]></string>
+	<string name="_bx_channels_page_block_title_entries_actions"><![CDATA[Channels actions]]></string>
+	<string name="_bx_channels_page_block_title_sys_entries_of_author"><![CDATA[Followed Сhannels]]></string>
+	<string name="_bx_channels_page_block_title_entries_of_author"><![CDATA[Followed Сhannels]]></string>
+	<string name="_bx_channels_page_block_title_favorites_of_author"><![CDATA[Favorite Channels]]></string>
+	<string name="_bx_channels_page_block_title_sys_favorites_of_author"><![CDATA[Favorite Channels]]></string>
+	<string name="_bx_channels_page_block_title_edit_profile"><![CDATA[Edit Channel]]></string>
+	<string name="_bx_channels_page_block_title_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+	<string name="_bx_channels_page_block_title_delete_profile"><![CDATA[Delete Channel]]></string>
+	<string name="_bx_channels_page_block_title_profile_info_link"><![CDATA[About <a href="{profile_link}">{display_name}</a>]]></string>
+	<string name="_bx_channels_page_block_title_profile_info"><![CDATA[Info]]></string>
+	<string name="_bx_channels_page_block_title_system_profile_info"><![CDATA[Info]]></string>
+	<string name="_bx_channels_page_block_title_profile_description"><![CDATA[Description]]></string>
+	<string name="_bx_channels_page_block_title_profile_friends_link"><![CDATA[Friends of <a href="{profile_link}">{display_name}</a>]]></string>
+	<string name="_bx_channels_page_block_title_profile_friends"><![CDATA[Friends]]></string>
+	<string name="_bx_channels_page_block_title_system_profile_friends"><![CDATA[Friends]]></string>
+	<string name="_bx_channels_page_block_title_admins"><![CDATA[Administrators]]></string>
+	<string name="_bx_channels_page_block_title_profile_comments"><![CDATA[Comments]]></string>
+	<string name="_bx_channels_page_block_title_profile_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+	<string name="_bx_channels_page_block_title_profile_actions"><![CDATA[Actions]]></string>
+	<string name="_bx_channels_page_block_title_featured_profiles"><![CDATA[Featured Channels]]></string>
+	<string name="_bx_channels_page_block_title_latest_profiles"><![CDATA[New Channels]]></string>
+	<string name="_bx_channels_page_block_title_system_manage"><![CDATA[Manage Own Channels]]></string>
+	<string name="_bx_channels_page_block_title_system_manage_administration"><![CDATA[Manage All Channels]]></string>
+	<string name="_bx_channels_page_block_title_manage"><![CDATA[Manage Channels]]></string>
+	<string name="_bx_channels_page_block_title_top_profiles"><![CDATA[Top Channels]]></string>
+        <string name="_bx_channels_page_block_title_entry_all_actions"><![CDATA[All Actions]]></string>
+	<string name="_bx_channels_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+        <string name="_bx_channels_page_block_title_entry_breadcrumb"><![CDATA[Breadcrumb]]></string>
+        <string name="_bx_channels_page_block_title_entry_parent"><![CDATA[Parent Channel]]></string>
+        <string name="_bx_channels_page_block_title_entry_childs"><![CDATA[Child Channels]]></string>
+	<string name="_bx_channels_page_block_title_search_form"><![CDATA[Search Form]]></string>
+  <string name="_bx_channels_page_block_title_toplevel"><![CDATA[Top level]]></string>
+        <string name="_bx_channels_page_block_title_entries_my"><![CDATA[My Followed Channels]]></string>
+        <string name="_bx_channels_page_trigger_block_title_entries_my"><![CDATA[My Followed Channels]]></string>
+        <string name="_bx_channels_page_block_title_search_results"><![CDATA[Search Results]]></string>
+        <string name="_bx_channels_page_block_title_search_results_by_hashtag"><![CDATA[Search Results By Hashtag]]></string>
+	<string name="_bx_channels_page_block_title_search_form_cmts"><![CDATA[Comments Search Form]]></string>
+	<string name="_bx_channels_page_block_title_search_results_cmts"><![CDATA[Comments Search Results]]></string>
+	<string name="_bx_channels_page_block_title_sys_featured_entries_view_showcase"><![CDATA[Featured Channels (Showcase View)]]></string>
+	<string name="_bx_channels_page_block_title_featured_entries_view_showcase"><![CDATA[Featured Channels]]></string>
+	<string name="_bx_channels_page_block_title_sys_recommended_entries_view_showcase"><![CDATA[Recommended Channels (Showcase View)]]></string>
+	<string name="_bx_channels_page_block_title_recommended_entries_view_showcase"><![CDATA[Recommended Channels]]></string>
+  <string name="_bx_channels_page_block_title_sys_cover_block"><![CDATA[Cover]]></string>
+  <string name="_bx_channels_page_block_title_cover_block"><![CDATA[Cover]]></string>
+
+	<string name="_bx_channels_menu_title_submenu"><![CDATA[Channels Submenu]]></string>
+	<string name="_bx_channels_menu_set_title_submenu"><![CDATA[Channels Submenu]]></string>
+	<string name="_bx_channels_menu_set_title_view_profile_actions"><![CDATA[Channel Actions]]></string>
+	<string name="_bx_channels_menu_title_view_profile_actions"><![CDATA[Channel Actions]]></string>
+	<string name="_bx_channels_menu_set_title_view_profile_actions_more"><![CDATA[Channel More Actions]]></string>
+	<string name="_bx_channels_menu_title_view_profile_actions_more"><![CDATA[Channel More Actions]]></string>
+	<string name="_bx_channels_menu_set_title_view_profile_submenu"><![CDATA[View Channel Submenu]]></string>
+	<string name="_bx_channels_menu_title_entries_my"><![CDATA[Profile Channels Action Menu]]></string>
+	<string name="_bx_channels_menu_set_title_entries_my"><![CDATA[Profile Channels Menu]]></string>
+	<string name="_bx_channels_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+	<string name="_bx_channels_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+	<string name="_bx_channels_menu_item_title_system_delete"><![CDATA[Delete]]></string>
+	<string name="_bx_channels_menu_item_title_delete"><![CDATA[Delete]]></string>
+	<string name="_bx_channels_menu_item_title_system_delete_with_content"><![CDATA[Delete With Content]]></string>
+	<string name="_bx_channels_menu_item_title_delete_with_content"><![CDATA[Delete With Content]]></string>
+	<string name="_bx_channels_menu_item_title_system_edit_cover"><![CDATA[Edit Cover]]></string>
+	<string name="_bx_channels_menu_item_title_edit_cover"><![CDATA[Edit Cover]]></string>
+	<string name="_bx_channels_menu_item_title_system_edit_profile"><![CDATA[Edit Channel]]></string>
+	<string name="_bx_channels_menu_item_title_edit_profile"><![CDATA[Edit Channel]]></string>
+	<string name="_bx_channels_menu_item_title_system_delete_profile"><![CDATA[Delete Channel]]></string>
+	<string name="_bx_channels_menu_item_title_delete_profile"><![CDATA[Delete Channel]]></string>
+	<string name="_bx_channels_menu_item_title_system_delete_account"><![CDATA[Delete Account]]></string>
+	<string name="_bx_channels_menu_item_title_delete_account"><![CDATA[Delete Account]]></string>
+	<string name="_bx_channels_menu_item_title_system_profile_type"><![CDATA[Channel]]></string>
+	<string name="_bx_channels_menu_item_title_profile_type"><![CDATA[Channel]]></string>
+	<string name="_bx_channels_menu_item_title_system_view_profile_friends"><![CDATA[Friends]]></string>
+	<string name="_bx_channels_menu_item_title_view_profile_friends"><![CDATA[Friends]]></string>
+	<string name="_bx_channels_menu_item_title_system_view_profile_comments"><![CDATA[Comments]]></string>
+	<string name="_bx_channels_menu_item_title_view_profile_comments"><![CDATA[Comments]]></string>
+	<string name="_bx_channels_menu_item_title_system_view_profile_info"><![CDATA[Info]]></string>
+	<string name="_bx_channels_menu_item_title_view_profile_info"><![CDATA[Info]]></string>
+	<string name="_bx_channels_menu_item_title_system_view_profile_view"><![CDATA[Channel]]></string>
+	<string name="_bx_channels_menu_item_title_view_profile_view"><![CDATA[Channel]]></string>
+        <string name="_bx_channels_menu_item_title_system_view_profile_more_auto"><![CDATA[More]]></string>
+        <string name="_bx_channels_menu_item_title_view_profile_more_auto"><![CDATA[More]]></string>
+	<string name="_bx_channels_menu_item_title_system_invite"><![CDATA[Invite]]></string>
+	<string name="_bx_channels_menu_item_title_invite"><![CDATA[Invite]]></string>
+	
+	<string name="_bx_channels_menu_item_title_system_befriend"><![CDATA[Add friend]]></string>
+	<string name="_bx_channels_menu_item_title_befriend"><![CDATA[Add friend]]></string>
+	<string name="_bx_channels_menu_item_title_befriend_sent"><![CDATA[Add friend (requested)]]></string>
+	<string name="_bx_channels_menu_item_title_befriend_confirm"><![CDATA[Accept friend request]]></string>
+	<string name="_bx_channels_menu_item_title_system_unfriend"><![CDATA[Unfriend]]></string>
+	<string name="_bx_channels_menu_item_title_unfriend"><![CDATA[Unfriend]]></string>
+	<string name="_bx_channels_menu_item_title_unfriend_cancel_request"><![CDATA[Cancel friend request]]></string>
+	<string name="_bx_channels_menu_item_title_unfriend_reject_request"><![CDATA[Reject friend request]]></string>
+	
+	<string name="_bx_channels_menu_item_title_system_subscribe"><![CDATA[Follow]]></string>
+	<string name="_bx_channels_menu_item_title_subscribe"><![CDATA[Follow]]></string>
+	<string name="_bx_channels_menu_item_title_system_unsubscribe"><![CDATA[Unfollow]]></string>
+	<string name="_bx_channels_menu_item_title_unsubscribe"><![CDATA[Unfollow]]></string>
+	<string name="_bx_channels_menu_item_title_system_more_actions"><![CDATA[More Actions]]></string>
+	<string name="_bx_channels_menu_item_title_more_actions"><![CDATA[]]></string>
+	<string name="_bx_channels_menu_item_title_system_friends"><![CDATA[Friends]]></string>
+	<string name="_bx_channels_menu_item_title_friends"><![CDATA[Friends]]></string>
+	<string name="_bx_channels_menu_item_title_system_manage_my_channels"><![CDATA[My channels]]></string>
+	<string name="_bx_channels_menu_item_title_manage_my_channels"><![CDATA[{addon} channels]]></string>
+	<string name="_bx_channels_menu_item_title_system_entries_recent"><![CDATA[New]]></string>
+	<string name="_bx_channels_menu_item_title_entries_recent"><![CDATA[New]]></string>
+	<string name="_bx_channels_menu_item_title_system_entries_search"><![CDATA[Search]]></string>
+	<string name="_bx_channels_menu_item_title_entries_search"><![CDATA[Search]]></string>
+  <string name="_bx_channels_menu_item_title_system_entries_toplevel"><![CDATA[Top level]]></string>
+  <string name="_bx_channels_menu_item_title_entries_toplevel"><![CDATA[Top level]]></string>
+        <string name="_bx_channels_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+	<string name="_bx_channels_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+	<string name="_bx_channels_menu_item_title_system_entries_home"><![CDATA[Channels]]></string>
+	<string name="_bx_channels_menu_item_title_entries_home"><![CDATA[Channels]]></string>
+	<string name="_bx_channels_menu_item_title_system_admt_channels"><![CDATA[Channels]]></string>
+	<string name="_bx_channels_menu_item_title_admt_channels"><![CDATA[Channels]]></string>
+	<string name="_bx_channels_menu_item_title_manage_my"><![CDATA[My Channels]]></string>
+	<string name="_bx_channels_menu_item_title_manage_all"><![CDATA[All Channels]]></string>
+	<string name="_bx_channels_menu_item_title_system_entries_top"><![CDATA[Top]]></string>
+	<string name="_bx_channels_menu_item_title_entries_top"><![CDATA[Top]]></string>
+        <string name="_bx_channels_menu_item_title_system_view_entries_author"><![CDATA[Channels]]></string>
+        <string name="_bx_channels_menu_item_title_view_entries_author"><![CDATA[Channels]]></string>
+        <string name="_bx_channels_menu_item_title_system_followings"><![CDATA[Channels]]></string>
+        <string name="_bx_channels_menu_item_title_followings"><![CDATA[Channels]]></string>
+
+	<string name="_bx_channels_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+        <string name="_bx_channels_grid_filter_item_title_adm_select_one_filter2"><![CDATA[Any Audience]]></string>
+	<string name="_bx_channels_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+        <string name="_bx_channels_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+	<string name="_bx_channels_grid_filter_item_title_adm_pending"><![CDATA[Pending]]></string>
+	<string name="_bx_channels_grid_filter_item_title_adm_suspended"><![CDATA[Suspended]]></string>
+	<string name="_bx_channels_grid_column_title_adm_active"><![CDATA[Active]]></string>
+	<string name="_bx_channels_grid_column_title_adm_name"><![CDATA[Name]]></string>
+	<string name="_bx_channels_grid_column_title_adm_added"><![CDATA[Created]]></string>
+	<string name="_bx_channels_grid_column_title_adm_account"><![CDATA[Account]]></string>
+	<string name="_bx_channels_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+	<string name="_bx_channels_grid_action_title_adm_delete_with_content"><![CDATA[Delete With Content]]></string>
+	<string name="_bx_channels_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+  <string name="_bx_channels_grid_action_title_adm_audit_context"><![CDATA[Audit actions in context]]></string>
+  <string name="_bx_channels_grid_action_title_adm_audit_content"><![CDATA[Audit actions with content]]></string>
+	<string name="_bx_channels_grid_action_err_delete"><![CDATA[Cannot delete the selected channel(s).]]></string>
+	<string name="_bx_channels_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+	
+	<string name="_bx_channels_chart_growth"><![CDATA[Channels: Growth]]></string>
+	<string name="_bx_channels_chart_growth_speed"><![CDATA[Channels: Growth Speed]]></string>
+	
+	<string name="_bx_channels_search_extended"><![CDATA[Channels Search]]></string>
+	<string name="_bx_channels_search_extended_cmts"><![CDATA[Channels Comments Search]]></string>
+
+	<string name="_bx_channels_txt_account_pending"><![CDATA[This channel is pending approval, please wait until it is activated.]]></string>
+	<string name="_bx_channels_txt_account_suspended"><![CDATA[This channel is suspended.]]></string>
+	<string name="_bx_channels_txt_sample_single"><![CDATA[channel]]></string>
+	<string name="_bx_channels_txt_sample_single_with_article"><![CDATA[a channel]]></string>
+	<string name="_bx_channels_txt_sample_comment_single"><![CDATA[comment to channel]]></string>
+	<string name="_bx_channels_txt_sample_vote_single"><![CDATA[vote to channel]]></string>
+        <string name="_bx_channels_txt_sample_score_up_single"><![CDATA[score up vote to channel]]></string>
+        <string name="_bx_channels_txt_sample_score_down_single"><![CDATA[score down vote to channel]]></string>
+        <string name="_bx_channels_msg_empty_author"><![CDATA['Default author for automatically created channels' is empty. You need to select some profile in this setting.]]></string>
+
+    <string name="_bx_channels_txt_ntfs_timeline_post_common"><![CDATA[New post <b class="bx-ntfs-content-entry">{subentry_sample}</b> in <b class="bx-ntfs-content-profile">{owner_name}</b> channel timeline]]></string>
+    <string name="_bx_channels_ntfs_txt_subobject_added"><![CDATA[New content <b class="bx-ntfs-content-entry">{entry_caption}</b> in <b class="bx-ntfs-content-profile">{owner_name}</b> channel]]></string>
+    <string name="_bx_channels_ntfs_txt_subobject_added_profile"><![CDATA[<b class="bx-ntfs-content-entry">{entry_caption}</b> was added to <b class="bx-ntfs-content-profile">{owner_name}</b> channel]]></string>
+    <string name="_bx_channels_alert_action_hashtag_added"><![CDATA[New hashtags]]></string>
+    <string name="_bx_channels_alert_action_hashtag_added_notif_follow_context"><![CDATA[New hashtags]]></string>
+</resources>

+ 428 - 0
modules/boonex/channels/updates/13.0.2_13.0.3/source/install/sql/enable.sql

@@ -0,0 +1,428 @@
+
+-- SETTINGS
+
+SET @iTypeOrder = (SELECT MAX(`order`) FROM `sys_options_types` WHERE `group` = 'modules');
+INSERT INTO `sys_options_types`(`group`, `name`, `caption`, `icon`, `order`) VALUES 
+('modules', 'bx_channels', '_bx_channels', 'bx_channels@modules/boonex/channels/|std-icon.svg', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_channels', '_bx_channels', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `extra`, `check`, `check_params`, `check_error`, `order`) VALUES
+('bx_channels_default_author', '', @iCategId, '_bx_channels_option_default_author', 'select', 'a:2:{s:6:"module";s:11:"bx_channels";s:6:"method";s:26:"get_options_default_author";}', '', '', '', 1),
+('bx_channels_num_connections_quick', '6', @iCategId, '_bx_channels_option_num_connections_quick', 'digit', '', '', '', '', 10),
+('bx_channels_per_page_browse', '24', @iCategId, '_bx_channels_option_per_page_browse', 'digit', '', '', '', '', 11),
+('bx_channels_num_rss', '10', @iCategId, '_bx_channels_option_num_rss', 'digit', '', '', '', '', 12),
+('bx_channels_per_page_browse_showcase', '32', @iCategId, '_sys_option_per_page_browse_showcase', 'digit', '', '', '', '', 15),
+('bx_channels_per_page_browse_recommended', '10', @iCategId, '_sys_option_per_page_browse_recommended', 'digit', '', '', '', '', 16),
+('bx_channels_searchable_fields', 'channel_name', @iCategId, '_bx_channels_option_searchable_fields', 'list', 'a:2:{s:6:"module";s:11:"bx_channels";s:6:"method";s:21:"get_searchable_fields";}', '', '', '', 30),
+('bx_channels_labels_autofollow', 'on', @iCategId, '_bx_channels_option_labels_autofollow', 'checkbox', '', '', '', '', 40);
+
+
+-- PAGES
+
+-- PAGE: view profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_view_profile', 'view-channel-profile', '_bx_channels_page_title_sys_view_profile', '_bx_channels_page_title_view_profile', 'bx_channels', 10, 2147483647, 1, 'page.php?i=view-channel-profile', '', '', '', 0, 1, 0, 'BxCnlPageEntry', 'modules/boonex/channels/classes/BxCnlPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('bx_channels_view_profile', 1, 'bx_channels', '', '_bx_channels_page_block_title_entry_social_sharing', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:21:\"entity_social_sharing\";}', 0, 0, 0, 0),
+('bx_channels_view_profile', 1, 'bx_channels', '', '_bx_channels_page_block_title_entry_all_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:18:\"entity_all_actions\";}', 0, 0, 0, 0),
+('bx_channels_view_profile', 1, 'bx_channels', '', '_bx_channels_page_block_title_entry_breadcrumb', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_channels";s:6:"method";s:17:"entity_breadcrumb";}', 0, 0, 1, 1),
+('bx_channels_view_profile', 2, 'bx_channels', '', '_bx_channels_page_block_title_entry_parent', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_channels";s:6:"method";s:13:"entity_parent";}', 0, 0, 1, 1),
+('bx_channels_view_profile', 3, 'bx_channels', '', '_bx_channels_page_block_title_entry_childs', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_channels";s:6:"method";s:13:"entity_childs";}', 0, 0, 1, 1),
+('bx_channels_view_profile', 4, 'bx_channels', '', '_bx_channels_page_block_title_search_results_by_hashtag', 0, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:24:\"search_result_by_hashtag\";}', 0, 0, 0, 0),
+('bx_channels_view_profile', 4, 'bx_channels', '', '_bx_channels_page_block_title_profile_comments', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 0, 1),
+('bx_channels_view_profile', 4, 'bx_channels', '', '_bx_channels_page_block_title_profile_subscribed_me', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:21:\"profile_subscribed_me\";}', 0, 1, 1, 0),
+('bx_channels_view_profile', 4, 'bx_channels', '', '_bx_channels_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:14:\"entity_reports\";}', 0, 0, 1, 6);
+
+-- PAGE: view closed profile 
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_view_profile_closed', 'view-channel-profile-closed', '_bx_channels_page_title_sys_view_profile_closed', '_bx_channels_page_title_view_profile', 'bx_channels', 10, 2147483647, 1, 'page.php?i=view-channel-profile', '', '', '', 0, 1, 0, 'BxCnlPageEntry', 'modules/boonex/channels/classes/BxCnlPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_channels_view_profile_closed', 2, 'bx_channels', '', '_bx_channels_page_block_title_profile_info', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:11:\"entity_info\";}', 0, 0, 1, 0);
+
+-- PAGE: edit profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_edit_profile', 'edit-channel-profile', '_bx_channels_page_title_sys_edit_profile', '_bx_channels_page_title_edit_profile', 'bx_channels', 5, 2147483647, 1, 'page.php?i=edit-channel-profile', '', '', '', 0, 1, 0, 'BxCnlPageEntry', 'modules/boonex/channels/classes/BxCnlPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_channels_edit_profile', 1, 'bx_channels', '_bx_channels_page_block_title_edit_profile', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:11:\"entity_edit\";}', 0, 0, 0);
+
+-- PAGE: edit profile cover
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_edit_profile_cover', 'edit-channel-cover', '_bx_channels_page_title_sys_edit_profile_cover', '_bx_channels_page_title_edit_profile_cover', 'bx_channels', 5, 2147483647, 1, 'page.php?i=edit-channel-cover', '', '', '', 0, 1, 0, 'BxCnlPageEntry', 'modules/boonex/channels/classes/BxCnlPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_channels_edit_profile_cover', 1, 'bx_channels', '_bx_channels_page_block_title_edit_profile_cover', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:17:\"entity_edit_cover\";}', 0, 0, 0);
+
+-- PAGE: delete profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_delete_profile', 'delete-channel-profile', '_bx_channels_page_title_sys_delete_profile', '_bx_channels_page_title_delete_profile', 'bx_channels', 5, 2147483647, 1, 'page.php?i=delete-channel-profile', '', '', '', 0, 1, 0, 'BxCnlPageEntry', 'modules/boonex/channels/classes/BxCnlPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_channels_delete_profile', 1, 'bx_channels', '_bx_channels_page_block_title_delete_profile', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:13:\"entity_delete\";}', 0, 0, 0);
+
+-- PAGE: view entry comments
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_profile_comments', '_bx_channels_page_title_sys_profile_comments', '_bx_channels_page_title_profile_comments', 'bx_channels', 5, 2147483647, 1, 'channel-profile-comments', '', '', '', '', 0, 1, 0, 'BxCnlPageEntry', 'modules/boonex/channels/classes/BxCnlPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_channels_profile_comments', 1, 'bx_channels', '_bx_channels_page_block_title_profile_comments', '_bx_channels_page_block_title_profile_comments_link', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 0, 1);
+
+-- PAGE: entries of author
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_author', 'channels-author', '_bx_channels_page_title_sys_entries_of_author', '_bx_channels_page_title_entries_of_author', 'bx_channels', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxCnlPageAuthor', 'modules/boonex/channels/classes/BxCnlPageAuthor.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_channels_author', 1, 'bx_channels', '_bx_channels_page_block_title_sys_favorites_of_author', '_bx_channels_page_block_title_favorites_of_author', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:11:"bx_channels";s:6:"method";s:15:"browse_favorite";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 0, 1, 1, 1),
+('bx_channels_author', 1, 'bx_channels', '_bx_channels_page_block_title_sys_entries_of_author', '_bx_channels_page_block_title_entries_of_author', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:11:"bx_channels";s:6:"method";s:13:"browse_author";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:1:{s:13:"empty_message";b:1;}}}}', 0, 0, 1, 2);
+
+-- PAGE: module home
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_home', '_bx_channels_page_title_sys_recent', '_bx_channels_page_title_recent', 'bx_channels', 5, 2147483647, 1, 'channels-home', 'page.php?i=channels-home', '', '', '', 0, 1, 0, 'BxCnlPageBrowse', 'modules/boonex/channels/classes/BxCnlPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('bx_channels_home', 1, 'bx_channels', '_bx_channels_page_block_title_featured_profiles', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:11:"bx_channels";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:7:"gallery";}}', 0, 1, 1, 0),
+('bx_channels_home', 1, 'bx_channels', '_bx_channels_page_block_title_latest_profiles', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:22:\"browse_recent_profiles\";s:6:"params";a:1:{i:0;b:1;}}', 0, 1, 1, 1),
+('bx_channels_home', 1, 'bx_channels', '_bx_channels_page_block_title_entries_my', 11, 2147483646, 'service', 'a:2:{s:6:"module";s:11:"bx_channels";s:6:"method";s:13:"browse_author";}',  0, 1, 0, 0);
+
+-- PAGE: top profiles
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_top', '_bx_channels_page_title_sys_top', '_bx_channels_page_title_top', 'bx_channels', 5, 2147483647, 1, 'channels-top', 'page.php?i=channels-top', '', '', '', 0, 1, 0, 'BxCnlPageBrowse', 'modules/boonex/channels/classes/BxCnlPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_channels_top', 1, 'bx_channels', '_bx_channels_page_block_title_top_profiles', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:19:\"browse_top_profiles\";s:6:"params";a:1:{i:0;b:1;}}', 0, 1, 0);
+
+-- PAGE: top level entries
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_toplevel', '_bx_channels_page_title_sys_entries_toplevel', '_bx_channels_page_title_entries_toplevel', 'bx_channels', 5, 2147483647, 1, 'channels-toplevel', 'page.php?i=toplevel', '', '', '', 0, 1, 0, 'BxCnlPageBrowse', 'modules/boonex/channels/classes/BxCnlPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_channels_toplevel', 1, 'bx_channels', '_bx_channels_page_block_title_toplevel', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:15:\"browse_by_level\";s:6:"params";a:2:{i:0;i:0;i:1;b:1;}}', 0, 1, 1, 1);
+
+-- PAGE: search for entries
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_search', '_bx_channels_page_title_sys_entries_search', '_bx_channels_page_title_entries_search', 'bx_channels', 5, 2147483647, 1, 'channels-search', 'page.php?i=channels-search', '', '', '', 0, 1, 0, 'BxCnlPageBrowse', 'modules/boonex/channels/classes/BxCnlPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_channels_search', 1, 'bx_channels', '_bx_channels_page_block_title_search_form', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:11:"bx_channels";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1),
+('bx_channels_search', 1, 'bx_channels', '_bx_channels_page_block_title_search_results', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:11:"bx_channels";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 2),
+('bx_channels_search', 1, 'bx_channels', '_bx_channels_page_block_title_search_form_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:16:"bx_channels_cmts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 3),
+('bx_channels_search', 1, 'bx_channels', '_bx_channels_page_block_title_search_results_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:16:"bx_channels_cmts";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 4);
+
+-- PAGE: module manage all
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_administration', '_bx_channels_page_title_sys_manage_administration', '_bx_channels_page_title_manage', 'bx_channels', 5, 128, 1, 'channels-administration', 'page.php?i=channels-administration', '', '', '', 0, 1, 0, 'BxCnlPageBrowse', 'modules/boonex/channels/classes/BxCnlPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_channels_administration', 1, 'bx_channels', '_bx_channels_page_block_title_system_manage_administration', '_bx_channels_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:12:\"manage_tools\";s:6:\"params\";a:1:{i:0;s:14:\"administration\";}}', 0, 1, 0);
+
+-- PAGE: add block to homepage
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = 'sys_home' AND `cell_id` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('sys_home', 1, 'bx_channels', '', '_bx_channels_page_block_title_latest_profiles', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_channels";s:6:"method";s:22:"browse_recent_profiles";}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1),
+('sys_home', 1, 'bx_channels', '_bx_channels_page_block_title_sys_recommended_entries_view_showcase', '_bx_channels_page_block_title_recommended_entries_view_showcase', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_channels";s:6:"method";s:18:"browse_recommended";}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 2);
+
+-- PAGE: service blocks
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = '' AND `cell_id` = 0 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('', 0, 'bx_channels', '_bx_channels_page_block_title_sys_featured_entries_view_showcase', '_bx_channels_page_block_title_featured_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:15:\"browse_featured\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 1),
+('', 0, 'bx_channels', '_bx_channels_page_block_title_sys_recommended_entries_view_showcase', '_bx_channels_page_block_title_recommended_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:18:\"browse_recommended\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 2),
+('', 0, 'bx_channels', '_bx_channels_page_block_title_sys_cover_block', '_bx_channels_page_block_title_cover_block', 3, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:12:\"entity_cover\";}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 3);
+
+-- PAGES: add page block to profiles modules (trigger* page objects are processed separately upon modules enable/disable)
+SET @iPBCellProfile = 3;
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_channels', '_bx_channels_page_trigger_block_title_entries_my', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:11:"bx_channels";s:6:"method";s:13:"browse_author";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:1:{s:13:"empty_message";b:0;}}}', 0, 0, 0);
+
+
+-- MENU
+
+-- MENU: add to site menu
+
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' AND `active` = 1 AND `order` < 9999 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_site', 'bx_channels', 'channels-home', '_bx_channels_menu_item_title_system_entries_home', '_bx_channels_menu_item_title_entries_home', 'page.php?i=channels-home', '', '', 'hashtag col-red2', 'bx_channels_submenu', 2147483647, 1, 1, IFNULL(@iSiteMenuOrder, 0) + 1);
+
+-- MENU: add to homepage menu
+
+SET @iHomepageMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_homepage' AND `active` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_homepage', 'bx_channels', 'channels-home', '_bx_channels_menu_item_title_system_entries_home', '_bx_channels_menu_item_title_entries_home', 'page.php?i=channels-home', '', '', 'hashtag col-red2', 'bx_channels_submenu', 2147483647, 1, 1, IFNULL(@iHomepageMenuOrder, 0) + 1);
+
+-- MENU: view actions
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_view_actions', '_bx_channels_menu_title_view_profile_actions', 'bx_channels_view_actions', 'bx_channels', 9, 0, 1, 'BxCnlMenuViewActions', 'modules/boonex/channels/classes/BxCnlMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_channels_view_actions', 'bx_channels', '_bx_channels_menu_set_title_view_profile_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_channels_view_actions', 'bx_channels', 'profile-subscribe-add', '_bx_channels_menu_item_title_system_subscribe', '_bx_channels_menu_item_title_subscribe', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_subscriptions\', \'add\', \'{profile_id}\')', '', 'check', '', 0, 2147483647, 1, 0, 1, 20),
+('bx_channels_view_actions', 'bx_channels', 'profile-actions-more', '_bx_channels_menu_item_title_system_more_actions', '_bx_channels_menu_item_title_more_actions', 'javascript:void(0)', 'bx_menu_popup(''bx_channels_view_actions_more'', this, {}, {profile_id:{profile_id}});', '', 'cog', 'bx_channels_view_actions_more', 1, 2147483647, 1, 0, 1, 9999);
+
+-- MENU: view actions more
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_view_actions_more', '_bx_channels_menu_title_view_profile_actions_more', 'bx_channels_view_actions_more', 'bx_channels', 6, 0, 1, 'BxCnlMenuViewActions', 'modules/boonex/channels/classes/BxCnlMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_channels_view_actions_more', 'bx_channels', '_bx_channels_menu_set_title_view_profile_actions_more', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_channels_view_actions_more', 'bx_channels', 'profile-subscribe-remove', '_bx_channels_menu_item_title_system_unsubscribe', '_bx_channels_menu_item_title_unsubscribe', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_subscriptions\', \'remove\', \'{profile_id}\')', '', 'check', '', 2147483647, 1, 0, 20),
+('bx_channels_view_actions_more', 'bx_channels', 'edit-channel-cover', '_bx_channels_menu_item_title_system_edit_cover', '_bx_channels_menu_item_title_edit_cover', 'page.php?i=edit-channel-cover&id={content_id}', '', '', 'pencil-alt', '', 2147483647, 1, 0, 30),
+('bx_channels_view_actions_more', 'bx_channels', 'edit-channel-profile', '_bx_channels_menu_item_title_system_edit_profile', '_bx_channels_menu_item_title_edit_profile', 'page.php?i=edit-channel-profile&id={content_id}', '', '', 'pencil-alt', '', 2147483647, 0, 0, 40),
+('bx_channels_view_actions_more', 'bx_channels', 'delete-channel-profile', '_bx_channels_menu_item_title_system_delete_profile', '_bx_channels_menu_item_title_delete_profile', 'page.php?i=delete-channel-profile&id={content_id}', '', '', 'remove', '', 2147483647, 1, 0, 50);
+
+-- MENU: all actions menu for view entry 
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_view_actions_all', '_sys_menu_title_view_actions', 'bx_channels_view_actions_all', 'bx_channels', 15, 0, 1, 'BxCnlMenuViewActionsAll', 'modules/boonex/channels/classes/BxCnlMenuViewActionsAll.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_channels_view_actions_all', 'bx_channels', '_sys_menu_set_title_view_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_channels_view_actions_all', 'bx_channels', 'profile-subscribe-add', '_bx_channels_menu_item_title_system_subscribe', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 10),
+('bx_channels_view_actions_all', 'bx_channels', 'profile-subscribe-remove', '_bx_channels_menu_item_title_system_unsubscribe', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 20),
+('bx_channels_view_actions_all', 'bx_channels', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 200),
+('bx_channels_view_actions_all', 'bx_channels', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 210),
+('bx_channels_view_actions_all', 'bx_channels', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 220),
+('bx_channels_view_actions_all', 'bx_channels', 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 230),
+('bx_channels_view_actions_all', 'bx_channels', 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 240),
+('bx_channels_view_actions_all', 'bx_channels', 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 250),
+('bx_channels_view_actions_all', 'bx_channels', 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 260),
+('bx_channels_view_actions_all', 'bx_channels', 'notes', '_sys_menu_item_title_system_va_notes', '_sys_menu_item_title_va_notes', 'javascript:void(0)', 'javascript:bx_get_notes(this,  ''{module_uri}'', {content_id});', '', 'exclamation-triangle', '', '', 0, 2147483647, 1, 0, 280),
+('bx_channels_view_actions_all', 'bx_channels', 'social-sharing', '_sys_menu_item_title_system_social_sharing', '_sys_menu_item_title_social_sharing', 'javascript:void(0)', 'oBxDolPage.share(this, \'{url_encoded}\')', '', 'share', '', '', 0, 2147483647, 1, 0, 300),
+('bx_channels_view_actions_all', 'bx_channels', 'edit-channel-cover', '_bx_channels_menu_item_title_system_edit_cover', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 400),
+('bx_channels_view_actions_all', 'bx_channels', 'edit-channel-profile', '_bx_channels_menu_item_title_system_edit_profile', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 410),
+('bx_channels_view_actions_all', 'bx_channels', 'delete-channel-profile', '_bx_channels_menu_item_title_system_delete_profile', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 420),
+('bx_channels_view_actions_all', 'bx_channels', 'more-auto', '_sys_menu_item_title_system_va_more_auto', '_sys_menu_item_title_va_more_auto', 'javascript:void(0)', '', '', 'ellipsis-v', '', '', 0, 2147483647, 1, 0, 9999);
+
+-- MENU: actions menu for my entries
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_my', '_bx_channels_menu_title_entries_my', 'bx_channels_my', 'bx_channels', 9, 0, 1, 'BxCnlMenu', 'modules/boonex/channels/classes/BxCnlMenu.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_channels_my', 'bx_channels', '_bx_channels_menu_set_title_entries_my', 0);
+
+-- MENU: module sub-menu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_submenu', '_bx_channels_menu_title_submenu', 'bx_channels_submenu', 'bx_channels', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_channels_submenu', 'bx_channels', '_bx_channels_menu_set_title_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_channels_submenu', 'bx_channels', 'channels-home', '_bx_channels_menu_item_title_system_entries_recent', '_bx_channels_menu_item_title_entries_recent', 'page.php?i=channels-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_channels_submenu', 'bx_channels', 'channels-top', '_bx_channels_menu_item_title_system_entries_top', '_bx_channels_menu_item_title_entries_top', 'page.php?i=channels-top', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_channels_submenu', 'bx_channels', 'channels-toplevel', '_bx_channels_menu_item_title_system_entries_toplevel', '_bx_channels_menu_item_title_entries_toplevel', 'page.php?i=channels-toplevel', '', '', '', '', 2147483647, 1, 1, 3),
+('bx_channels_submenu', 'bx_channels', 'channels-search', '_bx_channels_menu_item_title_system_entries_search', '_bx_channels_menu_item_title_entries_search', 'page.php?i=channels-search', '', '', '', '', 2147483647, 1, 1, 4),
+('bx_channels_submenu', 'bx_channels', 'channels-administration', '_bx_channels_menu_item_title_system_entries_manage', '_bx_courses_menu_item_title_entries_manage', 'page.php?i=channels-administration', '', '', '', '', 192, 1, 1, 5);
+
+-- MENU: custom menu for snippet meta info
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_snippet_meta', '_sys_menu_title_snippet_meta', 'bx_channels_snippet_meta', 'bx_channels', 15, 0, 1, 'BxCnlMenuSnippetMeta', 'modules/boonex/channels/classes/BxCnlMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_channels_snippet_meta', 'bx_channels', '_sys_menu_set_title_snippet_meta', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES
+('bx_channels_snippet_meta', 'bx_channels', 'date', '_sys_menu_item_title_system_sm_date', '_sys_menu_item_title_sm_date', '', '', '', '', '', 2147483647, 0, 0, 1, 1),
+('bx_channels_snippet_meta', 'bx_channels', 'tags', '_sys_menu_item_title_system_sm_tags', '_sys_menu_item_title_sm_tags', '', '', '', '', '', 2147483647, 0, 0, 1, 2),
+('bx_channels_snippet_meta', 'bx_channels', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 2147483647, 0, 0, 1, 3),
+('bx_channels_snippet_meta', 'bx_channels', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 2147483647, 0, 0, 1, 4),
+('bx_channels_snippet_meta', 'bx_channels', 'members', '_sys_menu_item_title_system_sm_members', '_sys_menu_item_title_sm_members', '', '', '', '', '', 2147483647, 1, 0, 1, 5),
+('bx_channels_snippet_meta', 'bx_channels', 'subscribers', '_sys_menu_item_title_system_sm_subscribers', '_sys_menu_item_title_sm_subscribers', '', '', '', '', '', 2147483647, 1, 0, 1, 6),
+('bx_channels_snippet_meta', 'bx_channels', 'nl', '_sys_menu_item_title_system_sm_nl', '_sys_menu_item_title_sm_nl', '', '', '', '', '', 2147483647, 1, 0, 1, 7),
+('bx_channels_snippet_meta', 'bx_channels', 'subscribe', '_sys_menu_item_title_system_sm_subscribe', '_sys_menu_item_title_sm_subscribe', '', '', '', '', '', 2147483647, 1, 0, 1, 8),
+('bx_channels_snippet_meta', 'bx_channels', 'unsubscribe', '_sys_menu_item_title_system_sm_unsubscribe', '_sys_menu_item_title_sm_unsubscribe', '', '', '', '', '', 2147483647, 1, 0, 1, 9);
+
+-- MENU: manage tools submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channels_menu_manage_tools', '_bx_channels_menu_title_manage_tools', 'bx_channels_menu_manage_tools', 'bx_channels', 6, 0, 1, 'BxCnlMenuManageTools', 'modules/boonex/channels/classes/BxCnlMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_channels_menu_manage_tools', 'bx_channels', '_bx_channels_menu_set_title_manage_tools', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_channels_menu_manage_tools', 'bx_channels', 'delete', '_bx_channels_menu_item_title_system_delete', '_bx_channels_menu_item_title_delete', 'javascript:void(0)', 'javascript:{js_object}.onClickDelete({content_id});', '_self', 'far trash-alt', '', 2147483647, 1, 0, 1),
+('bx_channels_menu_manage_tools', 'bx_channels', 'delete-with-content', '_bx_channels_menu_item_title_system_delete_with_content', '_bx_channels_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'far trash-alt', '', 2147483647, 0, 0, 2);
+
+-- MENU: dashboard manage tools
+SET @iManageMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard_manage_tools' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_account_dashboard_manage_tools', 'bx_channels', 'channels-administration', '_bx_channels_menu_item_title_system_admt_channels', '_bx_channels_menu_item_title_admt_channels', 'page.php?i=channels-administration', '', '_self', 'hashtag', 'a:2:{s:6:"module";s:11:"bx_channels";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 128, 1, 0, @iManageMenuOrder + 1);
+
+-- MENU: profile followings
+SET @iFollowingsMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_profile_followings' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `collapsed`, `active`, `copyable`, `order`) VALUES 
+('sys_profile_followings', 'bx_channels', 'channels', '_bx_channels_menu_item_title_system_followings', '_bx_channels_menu_item_title_followings', 'javascript:void(0)', '', '_self', 'hashtag col-red2', '', '', 2147483647, 0, 1, 0, @iFollowingsMenuOrder + 1);
+
+-- MENU: add menu item to profiles modules (trigger* menu sets are processed separately upon modules enable/disable)
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('trigger_profile_view_submenu', 'bx_channels', 'channels-author', '_bx_channels_menu_item_title_system_view_entries_author', '_bx_channels_menu_item_title_view_entries_author', 'page.php?i=channels-author&profile_id={profile_id}', '', '', 'hashtag col-red2', '', 2147483647, 1, 0, 0);
+
+
+-- ACL
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_channels', 'delete entry', NULL, '_bx_channels_acl_action_delete_profile', '', 1, 1);
+SET @iIdActionProfileDelete = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_channels', 'view entry', NULL, '_bx_channels_acl_action_view_profile', '', 1, 0);
+SET @iIdActionProfileView = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_channels', 'edit any entry', NULL, '_bx_channels_acl_action_edit_any_profile', '', 1, 3);
+SET @iIdActionProfileEditAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_channels', 'delete any entry', NULL, '_bx_channels_acl_action_delete_any_profile', '', 1, 3);
+SET @iIdActionProfileDeleteAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_channels', 'create channel auto', NULL, '_bx_channels_acl_action_create_channel_auto', '_bx_channels_acl_action_create_channel_auto_info', 1, 1);
+SET @iIdActionCreateChannelAuto = LAST_INSERT_ID();
+
+SET @iUnauthenticated = 1;
+SET @iAccount = 2;
+SET @iStandard = 3;
+SET @iUnconfirmed = 4;
+SET @iPending = 5;
+SET @iSuspended = 6;
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+
+-- profile delete
+(@iAdministrator, @iIdActionProfileDelete),
+
+-- profile view
+(@iUnauthenticated, @iIdActionProfileView),
+(@iAccount, @iIdActionProfileView),
+(@iStandard, @iIdActionProfileView),
+(@iUnconfirmed, @iIdActionProfileView),
+(@iPending, @iIdActionProfileView),
+(@iModerator, @iIdActionProfileView),
+(@iAdministrator, @iIdActionProfileView),
+(@iPremium, @iIdActionProfileView),
+
+-- any profile edit
+(@iModerator, @iIdActionProfileEditAny),
+(@iAdministrator, @iIdActionProfileEditAny),
+
+-- any profile delete
+(@iAdministrator, @iIdActionProfileDeleteAny),
+
+-- create channel auto
+(@iAccount, @iIdActionCreateChannelAuto),
+(@iStandard, @iIdActionCreateChannelAuto),
+(@iUnconfirmed, @iIdActionCreateChannelAuto),
+(@iPending, @iIdActionCreateChannelAuto),
+(@iModerator, @iIdActionCreateChannelAuto),
+(@iAdministrator, @iIdActionCreateChannelAuto),
+(@iPremium, @iIdActionCreateChannelAuto);
+
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `module`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_channels', 'bx_channels', 'bx_cnl_meta_keywords', '', 'bx_cnl_meta_mentions', '', '');
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+('bx_channels', '_bx_channels', @iSearchOrder + 1, 'BxCnlSearchResult', 'modules/boonex/channels/classes/BxCnlSearchResult.php');
+
+-- STATS
+SET @iMaxOrderStats = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_statistics`);
+INSERT INTO `sys_statistics` (`module`, `name`, `title`, `link`, `icon`, `query`, `order`) VALUES 
+('bx_channels', 'bx_channels', '_bx_channels', 'page.php?i=channels-home', 'hashtag col-red2', 'SELECT COUNT(*) FROM `bx_cnl_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id` = `tp`.`content_id` AND `tp`.`type`=''bx_channels'' WHERE 1 AND `tp`.`status`=''active''', @iMaxOrderStats + 1);
+
+-- CHARTS
+SET @iMaxOrderCharts = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_objects_chart`);
+INSERT INTO `sys_objects_chart` (`object`, `title`, `table`, `field_date_ts`, `field_date_dt`, `field_status`, `query`, `active`, `order`, `class_name`, `class_file`) VALUES
+('bx_channels_growth', '_bx_channels_chart_growth', 'bx_cnl_data', 'added', '', '', 'SELECT {field_date_formatted} AS `period`, COUNT(*) AS {object} FROM {table} LEFT JOIN `sys_profiles` AS `tp` ON {table}.`id` = `tp`.`content_id` AND `tp`.`type`=''bx_channels'' WHERE 1 AND `tp`.`status`=''active'' {where_inteval} GROUP BY `period` ORDER BY {table}.{field_date} ASC', 1, @iMaxOrderCharts + 1, 'BxDolChartGrowth', ''),
+('bx_channels_growth_speed', '_bx_channels_chart_growth_speed', 'bx_cnl_data', 'added', '', '', 'SELECT {field_date_formatted} AS `period`, COUNT(*) AS {object} FROM {table} LEFT JOIN `sys_profiles` AS `tp` ON {table}.`id` = `tp`.`content_id` AND `tp`.`type`=''bx_channels'' WHERE 1 AND `tp`.`status`=''active'' {where_inteval} GROUP BY `period` ORDER BY {table}.{field_date} ASC', 1, @iMaxOrderCharts + 2, 'BxDolChartGrowthSpeed', '');
+
+-- GRIDS: administration
+
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_channels_administration', 'Sql', 'SELECT `td`.*, `td`.`channel_name` AS `name`, `ta`.`email` AS `account`, `td`.`added` AS `added_ts`, `tp`.`status` AS `status` FROM `bx_cnl_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id`=`tp`.`content_id` AND `tp`.`type`=''bx_channels'' LEFT JOIN `sys_accounts` AS `ta` ON `tp`.`account_id`=`ta`.`id` WHERE 1 ', 'bx_cnl_data', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'channel_name', '', 'like', 'reports', '', 192, 'BxCnlGridAdministration', 'modules/boonex/channels/classes/BxCnlGridAdministration.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_channels_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_channels_administration', 'switcher', '_bx_channels_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_channels_administration', 'reports', '_sys_txt_reports_title', '5%', 0, '', '', 3),
+('bx_channels_administration', 'name', '_bx_channels_grid_column_title_adm_name', '45%', 0, '', '', 4),
+('bx_channels_administration', 'added_ts', '_bx_channels_grid_column_title_adm_added', '20%', 1, '25', '', 5),
+('bx_channels_administration', 'actions', '', '20%', 0, '', '', 6);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `active`, `order`) VALUES
+('bx_channels_administration', 'bulk', 'delete', '_bx_channels_grid_action_title_adm_delete', '', 0, 1, 1, 2),
+('bx_channels_administration', 'bulk', 'delete_with_content', '_bx_channels_grid_action_title_adm_delete_with_content', '', 0, 1, 0, 3),
+('bx_channels_administration', 'single', 'settings', '_bx_channels_grid_action_title_adm_more_actions', 'cog', 1, 0, 1, 2),
+('bx_channels_administration', 'single', 'audit_content', '_bx_channels_grid_action_title_adm_audit_content', 'search', 1, 0, 1, 3),
+('bx_channels_administration', 'single', 'audit_profile', '_bx_channels_grid_action_title_adm_audit_context', 'search-location', 1, 0, 1, 4);
+
+
+-- ALERTS
+
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_channels', 'BxCnlAlertsResponse', 'modules/boonex/channels/classes/BxCnlAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('bx_timeline', 'post_common', @iHandler),
+('bx_channels_pics', 'file_deleted', @iHandler),
+('profile', 'delete', @iHandler),
+('bx_channels', 'timeline_view', @iHandler),
+('bx_channels', 'timeline_post', @iHandler),
+('bx_channels', 'timeline_delete', @iHandler),
+('bx_channels', 'timeline_comment', @iHandler),
+('bx_channels', 'timeline_vote', @iHandler),
+('bx_channels', 'timeline_score', @iHandler),
+('bx_channels', 'timeline_report', @iHandler),
+('bx_channels', 'timeline_repost', @iHandler),
+('bx_channels', 'timeline_pin', @iHandler),
+('bx_channels', 'timeline_promote', @iHandler),
+('bx_persons', 'added', @iHandler),
+('bx_persons', 'edited', @iHandler),
+('bx_organizations', 'added', @iHandler),
+('bx_organizations', 'edited', @iHandler),
+('meta_keyword', 'added', @iHandler),
+('meta_keyword', 'url', @iHandler),
+('meta_keyword', 'deleted', @iHandler);
+
+
+-- PRIVACY 
+
+INSERT INTO `sys_objects_privacy` (`object`, `module`, `action`, `title`, `default_group`, `spaces`, `table`, `table_field_id`, `table_field_author`, `override_class_name`, `override_class_file`) VALUES
+('bx_channels_allow_view_to', 'bx_channels', 'view', '_bx_channels_form_profile_input_allow_view_to', '3', '', 'bx_cnl_data', 'id', 'author', 'BxCnlPrivacy', 'modules/boonex/channels/classes/BxCnlPrivacy.php'),
+('bx_channels_allow_view_notification_to', 'bx_channels', 'view_event', '_bx_channels_form_profile_input_allow_view_notification_to', '3', '', 'bx_notifications_events', 'id', 'object_owner_id', 'BxCnlPrivacyNotifications', 'modules/boonex/channels/classes/BxCnlPrivacyNotifications.php');
+
+
+-- UPLOADERS
+
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_channels_cover_crop', 1, 'BxCnlUploaderCoverCrop', 'modules/boonex/channels/classes/BxCnlUploaderCoverCrop.php'),
+('bx_channels_picture_crop', 1, 'BxCnlUploaderPictureCrop', 'modules/boonex/channels/classes/BxCnlUploaderPictureCrop.php');

+ 3 - 0
modules/boonex/channels/updates/13.0.2_13.0.3/source/template/my_channels.html

@@ -0,0 +1,3 @@
+<div class="bx-base-pofile-units-wrapper flex flex-wrap items-start -mb-4">
+    <bx_repeat:items>__unit__</bx_repeat:items>
+</div>

+ 51 - 0
modules/boonex/convos/updates/13.0.2_13.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Conversations',
+    'version_from' => '13.0.2',
+    'version_to' => '13.0.3',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/convos/updates/update_13.0.2_13.0.3/',
+    'home_uri' => 'convos_update_1302_1303',
+
+    'module_dir' => 'boonex/convos/',
+    'module_uri' => 'convos',
+
+    'db_prefix' => 'bx_convos_',
+    'class_prefix' => 'BxCnv',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Conversations',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/convos/updates/13.0.2_13.0.3/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxCnvUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 570 - 0
modules/boonex/convos/updates/13.0.2_13.0.3/source/classes/BxCnvModule.php

@@ -0,0 +1,570 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Convos Convos
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define('BX_CNV_FOLDER_INBOX', 1);
+define('BX_CNV_FOLDER_DRAFTS', 2);
+define('BX_CNV_FOLDER_SPAM', 3);
+define('BX_CNV_FOLDER_TRASH', 4);
+
+/**
+ * Conversations module
+ */
+class BxCnvModule extends BxBaseModTextModule
+{
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+
+    public function sortCollaborators ($aCollaborators, $iProfileIdLastComment, $iProfileIdAuthor, $iProfileIdCurrent = 0)
+    {
+        if (!$iProfileIdCurrent)
+            $iProfileIdCurrent = bx_get_logged_profile_id();
+
+        $aMoveUp = array($iProfileIdCurrent, $iProfileIdLastComment, $iProfileIdAuthor);
+
+        asort($aCollaborators, SORT_NUMERIC);
+
+        foreach ($aMoveUp as $iProfileId) {
+            if (!isset($aCollaborators[$iProfileId]))
+                continue;
+
+            $a = array($iProfileId => $aCollaborators[$iProfileId]);
+            unset($aCollaborators[$iProfileId]);
+            $aCollaborators = $a + $aCollaborators;
+        }
+
+        return $aCollaborators;
+    }
+
+    public function setModuleSubmenu ($iCurrentFolderId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aMapFolderId2MenuName = array (
+            BX_CNV_FOLDER_INBOX => 'convos-folder-inbox',
+            BX_CNV_FOLDER_DRAFTS => 'convos-drafts',
+            BX_CNV_FOLDER_SPAM => 'convos-spam',
+            BX_CNV_FOLDER_TRASH => 'convos-trash',
+        );
+
+        $oMenuSubmenu = BxDolMenu::getObjectInstance('sys_site_submenu');
+        if (!$oMenuSubmenu)
+            return;
+
+        $oMenuSubmenu->setObjectSubmenu($CNF['OBJECT_MENU_SUBMENU'], array (
+            'title' => _t('_bx_cnv'),
+            'link' => BX_DOL_URL_ROOT . $CNF['URL_HOME'],
+            'icon' => '',
+        ));
+
+        $oMenuModule = BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_SUBMENU']);
+        if ($oMenuModule && isset($aMapFolderId2MenuName[$iCurrentFolderId]))
+            $oMenuModule->setSelected($this->_aModule['name'], $aMapFolderId2MenuName[$iCurrentFolderId]);
+    }
+
+    /**
+     * Mark conversation as unread for the current user
+     * @return error string on error, or empty string on success
+     */
+    public function markUnread ($iContentId)
+    {
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if (!$aContentInfo)
+            return _t('_sys_request_page_not_found_cpt');
+
+        if (CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $this->checkAllowedView($aContentInfo)))
+            return $sMsg;
+
+        if (!$this->_oDb->updateReadComments(bx_get_logged_profile_id(), (int)$iContentId, -1))
+            return _t('_error occured');
+
+        return '';
+    }
+
+    /**
+     * Delete conversation for current user by content id, before deletetion it checks user permission to delete convos
+     * @return error string on error, or empty string on success
+     */
+    public function deleteConvo ($iContentId)
+    {
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if (!$aContentInfo)
+            return _t('_sys_request_page_not_found_cpt');
+
+        if (CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $this->checkAllowedDelete($aContentInfo)))
+            return $sMsg;
+
+        if (!$this->_oDb->moveConvo((int)$iContentId, bx_get_logged_profile_id(), BX_CNV_FOLDER_TRASH))
+            return _t('_error occured');
+
+        return '';
+    }
+
+    /**
+     * Delete whole conversation for all users by content id
+     * @return error string on error, or empty string on success
+     */
+    public function deleteConvoForever ($iContentId)
+    {
+        return $this->_oDb->deleteConvo((int)$iContentId);
+    }
+
+    public function actionMarkUnread($iContentId)
+    {
+        header('Content-Type:text/plain; charset=utf-8');
+
+        if ($s = $this->markUnread ($iContentId)) {
+            echo $s;
+            exit;
+        }
+
+        echo BX_DOL_URL_ROOT . $this->_oConfig->CNF['URL_HOME'];
+        exit;
+    }
+
+    public function actionDelete($iContentId)
+    {
+        header('Content-Type:text/plain; charset=utf-8');
+
+        if ($s = $this->deleteConvo ($iContentId)) {
+            echo $s;
+            exit;
+        }
+
+        echo BX_DOL_URL_ROOT . $this->_oConfig->CNF['URL_HOME'];
+        exit;
+    }
+
+    /**
+     * Display convos in folder
+     */
+    public function actionFolder ($iFolderId)
+    {
+        $oTemplate = BxDolTemplate::getInstance();
+
+        $aFolder = $this->_oDb->getFolder((int)$iFolderId);
+        $oPage = BxDolPage::getObjectInstance('bx_convos_home');
+
+        if (!$aFolder || !$oPage) {
+            $this->_oTemplate->displayPageNotFound();
+            exit;
+        }
+
+        // add replaceable markers
+        $oPage->addMarkers(array(
+            'folder_id' => (int)$iFolderId,
+            'folder' => _t($aFolder['name']),
+        ));
+
+        $s = $oPage->getCode();
+
+        $this->_oTemplate = BxDolTemplate::getInstance();
+        $this->_oTemplate->setPageNameIndex (BX_PAGE_DEFAULT);
+        $this->_oTemplate->setPageContent ('page_main_code', $s);
+        $_GET['i']='convos-folder'; //#1148
+        $this->_oTemplate->getPageCode();
+    }
+
+    /**
+     * Get possible recipients for start conversation form
+     */
+    public function actionAjaxGetRecipients ()
+    {
+        $sTerm = bx_get('term');
+
+        $a = BxDolService::call('system', 'profiles_search', array($sTerm), 'TemplServiceProfiles');
+
+        header('Content-Type:text/javascript; charset=utf-8');
+        echo(json_encode($a));
+    }
+
+    public function serviceGetSafeServices()
+    {
+        return array (
+            // other
+            'ModuleIcon' => '',
+            'GetLink' => '',
+            // forms
+            'GetCreatePostForm' => '',
+            'EntityEdit' => '',
+            'EntityDelete' => '',
+            // page blocks
+            'EntityTextBlock' => '',
+            'EntityInfo' => '',
+            'EntityComments' => '',
+            'EntityAttachments' => '',
+            // menu
+            'EntityAllActions' => '',
+            'EntityActions' => '',
+            'MyEntriesActions' => '',
+            // own methods
+            'ConversationsInFolder' => '',
+        );
+    }
+
+    public function serviceIsAllowedContact($iProfileId)
+    {
+        return $this->checkAllowedContact($iProfileId) === CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_convos Conversations
+     * @subsection bx_convos-page_blocks Page Blocks
+     * @subsubsection bx_convos-conversations_in_folder conversations_in_folder
+     * 
+     * @code bx_srv('bx_convos', 'conversations_in_folder', [...]); @endcode
+     * 
+     * Display conversations in particulr folder for currently logged-in user
+     * @param $iFolderId folder ID
+     * 
+     * @see BxCnvModule::serviceConversationsInFolder
+     */
+    /** 
+     * @ref bx_convos-conversations_in_folder "conversations_in_folder"
+     */
+    public function serviceConversationsInFolder ($iFolderId = BX_CNV_FOLDER_INBOX)
+    {
+        $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->CNF['OBJECT_GRID']);
+        if (!$oGrid)
+            return false;
+
+        $aFolder = $this->_oDb->getFolder((int)$iFolderId);
+        if (!$aFolder)
+            return false;
+
+        $this->setModuleSubmenu ((int)$iFolderId);
+
+        // TODO: incorporate markers into custom class, so replace will work in search and so on
+        $oGrid->addMarkers(array(
+            'folder_id' => (int)$iFolderId,
+            'profile_id' => bx_get_logged_profile_id(),
+        ));
+
+        $this->_oTemplate->addCss(array('manage_tools.css'));
+        $this->_oTemplate->addJs(array('manage_tools.js'));
+        $this->_oTemplate->addJsTranslation(array('_sys_grid_search'));
+        
+        return $this->_oTemplate->getJsCode('manage_tools', array('sObjNameGrid' => $this->_oConfig->CNF['OBJECT_GRID'])) . $oGrid->getCode();
+    }
+
+    public function serviceMessagesPreviews ($iProfileId = 0, $bEmptyMessage = true)
+    {
+        if (!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        $a = $this->_oDb->getMessagesPreviews($iProfileId, 0, (int)getParam('bx_convos_preview_messages_num'));
+        if((empty($a) || !is_array($a)) && !$bEmptyMessage)
+            return '';
+
+        return $this->_oTemplate->getMessagesPreviews($a);
+    }
+
+    /**
+     * Returns preview of profile's conversations with statistic for React Jot
+     * @param int $iProfileId
+     * @param int $iStart
+     * @param int $iPerPage
+     * @param int $iFolderId
+     * @return mixed
+     */
+    public function serviceGetMessagesPreviews ($iProfileId = 0, $iStart = 0, $iPerPage = 10, $iFolderId = BX_CNV_FOLDER_INBOX)
+    {
+        if (!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        return $this->_oDb->getMessagesPreviews($iProfileId, (int)$iStart, (int)$iPerPage, $iFolderId);
+    }
+
+    /**
+     * Get number of unread messages for spme profile
+     * @param $iProfileId - profile to get unread messages for, if omitted then currently logged is profile is used
+     * @return integer
+     */
+    public function serviceGetUnreadMessagesNum ($iProfileId = 0)
+    {
+        if (!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        return $this->_oDb->getUnreadMessagesNum((int)$iProfileId);
+    }
+
+    public function serviceGetLiveUpdates($aMenuItemParent, $aMenuItemChild, $iCount = 0)
+    {
+        $iProfileId = (int)bx_get_logged_profile_id();
+        $iCountNew = $this->_oDb->getUnreadMessagesNum($iProfileId);
+        if($iCountNew == $iCount)
+			return false;
+
+        return array(
+    		'count' => $iCountNew, // required
+    		'method' => 'bx_menu_show_live_update(oData)', // required
+    		'data' => array(
+    			'code' => BxDolTemplate::getInstance()->parseHtmlByTemplateName('menu_item_addon', array(
+    				'content' => '{count}'
+                )),
+                'mi_parent' => $aMenuItemParent,
+                'mi_child' => $aMenuItemChild
+    		),  // optional, may have some additional data to be passed in JS method provided using 'method' param above.
+    	);
+    }
+
+    /**
+     * Update last comment time and author
+     */
+    public function serviceTriggerCommentPost ($iContentId, $iProfileId, $iCommentId, $iTimestamp = 0, $sCommentText = '')
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        if (!(int)$iContentId)
+            return false;
+        $aContentInfo = $this->_oDb->getContentInfoById((int)$iContentId);
+        if (!$aContentInfo)
+            return false;
+
+        // add author to the list of collaborators when somebody replies
+        // if author is removed from collaborators
+        // of if authot placed message to trash
+        $aCollaborators = $this->_oDb->getCollaborators($aContentInfo[$CNF['FIELD_ID']]);
+        if (!isset($aCollaborators[$aContentInfo[$CNF['FIELD_AUTHOR']]]) || BX_CNV_FOLDER_TRASH == $this->_oDb->getConversationFolder($aContentInfo[$CNF['FIELD_ID']], $aContentInfo[$CNF['FIELD_AUTHOR']])) {
+            $oFormsHelper = $this->serviceFormsHelper ();
+            $oForm = $oFormsHelper->getObjectFormEdit();
+            $oForm->updateParticipants($aContentInfo[$CNF['FIELD_ID']], BX_CNV_FOLDER_INBOX, false, array($aContentInfo[$CNF['FIELD_AUTHOR']]));
+        }
+
+
+        $oCmts = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], $iContentId);
+        if(!$oCmts)
+            return false;
+            
+        if (!$iTimestamp)
+            $iTimestamp = time();
+
+        if ($iProfileId == bx_get_logged_profile_id())
+            $this->_oDb->updateReadComments($iProfileId, $aContentInfo[$CNF['FIELD_ID']], $aContentInfo[$CNF['FIELD_COMMENTS']]);
+
+        if (!$this->_oDb->updateLastCommentTimeProfile((int)$iContentId, (int)$iProfileId, (int)$iCommentId, $iTimestamp))
+            return false;
+
+        // send notification to all collaborators
+        if ($oProfile = BxDolProfile::getInstance($iProfileId)) {
+            foreach ($aCollaborators as $iCollaborator => $iReadComments) {
+                if ($iCollaborator == $iProfileId)
+                    continue;
+                sendMailTemplate('bx_cnv_new_reply', 0, $iCollaborator, array(
+                    'SenderDisplayName' => $oProfile->getDisplayName(),
+                    'SenderUrl' => $oProfile->getUrl(),
+                    'PageUrl' => $oCmts->getItemUrl($iCommentId),
+                    'PageTitle' => $oCmts->getObjectTitle(),
+                    'Message' => $sCommentText,
+                ), BX_EMAIL_NOTIFY, true);
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Create entry form
+     * @return HTML string
+     */
+    public function serviceEntityCreate ($sParams = false)
+    {
+        $sProfilesIds = bx_get('profiles');
+        if($sProfilesIds !== false) {
+            $sDiv = ',';
+            $aIds = explode($sDiv, $sProfilesIds);
+
+            $aIdsAllowed = array();
+            foreach($aIds as $iId)
+                if($this->checkAllowedContact($iId) === CHECK_ACTION_RESULT_ALLOWED)
+                    $aIdsAllowed[] = $iId;
+
+            if(empty($aIdsAllowed))
+                return MsgBox(_t('_sys_txt_access_denied'));
+            
+            bx_set('profiles', implode($sDiv, $aIdsAllowed));
+        }
+
+        return parent::serviceEntityCreate();
+    }
+
+    /**
+     * Entry collaborators block
+     */
+    public function serviceEntityCollaborators ($iContentId = 0)
+    {
+        if (!$iContentId)
+            $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if (!$iContentId)
+            return false;
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if (!$aContentInfo)
+            return false;
+
+        return $this->_oTemplate->entryCollaborators ($aContentInfo, 5, 'right');
+    }
+
+    /**
+     * No social sharing for private conversations
+     */
+    public function serviceEntitySocialSharing ($mixedContent = false, $aParams = array())
+    {
+        return '';
+    }
+
+    /**
+     * Delete content entry
+     * @param $iContentId content id 
+     * @return error message or empty string on success
+     */
+    public function serviceDeleteEntity ($iContentId, $sFuncDelete = 'deleteData')
+    {
+        return $this->_oDb->deleteConvo($iContentId);
+    }
+    
+    /**
+     * Delete profile from all conversation (when profile is delete without content)
+     * @param $iProfileId profile id 
+     * @return number of deleted items
+     */    
+    public function serviceRemoveCollaboratorFromAllConversations ($iProfileId)
+    {
+        return $this->_oDb->removeCollaboratorFromAllConversations((int)$iProfileId);
+    }
+    
+    /**
+     * Delete all content by profile (when profile is delete with content)
+     * @param $iProfileId profile id 
+     * @return number of deleted items
+     */
+    public function serviceDeleteEntitiesByAuthor ($iProfileId)
+    {
+        $a = $this->_oDb->getEntriesByAuthor((int)$iProfileId);
+        if (!$a)
+            return 0;
+
+        $iCount = 0;
+        foreach ($a as $aContentInfo)
+            $iCount += ('' == $this->serviceDeleteEntity($aContentInfo[$this->_oConfig->CNF['FIELD_ID']]) ? 1 : 0);
+
+        return $iCount;
+    }
+    
+    /**
+     * No moderators for personal convos
+     */
+    public function _isModerator ($isPerformAction = false)
+    {
+        return false;
+    }
+
+    /**
+     * No thumbs for convos
+     */
+    public function checkAllowedSetThumb ($iContentId = 0)
+    {
+        return _t('_sys_txt_access_denied');
+    }
+
+    /**
+     * There is no 'moderator' access in convos
+     */
+    public function checkAllowedEditAnyEntry ($isPerformAction = false)
+    {
+    	return _t('_sys_txt_access_denied');
+    }
+
+    public function checkAllowedEditAnyEntryForProfile ($isPerformAction = false, $iProfileId = false)
+    {
+    	return _t('_sys_txt_access_denied');
+    }
+	
+	public function checkAllowedDeleteAnyEntryForProfile ($isPerformAction = false, $iProfileId = false)
+    {
+        return _t('_sys_txt_access_denied');
+    }
+
+    public function checkAllowedEdit ($aDataEntry, $isPerformAction = false)
+    {       
+        if ($aDataEntry[$this->_oConfig->CNF['FIELD_ALLOW_EDIT']] && $this->isCollaborator($aDataEntry, bx_get_logged_profile_id()))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return parent::checkAllowedEdit ($aDataEntry, $isPerformAction);
+    }
+    
+    /**
+     * Conversations can be deleted by author and/or collaborators only.
+     * Admins can't delete conversations, since it's designed for participant only, it's moved to trash actually, also it's private content.
+     */
+    public function checkAllowedDelete (&$aDataEntry, $isPerformAction = false)
+    {
+        if ($aDataEntry[$this->_oConfig->CNF['FIELD_AUTHOR']] == $this->_iProfileId || $this->isCollaborator($aDataEntry, bx_get_logged_profile_id()))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        if ($this->_isModerator($isPerformAction))
+            return _t('_sys_txt_access_denied');
+
+        return parent::checkAllowedDelete ($aDataEntry, $isPerformAction);
+    }
+
+    /**
+     * Only collaborators can view convo
+     */
+    public function checkAllowedView ($aDataEntry, $isPerformAction = false)
+    {
+        return $this->serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction);
+    }
+
+    /**
+     * Checks whether contact is allowed.
+     * @param integer $iProfileId - recipient profile ID
+     * @param boolean $isPerformAction - perform or just check the action
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedContact($iProfileId, $isPerformAction = false)
+    {
+        $oProfile = BxDolProfile::getInstance($iProfileId);
+        if(!$oProfile)
+            return _t('_sys_txt_access_denied');
+
+        $mixedResult = $oProfile->checkAllowedProfileContact();
+        if($mixedResult !== CHECK_ACTION_RESULT_ALLOWED)
+            return _t('_sys_txt_access_denied');
+
+        return $this->checkAllowedAdd($isPerformAction);
+    }
+
+    public function serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction = false, $iProfileId = false)
+    {
+        if (CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = parent::serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction, $iProfileId)))
+            return $sMsg;
+
+        if (!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        return $this->isCollaborator($aDataEntry, $iProfileId) ? CHECK_ACTION_RESULT_ALLOWED : _t('_sys_txt_access_denied');
+    }
+
+    protected function isCollaborator($aDataEntry, $iProfileId)
+    {
+        $aCollaborators = $this->_oDb->getCollaborators($aDataEntry[$this->_oConfig->CNF['FIELD_ID']]);
+        return isset($aCollaborators[$iProfileId]);
+    }
+
+    public function serviceIsAllowedPostInContext()
+    {
+        return false;
+    }
+}
+
+/** @} */

+ 262 - 0
modules/boonex/convos/updates/13.0.2_13.0.3/source/classes/BxCnvTemplate.php

@@ -0,0 +1,262 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Convos Convos
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/*
+ * Module representation.
+ */
+class BxCnvTemplate extends BxBaseModTextTemplate
+{
+    /**
+     * Constructor
+     */
+    function __construct(&$oConfig, &$oDb)
+    {
+        $this->MODULE = 'bx_convos';
+        parent::__construct($oConfig, $oDb);
+    }
+
+    public function entryCollaborators ($aContentInfo, $iMaxVisible = 2, $sFloat = 'left')
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        $aCollaborators = $this->_oDb->getCollaborators($aContentInfo[$CNF['FIELD_ID']]);
+        //unset($aCollaborators[$aContentInfo[$CNF['FIELD_AUTHOR']]]);
+
+        // sort collaborators: first - current user, second - last replier, third - author, all others sorted by max number of posts
+        $aCollaborators = $oModule->sortCollaborators($aCollaborators, $aContentInfo['last_reply_profile_id'], $aContentInfo[$CNF['FIELD_AUTHOR']]);
+        $iCollaboratorsNum = count($aCollaborators);
+
+        // prepare template variables
+        $aVarsPopup = array (
+            'float' => 'none',
+            'bx_repeat:collaborators' => array(),
+            'bx_if:collaborators_more' => array(
+                'condition' => false,
+                'content' => array(),
+            ),
+        );
+        $aVars = array (
+            'float' => $sFloat,
+            'bx_repeat:collaborators' => array(),
+            'bx_if:collaborators_more' => array(
+                'condition' => $iCollaboratorsNum > $iMaxVisible,
+                'content' => array(
+                    'popup' => '',
+                    'title_more' => _t('_bx_cnv_more', $iCollaboratorsNum - $iMaxVisible),
+                    'float' => $sFloat,
+                    'id' => $this->MODULE . '-popup-' . $aContentInfo[$CNF['FIELD_ID']],
+                ),
+            ),
+        );
+        $i = 0;
+        $aCollaborators = array_slice($aCollaborators, 0, 30, true);
+        foreach ($aCollaborators as $iProfileId => $iReadComments) {
+            $oProfile = BxDolProfile::getInstanceMagic($iProfileId);
+
+            $aCollaborator = array (
+                'id' => $oProfile->id(),
+                'unit' => $oProfile->getUnit(0, array('template' => 'unit_wo_info')),
+                'float' => $sFloat,
+                'class' => $aContentInfo[$CNF['FIELD_AUTHOR']] == $iProfileId ? 'bx-cnv-collaborator-author' : '',
+                'bx_if:last_replier' => array (
+                    'condition' => ($aContentInfo['last_reply_profile_id'] == $iProfileId),
+                    'content' => array (
+                        'id' => $oProfile->id(),
+                        'title' => bx_html_attribute(_t('_bx_cnv_collaborator_last_replier')),
+                    ),
+                ),
+                'bx_if:author'  => array (
+                    'condition' => $aContentInfo[$CNF['FIELD_AUTHOR']] == $iProfileId,
+                    'content' => array (
+                        'id' => $oProfile->id(),
+                        'title' => bx_html_attribute(_t('_bx_cnv_collaborator_author')),
+                    ),
+                ),
+            );
+
+            if ($i < $iMaxVisible)
+                $aVars['bx_repeat:collaborators'][] = $aCollaborator;
+            if ($i >= $iMaxVisible)
+                $aVarsPopup['bx_repeat:collaborators'][] = $aCollaborator;
+
+            ++$i;
+        }
+
+        if ($aVarsPopup['bx_repeat:collaborators']) {
+            $aVars['bx_if:collaborators_more']['content']['popup'] = BxTemplFunctions::getInstance()->transBox('', '<div class="bx-def-padding">' . $this->parseHtmlByName('collaborators.html', $aVarsPopup) . '</div>');
+        }
+
+        return $this->parseHtmlByName('collaborators.html', $aVars);
+    }
+
+    function getAuthorDesc ($aData, $oProfile)
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        if ($aData['last_reply_timestamp'] == $aData[$oModule->_oConfig->CNF['FIELD_ADDED']])
+            return bx_time_js($aData[$oModule->_oConfig->CNF['FIELD_ADDED']], BX_FORMAT_DATE);
+
+        return _t('_bx_cnv_author_desc', bx_time_js($aData[$oModule->_oConfig->CNF['FIELD_ADDED']], BX_FORMAT_DATE), bx_time_js($aData['last_reply_timestamp'], BX_FORMAT_DATE));
+    }
+
+    function getMessageLabel ($iCount, $r, $oProfileLast = null)
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+
+        if (!$oProfileLast) {
+            $oProfileLast = BxDolProfile::getInstance($r['last_reply_profile_id']);
+            if (!$oProfileLast)
+                $oProfileLast = BxDolProfileUndefined::getInstance();
+        }
+
+        if (!isset($r['unread_messages']))
+            $r['unread_messages'] = $r['comments'] - $r['read_comments'];
+
+        $bReadByAll = true;
+        $aCollaborators = $oModule->_oDb->getCollaborators($r['id']);
+        foreach ($aCollaborators as $iReadComments) {
+            if ($r['comments'] - $iReadComments) {
+                $bReadByAll = false;
+                break;
+            }
+        }
+
+        if (!isset($r['unread_messages']))
+            $r['unread_messages'] = $r['comments'] - $r['read_comments'];
+
+        return $this->parseHtmlByName('message_label.html', array (
+            'count' => $iCount,
+            'bx_if:unread_messages' => array (
+                'condition' => $r['unread_messages'] > 0,
+                'content' => array (
+                    'unread_messages' => $r['unread_messages'],
+                ),
+            ),
+            'bx_if:viewer_is_last_replier' => array (
+                'condition' => !$bReadByAll && $oProfileLast->id() == bx_get_logged_profile_id(),
+                'content' => array (),
+            ),
+            'bx_if:is_read_by_all' => array (
+                'condition' => $bReadByAll,
+                'content' => array (),
+            ),
+        ));
+    }
+
+    function getMessagesPreviews ($a)
+    {
+        if (empty($a))
+            return MsgBox(_t('_Empty'));
+
+        $oModule = BxDolModule::getInstance($this->MODULE);
+
+        $aVars = array(
+            'see_all_url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink($oModule->_oConfig->CNF['URL_HOME']),
+            'bx_repeat:messages' => array(),
+        );
+        foreach ($a as $r) {
+
+            $oProfileAuthor = BxDolProfile::getInstance($r['author']);
+            if (!$oProfileAuthor)
+                $oProfileAuthor = BxDolProfileUndefined::getInstance();
+
+            $oProfileLast = BxDolProfile::getInstance($r['last_reply_profile_id']);
+            if (!$oProfileLast)
+                $oProfileLast = BxDolProfileUndefined::getInstance();
+
+            $sText = strmaxtextlen($r['text'], 90);
+            $sTextCmt = strmaxtextlen($r['cmt_text'], 50);
+
+            $aVars['bx_repeat:messages'][] = array (
+                'id' => $r['id'],
+                'url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $oModule->_oConfig->CNF['URI_VIEW_ENTRY'] . '&id=' . $r['id']),
+                'text' => $sText ? $sText : $oProfileAuthor->getDisplayName(),
+                'cmt_text' => $sTextCmt,
+                'unread_messages' => $r['unread_messages'],
+                'last_reply_time_and_replier' => _t('_bx_cnv_x_date_by_x_replier', bx_time_js($r['last_reply_timestamp'], BX_FORMAT_DATE), $oProfileLast->getDisplayName()),
+                'font_weight' => $r['unread_messages'] > 0 ? 'bold' : 'normal',
+                'label' => $this->getMessageLabel($r['comments'] + 1, $r, $oProfileLast),
+
+                'author_id' => $oProfileAuthor->id(),
+                'author_url' => $oProfileAuthor->getUrl(),
+                'author_title' => $oProfileAuthor->getDisplayName(),
+                'author_title_attr' => bx_html_attribute($oProfileAuthor->getDisplayName()),
+                'author_thumb_url' => $oProfileAuthor->getThumb(),
+
+                'last_replier_id' => $oProfileLast->id(),
+                'last_replier_url' => $oProfileLast->getUrl(),
+                'last_replier_title' => $oProfileLast->getDisplayName(),
+                'last_replier_title_attr' => bx_html_attribute($oProfileLast->getDisplayName()),
+                'last_replier_thumb_url' => $oProfileLast->getThumb(),
+            );
+        }
+        return $this->parseHtmlByName('messages_previews.html', $aVars);
+    }
+
+    function entryMessagePreviewInGrid ($r)
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+
+        $oProfileLast = BxDolProfile::getInstance($r['last_reply_profile_id']);
+        if (!$oProfileLast)
+            $oProfileLast = BxDolProfileUndefined::getInstance();
+
+        $sText = strmaxtextlen($r['text'], 100);
+        $sTextCmt = strmaxtextlen($r['cmt_text'], 100);
+
+        if (!isset($r['unread_messages']))
+            $r['unread_messages'] = $r['comments'] - $r['read_comments'];
+
+        $aVars = array (
+            'url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $oModule->_oConfig->CNF['URI_VIEW_ENTRY'] . '&id=' . $r['id']),
+            'text' => $sText ? $sText : _t('_Empty'),
+            'cmt_text' => $sTextCmt,
+            'last_reply_time_and_replier' => _t('_bx_cnv_x_date_by_x_replier', bx_time_js($r['last_reply_timestamp'], BX_FORMAT_DATE), $oProfileLast->getDisplayName()),
+            'bx_if:unread_messages' => array (
+                'condition' => $r['unread_messages'] > 0,
+                'content' => array (),
+            ),
+        );
+        $aVars['bx_if:unread_messages2'] = $aVars['bx_if:unread_messages'];
+        return $this->parseHtmlByName('message_preview_in_grid.html', $aVars);
+    }
+
+    function getAuthorAddon ($aData, $oProfile)
+    {
+        return '';
+    }
+
+	public function entryBreadcrumb($aContentInfo, $aTmplVarsItems = array())
+    {
+        $CNF = &BxDolModule::getInstance($this->MODULE)->_oConfig->CNF;
+
+        $oPermalink = BxDolPermalinks::getInstance();
+
+        $oAuthor = BxDolProfile::getInstance($aContentInfo[$CNF['FIELD_AUTHOR']]);
+		if(!$oAuthor)
+			$oAuthor = BxDolProfileUndefined::getInstance();
+
+        $sText = strmaxtextlen($aContentInfo[$CNF['FIELD_TEXT']], 50);
+        $iFolder = $this->_oDb->getConversationFolder($aContentInfo[$CNF['FIELD_ID']], bx_get_logged_profile_id());
+
+    	$aTmplVarsItems = array(array(
+        	'url' => BX_DOL_URL_ROOT . $oPermalink->permalink($CNF['URL_FOLDER'] . $iFolder),
+        	'title' => _t($CNF['T']['txt_folder_' . $iFolder])
+        ), array(
+        	'url' => BX_DOL_URL_ROOT . $oPermalink->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]),
+        	'title' => $sText ? $sText : $oAuthor->getDisplayName(),
+        ));
+
+    	return parent::entryBreadcrumb($aContentInfo, $aTmplVarsItems);
+    }
+}
+
+/** @} */

+ 104 - 0
modules/boonex/convos/updates/13.0.2_13.0.3/source/install/config.php

@@ -0,0 +1,104 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Convos Convos
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_convos',
+    'title' => 'Conversations',
+    'note' => 'Conversations module.',
+    'version' => '13.0.3',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/convos/',
+    'home_uri' => 'convos',
+
+    'db_prefix' => 'bx_convos_',
+    'class_prefix' => 'BxCnv',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Conversations',
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+        'trigger_profile_view_actions',
+        'trigger_group_view_actions',
+    ),
+
+	/**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_convos_files'
+    ),
+
+	/**
+     * Transcoders.
+     */
+    'transcoders' => array(
+		'bx_convos_preview'
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+	'enable_success' => array(
+    	'process_menu_triggers' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'unregister_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 51 - 0
modules/boonex/courses/updates/13.0.2_13.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Courses',
+    'version_from' => '13.0.2',
+    'version_to' => '13.0.3',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/courses/updates/update_13.0.2_13.0.3/',
+    'home_uri' => 'courses_update_1302_1303',
+
+    'module_dir' => 'boonex/courses/',
+    'module_uri' => 'courses',
+
+    'db_prefix' => 'bx_courses_',
+    'class_prefix' => 'BxCourses',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Courses',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/courses/updates/13.0.2_13.0.3/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxCoursesUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 4 - 0
modules/boonex/courses/updates/13.0.2_13.0.3/install/langs/en.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string_add name="_bx_courses_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string_add>
+</resources>

+ 7 - 0
modules/boonex/courses/updates/13.0.2_13.0.3/install/sql/enable.sql

@@ -0,0 +1,7 @@
+-- MENUS
+UPDATE `sys_menu_items` SET `active`='0' WHERE `set_name`='bx_courses_menu_manage_tools' AND `name`='delete-with-content';
+
+
+-- GRIDS
+UPDATE `sys_grid_actions` SET `active`='0' WHERE `object`='bx_courses_administration' AND `type`='bulk' AND `name`='delete_with_content';
+UPDATE `sys_grid_actions` SET `active`='0' WHERE `object`='bx_courses_common' AND `type`='bulk' AND `name`='delete_with_content';

+ 152 - 0
modules/boonex/courses/updates/13.0.2_13.0.3/source/install/config.php

@@ -0,0 +1,152 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Courses Courses
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_courses',
+    'title' => 'Courses',
+    'note' => 'Basic course profiles functionality.',
+    'version' => '13.0.3',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/courses/',
+    'home_uri' => 'courses',
+
+    'db_prefix' => 'bx_courses_',
+    'class_prefix' => 'BxCourses',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Courses',
+
+    /**
+     * Connections.
+     */
+    'connections' => array(
+        'sys_profiles_friends' => array ('type' => 'profiles'),
+        'sys_profiles_subscriptions' => array ('type' => 'profiles'),
+    ),
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+    	'trigger_profile_view_submenu',
+        'trigger_group_view_submenu',
+        'trigger_group_snippet_meta',
+        'trigger_group_view_actions',
+    ),
+
+    /**
+     * Page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_group_view_entry', 
+    ),
+
+	/**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_courses_pics'
+    ),
+
+	/**
+     * Transcoders.
+     */
+    'transcoders' => array(
+    	'bx_courses_icon', 
+    	'bx_courses_thumb', 
+    	'bx_courses_avatar', 
+        'bx_courses_avatar_big', 
+    	'bx_courses_picture', 
+    	'bx_courses_cover', 
+    	'bx_courses_cover_thumb',
+        'bx_courses_gallery'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_courses',
+    	'bx_courses_cmts',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'process_connections' => 1,
+        'process_deleted_profiles' => 1,
+    	'update_relations' => 1,        
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+    	'process_menu_triggers' => 1,
+    	'process_page_triggers' => 1,
+    	'process_esearches' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'unregister_transcoders' => 1,
+        'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Connections Section
+     */
+    'relations' => array(
+        'bx_timeline',
+        'bx_notifications',
+    ),
+);
+
+/** @} */

+ 451 - 0
modules/boonex/courses/updates/13.0.2_13.0.3/source/install/langs/en.xml

@@ -0,0 +1,451 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string name="_bx_courses"><![CDATA[Courses]]></string>
+    <string name="_bx_courses_cmts"><![CDATA[Courses' Comments]]></string>
+
+    <string name="_bx_courses_option_enable_auto_approve"><![CDATA[Auto approve a course after creation]]></string>
+    <string name="_bx_courses_option_num_connections_quick"><![CDATA[Number of items in friends block]]></string>
+    <string name="_bx_courses_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+    <string name="_bx_courses_option_num_rss"><![CDATA[Number of items in RSS feed]]></string>
+    <string name="_bx_courses_option_searchable_fields"><![CDATA[Searchable fields]]></string>
+    <string name="_bx_courses_option_members_mode"><![CDATA[Special mode for course members]]></string>
+    <string name="_bx_courses_option_members_mode_multi_roles"><![CDATA[Multi Roles]]></string>
+    <string name="_bx_courses_option_per_page_for_favorites_lists"><![CDATA[Number of favorite lists per page]]></string>
+    <string name="_bx_courses_option_internal_notifications"><![CDATA[Use internal notifications]]></string>
+
+    <string name="_bx_courses_form_profile"><![CDATA[Courses]]></string>
+    <string name="_bx_courses_form_profile_display_add"><![CDATA[Add Course]]></string>
+    <string name="_bx_courses_form_profile_display_edit"><![CDATA[Edit Course]]></string>
+    <string name="_bx_courses_form_profile_display_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_courses_form_profile_display_delete"><![CDATA[Delete Course]]></string>
+    <string name="_bx_courses_form_profile_display_view"><![CDATA[View Course]]></string>
+    <string name="_bx_courses_form_profile_display_view_full"><![CDATA[Full View Course]]></string>
+    <string name="_bx_courses_form_profile_display_invite"><![CDATA[Invite to Course]]></string>
+    <string name="_bx_courses_form_entry_input_author"><![CDATA[Author]]></string>
+    <string name="_bx_courses_form_profile_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_courses_form_profile_input_sys_join_confirm"><![CDATA[Join confirmation]]></string>
+    <string name="_bx_courses_form_profile_input_join_confirm"><![CDATA[Approval required to join]]></string>
+    <string name="_bx_courses_form_profile_input_sys_allow_view_to"><![CDATA[Visible to]]></string>
+    <string name="_bx_courses_form_profile_input_allow_view_to"><![CDATA[Visible to]]></string>
+    <string name="_bx_courses_form_profile_input_allow_view_favorite_list"><![CDATA[Visibility]]></string>
+    <string name="_bx_courses_form_profile_input_allow_view_to_desc"><![CDATA[Closed - anyone can find the course and see who's in it, only students can see posts. Secret - only students can find the course and see posts.]]></string>
+    <string name="_bx_courses_form_profile_input_sys_allow_post_to"><![CDATA[Who can post]]></string>
+    <string name="_bx_courses_form_profile_input_allow_post_to"><![CDATA[Who can post]]></string>
+    <string name="_bx_courses_form_profile_input_sys_initial_members"><![CDATA[Invite Students]]></string>
+    <string name="_bx_courses_form_profile_input_initial_members"><![CDATA[Invite Students]]></string>
+    <string name="_bx_courses_form_profile_input_sys_name"><![CDATA[Name]]></string>
+    <string name="_bx_courses_form_profile_input_name"><![CDATA[Name]]></string>
+    <string name="_bx_courses_form_profile_input_name_err"><![CDATA[This information is essential. Please, fill in this field.]]></string>
+    <string name="_bx_courses_form_profile_input_sys_desc"><![CDATA[Description]]></string>
+    <string name="_bx_courses_form_profile_input_desc"><![CDATA[Description]]></string>
+    <string name="_bx_courses_form_profile_input_sys_cat"><![CDATA[Category]]></string>
+    <string name="_bx_courses_form_profile_input_cat"><![CDATA[Category]]></string>
+    <string name="_bx_courses_form_profile_input_cat_err"><![CDATA[Category field is mandatory]]></string>
+    <string name="_bx_courses_form_profile_input_sys_picture"><![CDATA[Course Picture]]></string>
+    <string name="_bx_courses_form_profile_input_picture"><![CDATA[Upload New Course Picture]]></string>
+    <string name="_bx_courses_form_profile_input_picture_err"><![CDATA[Course picture is mandatory.]]></string>
+    <string name="_bx_courses_form_profile_input_sys_cover"><![CDATA[Cover Picture]]></string>
+    <string name="_bx_courses_form_profile_input_cover"><![CDATA[Upload New Cover Picture]]></string>
+    <string name="_bx_courses_form_profile_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+    <string name="_bx_courses_form_profile_input_delete_confirm"><![CDATA[I am sure I want to delete this course]]></string>
+    <string name="_bx_courses_form_profile_input_delete_confirm_info"><![CDATA[This action can not be undone.]]></string>
+    <string name="_bx_courses_form_profile_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete course.]]></string>
+
+    <string name="_bx_courses_form_price"><![CDATA[Price]]></string>
+    <string name="_bx_courses_form_price_display_add"><![CDATA[Add]]></string>
+    <string name="_bx_courses_form_price_display_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_courses_form_price_input_sys_id"><![CDATA[ID]]></string>
+    <string name="_bx_courses_form_price_input_sys_role_id"><![CDATA[Role ID]]></string>
+    <string name="_bx_courses_form_price_input_sys_name"><![CDATA[Name]]></string>
+    <string name="_bx_courses_form_price_input_name"><![CDATA[Name]]></string>
+    <string name="_bx_courses_form_price_input_inf_name"><![CDATA[Unique value which will be used in back end and API calls]]></string>
+    <string name="_bx_courses_form_price_input_err_name"><![CDATA[You need to enter a unique value here]]></string>
+    <string name="_bx_courses_form_price_input_sys_period"><![CDATA[Period]]></string>
+    <string name="_bx_courses_form_price_input_period"><![CDATA[Period]]></string>
+    <string name="_bx_courses_form_price_input_inf_period"><![CDATA[Use 0 for lifetime]]></string>
+    <string name="_bx_courses_form_price_input_sys_period_unit"><![CDATA[Period unit]]></string>
+    <string name="_bx_courses_form_price_input_period_unit"><![CDATA[Period unit]]></string>
+    <string name="_bx_courses_form_price_input_inf_period_unit"><![CDATA[Leave empty for lifetime level.]]></string>
+    <string name="_bx_courses_form_price_input_err_period_unit"><![CDATA[You need to select a period unit here.]]></string>
+    <string name="_bx_courses_form_price_input_sys_price"><![CDATA[Price]]></string>
+    <string name="_bx_courses_form_price_input_price"><![CDATA[Price]]></string>
+    <string name="_bx_courses_form_price_input_inf_price"><![CDATA[Use 0 or leave empty to create free level.]]></string>
+    <string name="_bx_courses_form_price_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_courses_form_price_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_courses_form_price_input_sys_do_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_courses_form_price_input_do_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_courses_acl_action_create_profile"><![CDATA[Create Course]]></string>
+    <string name="_bx_courses_acl_action_use_paid_join"><![CDATA[Use paid join]]></string>
+    <string name="_bx_courses_acl_action_delete_profile"><![CDATA[Delete Course]]></string>
+    <string name="_bx_courses_acl_action_view_profile"><![CDATA[View Course]]></string>
+    <string name="_bx_courses_acl_action_edit_any_profile"><![CDATA[Edit Any Course]]></string>
+    <string name="_bx_courses_acl_action_delete_any_profile"><![CDATA[Delete Any Course]]></string>
+    <string name="_bx_courses_acl_action_delete_invites"><![CDATA[Delete Invites]]></string>
+
+    <string name="_bx_courses_page_title_sys_joined_entries"><![CDATA[Profile Courses]]></string>
+    <string name="_bx_courses_page_title_joined_entries"><![CDATA[Profile Courses]]></string>
+    <string name="_bx_courses_page_title_sys_create_profile"><![CDATA[Create Course]]></string>
+    <string name="_bx_courses_page_title_create_profile"><![CDATA[Create Course]]></string>
+    <string name="_bx_courses_page_title_sys_edit_profile"><![CDATA[Edit Course]]></string>
+    <string name="_bx_courses_page_title_edit_profile"><![CDATA[Edit Course]]></string>
+    <string name="_bx_courses_page_title_sys_edit_profile_cover"><![CDATA[Edit Course Cover]]></string>
+    <string name="_bx_courses_page_title_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_courses_page_title_sys_delete_profile"><![CDATA[Delete Course]]></string>
+    <string name="_bx_courses_page_title_delete_profile"><![CDATA[Delete Course]]></string>
+    <string name="_bx_courses_page_title_sys_join_profile"><![CDATA[Join Course]]></string>
+    <string name="_bx_courses_page_title_join_profile"><![CDATA[Join Course]]></string>
+    <string name="_bx_courses_page_title_sys_view_profile_closed"><![CDATA[View Closed Course]]></string>
+    <string name="_bx_courses_page_title_sys_view_profile"><![CDATA[View Course]]></string>
+    <string name="_bx_courses_page_title_view_profile"><![CDATA[{display_name}]]></string>
+    <string name="_bx_courses_page_title_browse"><![CDATA[Courses]]></string>
+    <string name="_bx_courses_page_title_browse_by_author"><![CDATA[Courses of {display_name}]]></string>
+    <string name="_bx_courses_page_title_browse_featured"><![CDATA[Featured Courses]]></string>
+    <string name="_bx_courses_page_title_browse_top"><![CDATA[Top Courses]]></string>
+    <string name="_bx_courses_page_title_browse_recent"><![CDATA[New Courses]]></string>
+    <string name="_bx_courses_page_title_browse_connections"><![CDATA[{0} connections]]></string>
+    <string name="_bx_courses_page_title_browse_connections_mutual"><![CDATA[{0} and {1} mutual connections]]></string>
+    <string name="_bx_courses_page_title_sys_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_courses_page_title_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_courses_page_title_sys_entry_fans"><![CDATA[Students]]></string>
+    <string name="_bx_courses_page_title_entry_fans"><![CDATA[Students]]></string>
+    <string name="_bx_courses_page_title_sys_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_courses_page_title_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_courses_page_block_title_entry_reports"><![CDATA[Reports]]></string>
+    <string name="_bx_courses_page_title_sys_profile_info"><![CDATA[Course Info]]></string>
+    <string name="_bx_courses_page_title_profile_info"><![CDATA[Info about {display_name}]]></string>
+    <string name="_bx_courses_page_title_sys_profile_pricing"><![CDATA[Pricing]]></string>
+    <string name="_bx_courses_page_title_profile_pricing"><![CDATA[Pricing]]></string>
+    <string name="_bx_courses_page_title_sys_recent"><![CDATA[New Courses]]></string>
+    <string name="_bx_courses_page_title_recent"><![CDATA[New Courses]]></string>
+    <string name="_bx_courses_page_title_sys_manage"><![CDATA[Manage Own Courses]]></string>
+    <string name="_bx_courses_page_title_sys_manage_administration"><![CDATA[Manage All Courses]]></string>
+    <string name="_bx_courses_page_title_manage"><![CDATA[Manage Courses]]></string>
+    <string name="_bx_courses_page_title_sys_top"><![CDATA[Top Courses]]></string>
+    <string name="_bx_courses_page_title_top"><![CDATA[Top Courses]]></string>
+    <string name="_bx_courses_page_title_sys_joined"><![CDATA[Attended  Courses]]></string>
+    <string name="_bx_courses_page_title_joined"><![CDATA[Attended Courses]]></string>
+    <string name="_bx_courses_page_title_sys_invite_to_course"><![CDATA[Invite Students to the Course]]></string>
+    <string name="_bx_courses_page_title_invite_to_course"><![CDATA[Invite Students to the Course]]></string>
+    <string name="_bx_courses_page_title_sys_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_courses_page_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_courses_page_title_sys_entries_favorites"><![CDATA[Favorites Courses]]></string>
+    <string name="_bx_courses_page_title_entries_favorites"><![CDATA[Favorites Courses]]></string>
+
+    <string name="_bx_courses_page_block_title_sys_entries_actions"><![CDATA[Courses actions]]></string>
+    <string name="_bx_courses_page_block_title_entries_actions"><![CDATA[Courses actions]]></string>
+    <string name="_bx_courses_page_block_title_sys_favorites_entries"><![CDATA[Favorite List]]></string>
+    <string name="_bx_courses_page_block_title_favorites_entries"><![CDATA["{title}" List]]></string>
+    <string name="_bx_courses_page_block_title_favorites_entries_info"><![CDATA[Info]]></string>
+    <string name="_bx_courses_page_block_title_favorites_entries_actions"><![CDATA[Favorites List Actions]]></string>
+    <string name="_bx_courses_page_block_title_sys_entries_of_author"><![CDATA[Courses of author]]></string>
+    <string name="_bx_courses_page_block_title_entries_of_author"><![CDATA[Courses by {display_name}]]></string>
+    <string name="_bx_courses_page_block_title_favorites_of_author"><![CDATA[Favorite Courses]]></string>
+    <string name="_bx_courses_page_block_title_sys_favorites_of_author"><![CDATA[Favorite Courses]]></string>
+    <string name="_bx_courses_page_block_title_sys_joined_entries"><![CDATA[Attended Courses]]></string>
+    <string name="_bx_courses_page_block_title_joined_entries"><![CDATA[Attended Courses]]></string>
+    <string name="_bx_courses_page_block_title_create_profile"><![CDATA[Create Course]]></string>
+    <string name="_bx_courses_page_block_title_edit_profile"><![CDATA[Edit Course]]></string>
+    <string name="_bx_courses_page_block_title_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_courses_page_block_title_delete_profile"><![CDATA[Delete Course]]></string>
+    <string name="_bx_courses_page_block_title_join_profile"><![CDATA[Join Course]]></string>
+    <string name="_bx_courses_page_block_title_profile_info_link"><![CDATA[About <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_courses_page_block_title_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_courses_page_block_title_system_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_courses_page_block_title_system_profile_pricing"><![CDATA[Pricing]]></string>
+    <string name="_bx_courses_page_block_title_profile_pricing"><![CDATA[Pricing]]></string>
+    <string name="_bx_courses_page_block_title_profile_pricing_link"><![CDATA[Pricing of <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_courses_page_block_title_profile_description"><![CDATA[Description]]></string>
+    <string name="_bx_courses_page_block_title_profile_friends_link"><![CDATA[Friends of <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_courses_page_block_title_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_courses_page_block_title_system_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_courses_page_block_title_admins"><![CDATA[Instructors]]></string>
+    <string name="_bx_courses_page_block_title_fans_link"><![CDATA[Students of <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_courses_page_block_title_fans"><![CDATA[Students]]></string>
+    <string name="_bx_courses_page_block_title_system_fans"><![CDATA[Students]]></string>
+    <string name="_bx_courses_page_block_title_fans_invites"><![CDATA[Invites]]></string>
+    <string name="_bx_courses_page_block_title_system_invites"><![CDATA[Invites]]></string>
+    <string name="_bx_courses_page_block_title_profile_location"><![CDATA[Location]]></string>
+    <string name="_bx_courses_page_block_title_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_courses_page_block_title_profile_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_courses_page_block_title_profile_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_courses_page_block_title_featured_profiles"><![CDATA[Featured Courses]]></string>
+    <string name="_bx_courses_page_block_title_latest_profiles"><![CDATA[New Courses]]></string>
+    <string name="_bx_courses_page_block_title_system_manage"><![CDATA[Manage Own Courses]]></string>
+    <string name="_bx_courses_page_block_title_system_manage_administration"><![CDATA[Manage All Courses]]></string>
+    <string name="_bx_courses_page_block_title_manage"><![CDATA[Manage Courses]]></string>
+    <string name="_bx_courses_page_block_title_top_profiles"><![CDATA[Top Courses]]></string>
+    <string name="_bx_courses_page_block_title_joined_profiles"><![CDATA[Attended Courses]]></string>
+    <string name="_bx_courses_page_block_title_entry_all_actions"><![CDATA[All Actions]]></string>
+    <string name="_bx_courses_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+    <string name="_bx_courses_page_block_title_categories"><![CDATA[Courses Categories]]></string>
+    <string name="_bx_courses_page_block_title_invite_to_course"><![CDATA[Invite Students to the Course]]></string>
+    <string name="_bx_courses_page_block_title_search_form"><![CDATA[Search Form]]></string>
+    <string name="_bx_courses_page_block_title_search_results"><![CDATA[Search Results]]></string>
+    <string name="_bx_courses_page_block_title_search_form_cmts"><![CDATA[Comments Search Form]]></string>
+    <string name="_bx_courses_page_block_title_search_results_cmts"><![CDATA[Comments Search Results]]></string>
+    <string name="_bx_courses_page_block_title_sys_featured_entries_view_showcase"><![CDATA[Featured Courses (Showcase View)]]></string>
+    <string name="_bx_courses_page_block_title_featured_entries_view_showcase"><![CDATA[Featured Courses]]></string>
+    <string name="_bx_courses_page_block_title_sys_recommended_entries_view_showcase"><![CDATA[Recommended Courses (Showcase View)]]></string>
+    <string name="_bx_courses_page_block_title_recommended_entries_view_showcase"><![CDATA[Recommended Courses]]></string>
+    <string name="_bx_courses_page_block_title_sys_labels_tree"><![CDATA[Labels tree]]></string>
+    <string name="_bx_courses_page_block_title_labels_tree"><![CDATA[Labels tree]]></string>
+    <string name="_bx_courses_page_block_title_sys_browse_by_label"><![CDATA[Browse by label]]></string>
+    <string name="_bx_courses_page_block_title_browse_by_label"><![CDATA[Browse by label]]></string>
+    <string name="_bx_courses_page_block_title_sys_labels_breadcrumbs"><![CDATA[Labels breadcrumbs]]></string>
+    <string name="_bx_courses_page_block_title_labels_breadcrumbs"><![CDATA[Labels breadcrumbs]]></string>
+    <string name="_bx_courses_page_block_title_sys_cover_block"><![CDATA[Cover]]></string>
+    <string name="_bx_courses_page_block_title_cover_block"><![CDATA[Cover]]></string>
+
+
+    <string name="_bx_courses_menu_title_submenu"><![CDATA[Courses Submenu]]></string>
+    <string name="_bx_courses_menu_set_title_submenu"><![CDATA[Courses Submenu]]></string>
+    <string name="_bx_courses_menu_set_title_view_profile_actions"><![CDATA[Course Actions]]></string>
+    <string name="_bx_courses_menu_title_view_profile_actions"><![CDATA[Course Actions]]></string>
+    <string name="_bx_courses_menu_set_title_view_profile_actions_more"><![CDATA[Course More Actions]]></string>
+    <string name="_bx_courses_menu_title_view_profile_actions_more"><![CDATA[Course More Actions]]></string>
+    <string name="_bx_courses_menu_title_view_profile_meta"><![CDATA[Course Meta]]></string>
+    <string name="_bx_courses_menu_set_title_view_profile_meta"><![CDATA[Course Meta]]></string>
+    <string name="_bx_courses_menu_set_title_view_profile_submenu"><![CDATA[View Course Submenu]]></string>
+    <string name="_bx_courses_menu_title_view_profile_submenu"><![CDATA[View Course Submenu]]></string>
+    <string name="_bx_courses_menu_title_entries_my"><![CDATA[Profile Courses Action Menu]]></string>
+    <string name="_bx_courses_menu_set_title_entries_my"><![CDATA[Profile Courses Menu]]></string>
+    <string name="_bx_courses_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_courses_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_courses_menu_item_title_system_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_courses_menu_item_title_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_courses_menu_item_title_system_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_courses_menu_item_title_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_courses_menu_item_title_system_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_courses_menu_item_title_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_courses_menu_item_title_system_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_courses_menu_item_title_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_courses_menu_item_title_system_edit_pricing"><![CDATA[Edit Pricing]]></string>
+    <string name="_bx_courses_menu_item_title_edit_pricing"><![CDATA[Edit Pricing]]></string>
+    <string name="_bx_courses_menu_item_title_system_edit_profile"><![CDATA[Edit Course]]></string>
+    <string name="_bx_courses_menu_item_title_edit_profile"><![CDATA[Edit Course]]></string>
+    <string name="_bx_courses_menu_item_title_system_delete_profile"><![CDATA[Delete Course]]></string>
+    <string name="_bx_courses_menu_item_title_delete_profile"><![CDATA[Delete Course]]></string>
+    <string name="_bx_courses_menu_item_title_system_delete_account"><![CDATA[Delete Account]]></string>
+    <string name="_bx_courses_menu_item_title_delete_account"><![CDATA[Delete Account]]></string>
+    <string name="_bx_courses_menu_item_title_system_profile_type"><![CDATA[Course]]></string>
+    <string name="_bx_courses_menu_item_title_profile_type"><![CDATA[Course]]></string>
+    <string name="_bx_courses_menu_item_title_system_create_profile"><![CDATA[Course]]></string>
+    <string name="_bx_courses_menu_item_title_create_profile"><![CDATA[Course]]></string>
+    <string name="_bx_courses_menu_item_title_system_view_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_courses_menu_item_title_view_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_courses_menu_item_title_system_view_joined_entries"><![CDATA[Courses]]></string>
+    <string name="_bx_courses_menu_item_title_view_joined_entries"><![CDATA[Courses]]></string>
+    <string name="_bx_courses_menu_item_title_system_view_fans"><![CDATA[Students]]></string>
+    <string name="_bx_courses_menu_item_title_view_fans"><![CDATA[Students]]></string>
+    <string name="_bx_courses_menu_item_title_system_view_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_courses_menu_item_title_view_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_courses_menu_item_title_system_view_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_courses_menu_item_title_view_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_courses_menu_item_title_system_view_profile_view"><![CDATA[Course]]></string>
+    <string name="_bx_courses_menu_item_title_view_profile_view"><![CDATA[Course]]></string>
+    <string name="_bx_courses_menu_item_title_system_view_profile_more_auto"><![CDATA[More]]></string>
+    <string name="_bx_courses_menu_item_title_view_profile_more_auto"><![CDATA[More]]></string>
+    <string name="_bx_courses_menu_item_title_system_invite"><![CDATA[Invite]]></string>
+    <string name="_bx_courses_menu_item_title_invite"><![CDATA[Invite]]></string>
+
+    <string name="_bx_courses_menu_item_title_system_befriend"><![CDATA[Add friend]]></string>
+    <string name="_bx_courses_menu_item_title_befriend"><![CDATA[Add friend]]></string>
+    <string name="_bx_courses_menu_item_title_befriend_sent"><![CDATA[Add friend (requested)]]></string>
+    <string name="_bx_courses_menu_item_title_befriend_confirm"><![CDATA[Accept friend request]]></string>
+    <string name="_bx_courses_menu_item_title_system_unfriend"><![CDATA[Unfriend]]></string>
+    <string name="_bx_courses_menu_item_title_unfriend"><![CDATA[Unfriend]]></string>
+    <string name="_bx_courses_menu_item_title_unfriend_cancel_request"><![CDATA[Cancel friend request]]></string>
+    <string name="_bx_courses_menu_item_title_unfriend_reject_request"><![CDATA[Reject friend request]]></string>
+
+    <string name="_bx_courses_menu_item_title_system_become_fan"><![CDATA[Attend Course]]></string>
+    <string name="_bx_courses_menu_item_title_become_fan"><![CDATA[Attend Course]]></string>
+    <string name="_bx_courses_menu_item_title_become_fan_sent"><![CDATA[Attend Course (requested)]]></string>
+    <string name="_bx_courses_menu_item_title_become_fan_confirm"><![CDATA[Accept Request]]></string>
+    <string name="_bx_courses_menu_item_title_system_leave_entry"><![CDATA[Leave Course]]></string>
+    <string name="_bx_courses_menu_item_title_leave_entry"><![CDATA[Leave Course]]></string>
+    <string name="_bx_courses_menu_item_title_leave_entry_cancel_request"><![CDATA[Cancel Request]]></string>
+    <string name="_bx_courses_menu_item_title_leave_entry_reject_request"><![CDATA[Reject Request]]></string>
+
+    <string name="_bx_courses_menu_item_title_system_pay_and_join"><![CDATA[Pay & Join]]></string>
+    <string name="_bx_courses_menu_item_title_pay_and_join"><![CDATA[Pay & Join]]></string>
+
+    <string name="_bx_courses_menu_item_title_system_subscribe"><![CDATA[Follow]]></string>
+    <string name="_bx_courses_menu_item_title_subscribe"><![CDATA[Follow]]></string>
+    <string name="_bx_courses_menu_item_title_system_unsubscribe"><![CDATA[Unfollow]]></string>
+    <string name="_bx_courses_menu_item_title_unsubscribe"><![CDATA[Unfollow]]></string>
+    <string name="_bx_courses_menu_item_title_system_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_courses_menu_item_title_more_actions"><![CDATA[]]></string>
+    <string name="_bx_courses_menu_item_title_system_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_courses_menu_item_title_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_courses_menu_item_title_system_manage_my_entries"><![CDATA[My courses]]></string>
+    <string name="_bx_courses_menu_item_title_manage_my_entries"><![CDATA[Courses]]></string>
+    <string name="_bx_courses_menu_item_title_system_followings"><![CDATA[Courses]]></string>
+    <string name="_bx_courses_menu_item_title_followings"><![CDATA[Courses]]></string>
+    <string name="_bx_courses_menu_item_title_system_entries_recent"><![CDATA[New]]></string>
+    <string name="_bx_courses_menu_item_title_entries_recent"><![CDATA[New]]></string>
+    <string name="_bx_courses_menu_item_title_system_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_courses_menu_item_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_courses_menu_item_title_system_entries_joined"><![CDATA[Attended]]></string>
+    <string name="_bx_courses_menu_item_title_entries_joined"><![CDATA[Attended]]></string>
+    <string name="_bx_courses_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_courses_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_courses_menu_item_title_system_entries_home"><![CDATA[Courses]]></string>
+    <string name="_bx_courses_menu_item_title_entries_home"><![CDATA[Courses]]></string>
+    <string name="_bx_courses_menu_item_title_system_admt_entries"><![CDATA[Courses]]></string>
+    <string name="_bx_courses_menu_item_title_admt_entries"><![CDATA[Courses]]></string>
+    <string name="_bx_courses_menu_item_title_manage_my"><![CDATA[My Courses]]></string>
+    <string name="_bx_courses_menu_item_title_manage_all"><![CDATA[All Courses]]></string>
+    <string name="_bx_courses_menu_item_title_system_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_courses_menu_item_title_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_courses_menu_item_title_system_sm_privacy"><![CDATA[Privacy]]></string>
+    <string name="_bx_courses_menu_item_title_sm_privacy"><![CDATA[Privacy]]></string>
+    <string name="_bx_courses_menu_item_title_system_sm_members"><![CDATA[Students]]></string>
+    <string name="_bx_courses_menu_item_title_sm_members"><![CDATA[{0} students]]></string>
+    <string name="_bx_courses_menu_item_title_system_sm_join"><![CDATA[Attend]]></string>
+    <string name="_bx_courses_menu_item_title_sm_join"><![CDATA[Attend]]></string>
+    <string name="_bx_courses_menu_item_title_sm_join_confirm"><![CDATA[Accept attend request]]></string>
+    <string name="_bx_courses_menu_item_title_sm_leave"><![CDATA[Leave]]></string>
+    <string name="_bx_courses_menu_item_title_sm_leave_reject"><![CDATA[Reject attend request]]></string>
+    <string name="_bx_courses_menu_item_title_sm_leave_cancel"><![CDATA[Cancel attend request]]></string>
+
+    <string name="_bx_courses_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+    <string name="_bx_courses_grid_filter_item_title_adm_select_one_filter2"><![CDATA[Any Audience]]></string>
+    <string name="_bx_courses_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_courses_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+    <string name="_bx_courses_grid_filter_item_title_adm_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_courses_grid_filter_item_title_adm_suspended"><![CDATA[Suspended]]></string>
+    <string name="_bx_courses_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_courses_grid_column_title_adm_name"><![CDATA[Name]]></string>
+    <string name="_bx_courses_grid_column_title_adm_added"><![CDATA[Created]]></string>
+    <string name="_bx_courses_grid_column_title_adm_account"><![CDATA[Account]]></string>
+    <string name="_bx_courses_grid_action_title_adm_audit_context"><![CDATA[Audit actions in context]]></string>
+    <string name="_bx_courses_grid_action_title_adm_audit_content"><![CDATA[Audit actions with context]]></string>
+    <string name="_bx_courses_grid_action_title_adm_clear_reports"><![CDATA[Сlear reports]]></string>
+    <string name="_bx_courses_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_courses_grid_action_title_adm_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_courses_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_courses_grid_action_err_delete"><![CDATA[Cannot delete the selected course(s).]]></string>
+    <string name="_bx_courses_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_courses_grid_column_title_name"><![CDATA[Name]]></string>
+    <string name="_bx_courses_grid_column_title_role_id"><![CDATA[Role]]></string>
+    <string name="_bx_courses_grid_column_title_period"><![CDATA[Period]]></string>
+    <string name="_bx_courses_grid_column_title_price"><![CDATA[Price]]></string>
+    <string name="_bx_courses_grid_action_title_add"><![CDATA[Add]]></string>
+    <string name="_bx_courses_grid_action_title_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_courses_grid_action_title_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_courses_grid_action_title_buy"><![CDATA[Buy]]></string>
+    <string name="_bx_courses_grid_action_title_buy_title"><![CDATA[One-time payment]]></string>
+    <string name="_bx_courses_grid_action_title_subscribe"><![CDATA[Subscribe]]></string>
+    <string name="_bx_courses_grid_action_title_subscribe_title"><![CDATA[Create a subscription with recurring billing]]></string>
+    <string name="_bx_courses_grid_action_title_choose"><![CDATA[Choose]]></string>
+    <string name="_bx_courses_grid_action_title_choose_title"><![CDATA[Switch to the level for free]]></string>
+    <string name="_bx_courses_popup_title_price_add"><![CDATA[Add Pricing Plan]]></string>
+    <string name="_bx_courses_popup_title_price_edit"><![CDATA[Edit Pricing Plan]]></string>
+
+    <string name="_bx_courses_chart_growth"><![CDATA[Courses: Growth]]></string>
+    <string name="_bx_courses_chart_growth_speed"><![CDATA[Courses: Growth Speed]]></string>
+
+    <string name="_bx_courses_search_extended"><![CDATA[Courses Search]]></string>
+    <string name="_bx_courses_search_extended_cmts"><![CDATA[Courses Comments Search]]></string>
+
+    <string name="_bx_courses_txt_account_pending"><![CDATA[This course is pending approval, please wait until it is activated.]]></string>
+    <string name="_bx_courses_txt_account_suspended"><![CDATA[This course is suspended.]]></string>
+    <string name="_bx_courses_txt_status_hidden"><![CDATA[This course was hidden.]]></string>
+    <string name="_bx_courses_txt_N_fans"><![CDATA[{0} students]]></string>
+    <string name="_bx_courses_txt_role"><![CDATA[Role]]></string>
+    <string name="_bx_courses_txt_role_added"><![CDATA[Added]]></string>
+    <string name="_bx_courses_txt_role_expired"><![CDATA[Expires]]></string>
+    <string name="_bx_courses_txt_sample_single"><![CDATA[course]]></string>
+    <string name="_bx_courses_txt_sample_single_with_article"><![CDATA[a course]]></string>
+    <string name="_bx_courses_txt_sample_comment_single"><![CDATA[comment to course]]></string>
+    <string name="_bx_courses_txt_sample_vote_single"><![CDATA[vote to course]]></string>
+    <string name="_bx_courses_txt_sample_score_up_single"><![CDATA[score up vote to course]]></string>
+    <string name="_bx_courses_txt_sample_score_down_single"><![CDATA[score down vote to course]]></string>
+    <string name="_bx_courses_txt_set_role"><![CDATA[Set Role]]></string>
+    <string name="_bx_courses_txt_private_entry"><![CDATA[Private course]]></string>
+    <string name="_bx_courses_txt_invite_popup_text"><![CDATA[You have been invited to a course. Click the button below to accept the invitation.]]></string>
+    <string name="_bx_courses_txt_invite_popup_title"><![CDATA[Invitation to a course]]></string>
+    <string name="_bx_courses_txt_invite_popup_button_accept"><![CDATA[Accept]]></string>
+    <string name="_bx_courses_txt_invite_popup_button_decline"><![CDATA[Decline]]></string>
+    <string name="_bx_courses_txt_invite_popup_error_invitation_absent"><![CDATA[Sorry, an error has occurred. You can not join this course. The invitation is expired or deleted.]]></string>
+    <string name="_bx_courses_txt_invite_popup_error_invitation_wrong_user"><![CDATA[Sorry, an error has occurred. You can not join this course. This invitation cannot be used by you.]]></string>
+    <string name="_bx_courses_txt_n_unit"><![CDATA[{0} ({1})]]></string>
+    <string name="_bx_courses_txt_cart_item_title"><![CDATA[{0}: {1} ({2} {3})]]></string>
+    <string name="_bx_courses_txt_cart_item_title_lifetime"><![CDATA[{0}: {1} (lifetime)]]></string>    
+
+    <string name="_bx_courses_msg_performed"><![CDATA[The action was successfully performed.]]></string>
+    <string name="_bx_courses_err_price_duplicate"><![CDATA[Similar pricing plan is already exists.]]></string>
+    <string name="_bx_courses_err_cannot_perform"><![CDATA[An error appeared. Please report.]]></string>
+
+    <string name="_bx_courses_alert_action_fan_added"><![CDATA[member joined]]></string>
+    <string name="_bx_courses_txt_ntfs_fan_added"><![CDATA[Course <b class="bx-ntfs-content-profile">{owner_name}</b> has got a member <b class="bx-ntfs-content-entry">{subentry_sample}</b>]]></string>
+    <string name="_bx_courses_alert_action_join_invitation_notif"><![CDATA[join invitation]]></string>
+    <string name="_bx_courses_alert_action_join_request"><![CDATA[join request]]></string>
+    <string name="_bx_courses_txt_ntfs_join_invitation"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> course's representative invites <b class="bx-ntfs-content-entry">{subentry_sample}</b> to join course]]></string>
+    <string name="_bx_courses_txt_ntfs_join_request"><![CDATA[Course <b class="bx-ntfs-content-profile">{owner_name}</b> has a join request from <b class="bx-ntfs-content-entry">{subentry_sample}</b>]]></string>
+    <string name="_bx_courses_txt_ntfs_timeline_post_common"><![CDATA[New post <b class="bx-ntfs-content-entry">{subentry_sample}</b> in <b class="bx-ntfs-content-profile">{owner_name}</b> course timeline]]></string>
+
+    <string name="_bx_courses_pre_lists_cats"><![CDATA[Course categories]]></string>
+    <string name="_bx_courses_cat_General"><![CDATA[General]]></string>
+
+    <string name="_bx_courses_pre_lists_roles"><![CDATA[Course roles]]></string>
+    <string name="_bx_courses_role_regular"><![CDATA[Student]]></string>
+    <string name="_bx_courses_role_administrator"><![CDATA[Instructor]]></string>
+    <string name="_bx_courses_role_moderator"><![CDATA[Assistant]]></string>
+
+    <string name="_bx_courses_pre_lists_period_units"><![CDATA[Billing Interval]]></string>
+    <string name="_bx_courses_period_unit_day"><![CDATA[day]]></string>
+    <string name="_bx_courses_period_unit_week"><![CDATA[week]]></string>
+    <string name="_bx_courses_period_unit_month"><![CDATA[month]]></string>
+    <string name="_bx_courses_period_unit_year"><![CDATA[year]]></string>
+
+    <string name="_bx_courses_email_join_request"><![CDATA[Course join request]]></string>
+    <string name="_bx_courses_email_join_request_subject"><![CDATA[Request to join your course]]></string>
+    <string name="_bx_courses_email_join_request_body"><![CDATA[{email_header}
+<p>New request to join <a href="{EntryUrl}">{EntryTitle}</a> course from <a href="{NewMemberUrl}">{NewMemberDisplayName}</a></p>
+{email_footer}]]></string>
+
+    <string name="_bx_courses_email_join_reject"><![CDATA[Course join request was rejected]]></string>
+    <string name="_bx_courses_email_join_reject_subject"><![CDATA[Request to join a course was rejected]]></string>
+    <string name="_bx_courses_email_join_reject_body"><![CDATA[{email_header}
+<p>Your request to join <a href="{EntryUrl}">{EntryTitle}</a> course was rejected by course admin.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_courses_email_join_confirm"><![CDATA[Course join request was confirmed]]></string>
+    <string name="_bx_courses_email_join_confirm_subject"><![CDATA[Your request to join a course was confirmed]]></string>
+    <string name="_bx_courses_email_join_confirm_body"><![CDATA[{email_header}
+<p>Your request to join <a href="{EntryUrl}">{EntryTitle}</a> course was confirmed by the course admin.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_courses_email_fan_remove"><![CDATA[Profile was removed from course fans]]></string>
+    <string name="_bx_courses_email_fan_remove_subject"><![CDATA[Your profile was removed from the course]]></string>
+    <string name="_bx_courses_email_fan_remove_body"><![CDATA[{email_header}
+<p>Your profile was removed from <a href="{EntryUrl}">{EntryTitle}</a> course by the course admin.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_courses_email_fan_become_admin"><![CDATA[Course instructor status was granted]]></string>
+    <string name="_bx_courses_email_fan_become_admin_subject"><![CDATA[You are a course instructor now]]></string>
+    <string name="_bx_courses_email_fan_become_admin_body"><![CDATA[{email_header}
+<p>You are an instructor of <a href="{EntryUrl}">{EntryTitle}</a> course now.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_courses_email_admin_become_fan"><![CDATA[Course instructor status was revoked]]></string>
+    <string name="_bx_courses_email_admin_become_fan_subject"><![CDATA[Your course instructor status was revoked]]></string>
+    <string name="_bx_courses_email_admin_become_fan_body"><![CDATA[{email_header}
+<p>Your instructor status was revoked from <a href="{EntryUrl}">{EntryTitle}</a> course.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_courses_email_invitation"><![CDATA[Invitation to course]]></string>
+    <string name="_bx_courses_email_invitation_subject"><![CDATA[Invitation to "{EntryTitle}" course]]></string>
+    <string name="_bx_courses_email_invitation_body"><![CDATA[{email_header}
+<p><a href="{InviterUrl}">{InviterDisplayName}</a> invited you to <a href="{EntryUrl}">{EntryTitle} course</a>.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_courses_email_set_role"><![CDATA[Course member status was changed]]></string>
+    <string name="_bx_courses_email_set_role_subject"><![CDATA[Your course status was changed]]></string>
+    <string name="_bx_courses_email_set_role_body"><![CDATA[{email_header}
+<p>Your status in <a href="{EntryUrl}">{EntryTitle}</a> course was changed to <b>{Role}</b>.</p>
+{email_footer}]]></string>
+</resources>

+ 681 - 0
modules/boonex/courses/updates/13.0.2_13.0.3/source/install/sql/enable.sql

@@ -0,0 +1,681 @@
+
+-- SETTINGS
+
+SET @iTypeOrder = (SELECT MAX(`order`) FROM `sys_options_types` WHERE `group` = 'modules');
+INSERT INTO `sys_options_types`(`group`, `name`, `caption`, `icon`, `order`) VALUES 
+('modules', 'bx_courses', '_bx_courses', 'bx_courses@modules/boonex/courses/|std-icon.svg', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_courses', '_bx_courses', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+('bx_courses_enable_auto_approve', 'on', @iCategId, '_bx_courses_option_enable_auto_approve', 'checkbox', '', '', '', 0),
+('bx_courses_num_connections_quick', '6', @iCategId, '_bx_courses_option_num_connections_quick', 'digit', '', '', '', 10),
+('bx_courses_per_page_browse', '24', @iCategId, '_bx_courses_option_per_page_browse', 'digit', '', '', '', 11),
+('bx_courses_num_rss', '10', @iCategId, '_bx_courses_option_num_rss', 'digit', '', '', '', 12),
+('bx_courses_per_page_browse_showcase', '32', @iCategId, '_sys_option_per_page_browse_showcase', 'digit', '', '', '', 15),
+('bx_courses_per_page_browse_recommended', '10', @iCategId, '_sys_option_per_page_browse_recommended', 'digit', '', '', '', 16),
+('bx_courses_per_page_for_favorites_lists', '5', @iCategId, '_bx_courses_option_per_page_for_favorites_lists', 'digit', '', '', '', 17),
+('bx_courses_searchable_fields', 'name,desc', @iCategId, '_bx_courses_option_searchable_fields', 'list', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:21:"get_searchable_fields";}', '', '', 30),
+('bx_courses_members_mode', '', @iCategId, '_bx_courses_option_members_mode', 'select', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:24:"get_options_members_mode";}', '', '', 40), 
+('bx_courses_internal_notifications', '', @iCategId, '_bx_courses_option_internal_notifications', 'checkbox', '', '', '', 50);
+
+-- PAGES
+
+-- PAGE: create profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_create_profile', 'create-course-profile', '_bx_courses_page_title_sys_create_profile', '_bx_courses_page_title_create_profile', 'bx_courses', 5, 2147483647, 1, 'page.php?i=create-course-profile', '', '', '', 0, 1, 0, '', '');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_courses_create_profile', 1, 'bx_courses', '_bx_courses_page_block_title_create_profile', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:13:"entity_create";}', 0, 1, 1);
+
+-- PAGE: view profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_view_profile', 'view-course-profile', '_bx_courses_page_title_sys_view_profile', '_bx_courses_page_title_view_profile', 'bx_courses', 12, 2147483647, 1, 'page.php?i=view-course-profile', '', '', '', 0, 1, 0, 'BxCoursesPageEntry', 'modules/boonex/courses/classes/BxCoursesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('bx_courses_view_profile', 1, 'bx_courses', '', '_bx_courses_page_block_title_entry_social_sharing', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:21:"entity_social_sharing";}', 0, 0, 0, 0),
+('bx_courses_view_profile', 1, 'bx_courses', '', '_bx_courses_page_block_title_entry_all_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:18:"entity_all_actions";}', 0, 0, 0, 0),
+('bx_courses_view_profile', 2, 'bx_courses', '', '_bx_courses_page_block_title_profile_description', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:17:"entity_text_block";}', 0, 0, 1, 0),
+('bx_courses_view_profile', 3, 'bx_courses', '', '_bx_courses_page_block_title_profile_location', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:15:"entity_location";}', 0, 0, 0, 0),
+('bx_courses_view_profile', 3, 'bx_courses', '', '_bx_courses_page_block_title_profile_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:11:"entity_info";}', 0, 0, 1, 0),
+('bx_courses_view_profile', 3, 'bx_courses', '', '_bx_courses_page_block_title_admins', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:6:"admins";}', 0, 0, 1, 1),
+('bx_courses_view_profile', 3, 'bx_courses', '', '_bx_courses_page_block_title_fans', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:19:"fans_without_admins";}', 0, 0, 1, 2),
+('bx_courses_view_profile', 3, 'bx_courses', '', '_bx_courses_page_block_title_profile_location', 3, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:13:"locations_map";s:6:"params";a:2:{i:0;s:10:"bx_courses";i:1;s:12:"{content_id}";}s:5:"class";s:20:"TemplServiceMetatags";}', 0, 0, 1, 3),
+('bx_courses_view_profile', 4, 'bx_courses', '', '_bx_courses_page_block_title_profile_comments', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:15:"entity_comments";}', 0, 0, 0, 0),
+('bx_courses_view_profile', 2, 'bx_courses', '', '_bx_courses_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_courses\";s:6:\"method\";s:14:\"entity_reports\";}', 0, 0, 1, 6);
+
+
+-- PAGE: view closed profile 
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_view_profile_closed', 'view-course-profile-closed', '_bx_courses_page_title_sys_view_profile_closed', '_bx_courses_page_title_view_profile', 'bx_courses', 10, 2147483647, 1, 'page.php?i=view-course-profile', '', '', '', 0, 1, 0, 'BxCoursesPageEntry', 'modules/boonex/courses/classes/BxCoursesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_courses_view_profile_closed', 2, 'bx_courses', '', '_bx_courses_page_block_title_profile_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:11:"entity_info";}', 0, 0, 1, 0),
+('bx_courses_view_profile_closed', 3, 'bx_courses', '', '_bx_courses_page_block_title_fans', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:4:"fans";}', 0, 0, 1, 0);
+
+-- PAGE: edit profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_edit_profile', 'edit-course-profile', '_bx_courses_page_title_sys_edit_profile', '_bx_courses_page_title_edit_profile', 'bx_courses', 5, 2147483647, 1, 'page.php?i=edit-course-profile', '', '', '', 0, 1, 0, 'BxCoursesPageEntry', 'modules/boonex/courses/classes/BxCoursesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_courses_edit_profile', 1, 'bx_courses', '_bx_courses_page_block_title_edit_profile', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:11:"entity_edit";}', 0, 0, 0);
+
+-- PAGE: edit profile cover
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_edit_profile_cover', 'edit-course-cover', '_bx_courses_page_title_sys_edit_profile_cover', '_bx_courses_page_title_edit_profile_cover', 'bx_courses', 5, 2147483647, 1, 'page.php?i=edit-course-cover', '', '', '', 0, 1, 0, 'BxCoursesPageEntry', 'modules/boonex/courses/classes/BxCoursesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_courses_edit_profile_cover', 1, 'bx_courses', '_bx_courses_page_block_title_edit_profile_cover', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:17:"entity_edit_cover";}', 0, 0, 0);
+
+-- PAGE: invite members
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_invite', 'invite-to-course', '_bx_courses_page_title_sys_invite_to_course', '_bx_courses_page_title_invite_to_course', 'bx_courses', 5, 2147483647, 1, 'page.php?i=invite-to-course', '', '', '', 0, 1, 0, 'BxCoursesPageEntry', 'modules/boonex/courses/classes/BxCoursesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_courses_invite', 1, 'bx_courses', '_bx_courses_page_block_title_invite_to_course', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:13:"entity_invite";}', 0, 0, 0);
+
+-- PAGE: delete profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_delete_profile', 'delete-course-profile', '_bx_courses_page_title_sys_delete_profile', '_bx_courses_page_title_delete_profile', 'bx_courses', 5, 2147483647, 1, 'page.php?i=delete-course-profile', '', '', '', 0, 1, 0, 'BxCoursesPageEntry', 'modules/boonex/courses/classes/BxCoursesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_courses_delete_profile', 1, 'bx_courses', '_bx_courses_page_block_title_delete_profile', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:13:"entity_delete";}', 0, 0, 0);
+
+-- PAGE: join profile
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_join_profile', 'join-course-profile', '_bx_courses_page_title_sys_join_profile', '_bx_courses_page_title_join_profile', 'bx_courses', 5, 2147483647, 1, 'page.php?i=join-course-profile', '', '', '', 0, 1, 0, 'BxCoursesPageEntry', 'modules/boonex/courses/classes/BxCoursesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_courses_join_profile', 1, 'bx_courses', '_bx_courses_page_block_title_join_profile', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:11:"entity_join";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 0, 0, 0);
+
+-- PAGE: profile info
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_profile_info', 'course-profile-info', '_bx_courses_page_title_sys_profile_info', '_bx_courses_page_title_profile_info', 'bx_courses', 5, 2147483647, 1, 'page.php?i=course-profile-info', '', '', '', 0, 1, 0, 'BxCoursesPageEntry', 'modules/boonex/courses/classes/BxCoursesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_courses_profile_info', 1, 'bx_courses', '_bx_courses_page_block_title_system_profile_info', '_bx_courses_page_block_title_profile_info_link', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:16:"entity_info_full";}', 0, 0, 1, 1),
+('bx_courses_profile_info', 1, 'bx_courses', '', '_bx_courses_page_block_title_profile_description', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:17:"entity_text_block";}', 0, 0, 1, 2);
+
+-- PAGE: manage profile pricing
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_profile_pricing', 'edit-course-pricing', '_bx_courses_page_title_sys_profile_pricing', '_bx_courses_page_title_profile_pricing', 'bx_courses', 5, 2147483647, 1, 'page.php?i=edit-course-pricing', '', '', '', 0, 1, 0, 'BxCoursesPageEntry', 'modules/boonex/courses/classes/BxCoursesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_courses_profile_pricing', 1, 'bx_courses', '_bx_courses_page_block_title_system_profile_pricing', '_bx_courses_page_block_title_profile_pricing_link', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:14:"entity_pricing";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 0, 0, 1, 1);
+
+-- PAGE: course fans
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_fans', 'course-fans', '_bx_courses_page_title_sys_entry_fans', '_bx_courses_page_title_entry_fans', 'bx_courses', 5, 2147483647, 1, 'page.php?i=course-fans', '', '', '', 0, 1, 0, 'BxCoursesPageEntry', 'modules/boonex/courses/classes/BxCoursesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_courses_fans', 1, 'bx_courses', '_bx_courses_page_block_title_system_fans', '_bx_courses_page_block_title_fans_link', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:10:"fans_table";}', 0, 0, 1, 1),
+('bx_courses_fans', 1, 'bx_courses', '_bx_courses_page_block_title_system_invites', '_bx_courses_page_block_title_fans_invites', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:13:"invites_table";}', 0, 0, 1, 1);
+
+-- PAGE: view entry comments
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_profile_comments', '_bx_courses_page_title_sys_profile_comments', '_bx_courses_page_title_profile_comments', 'bx_courses', 5, 2147483647, 1, 'course-profile-comments', '', '', '', '', 0, 1, 0, 'BxCoursesPageEntry', 'modules/boonex/courses/classes/BxCoursesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_courses_profile_comments', 1, 'bx_courses', '_bx_courses_page_block_title_profile_comments', '_bx_courses_page_block_title_profile_comments_link', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:15:"entity_comments";}', 0, 0, 0, 1);
+
+-- PAGE: module home
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_home', '_bx_courses_page_title_sys_recent', '_bx_courses_page_title_recent', 'bx_courses', 5, 2147483647, 1, 'courses-home', 'page.php?i=courses-home', '', '', '', 0, 1, 0, 'BxCoursesPageBrowse', 'modules/boonex/courses/classes/BxCoursesPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_courses_home', 1, 'bx_courses', '_bx_courses_page_block_title_featured_profiles', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:7:"gallery";}}', 0, 1, 0),
+('bx_courses_home', 1, 'bx_courses', '_bx_courses_page_block_title_latest_profiles', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:22:"browse_recent_profiles";s:6:"params";a:1:{i:0;b:1;}}', 0, 1, 1);
+
+-- PAGE: top profiles
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_top', '_bx_courses_page_title_sys_top', '_bx_courses_page_title_top', 'bx_courses', 5, 2147483647, 1, 'courses-top', 'page.php?i=courses-top', '', '', '', 0, 1, 0, 'BxCoursesPageBrowse', 'modules/boonex/courses/classes/BxCoursesPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_courses_top', 1, 'bx_courses', '_bx_courses_page_block_title_top_profiles', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:19:"browse_top_profiles";s:6:"params";a:1:{i:0;b:1;}}', 0, 1, 0);
+
+-- PAGE: search for entries
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_search', '_bx_courses_page_title_sys_entries_search', '_bx_courses_page_title_entries_search', 'bx_courses', 5, 2147483647, 1, 'courses-search', 'page.php?i=courses-search', '', '', '', 0, 1, 0, 'BxCoursesPageBrowse', 'modules/boonex/courses/classes/BxCoursesPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_courses_search', 1, 'bx_courses', '_bx_courses_page_block_title_search_form', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:10:"bx_courses";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1),
+('bx_courses_search', 1, 'bx_courses', '_bx_courses_page_block_title_search_results', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:10:"bx_courses";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 2),
+('bx_courses_search', 1, 'bx_courses', '_bx_courses_page_block_title_search_form_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:15:"bx_courses_cmts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 3),
+('bx_courses_search', 1, 'bx_courses', '_bx_courses_page_block_title_search_results_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:15:"bx_courses_cmts";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 4);
+
+-- PAGE: joined profiles
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_joined_courses', '_bx_courses_page_title_sys_joined', '_bx_courses_page_title_joined', 'bx_courses', 5, 2147483647, 1, 'courses-joined', 'page.php?i=courses-joined', '', '', '', 0, 1, 0, 'BxCoursesPageBrowse', 'modules/boonex/courses/classes/BxCoursesPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_joined_courses', 1, 'bx_courses', '_bx_courses_page_block_title_joined_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:21:"browse_joined_entries";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;b:1;}}', 0, 1, 0);
+
+-- PAGE: module manage own
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_manage', '_bx_courses_page_title_sys_manage', '_bx_courses_page_title_manage', 'bx_courses', 5, 2147483647, 1, 'courses-manage', 'page.php?i=courses-manage', '', '', '', 0, 1, 0, 'BxCoursesPageBrowse', 'modules/boonex/courses/classes/BxCoursesPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_courses_manage', 1, 'bx_courses', '_bx_courses_page_block_title_system_manage', '_bx_courses_page_block_title_manage', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:12:"manage_tools";}}', 0, 1, 0);
+
+-- PAGE: module manage all
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_administration', '_bx_courses_page_title_sys_manage_administration', '_bx_courses_page_title_manage', 'bx_courses', 5, 192, 1, 'courses-administration', 'page.php?i=courses-administration', '', '', '', 0, 1, 0, 'BxCoursesPageBrowse', 'modules/boonex/courses/classes/BxCoursesPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_courses_administration', 1, 'bx_courses', '_bx_courses_page_block_title_system_manage_administration', '_bx_courses_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:12:"manage_tools";s:6:"params";a:1:{i:0;s:14:"administration";}}', 0, 1, 0);
+
+-- PAGE: user's courses
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_joined', 'joined-courses', '_bx_courses_page_title_sys_joined_entries', '_bx_courses_page_title_joined_entries', 'bx_courses', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxCoursesPageJoinedEntries', 'modules/boonex/courses/classes/BxCoursesPageJoinedEntries.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('bx_courses_joined', 1, 'bx_courses', '_bx_courses_page_block_title_sys_entries_actions', '_bx_courses_page_block_title_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:18:"my_entries_actions";}', 0, 0, 1, 1),
+('bx_courses_joined', 1, 'bx_courses', '_bx_courses_page_block_title_sys_entries_of_author', '_bx_courses_page_block_title_entries_of_author', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:22:"browse_created_entries";}', 0, 0, 0, 2),
+('bx_courses_joined', 1, 'bx_courses', '_bx_courses_page_block_title_sys_favorites_of_author', '_bx_courses_page_block_title_favorites_of_author', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:15:"browse_favorite";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 0, 1, 1, 3),
+('bx_courses_joined', 1, 'bx_courses', '_bx_courses_page_block_title_sys_joined_entries', '_bx_courses_page_block_title_joined_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:21:"browse_joined_entries";s:6:"params";a:2:{i:0;i:0;i:1;b:1;}}', 0, 0, 1, 4);
+
+-- PAGE: favorites by list
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_favorites', '_bx_courses_page_title_sys_entries_favorites', '_bx_courses_page_title_entries_favorites', 'bx_courses', 12, 2147483647, 1, 'courses-favorites', 'page.php?i=courses-favorites', '', '', '', 0, 1, 0, 'BxCoursesPageListEntry', 'modules/boonex/courses/classes/BxCoursesPageListEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_courses_favorites', 2, 'bx_courses', '_bx_courses_page_block_title_sys_favorites_entries', '_bx_courses_page_block_title_favorites_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:15:"browse_favorite";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1),
+('bx_courses_favorites', 3, 'bx_courses', '', '_bx_courses_page_block_title_favorites_entries_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:19:"favorites_list_info";}', 0, 0, 0),
+('bx_courses_favorites', 3, 'bx_courses', '', '_bx_courses_page_block_title_favorites_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:22:"favorites_list_actions";}', 0, 0, 1);
+
+-- PAGE: add block to homepage
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = 'sys_home' AND `cell_id` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('sys_home', 1, 'bx_courses', '', '_bx_courses_page_block_title_latest_profiles', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:22:"browse_recent_profiles";}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1),
+('sys_home', 1, 'bx_courses', '_bx_courses_page_block_title_sys_recommended_entries_view_showcase', '_bx_courses_page_block_title_recommended_entries_view_showcase', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:18:"browse_recommended";}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 2);
+
+-- PAGE: service blocks
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = '' AND `cell_id` = 0 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('', 0, 'bx_courses', '', '_bx_courses_page_block_title_categories', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:15:"categories_list";s:6:"params";a:2:{i:0;s:15:"bx_courses_cats";i:1;a:2:{s:10:"show_empty";b:1;s:21:"show_empty_categories";b:1;}}s:5:"class";s:20:"TemplServiceCategory";}', 1, 1, 1, IFNULL(@iBlockOrder, 0) + 1),
+('', 0, 'bx_courses', '_bx_courses_page_block_title_sys_featured_entries_view_showcase', '_bx_courses_page_block_title_featured_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:15:"browse_featured";s:6:"params";a:3:{s:9:"unit_view";s:8:"showcase";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 2),
+('', 0, 'bx_courses', '_bx_courses_page_block_title_sys_recommended_entries_view_showcase', '_bx_courses_page_block_title_recommended_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:18:"browse_recommended";s:6:"params";a:3:{s:9:"unit_view";s:8:"showcase";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 3),
+('', 0, 'bx_courses', '_bx_courses_page_block_title_sys_labels_tree', '_bx_courses_page_block_title_labels_tree', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:15:"get_lables_tree";}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 4),
+('', 0, 'bx_courses', '_bx_courses_page_block_title_sys_browse_by_label', '_bx_courses_page_block_title_browse_by_label', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:15:"browse_by_label";}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 5),
+('', 0, 'bx_courses', '_bx_courses_page_block_title_sys_labels_breadcrumbs', '_bx_courses_page_block_title_labels_breadcrumbs', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:22:"get_lables_breadcrumbs";}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 6),
+('', 0, 'bx_courses', '_bx_courses_page_block_title_sys_cover_block', '_bx_courses_page_block_title_cover_block', 3, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_courses\";s:6:\"method\";s:12:\"entity_cover\";}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 7);
+
+-- MENU
+
+-- MENU: add to site menu
+
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' AND `active` = 1 AND `order` < 9999 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_site', 'bx_courses', 'courses-home', '_bx_courses_menu_item_title_system_entries_home', '_bx_courses_menu_item_title_entries_home', 'page.php?i=courses-home', '', '', 'book-reader col-blue3-dark', 'bx_courses_submenu', 2147483647, 1, 1, IFNULL(@iSiteMenuOrder, 0) + 1);
+
+-- MENU: add to homepage menu
+
+SET @iHomepageMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_homepage' AND `active` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_homepage', 'bx_courses', 'courses-home', '_bx_courses_menu_item_title_system_entries_home', '_bx_courses_menu_item_title_entries_home', 'page.php?i=courses-home', '', '', 'book-reader col-blue3-dark', 'bx_courses_submenu', 2147483647, 1, 1, IFNULL(@iHomepageMenuOrder, 0) + 1);
+
+-- MENU: add to "add content" menu
+
+SET @iAddMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_add_content_links' AND `active` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_add_content_links', 'bx_courses', 'create-course-profile', '_bx_courses_menu_item_title_system_create_profile', '_bx_courses_menu_item_title_create_profile', 'page.php?i=create-course-profile', '', '', 'book-reader col-blue3-dark', '', 2147483647, 1, 1, IFNULL(@iAddMenuOrder, 0) + 1);
+
+-- MENU: view actions
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_view_actions', '_bx_courses_menu_title_view_profile_actions', 'bx_courses_view_actions', 'bx_courses', 9, 0, 1, 'BxCoursesMenuViewActions', 'modules/boonex/courses/classes/BxCoursesMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_courses_view_actions', 'bx_courses', '_bx_courses_menu_set_title_view_profile_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_courses_view_actions', 'bx_courses', 'join-course-profile', '_bx_courses_menu_item_title_system_pay_and_join', '_bx_courses_menu_item_title_pay_and_join', 'page.php?i=join-course-profile&profile_id={profile_id}', '', '', 'sign-in-alt', '', 0, 2147483647, 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:22:"is_paid_join_avaliable";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 1, 0, 0, 5),
+('bx_courses_view_actions', 'bx_courses', 'profile-fan-add', '_bx_courses_menu_item_title_system_become_fan', '{title_add_fan}', 'javascript:void(0)', 'bx_conn_action(this, \'bx_courses_fans\', \'add\', \'{profile_id}\')', '', 'sign-in-alt', '', 0, 2147483647, 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:22:"is_free_join_avaliable";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 1, 0, 0, 5),
+('bx_courses_view_actions', 'bx_courses', 'profile-subscribe-add', '_bx_courses_menu_item_title_system_subscribe', '_bx_courses_menu_item_title_subscribe', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_subscriptions\', \'add\', \'{profile_id}\')', '', 'check', '', 0, 2147483647, '', 1, 0, 1, 20),
+('bx_courses_view_actions', 'bx_courses', 'profile-set-badges', '_sys_menu_item_title_system_set_badges', '_sys_menu_item_title_set_badges', 'javascript:void(0)', 'bx_menu_popup(''sys_set_badges'', window, {}, {module: ''bx_courses'', content_id: {content_id}});', '', 'check-circle', '', 0, 192, 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:19:"is_badges_avaliable";}', 1, 0, 1, 30),
+
+('bx_courses_view_actions', 'bx_courses', 'profile-actions-more', '_bx_courses_menu_item_title_system_more_actions', '_bx_courses_menu_item_title_more_actions', 'javascript:void(0)', 'bx_menu_popup(''bx_courses_view_actions_more'', this, {}, {profile_id:{profile_id}});', '', 'cog', 'bx_courses_view_actions_more', 1, 2147483647, '', 1, 0, 1, 9999);
+
+-- MENU: view actions more
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_view_actions_more', '_bx_courses_menu_title_view_profile_actions_more', 'bx_courses_view_actions_more', 'bx_courses', 6, 0, 1, 'BxCoursesMenuViewActions', 'modules/boonex/courses/classes/BxCoursesMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_courses_view_actions_more', 'bx_courses', '_bx_courses_menu_set_title_view_profile_actions_more', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_courses_view_actions_more', 'bx_courses', 'profile-fan-remove', '_bx_courses_menu_item_title_system_leave_entry', '{title_remove_fan}', 'javascript:void(0)', 'bx_conn_action(this, \'bx_courses_fans\', \'remove\', \'{profile_id}\')', '', 'sign-out-alt', '', 2147483647, '', 1, 0, 10),
+('bx_courses_view_actions_more', 'bx_courses', 'profile-subscribe-remove', '_bx_courses_menu_item_title_system_unsubscribe', '_bx_courses_menu_item_title_unsubscribe', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_subscriptions\', \'remove\', \'{profile_id}\')', '', 'check', '', 2147483647, '', 1, 0, 20),
+('bx_courses_view_actions_more', 'bx_courses', 'edit-course-cover', '_bx_courses_menu_item_title_system_edit_cover', '_bx_courses_menu_item_title_edit_cover', 'page.php?i=edit-course-cover&id={content_id}', '', '', 'edit', '', 2147483647, '', 1, 0, 30),
+('bx_courses_view_actions_more', 'bx_courses', 'edit-course-profile', '_bx_courses_menu_item_title_system_edit_profile', '_bx_courses_menu_item_title_edit_profile', 'page.php?i=edit-course-profile&id={content_id}', '', '', 'pencil-alt', '', 2147483647, '', 1, 0, 40),
+('bx_courses_view_actions_more', 'bx_courses', 'edit-course-pricing', '_bx_courses_menu_item_title_system_edit_pricing', '_bx_courses_menu_item_title_edit_pricing', 'page.php?i=edit-course-pricing&profile_id={profile_id}', '', '', 'money-check-alt', '', 2147483647, 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:20:"is_pricing_avaliable";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 1, 0, 41),
+('bx_courses_view_actions_more', 'bx_courses', 'invite-to-course', '_bx_courses_menu_item_title_system_invite', '_bx_courses_menu_item_title_invite', 'page.php?i=invite-to-course&id={content_id}', '', '', 'user-friends', '', 2147483647, '', 1, 0, 42),
+('bx_courses_view_actions_more', 'bx_courses', 'delete-course-profile', '_bx_courses_menu_item_title_system_delete_profile', '_bx_courses_menu_item_title_delete_profile', 'page.php?i=delete-course-profile&id={content_id}', '', '', 'remove', '', 2147483647, '', 1, 0, 50),
+('bx_courses_view_actions_more', 'bx_courses', 'approve-course-profile', '_sys_menu_item_title_system_va_approve', '_sys_menu_item_title_va_approve', 'javascript:void(0)', 'javascript:bx_approve(this, ''{module_uri}'', {content_id});', '', 'check', '', 2147483647, '', 1, 0, 60);
+
+-- MENU: all actions menu for view entry 
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_view_actions_all', '_sys_menu_title_view_actions', 'bx_courses_view_actions_all', 'bx_courses', 15, 0, 1, 'BxCoursesMenuViewActionsAll', 'modules/boonex/courses/classes/BxCoursesMenuViewActionsAll.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_courses_view_actions_all', 'bx_courses', '_sys_menu_set_title_view_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_courses_view_actions_all', 'bx_courses', 'join-course-profile', '_bx_courses_menu_item_title_system_pay_and_join', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 5),
+('bx_courses_view_actions_all', 'bx_courses', 'profile-fan-add', '_bx_courses_menu_item_title_system_become_fan', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 10),
+('bx_courses_view_actions_all', 'bx_courses', 'profile-fan-remove', '_bx_courses_menu_item_title_system_leave_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 20),
+('bx_courses_view_actions_all', 'bx_courses', 'profile-subscribe-add', '_bx_courses_menu_item_title_system_subscribe', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 30),
+('bx_courses_view_actions_all', 'bx_courses', 'profile-subscribe-remove', '_bx_courses_menu_item_title_system_unsubscribe', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 40),
+('bx_courses_view_actions_all', 'bx_courses', 'profile-set-badges', '_sys_menu_item_title_system_set_badges', '', '', '', '', '', '', '', 0, 192, 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:19:"is_badges_avaliable";}', 1, 0, 50),
+('bx_courses_view_actions_all', 'bx_courses', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 200),
+('bx_courses_view_actions_all', 'bx_courses', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 210),
+('bx_courses_view_actions_all', 'bx_courses', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 220),
+('bx_courses_view_actions_all', 'bx_courses', 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 230),
+('bx_courses_view_actions_all', 'bx_courses', 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 240),
+('bx_courses_view_actions_all', 'bx_courses', 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 250),
+('bx_courses_view_actions_all', 'bx_courses', 'repost', '_sys_menu_item_title_system_va_repost', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 260),
+('bx_courses_view_actions_all', 'bx_courses', 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 270),
+('bx_courses_view_actions_all', 'bx_courses', 'notes', '_sys_menu_item_title_system_va_notes', '_sys_menu_item_title_va_notes', 'javascript:void(0)', 'javascript:bx_get_notes(this,  ''{module_uri}'', {content_id});', '', 'exclamation-triangle', '', '', 0, 2147483647, '', 1, 0, 280),
+('bx_courses_view_actions_all', 'bx_courses', 'audit', '_sys_menu_item_title_system_va_audit', '_sys_menu_item_title_va_audit', 'page.php?i=dashboard-audit&module=bx_courses&content_id={content_id}', '', '', 'history', '', '', 0, 192, '', 1, 0, 290),
+('bx_courses_view_actions_all', 'bx_courses', 'social-sharing', '_sys_menu_item_title_system_social_sharing', '_sys_menu_item_title_social_sharing', 'javascript:void(0)', 'oBxDolPage.share(this, \'{url_encoded}\')', '', 'share', '', '', 0, 2147483647, '', 1, 0, 300),
+('bx_courses_view_actions_all', 'bx_courses', 'edit-course-cover', '_bx_courses_menu_item_title_system_edit_cover', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 400),
+('bx_courses_view_actions_all', 'bx_courses', 'edit-course-profile', '_bx_courses_menu_item_title_system_edit_profile', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 410),
+('bx_courses_view_actions_all', 'bx_courses', 'edit-course-pricing', '_bx_courses_menu_item_title_system_edit_pricing', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 415),
+('bx_courses_view_actions_all', 'bx_courses', 'invite-to-course', '_bx_courses_menu_item_title_system_invite', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 420),
+('bx_courses_view_actions_all', 'bx_courses', 'delete-course-profile', '_bx_courses_menu_item_title_system_delete_profile', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 430),
+('bx_courses_view_actions_all', 'bx_courses', 'approve-course-profile', '_sys_menu_item_title_system_va_approve', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 440),
+('bx_courses_view_actions_all', 'bx_courses', 'more-auto', '_sys_menu_item_title_system_va_more_auto', '_sys_menu_item_title_va_more_auto', 'javascript:void(0)', '', '', 'ellipsis-v', '', '', 0, 2147483647, '', 1, 0, 9999);
+
+-- MENU: meta (counters) menu for view entry
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_view_meta', '_bx_courses_menu_title_view_profile_meta', 'bx_courses_view_meta', 'bx_courses', 15, 0, 1, 'BxCoursesMenuViewMeta', 'modules/boonex/courses/classes/BxCoursesMenuViewMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_courses_view_meta', 'bx_courses', '_bx_courses_menu_set_title_view_profile_meta', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_courses_view_meta', 'bx_courses', 'members', '_sys_menu_item_title_system_sm_members', '_sys_menu_item_title_sm_members', '', '', '', '', '', 0, 2147483647, '', 1, 0, 10),
+('bx_courses_view_meta', 'bx_courses', 'subscribers', '_sys_menu_item_title_system_sm_subscribers', '_sys_menu_item_title_sm_subscribers', '', '', '', '', '', 0, 2147483647, '', 1, 0, 20),
+('bx_courses_view_meta', 'bx_courses', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 0, 2147483647, '', 1, 0, 30),
+('bx_courses_view_meta', 'bx_courses', 'votes', '_sys_menu_item_title_system_sm_votes', '_sys_menu_item_title_sm_votes', '', '', '', '', '', 0, 2147483647, '', 1, 0, 40),
+('bx_courses_view_meta', 'bx_courses', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 0, 2147483647, '', 1, 0, 50);
+
+-- MENU: actions menu for my entries
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_my', '_bx_courses_menu_title_entries_my', 'bx_courses_my', 'bx_courses', 9, 0, 1, 'BxCoursesMenu', 'modules/boonex/courses/classes/BxCoursesMenu.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_courses_my', 'bx_courses', '_bx_courses_menu_set_title_entries_my', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_courses_my', 'bx_courses', 'create-course-profile', '_bx_courses_menu_item_title_system_create_profile', '_bx_courses_menu_item_title_create_profile', 'page.php?i=create-course-profile', '', '', 'plus', '', 2147483647, 1, 0, 0);
+
+-- MENU: module sub-menu
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_submenu', '_bx_courses_menu_title_submenu', 'bx_courses_submenu', 'bx_courses', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_courses_submenu', 'bx_courses', '_bx_courses_menu_set_title_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_courses_submenu', 'bx_courses', 'courses-home', '_bx_courses_menu_item_title_system_entries_recent', '_bx_courses_menu_item_title_entries_recent', 'page.php?i=courses-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_courses_submenu', 'bx_courses', 'courses-top', '_bx_courses_menu_item_title_system_entries_top', '_bx_courses_menu_item_title_entries_top', 'page.php?i=courses-top', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_courses_submenu', 'bx_courses', 'courses-search', '_bx_courses_menu_item_title_system_entries_search', '_bx_courses_menu_item_title_entries_search', 'page.php?i=courses-search', '', '', '', '', 2147483647, 1, 1, 3),
+('bx_courses_submenu', 'bx_courses', 'courses-joined', '_bx_courses_menu_item_title_system_entries_joined', '_bx_courses_menu_item_title_entries_joined', 'page.php?i=courses-joined', '', '', '', '', 2147483647, 1, 1, 4),
+('bx_courses_submenu', 'bx_courses', 'courses-manage', '_bx_courses_menu_item_title_system_entries_manage', '_bx_courses_menu_item_title_entries_manage', 'page.php?i=courses-manage', '', '', '', '', 2147483646, 1, 1, 5);
+
+-- MENU: view submenu
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_view_submenu', '_bx_courses_menu_title_view_profile_submenu', 'bx_courses_view_submenu', 'bx_courses', 18, 0, 1, 'BxCoursesMenuView', 'modules/boonex/courses/classes/BxCoursesMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_courses_view_submenu', 'bx_courses', '_bx_courses_menu_set_title_view_profile_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_courses_view_submenu', 'bx_courses', 'view-course-profile', '_bx_courses_menu_item_title_system_view_profile_view', '_bx_courses_menu_item_title_view_profile_view', 'page.php?i=view-course-profile&id={content_id}', '', '', 'book-reader col-blue3-dark', '', '', 0, 2147483647, 1, 0, 1),
+('bx_courses_view_submenu', 'bx_courses', 'course-profile-info', '_bx_courses_menu_item_title_system_view_profile_info', '_bx_courses_menu_item_title_view_profile_info', 'page.php?i=course-profile-info&id={content_id}', '', '', 'info-circle col-gray', '', '', 0, 2147483647, 1, 0, 2),
+('bx_courses_view_submenu', 'bx_courses', 'course-profile-comments', '_bx_courses_menu_item_title_system_view_profile_comments', '_bx_courses_menu_item_title_view_profile_comments', 'page.php?i=course-profile-comments&id={content_id}', '', '', '', '', '', 0, 2147483647, 0, 0, 3),
+('bx_courses_view_submenu', 'bx_courses', 'course-fans', '_bx_courses_menu_item_title_system_view_fans', '_bx_courses_menu_item_title_view_fans', 'page.php?i=course-fans&profile_id={profile_id}', '', '', 'users col-blue3', '', '', 0, 2147483647, 1, 0, 4),
+('bx_courses_view_submenu', 'bx_courses', 'more-auto', '_bx_courses_menu_item_title_system_view_profile_more_auto', '_bx_courses_menu_item_title_view_profile_more_auto', 'javascript:void(0)', '', '', 'ellipsis-v', '', '', 0, 2147483647, 1, 0, 9999);
+
+-- MENU: custom menu for snippet meta info
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_snippet_meta', '_sys_menu_title_snippet_meta', 'bx_courses_snippet_meta', 'bx_courses', 15, 0, 1, 'BxCoursesMenuSnippetMeta', 'modules/boonex/courses/classes/BxCoursesMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_courses_snippet_meta', 'bx_courses', '_sys_menu_set_title_snippet_meta', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `editable`, `order`) VALUES
+('bx_courses_snippet_meta', 'bx_courses', 'privacy', '_bx_courses_menu_item_title_system_sm_privacy', '_bx_courses_menu_item_title_sm_privacy', '', '', '', '', '', 2147483647, '', 1, 0, 1, 0),
+('bx_courses_snippet_meta', 'bx_courses', 'date', '_sys_menu_item_title_system_sm_date', '_sys_menu_item_title_sm_date', '', '', '', '', '', 2147483647, '', 0, 0, 1, 1),
+('bx_courses_snippet_meta', 'bx_courses', 'category', '_sys_menu_item_title_system_sm_category', '_sys_menu_item_title_sm_category', '', '', '', '', '', 2147483647, '', 0, 0, 1, 5),
+('bx_courses_snippet_meta', 'bx_courses', 'tags', '_sys_menu_item_title_system_sm_tags', '_sys_menu_item_title_sm_tags', '', '', '', '', '', 2147483647, '', 0, 0, 1, 10),
+('bx_courses_snippet_meta', 'bx_courses', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 2147483647, '', 0, 0, 1, 15),
+('bx_courses_snippet_meta', 'bx_courses', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 2147483647, '', 0, 0, 1, 20),
+('bx_courses_snippet_meta', 'bx_courses', 'members', '_bx_courses_menu_item_title_system_sm_members', '_bx_courses_menu_item_title_sm_members', '', '', '', '', '', 2147483647, '', 1, 0, 1, 25),
+('bx_courses_snippet_meta', 'bx_courses', 'subscribers', '_sys_menu_item_title_system_sm_subscribers', '_sys_menu_item_title_sm_subscribers', '', '', '', '', '', 2147483647, '', 0, 0, 1, 30),
+('bx_courses_snippet_meta', 'bx_courses', 'nl', '_sys_menu_item_title_system_sm_nl', '_sys_menu_item_title_sm_nl', '', '', '', '', '', 2147483647, '', 1, 0, 1, 35),
+('bx_courses_snippet_meta', 'bx_courses', 'join-paid', '_sys_menu_item_title_system_sm_join_paid', '_sys_menu_item_title_sm_join_paid', '', '', '', '', '', 2147483647, 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:33:"is_paid_join_avaliable_by_content";s:6:"params";a:1:{i:0;s:12:"{content_id}";}}', 1, 0, 1, 40),
+('bx_courses_snippet_meta', 'bx_courses', 'join', '_bx_courses_menu_item_title_system_sm_join', '_bx_courses_menu_item_title_sm_join', '', '', '', '', '', 2147483647, 'a:3:{s:6:"module";s:10:"bx_courses";s:6:"method";s:33:"is_free_join_avaliable_by_content";s:6:"params";a:1:{i:0;s:12:"{content_id}";}}', 1, 0, 1, 45),
+('bx_courses_snippet_meta', 'bx_courses', 'leave', '_sys_menu_item_title_system_sm_leave', '_sys_menu_item_title_sm_leave', '', '', '', '', '', 2147483647, '', 0, 0, 1, 50),
+('bx_courses_snippet_meta', 'bx_courses', 'subscribe', '_sys_menu_item_title_system_sm_subscribe', '_sys_menu_item_title_sm_subscribe', '', '', '', '', '', 2147483647, '', 0, 0, 1, 55),
+('bx_courses_snippet_meta', 'bx_courses', 'unsubscribe', '_sys_menu_item_title_system_sm_unsubscribe', '_sys_menu_item_title_sm_unsubscribe', '', '', '', '', '', 2147483647, '', 0, 0, 1, 60);
+
+-- MENU: profile stats
+SET @iNotifMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name` = 'sys_profile_stats' AND `active` = 1 LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES
+('sys_profile_stats', 'bx_courses', 'profile-stats-my-courses', '_bx_courses_menu_item_title_system_manage_my_entries', '_bx_courses_menu_item_title_manage_my_entries', 'page.php?i=joined-courses&profile_id={member_id}', '', '_self', 'book-reader col-blue3-dark', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:41:"get_menu_addon_manage_tools_profile_stats";}', '', 2147483646, 1, 0, @iNotifMenuOrder + 2);
+
+-- MENU: profile followings
+SET @iFollowingsMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_profile_followings' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `collapsed`, `active`, `copyable`, `order`) VALUES 
+('sys_profile_followings', 'bx_courses', 'courses', '_bx_courses_menu_item_title_system_followings', '_bx_courses_menu_item_title_followings', 'javascript:void(0)', '', '_self', 'book-reader col-blue3-dark', '', '', 2147483647, 0, 1, 0, @iFollowingsMenuOrder + 1);
+
+-- MENU: manage tools submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_courses_menu_manage_tools', '_bx_courses_menu_title_manage_tools', 'bx_courses_menu_manage_tools', 'bx_courses', 6, 0, 1, 'BxCoursesMenuManageTools', 'modules/boonex/courses/classes/BxCoursesMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_courses_menu_manage_tools', 'bx_courses', '_bx_courses_menu_set_title_manage_tools', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_courses_menu_manage_tools', 'bx_courses', 'clear-reports', '_bx_courses_menu_item_title_system_clear_reports', '_bx_courses_menu_item_title_clear_reports', 'javascript:void(0)', 'javascript:{js_object}.onClickClearReports({content_id});', '_self', 'eraser', '', 2147483647, 1, 0, 1),
+('bx_courses_menu_manage_tools', 'bx_courses', 'delete', '_bx_courses_menu_item_title_system_delete', '_bx_courses_menu_item_title_delete', 'javascript:void(0)', 'javascript:{js_object}.onClickDelete({content_id});', '_self', 'far trash-alt', '', 2147483647, 1, 0, 2),
+('bx_courses_menu_manage_tools', 'bx_courses', 'delete-with-content', '_bx_courses_menu_item_title_system_delete_with_content', '_bx_courses_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'far trash-alt', '', 2147483647, 0, 0, 3);
+
+-- MENU: dashboard manage tools
+SET @iManageMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard_manage_tools' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_account_dashboard_manage_tools', 'bx_courses', 'courses-administration', '_bx_courses_menu_item_title_system_admt_entries', '_bx_courses_menu_item_title_admt_entries', 'page.php?i=courses-administration', '', '_self', 'users', 'a:2:{s:6:"module";s:10:"bx_courses";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
+
+-- MENU: add menu item to profiles modules (trigger* menu sets are processed separately upon modules enable/disable)
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('trigger_profile_view_submenu', 'bx_courses', 'joined-courses', '_bx_courses_menu_item_title_system_view_joined_entries', '_bx_courses_menu_item_title_view_joined_entries', 'page.php?i=joined-courses&profile_id={profile_id}', '', '', 'book-reader col-blue3-dark', '', 2147483647, 1, 0, 0);
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_courses', 'create entry', NULL, '_bx_courses_acl_action_create_profile', '', 1, 1);
+SET @iIdActionProfileCreate = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_courses', 'use paid join', NULL, '_bx_courses_acl_action_use_paid_join', '', 1, 1);
+SET @iIdActionUsePaidJoin = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_courses', 'delete entry', NULL, '_bx_courses_acl_action_delete_profile', '', 1, 1);
+SET @iIdActionProfileDelete = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_courses', 'view entry', NULL, '_bx_courses_acl_action_view_profile', '', 1, 0);
+SET @iIdActionProfileView = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_courses', 'edit any entry', NULL, '_bx_courses_acl_action_edit_any_profile', '', 1, 3);
+SET @iIdActionProfileEditAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_courses', 'delete any entry', NULL, '_bx_courses_acl_action_delete_any_profile', '', 1, 3);
+SET @iIdActionProfileDeleteAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_courses', 'delete invites', NULL, '_bx_courses_acl_action_delete_invites', '', 1, 3);
+SET @iIdActionProfileDeleteInvites = LAST_INSERT_ID();
+
+SET @iUnauthenticated = 1;
+SET @iAccount = 2;
+SET @iStandard = 3;
+SET @iUnconfirmed = 4;
+SET @iPending = 5;
+SET @iSuspended = 6;
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+
+-- profile create
+(@iAccount, @iIdActionProfileCreate),
+(@iStandard, @iIdActionProfileCreate),
+(@iUnconfirmed, @iIdActionProfileCreate),
+(@iPending, @iIdActionProfileCreate),
+(@iModerator, @iIdActionProfileCreate),
+(@iAdministrator, @iIdActionProfileCreate),
+(@iPremium, @iIdActionProfileCreate),
+
+-- use paid join
+(@iStandard, @iIdActionUsePaidJoin),
+(@iModerator, @iIdActionUsePaidJoin),
+(@iAdministrator, @iIdActionUsePaidJoin),
+(@iPremium, @iIdActionUsePaidJoin),
+
+-- profile delete
+(@iAccount, @iIdActionProfileDelete),
+(@iStandard, @iIdActionProfileDelete),
+(@iUnconfirmed, @iIdActionProfileDelete),
+(@iPending, @iIdActionProfileDelete),
+(@iModerator, @iIdActionProfileDelete),
+(@iAdministrator, @iIdActionProfileDelete),
+(@iPremium, @iIdActionProfileDelete),
+
+-- profile view
+(@iUnauthenticated, @iIdActionProfileView),
+(@iAccount, @iIdActionProfileView),
+(@iStandard, @iIdActionProfileView),
+(@iUnconfirmed, @iIdActionProfileView),
+(@iPending, @iIdActionProfileView),
+(@iModerator, @iIdActionProfileView),
+(@iAdministrator, @iIdActionProfileView),
+(@iPremium, @iIdActionProfileView),
+
+-- any profile edit
+(@iModerator, @iIdActionProfileEditAny),
+(@iAdministrator, @iIdActionProfileEditAny),
+
+-- any profile delete
+(@iAdministrator, @iIdActionProfileDeleteAny),
+
+-- any invites edit
+(@iModerator, @iIdActionProfileDeleteInvites),
+(@iAdministrator, @iIdActionProfileDeleteInvites);
+
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `module`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_courses', 'bx_courses', 'bx_courses_meta_keywords', 'bx_courses_meta_locations', 'bx_courses_meta_mentions', '', '');
+
+-- CATEGORY
+INSERT INTO `sys_objects_category` (`object`, `module`, `search_object`, `form_object`, `list_name`, `table`, `field`, `join`, `where`, `override_class_name`, `override_class_file`) VALUES
+('bx_courses_cats', 'bx_courses',  'bx_courses', 'bx_course', 'bx_courses_cats', 'bx_courses_data', 'cat', 'INNER JOIN `sys_profiles` ON (`sys_profiles`.`content_id` = `bx_courses_data`.`id` AND `sys_profiles`.`type` = ''bx_courses'')', 'AND `sys_profiles`.`status` = ''active''', '', '');
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+('bx_courses', '_bx_courses', @iSearchOrder + 1, 'BxCoursesSearchResult', 'modules/boonex/courses/classes/BxCoursesSearchResult.php');
+
+-- CONNECTIONS
+INSERT INTO `sys_objects_connection` (`object`, `table`, `profile_initiator`, `profile_content`, `type`, `override_class_name`, `override_class_file`) VALUES
+('bx_courses_fans', 'bx_courses_fans', 1, 1, 'mutual', '', '');
+
+-- STATS
+SET @iMaxOrderStats = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_statistics`);
+INSERT INTO `sys_statistics` (`module`, `name`, `title`, `link`, `icon`, `query`, `order`) VALUES 
+('bx_courses', 'bx_courses', '_bx_courses', 'page.php?i=courses-home', 'book-reader col-blue3-dark', 'SELECT COUNT(*) FROM `bx_courses_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id` = `tp`.`content_id` AND `tp`.`type`=''bx_courses'' WHERE 1 AND `tp`.`status`=''active''', @iMaxOrderStats + 1);
+
+-- CHARTS
+SET @iMaxOrderCharts = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_objects_chart`);
+INSERT INTO `sys_objects_chart` (`object`, `title`, `table`, `field_date_ts`, `field_date_dt`, `field_status`, `query`, `active`, `order`, `class_name`, `class_file`) VALUES
+('bx_courses_growth', '_bx_courses_chart_growth', 'bx_courses_data', 'added', '', '', 'SELECT {field_date_formatted} AS `period`, COUNT(*) AS {object} FROM {table} LEFT JOIN `sys_profiles` AS `tp` ON {table}.`id` = `tp`.`content_id` AND `tp`.`type`=''bx_courses'' WHERE 1 AND `tp`.`status`=''active'' {where_inteval} GROUP BY `period` ORDER BY {table}.{field_date} ASC', 1, @iMaxOrderCharts + 1, 'BxDolChartGrowth', ''),
+('bx_courses_growth_speed', '_bx_courses_chart_growth_speed', 'bx_courses_data', 'added', '', '', 'SELECT {field_date_formatted} AS `period`, COUNT(*) AS {object} FROM {table} LEFT JOIN `sys_profiles` AS `tp` ON {table}.`id` = `tp`.`content_id` AND `tp`.`type`=''bx_courses'' WHERE 1 AND `tp`.`status`=''active'' {where_inteval} GROUP BY `period` ORDER BY {table}.{field_date} ASC', 1, @iMaxOrderCharts + 2, 'BxDolChartGrowthSpeed', '');
+
+-- GRID: connections
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `responsive`, `override_class_name`, `override_class_file`) VALUES
+('bx_courses_fans', 'Sql', 'SELECT `p`.`id`, `c`.`added`, `c`.`mutual` FROM `sys_profiles` AS `p` INNER JOIN `sys_accounts` AS `a` ON (`a`.`id` = `p`.`account_id`) {join_connections}', 'sys_profiles', 'id', 'c`.`added', '', '', 10, NULL, 'start', '', 'name,email', '', 'auto', '', '', 2147483647, 0, 'BxCoursesGridConnections', 'modules/boonex/courses/classes/BxCoursesGridConnections.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `params`, `order`) VALUES
+('bx_courses_fans', 'name', '_sys_name', '50%', '', 10),
+('bx_courses_fans', 'role', '_bx_courses_txt_role', '10%', '', 15),
+('bx_courses_fans', 'role_added', '_bx_courses_txt_role_added', '10%', '', 16),
+('bx_courses_fans', 'role_expired', '_bx_courses_txt_role_expired', '10%', '', 17),
+('bx_courses_fans', 'actions', '', '20%', '', 20);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_courses_fans', 'single', 'accept', '_sys_accept', '', 0, 10),
+('bx_courses_fans', 'single', 'set_role', '_bx_courses_txt_set_role', '', 0, 20),
+('bx_courses_fans', 'single', 'set_role_submit', '', '', 0, 21),
+('bx_courses_fans', 'single', 'delete', '', 'remove', 1, 40);
+
+
+-- GRID: invites
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `responsive`, `override_class_name`, `override_class_file`) VALUES
+('bx_courses_invites', 'Sql', 'SELECT `bx_courses_invites`.`id`, `bx_courses_invites`.`invited_profile_id`, `bx_courses_invites`.`added`, `bx_courses_invites`.`author_profile_id` FROM `sys_profiles` AS `p` INNER JOIN `sys_accounts` AS `a` ON (`a`.`id` = `p`.`account_id`) INNER JOIN `bx_courses_invites` ON `bx_courses_invites`.`invited_profile_id` = `p`.`id` ', 'bx_courses_invites', 'id', 'bx_courses_invites`.`added', '', '', 10, NULL, 'start', '', 'name,email', '', 'auto', '', '', 2147483647, 0, 'BxCoursesGridInvites', 'modules/boonex/courses/classes/BxCoursesGridInvites.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `params`, `order`) VALUES
+('bx_courses_invites', 'name', '_sys_name', '33%', '', 10),
+('bx_courses_invites', 'added', '_sys_added', '33%', '', 20),
+('bx_courses_invites', 'actions', '', '34%', '', 30);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_courses_invites', 'single', 'delete', '', 'remove', 1, 10);
+
+
+-- GRIDS: administration
+
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_courses_administration', 'Sql', 'SELECT `td`.*, `td`.`name` AS `name`, `ta`.`email` AS `account`, `td`.`added` AS `added_ts`, `tp`.`status` AS `status` FROM `bx_courses_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id`=`tp`.`content_id` AND `tp`.`type`=''bx_courses'' LEFT JOIN `sys_accounts` AS `ta` ON `tp`.`account_id`=`ta`.`id` WHERE 1 ', 'bx_courses_data', 'id', 'added', 'status_admin', '', 20, NULL, 'start', '', 'name', '', 'like', 'reports', '', 192, 'BxCoursesGridAdministration', 'modules/boonex/courses/classes/BxCoursesGridAdministration.php'),
+('bx_courses_common', 'Sql', 'SELECT `td`.*, `td`.`name` AS `name`, `ta`.`email` AS `account`, `td`.`added` AS `added_ts`, `tp`.`status` AS `status` FROM `bx_courses_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id`=`tp`.`content_id` AND `tp`.`type`=''bx_courses'' LEFT JOIN `sys_accounts` AS `ta` ON `tp`.`account_id`=`ta`.`id` WHERE 1 ', 'bx_courses_data', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'name', '', 'like', '', '', 2147483647, 'BxCoursesGridCommon', 'modules/boonex/courses/classes/BxCoursesGridCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_courses_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_courses_administration', 'switcher', '_bx_courses_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_courses_administration', 'reports', '_sys_txt_reports_title', '5%', 0, '', '', 3),
+('bx_courses_administration', 'name', '_bx_courses_grid_column_title_adm_name', '25%', 0, '', '', 4),
+('bx_courses_administration', 'added_ts', '_bx_courses_grid_column_title_adm_added', '20%', 1, '25', '', 5),
+('bx_courses_administration', 'account', '_bx_courses_grid_column_title_adm_account', '20%', 0, '25', '', 6),
+('bx_courses_administration', 'actions', '', '20%', 0, '', '', 7),
+
+('bx_courses_common', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_courses_common', 'switcher', '_bx_courses_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_courses_common', 'name', '_bx_courses_grid_column_title_adm_name', '40%', 0, '', '', 3),
+('bx_courses_common', 'added_ts', '_bx_courses_grid_column_title_adm_added', '30%', 1, '25', '', 4),
+('bx_courses_common', 'actions', '', '20%', 0, '', '', 5);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `active`, `order`) VALUES
+('bx_courses_administration', 'bulk', 'clear_reports', '_bx_classes_grid_action_title_adm_clear_reports', '', 0, 1, 1, 1),
+('bx_courses_administration', 'bulk', 'delete', '_bx_courses_grid_action_title_adm_delete', '', 0, 1, 1, 2),
+('bx_courses_administration', 'bulk', 'delete_with_content', '_bx_courses_grid_action_title_adm_delete_with_content', '', 0, 1, 0, 3),
+('bx_courses_administration', 'single', 'settings', '_bx_courses_grid_action_title_adm_more_actions', 'cog', 1, 0, 1, 2),
+('bx_courses_administration', 'single', 'audit_content', '_bx_courses_grid_action_title_adm_audit_content', 'search', 1, 0, 1, 3),
+('bx_courses_administration', 'single', 'audit_context', '_bx_courses_grid_action_title_adm_audit_context', 'search-location', 1, 0, 1, 4),
+
+('bx_courses_common', 'bulk', 'delete', '_bx_courses_grid_action_title_adm_delete', '', 0, 1, 1, 1),
+('bx_courses_common', 'bulk', 'delete_with_content', '_bx_courses_grid_action_title_adm_delete_with_content', '', 0, 1, 0, 2),
+('bx_courses_common', 'single', 'settings', '_bx_courses_grid_action_title_adm_more_actions', 'cog', 1, 0, 1, 1);
+
+-- GRIDS: Pricing
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_courses_prices_manage', 'Sql', 'SELECT * FROM `bx_courses_prices` WHERE 1 ', 'bx_courses_prices', 'id', 'order', '', '', 100, NULL, 'start', '', 'period,period_unit,price', '', 'like', '', '', 2147483647, 'BxCoursesGridPricesManage', 'modules/boonex/courses/classes/BxCoursesGridPricesManage.php'),
+('bx_courses_prices_view', 'Sql', 'SELECT * FROM `bx_courses_prices` WHERE 1 ', 'bx_courses_prices', 'id', 'order', '', '', 100, NULL, 'start', '', 'period,period_unit,price', '', 'like', '', '', 2147483647, 'BxCoursesGridPricesView', 'modules/boonex/courses/classes/BxCoursesGridPricesView.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_courses_prices_manage', 'checkbox', '_sys_select', '1%', 0, '', '', 1),
+('bx_courses_prices_manage', 'order', '', '1%', 0, '', '', 2),
+('bx_courses_prices_manage', 'name', '_bx_courses_grid_column_title_name', '38%', 0, 32, '', 3),
+('bx_courses_prices_manage', 'price', '_bx_courses_grid_column_title_price', '20%', 0, 16, '', 4),
+('bx_courses_prices_manage', 'period', '_bx_courses_grid_column_title_period', '20%', 0, 16, '', 5),
+('bx_courses_prices_manage', 'actions', '', '20%', 0, '', '', 6),
+
+('bx_courses_prices_view', 'role_id', '_bx_courses_grid_column_title_role_id', '40%', 0, 32, '', 1),
+('bx_courses_prices_view', 'price', '_bx_courses_grid_column_title_price', '20%', 0, 16, '', 2),
+('bx_courses_prices_view', 'period', '_bx_courses_grid_column_title_period', '20%', 0, 16, '', 3),
+('bx_courses_prices_view', 'actions', '', '20%', 0, '', '', 4);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_courses_prices_manage', 'independent', 'add', '_bx_courses_grid_action_title_add', '', 0, 0, 1),
+('bx_courses_prices_manage', 'single', 'edit', '_bx_courses_grid_action_title_edit', 'pencil-alt', 1, 0, 1),
+('bx_courses_prices_manage', 'single', 'delete', '_bx_courses_grid_action_title_delete', 'remove', 1, 1, 2),
+('bx_courses_prices_manage', 'bulk', 'delete', '_bx_courses_grid_action_title_delete', '', 0, 1, 1),
+
+('bx_courses_prices_view', 'single', 'buy', '_bx_courses_grid_action_title_buy', 'cart-plus', 0, 0, 1),
+('bx_courses_prices_view', 'single', 'subscribe', '_bx_courses_grid_action_title_subscribe', 'credit-card', 0, 0, 2),
+('bx_courses_prices_view', 'single', 'choose', '_bx_courses_grid_action_title_choose', 'far check-square', 0, 0, 3);
+
+
+-- ALERTS
+
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_courses', 'BxCoursesAlertsResponse', 'modules/boonex/courses/classes/BxCoursesAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('bx_timeline', 'post_common', @iHandler),
+('bx_courses_pics', 'file_deleted', @iHandler),
+('bx_courses_fans', 'connection_added', @iHandler),
+('bx_courses_fans', 'connection_removed', @iHandler),
+('profile', 'delete', @iHandler),
+('bx_courses', 'fan_added', @iHandler),
+('bx_courses', 'join_invitation', @iHandler),
+('bx_courses', 'join_request', @iHandler),
+('bx_courses', 'join_request_accepted', @iHandler),
+('bx_courses', 'timeline_view', @iHandler),
+('bx_courses', 'timeline_post', @iHandler),
+('bx_courses', 'timeline_delete', @iHandler),
+('bx_courses', 'timeline_comment', @iHandler),
+('bx_courses', 'timeline_vote', @iHandler),
+('bx_courses', 'timeline_score', @iHandler),
+('bx_courses', 'timeline_report', @iHandler),
+('bx_courses', 'timeline_repost', @iHandler),
+('bx_courses', 'timeline_pin', @iHandler),
+('bx_courses', 'timeline_promote', @iHandler);
+
+-- PRIVACY
+
+INSERT INTO `sys_objects_privacy` (`object`, `module`, `action`, `title`, `default_group`, `spaces`, `table`, `table_field_id`, `table_field_author`, `override_class_name`, `override_class_file`) VALUES
+('bx_courses_allow_view_to', 'bx_courses', 'view', '_bx_courses_form_profile_input_allow_view_to', '3', '', 'bx_courses_data', 'id', 'author', 'BxCoursesPrivacy', 'modules/boonex/courses/classes/BxCoursesPrivacy.php'),
+('bx_courses_allow_view_notification_to', 'bx_courses', 'view_event', '_bx_courses_form_profile_input_allow_view_notification_to', '3', '', 'bx_notifications_events', 'id', 'object_owner_id', 'BxCoursesPrivacyNotifications', 'modules/boonex/courses/classes/BxCoursesPrivacyNotifications.php'),
+('bx_courses_allow_post_to', 'bx_courses', 'post', '_bx_courses_form_profile_input_allow_post_to', 'p', '', 'bx_courses_data', 'id', 'author', 'BxCoursesPrivacyPost', 'modules/boonex/courses/classes/BxCoursesPrivacyPost.php'),
+('bx_courses_allow_view_favorite_list', 'bx_courses', 'view_favorite_list', '_bx_courses_form_profile_input_allow_view_favorite_list', '3', '', 'bx_courses_favorites_lists', 'id', 'author_id', 'BxCoursesPrivacy', 'modules/boonex/courses/classes/BxCoursesPrivacy.php');
+
+-- EMAIL TEMPLATES
+
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES
+('bx_courses', '_bx_courses_email_join_request', 'bx_courses_join_request', '_bx_courses_email_join_request_subject', '_bx_courses_email_join_request_body'),
+('bx_courses', '_bx_courses_email_join_reject', 'bx_courses_join_reject', '_bx_courses_email_join_reject_subject', '_bx_courses_email_join_reject_body'),
+('bx_courses', '_bx_courses_email_join_confirm', 'bx_courses_join_confirm', '_bx_courses_email_join_confirm_subject', '_bx_courses_email_join_confirm_body'),
+('bx_courses', '_bx_courses_email_fan_remove', 'bx_courses_fan_remove', '_bx_courses_email_fan_remove_subject', '_bx_courses_email_fan_remove_body'),
+('bx_courses', '_bx_courses_email_fan_become_admin', 'bx_courses_fan_become_admin', '_bx_courses_email_fan_become_admin_subject', '_bx_courses_email_fan_become_admin_body'),
+('bx_courses', '_bx_courses_email_admin_become_fan', 'bx_courses_admin_become_fan', '_bx_courses_email_admin_become_fan_subject', '_bx_courses_email_admin_become_fan_body'),
+('bx_courses', '_bx_courses_email_set_role', 'bx_courses_set_role', '_bx_courses_email_set_role_subject', '_bx_courses_email_set_role_body'),
+('bx_courses', '_bx_courses_email_invitation', 'bx_courses_invitation', '_bx_courses_email_invitation_subject', '_bx_courses_email_invitation_body');
+
+-- UPLOADERS
+
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_courses_cover_crop', 1, 'BxCoursesUploaderCoverCrop', 'modules/boonex/courses/classes/BxCoursesUploaderCoverCrop.php'),
+('bx_courses_picture_crop', 1, 'BxCoursesUploaderPictureCrop', 'modules/boonex/courses/classes/BxCoursesUploaderPictureCrop.php');
+
+-- CRON
+
+INSERT INTO `sys_cron_jobs` (`name`, `time`, `class`, `file`, `service_call`) VALUES
+('bx_courses_pruning', '0 0 * * *', 'BxCoursesCronPruning', 'modules/boonex/courses/classes/BxCoursesCronPruning.php', '');

+ 16 - 0
modules/boonex/courses/updates/13.0.2_13.0.3/source/js/invite_popup.js

@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Courses Courses
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxCoursesInvitePopup(oOptions) {
+    BxBaseModGroupsInvitePopup.call(this, oOptions);
+}
+
+BxCoursesInvitePopup.prototype = Object.create(BxBaseModGroupsInvitePopup.prototype);
+BxCoursesInvitePopup.prototype.constructor = BxCoursesInvitePopup;

+ 51 - 0
modules/boonex/developer/updates/13.0.2_13.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Developer',
+    'version_from' => '13.0.2',
+    'version_to' => '13.0.3',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/developer/updates/update_13.0.2_13.0.3/',
+    'home_uri' => 'developer_update_1302_1303',
+
+    'module_dir' => 'boonex/developer/',
+    'module_uri' => 'developer',
+
+    'db_prefix' => 'bx_dev_',
+    'class_prefix' => 'BxDev',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'BoonEx Developer',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/developer/updates/13.0.2_13.0.3/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxDevUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 144 - 0
modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevFormsDisplays.php

@@ -0,0 +1,144 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Developer Developer
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxDevFormsDisplays extends BxTemplStudioFormsDisplays
+{
+    protected $oModule;
+
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+
+        $this->oModule = BxDolModule::getInstance('bx_developer');
+        $this->sUrlPage = BX_DOL_URL_STUDIO . 'module.php?name=' . $this->oModule->_oConfig->getName() . '&page=forms&form_page=displays';
+        $this->sUrlViewFields = BX_DOL_URL_STUDIO . 'module.php?name=' . $this->oModule->_oConfig->getName() . '&page=forms&form_page=fields&form_module=%s&form_object=%s&form_display=%s';
+
+        $sModule = bx_get('form_module');
+        if(!empty($sModule)) {
+            $this->sModule = bx_process_input($sModule);
+            $this->_aQueryAppend['module'] = $this->sModule;
+        }
+
+        $sObject = bx_get('form_object');
+        if(!empty($sObject)) {
+            $this->sObject = bx_process_input($sObject);
+            $this->_aQueryAppend['object'] = $this->sObject;
+        }
+    }
+
+    public function performActionAdd()
+    {
+        $sAction = 'add';
+        $sFormObject = $this->oModule->_oConfig->getObject('form_forms_display');
+        $sFormDisplay = $this->oModule->_oConfig->getObject('form_display_forms_display_add');
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->oModule->_oTemplate);
+        $this->_fillDisplayForm($oForm, $sAction);
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $sName = uriGenerate($oForm->getCleanValue('display_name'), 'sys_form_displays', 'display_name', ['empty' => 'display']);
+            BxDolForm::setSubmittedValue('display_name', $sName, $oForm->aFormAttrs['method']);
+
+            if(($iId = (int)$oForm->insert()) != 0)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_dev_frm_err_displays_create'));
+
+            echoJson($aRes);
+        } else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-frm-display-create-popup', _t('_bx_dev_frm_txt_displays_create_popup'), $this->_oTemplate->parseHtmlByName('form_add_display.html', array(
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+
+    public function performActionEdit()
+    {
+        $sAction = 'edit';
+        $sFormObject = $this->oModule->_oConfig->getObject('form_forms_display');
+        $sFormDisplay = $this->oModule->_oConfig->getObject('form_display_forms_display_edit');
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $iId = (int)bx_get('id');
+            if(!$iId) {
+                echoJson(array());
+                exit;
+            }
+
+            $aIds = array($iId);
+        }
+
+        $iId = $aIds[0];
+
+        $aDisplay = array();
+        $iDisplay = $this->oDb->getDisplays(array('type' => 'by_id', 'value' => $iId), $aDisplay);
+        if($iDisplay != 1 || empty($aDisplay)){
+            echoJson(array());
+            exit;
+        }
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->oModule->_oTemplate);
+
+        $this->_fillDisplayForm($oForm, $sAction);
+        $oForm->aInputs['controls'][0]['value'] = _t('_bx_dev_frm_btn_displays_save');
+
+        $oForm->initChecker($aDisplay);
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($iId) !== false)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_dev_frm_err_displays_edit'));
+
+            echoJson($aRes);
+        } else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-frm-display-edit-popup', _t('_bx_dev_frm_txt_displays_edit_popup', _t($aDisplay['title'])), $this->_oTemplate->parseHtmlByName('form_add_display.html', array(
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+
+    protected function _getActionAdd($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if($this->sObject == '')
+            $isDisabled = true;
+
+        return  parent::_getActionDefault($sType, $sKey, $a, false, $isDisabled, $aRow);
+    }
+
+    protected function _fillDisplayForm(&$oForm, $sAction)
+    {
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction . '&object=' . $this->sObject;
+        $oForm->aInputs['module']['values'] = array_merge(array('' => _t('_bx_dev_frm_txt_select_module')), BxDolStudioUtils::getModules());
+        $oForm->aInputs['module']['value'] = $this->sModule;
+
+        $aForms = array();
+        $this->oDb->getForms(array('type' => 'by_module', 'value' => $this->sModule), $aForms, false);
+        foreach($aForms as $aForm)
+            $oForm->aInputs['object']['values'][$aForm['object']] = _t($aForm['title']);
+
+        asort($oForm->aInputs['object']['values']);
+        $oForm->aInputs['object']['values'] = array_merge(array('' => _t('_bx_dev_frm_txt_select_object')), $oForm->aInputs['object']['values']);
+        $oForm->aInputs['object']['value'] = $this->sObject;
+    }
+}
+/** @} */

+ 755 - 0
modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevFormsField.php

@@ -0,0 +1,755 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Developer Developer
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+require_once('BxDevFunctions.php');
+
+class BxDevFormsField extends BxTemplStudioFormsField
+{
+    function __construct($aParams = array(), $aField = array())
+    {
+        parent::__construct($aParams, $aField);
+
+        $this->aTypes = array_merge($this->aTypes, array(
+        	'captcha' => array('add' => 1),
+        	'location' => array('add' => 1), 
+        	'custom' => array('add' => 1)
+        ));
+    }
+}
+
+class BxDevFormsFieldBlockHeader extends BxTemplStudioFormsFieldBlockHeader
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldBlockEnd extends BxTemplStudioFormsFieldBlockEnd
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldValue extends BxTemplStudioFormsFieldValue
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldText extends BxTemplStudioFormsFieldText
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldPassword extends BxTemplStudioFormsFieldPassword
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldTextarea extends BxTemplStudioFormsFieldTextarea
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+
+        $this->aForm['inputs'] = $this->addInArray($this->aForm['inputs'], 'required', array(
+            'unique' => $this->aFieldUnique
+        ));
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldNumber extends BxTemplStudioFormsFieldNumber
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldDatepicker extends BxTemplStudioFormsFieldDatepicker
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldDateselect extends BxTemplStudioFormsFieldDateselect
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldDatetime extends BxTemplStudioFormsFieldDatetime
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldCheckbox extends BxTemplStudioFormsFieldCheckbox
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+
+        $this->aForm['inputs']['value']['type'] = 'text';
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldSwitcher extends BxTemplStudioFormsFieldSwitcher
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+
+        $this->aForm['inputs']['value']['type'] = 'text';
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldFile extends BxTemplStudioFormsFieldFile
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldFiles extends BxTemplStudioFormsFieldFiles
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldSlider extends BxTemplStudioFormsFieldSlider
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+
+        $this->aForm['inputs'] = $this->addInArray($this->aForm['inputs'], 'required', array(
+            'unique' => $this->aFieldUnique
+        ));
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldDoublerange extends BxTemplStudioFormsFieldDoublerange
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+
+        $this->aForm['inputs'] = $this->addInArray($this->aForm['inputs'], 'required', array(
+            'unique' => $this->aFieldUnique
+        ));
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldHidden extends BxTemplStudioFormsFieldHidden
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldButton extends BxTemplStudioFormsFieldButton
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldReset extends BxTemplStudioFormsFieldReset
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldSubmit extends BxTemplStudioFormsFieldSubmit
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldImage extends BxTemplStudioFormsFieldImage
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldSelect extends BxTemplStudioFormsFieldSelect
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+
+        $this->aForm['inputs'] = $this->addInArray($this->aForm['inputs'], 'required', array(
+            'unique' => $this->aFieldUnique
+        ));
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldSelectMultiple extends BxTemplStudioFormsFieldSelectMultiple
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+
+        $this->aForm['inputs'] = $this->addInArray($this->aForm['inputs'], 'required', array(
+            'unique' => $this->aFieldUnique
+        ));
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldCheckboxSet extends BxTemplStudioFormsFieldCheckboxSet
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+
+        $this->aForm['inputs'] = $this->addInArray($this->aForm['inputs'], 'required', array(
+            'unique' => $this->aFieldUnique
+        ));
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldRadioSet extends BxTemplStudioFormsFieldRadioSet
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+
+        $this->aForm['inputs'] = $this->addInArray($this->aForm['inputs'], 'required', array(
+            'unique' => $this->aFieldUnique
+        ));
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldCustom extends BxTemplStudioFormsFieldCustom
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldInputSet extends BxTemplStudioFormsFieldInputSet
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldCaptcha extends BxTemplStudioFormsFieldCaptcha
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+
+class BxDevFormsFieldLocation extends BxTemplStudioFormsFieldLocation
+{
+    public function init()
+    {
+        parent::init();
+
+        BxDevFunctions::changeFormField($this->aParams, $this->aForm['inputs'], $this->oDb);
+    }
+
+    protected function getFormAdd($sAction, $sObject)
+    {
+        $aForm = parent::getFormAdd($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+
+    protected function getFormEdit($sAction, $sObject)
+    {
+        $aForm = parent::getFormEdit($sAction, $sObject);
+        BxDevFunctions::changeForm($sAction, $aForm, $this);
+        return $aForm;
+    }
+}
+/** @} */

+ 190 - 0
modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevFormsForms.php

@@ -0,0 +1,190 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Developer Developer
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxDevFormsForms extends BxTemplStudioFormsForms
+{
+    protected $oModule;
+
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+
+        $this->oModule = BxDolModule::getInstance('bx_developer');
+        $this->sUrlViewDisplays = BX_DOL_URL_STUDIO . 'module.php?name=' . $this->oModule->_oConfig->getName() . '&page=forms&form_page=displays&form_module=%s&form_object=%s';
+
+        $this->_aOptions['actions_single']['export']['attr']['title'] = _t('_bx_dev_frm_btn_forms_gl_export');
+    }
+
+    public function performActionAdd()
+    {
+        $sAction = 'add';
+        $sFormObject = $this->oModule->_oConfig->getObject('form_forms_form');
+        $sFormDisplay = $this->oModule->_oConfig->getObject('form_display_forms_form_add');
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+        $oForm->aInputs['module']['values'] = array_merge(array('' => _t('_bx_dev_frm_txt_select_module')), BxDolStudioUtils::getModules());
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $sObject = uriGenerate($oForm->getCleanValue('object'), 'sys_objects_form', 'object', ['empty' => 'object']);
+            BxDolForm::setSubmittedValue('object', $sObject, $oForm->aFormAttrs['method']);
+
+            if(($iId = (int)$oForm->insert()) != 0)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_dev_frm_err_forms_create'));
+
+            echoJson($aRes);
+        } else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-frm-form-create-popup', _t('_bx_dev_frm_txt_forms_create_popup'), $this->oModule->_oTemplate->parseHtmlByName('form_add_form.html', array(
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+
+    public function performActionEdit()
+    {
+        $sAction = 'edit';
+        $sFormObject = $this->oModule->_oConfig->getObject('form_forms_form');
+        $sFormDisplay = $this->oModule->_oConfig->getObject('form_display_forms_form_edit');
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $iId = (int)bx_get('id');
+            if(!$iId) {
+                echoJson(array());
+                exit;
+            }
+
+            $aIds = array($iId);
+        }
+
+        $iId = $aIds[0];
+
+        $aForm = array();
+        $this->oDb->getForms(array('type' => 'by_id', 'value' => $iId), $aForm, false);
+        if(empty($aForm) || !is_array($aForm)){
+            echoJson(array());
+            exit;
+        }
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+        $oForm->aInputs['module']['values'] = array_merge(array('' => _t('_bx_dev_frm_txt_select_module')), BxDolStudioUtils::getModules());
+        $oForm->aInputs['controls'][0]['value'] = _t('_bx_dev_frm_btn_forms_save');
+
+        $aForm['form_attrs'] = BxDevFunctions::unserializeString($aForm['form_attrs']);
+        $aForm['params'] = BxDevFunctions::unserializeString($aForm['params']);
+        $oForm->initChecker($aForm);
+
+        if($oForm->isSubmittedAndValid()) {
+            $sObject = $oForm->getCleanValue('object');
+            if(strcmp($sObject, $aForm['object']) != 0) {
+                $sObject = uriGenerate($sObject, 'sys_objects_form', 'object', ['empty' => 'object']);
+                BxDolForm::setSubmittedValue('object', $sObject, $oForm->aFormAttrs['method']);
+            }
+
+            $sValue = BxDolForm::getSubmittedValue('form_attrs', $oForm->aFormAttrs['method']);
+            $sValue = BxDevFunctions::serializeString($sValue);
+            BxDolForm::setSubmittedValue('form_attrs', $sValue, $oForm->aFormAttrs['method']);
+
+            $sValue = BxDolForm::getSubmittedValue('params', $oForm->aFormAttrs['method']);
+            $sValue = BxDevFunctions::serializeString($sValue);
+            BxDolForm::setSubmittedValue('params', $sValue, $oForm->aFormAttrs['method']);
+
+            if($oForm->update($iId) !== false)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_dev_frm_err_forms_edit'));
+
+            echoJson($aRes);
+        } else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-frm-form-edit-popup', _t('_bx_dev_frm_txt_forms_edit_popup', _t($aForm['title'])), $this->oModule->_oTemplate->parseHtmlByName('form_add_form.html', array(
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+
+    public function performActionExport()
+    {
+        $sContentInsert = $sContentDelete = "";
+
+        $aForm = $this->_getItem('getForms');
+        if($aForm === false) {
+            echoJson(array());
+            exit;
+        }
+
+        $sContentInsert .= ($this->oModule->_oDb->getQueryInsert('sys_objects_form', array($aForm), "Dumping data for '" . $aForm['object'] . "' form"));
+        $sContentDelete .= ($this->oModule->_oDb->getQueryDelete('sys_objects_form', 'object', array($aForm), "Deleting data for '" . $aForm['object'] . "' form"));
+
+        $aDisplays = array();
+        $this->oDb->getDisplays(array('type' => 'by_object', 'value' => $aForm['object']), $aDisplays, false);
+        $sContentInsert .= $this->oModule->_oDb->getQueryInsert('sys_form_displays', $aDisplays, false, array('id', 'name'));
+        $sContentDelete .= $this->oModule->_oDb->getQueryDelete('sys_form_displays', 'object', array($aForm), false);
+
+        $aFields = array();
+        $this->oDb->getInputs(array('type' => 'dump_inputs', 'value' => $aForm['object']), $aFields, false);
+        $sContentInsert .= $this->oModule->_oDb->getQueryInsert('sys_form_inputs', $aFields);
+        $sContentDelete .= $this->oModule->_oDb->getQueryDelete('sys_form_inputs', 'object', array($aForm), false);
+
+        $aConnections = array();
+        $this->oDb->getInputs(array('type' => 'dump_connections', 'value' => $aForm['object']), $aConnections, false);
+        $sContentInsert .= $this->oModule->_oDb->getQueryInsert('sys_form_display_inputs', $aConnections);
+        $sContentDelete .= $this->oModule->_oDb->getQueryDelete('sys_form_display_inputs', 'display_name', $aDisplays);
+
+        $aFormStructure = array(
+            'form_attrs' => array(),
+            'inputs' => array (
+                'insert' => array(
+                    'type' => 'textarea',
+                    'name' => 'insert',
+                    'caption' => _t('_bx_dev_frm_txt_forms_export_insert'),
+                    'value' => $sContentInsert,
+                    'code' => 1
+                ),
+                'delete' => array(
+                    'type' => 'textarea',
+                    'name' => 'delete',
+                    'caption' => _t('_bx_dev_frm_txt_forms_export_delete'),
+                    'value' => $sContentDelete,
+                ),
+                'done' => array (
+                    'type' => 'button',
+                    'name' => 'done',
+                    'value' => _t('_bx_dev_frm_btn_forms_done'),
+                    'attrs' => array(
+                        'onclick' => "$('.bx-popup-applied:visible').dolPopupHide()",
+                    ),
+                )
+            )
+        );
+        $oForm = new BxTemplStudioFormView($aFormStructure);
+
+        $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-frm-form-export-popup', _t('_bx_dev_frm_txt_forms_export_popup', _t($aForm['title'])), $this->oModule->_oTemplate->parseHtmlByName('form_export.html', array(
+            'content' => $oForm->getCode()
+        )));
+
+        echoJson(array('popup' => $sContent));
+    }
+}
+/** @} */

+ 166 - 0
modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevFormsPreLists.php

@@ -0,0 +1,166 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Developer Developer
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxDevFormsPreLists extends BxTemplStudioFormsPreLists
+{
+    protected $oModule;
+
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+
+        $this->oModule = BxDolModule::getInstance('bx_developer');
+        $this->sUrlViewValues = BX_DOL_URL_STUDIO . 'module.php?name=' . $this->oModule->_oConfig->getName() . '&page=forms&form_page=pre_values&form_module=%s&form_list=%s';
+    }
+
+    public function performActionAdd()
+    {
+        $sAction = 'add';
+        $sFormObject = $this->oModule->_oConfig->getObject('form_forms_prelist');
+        $sFormDisplay = $this->oModule->_oConfig->getObject('form_display_forms_prelist_add');
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+        $oForm->aInputs['module']['values'] = array_merge(array('' => _t('_bx_dev_frm_txt_select_module')), BxDolStudioUtils::getModules());
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $sObject = uriGenerate($oForm->getCleanValue('key'), 'sys_form_pre_lists', 'key', ['empty' => 'key']);
+            BxDolForm::setSubmittedValue('key', $sObject, $oForm->aFormAttrs['method']);
+
+            if(($iId = (int)$oForm->insert()) != 0)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_dev_frm_err_prelists_create'));
+
+            echoJson($aRes);
+        } else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-frm-prelist-create-popup', _t('_bx_dev_frm_txt_prelists_create_popup'), $this->oModule->_oTemplate->parseHtmlByName('form_add_list.html', array(
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+
+    public function performActionEdit()
+    {
+        $sAction = 'edit';
+        $sFormObject = $this->oModule->_oConfig->getObject('form_forms_prelist');
+        $sFormDisplay = $this->oModule->_oConfig->getObject('form_display_forms_prelist_edit');
+
+        $aList = $this->_getItem('getLists');
+        if($aList === false) {
+            echoJson(array());
+            exit;
+        }
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+        $oForm->aInputs['module']['values'] = array_merge(array('' => _t('_bx_dev_frm_txt_select_module')), BxDolStudioUtils::getModules());
+        $oForm->aInputs['controls'][0]['value'] = _t('_bx_dev_frm_btn_prelists_save');
+
+        $oForm->initChecker($aList);
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($aList['id']) !== false)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $aList['id']);
+            else
+                $aRes = array('msg' => _t('_bx_dev_frm_err_prelists_edit'));
+
+            echoJson($aRes);
+        } else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-frm-prelist-edit-popup', _t('_bx_dev_frm_txt_prelists_edit_popup', _t($aList['title'])), $this->oModule->_oTemplate->parseHtmlByName('form_add_list.html', array(
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+
+    public function performActionExport()
+    {
+        $sContentInsert = $sContentDelete = "";
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $iId = (int)bx_get('id');
+            if(!$iId) {
+                echoJson(array());
+                exit;
+            }
+
+            $aIds = array($iId);
+        }
+
+        $iId = $aIds[0];
+
+        $aList = array();
+        $this->oDb->getLists(array('type' => 'by_id', 'value' => $iId), $aList, false);
+        if(!is_array($aList) || empty($aList)){
+            echoJson(array());
+            exit;
+        }
+
+        $sContentInsert .= ($this->oModule->_oDb->getQueryInsert('sys_form_pre_lists', array($aList), "Dumping data for '" . $aList['key'] . "' data list"));
+        $sContentDelete .= ($this->oModule->_oDb->getQueryDelete('sys_form_pre_lists', 'key', array($aList), "Deleting data for '" . $aList['key'] . "' data list"));
+
+        $aValues = array();
+        $this->oDb->getValues(array('type' => 'by_key', 'value' => $aList['key']), $aValues, false);
+        $sContentInsert .= $this->oModule->_oDb->getQueryInsert('sys_form_pre_values', $aValues, false, array('id', 'key', 'value', 'lkey', 'lkey2', 'data', 'order'));
+        $sContentDelete .= $this->oModule->_oDb->getQueryDelete('sys_form_pre_values', 'Key', array(array('Key' => $aList['key'])), false);
+
+        $aFormStructure = array(
+            'form_attrs' => array(),
+            'inputs' => array (
+                'insert' => array(
+                    'type' => 'textarea',
+                    'name' => 'insert',
+                    'caption' => _t('_bx_dev_frm_txt_prelists_export_insert'),
+                    'value' => $sContentInsert,
+                ),
+                'delete' => array(
+                    'type' => 'textarea',
+                    'name' => 'delete',
+                    'caption' => _t('_bx_dev_frm_txt_prelists_export_delete'),
+                    'value' => $sContentDelete,
+                ),
+                'done' => array (
+                    'type' => 'button',
+                    'name' => 'done',
+                    'value' => _t('_bx_dev_frm_btn_prelists_done'),
+                    'attrs' => array(
+                        'onclick' => "$('.bx-popup-applied:visible').dolPopupHide()",
+                    ),
+                )
+            )
+        );
+        $oForm = new BxTemplStudioFormView($aFormStructure);
+
+        $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-frm-prelist-export-popup', _t('_bx_dev_frm_txt_prelists_export_popup', _t($aList['title'])), $this->oModule->_oTemplate->parseHtmlByName('form_export.html', array(
+            'content' => $oForm->getCode()
+        )));
+
+        echoJson(array('popup' => $sContent));
+    }
+
+    protected function _canDelete($aList)
+    {
+        return true;
+    }
+}
+
+/** @} */

+ 125 - 0
modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevFormsSearchForms.php

@@ -0,0 +1,125 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Developer Developer
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxDevFormsSearchForms extends BxTemplStudioFormsSearchForms
+{
+    protected $oModule;
+
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+
+        $this->oModule = BxDolModule::getInstance('bx_developer');
+        $this->sUrlViewFields = BX_DOL_URL_STUDIO . 'module.php?name=' . $this->oModule->_oConfig->getName() . '&page=forms&form_page=search_fields&form_module=%s&form_form=%s';
+
+        $this->_aOptions['actions_single']['edit']['attr']['title'] = _t('_bx_dev_frm_btn_search_forms_gl_edit');
+    }
+
+    public function performActionAdd()
+    {
+        $sAction = 'add';
+        $sFormObject = $this->oModule->_oConfig->getObject('form_forms_search_form');
+        $sFormDisplay = $this->oModule->_oConfig->getObject('form_display_forms_search_form_add');
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+
+        $oForm->aInputs['module']['values'] = array_merge(array('' => _t('_bx_dev_frm_txt_select_module')), BxDolStudioUtils::getModules());
+        $oForm->aInputs['object_content_info']['values'] = array('' => _t('_bx_dev_frm_txt_select_object_content_info'));
+        $aCiObjects = BxDolContentInfo::getSystems();
+        foreach($aCiObjects as $aCiObject)
+            $oForm->aInputs['object_content_info']['values'][$aCiObject['name']] = _t($aCiObject['title']);
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $sObject = uriGenerate($oForm->getCleanValue('object'), 'sys_objects_search_extended', 'object', ['empty' => 'object']);
+            BxDolForm::setSubmittedValue('object', $sObject, $oForm->aFormAttrs['method']);
+
+            if(($iId = (int)$oForm->insert()) != 0)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_dev_frm_err_search_forms_create'));
+
+            return echoJson($aRes);
+        }
+
+        $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-frm-search-form-create-popup', _t('_bx_dev_frm_txt_search_forms_create_popup'), $this->oModule->_oTemplate->parseHtmlByName('form_add_search_form.html', array(
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true),
+            'object' => $this->_sObject,
+            'action' => $sAction
+        )));
+
+        return echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+
+    public function performActionEdit()
+    {
+        $sAction = 'edit';
+        $sFormObject = $this->oModule->_oConfig->getObject('form_forms_search_form');
+        $sFormDisplay = $this->oModule->_oConfig->getObject('form_display_forms_search_form_edit');
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $iId = (int)bx_get('id');
+            if(!$iId) {
+                echoJson(array());
+                exit;
+            }
+
+            $aIds = array($iId);
+        }
+
+        $iId = $aIds[0];
+
+        $aForm = array();
+        $this->oDb->getSearchForms(array('type' => 'by_id', 'id' => $iId), $aForm, false);
+        if(empty($aForm) || !is_array($aForm)){
+            echoJson(array());
+            exit;
+        }
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+        $oForm->aInputs['module']['values'] = array_merge(array('' => _t('_bx_dev_frm_txt_select_module')), BxDolStudioUtils::getModules());
+        $oForm->aInputs['object_content_info']['values'] = array('' => _t('_bx_dev_frm_txt_select_object_content_info'));
+        $aCiObjects = BxDolContentInfo::getSystems();
+        foreach($aCiObjects as $aCiObject)
+            $oForm->aInputs['object_content_info']['values'][$aCiObject['name']] = _t($aCiObject['title']);
+        $oForm->aInputs['controls'][0]['value'] = _t('_bx_dev_frm_btn_search_forms_save');
+
+        $oForm->initChecker($aForm);
+        if($oForm->isSubmittedAndValid()) {
+            $sObject = $oForm->getCleanValue('object');
+            if(strcmp($sObject, $aForm['object']) != 0) {
+                $sObject = uriGenerate($sObject, 'sys_objects_search_extended', 'object', ['empty' => 'object']);
+                BxDolForm::setSubmittedValue('object', $sObject, $oForm->aFormAttrs['method']);
+            }
+
+            if($oForm->update($iId) !== false)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_dev_frm_err_forms_edit'));
+
+            return echoJson($aRes);
+        }
+
+        $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-frm-search-form-edit-popup', _t('_bx_dev_frm_txt_search_forms_edit_popup', _t($aForm['title'])), $this->oModule->_oTemplate->parseHtmlByName('form_add_search_form.html', array(
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true),
+            'object' => $this->_sObject,
+            'action' => $sAction
+        )));
+
+        return echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+}
+/** @} */

+ 137 - 0
modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevFunctions.php

@@ -0,0 +1,137 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Developer Developer
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxDevFunctions
+{
+    function __construct() {}
+
+    /*
+     * Is needed to change fields in "Form's Field" creation form.
+     * When the form is inited.
+     *
+     * @see BxDevFormsField
+     */
+    public static function changeFormField($aParams, &$aInputs, &$oDb)
+    {
+        $aInputs['module']['type'] = 'select';
+        $aInputs['module']['values'] = array_merge(array('' => _t('_bx_dev_frm_txt_select_module')), BxDolStudioUtils::getModules());
+        $aInputs['module']['value'] = $aParams['module'];
+
+        $aInputs['object']['type'] = 'select';
+        $aInputs['object']['value'] = $aParams['object'];
+        $aInputs['object']['values'] = array();
+
+    	$aForms = array();
+        $oDb->getForms(array('type' => 'by_module', 'value' => $aParams['module']), $aForms, false);
+        if(!empty($aForms) && is_array($aForms)) {
+	        foreach($aForms as $aForm)
+	            $aInputs['object']['values'][$aForm['object']] = _t($aForm['title']);
+
+	        asort($aInputs['object']['values']);
+        }
+        $aInputs['object']['values'] = array_merge(array('' => _t('_bx_dev_frm_txt_select_object')), $aInputs['object']['values']);
+
+        $aInputs['name']['type'] = 'text';
+
+        $sTrlTypePostfix = '_translatable';
+        $sTrlCheckFuncPostfix = 'Translatable';
+        foreach($aInputs as $sName => $aInput)
+            if(isset($aInput['type']) && stripos($aInput['type'], $sTrlTypePostfix) !== false) {
+                $aInputs[$sName]['type'] = 'text';
+                $aInputs[$sName]['html'] = 0;
+
+                if(isset($aInput['checker']['func']) && stripos($aInput['checker']['func'], $sTrlCheckFuncPostfix) !== false)
+                    $aInputs[$sName]['checker']['func'] = str_ireplace($sTrlCheckFuncPostfix, '', $aInput['checker']['func']);
+            }
+
+        unset($aInputs['required']['attrs']['onchange']);
+        unset($aInputs['checker_func']['attrs']['disabled'], $aInputs['checker_func']['tr_attrs']['style']);
+        unset($aInputs['checker_error']['attrs']['disabled'], $aInputs['checker_error']['tr_attrs']['style']);
+
+        $aFields = array(
+            'editable' => array(
+                'type' => 'switcher',
+                'name' => 'editable',
+                'caption' => _t('_bx_dev_frm_txt_field_title_editable'),
+                'info' => _t('_bx_dev_frm_txt_field_info_editable'),
+                'value' => '1',
+                'required' => '0',
+                'db' => array (
+                    'pass' => 'Int',
+                )
+            ),
+            'deletable' => array(
+                'type' => 'switcher',
+                'name' => 'deletable',
+                'caption' => _t('_bx_dev_frm_txt_field_title_deletable'),
+                'info' => _t('_bx_dev_frm_txt_field_info_deletable'),
+                'value' => '1',
+                'required' => '0',
+                'db' => array (
+                    'pass' => 'Int',
+                )
+            ),
+        );
+        $aInputs = BxDolStudioUtils::addInArray($aInputs, 'controls', $aFields, false);
+    }
+
+    /*
+     * Is needed to change form's array in "Form's Field" add/edit form. 
+     * It's called just before the form is displayed with "getCode" method.
+     *
+     * @see BxDevFormsField
+     */
+    public static function changeForm($sAction, &$aForm, &$oForm)
+    {
+        switch($sAction) {
+            case 'add':
+                break;
+
+            case 'edit':
+                if(isset($aForm['inputs']['checker_func'])) {
+                    if(isset($aForm['inputs']['checker_func']['attrs']['disabled']))
+                        unset($aForm['inputs']['checker_func']['attrs']['disabled']);
+
+                    $sCfValue = $aForm['inputs']['checker_func']['value'];
+                    if(!empty($sCfValue) && !in_array($sCfValue, $oForm->getCheckFunctions()))
+                        $aForm['inputs']['checker_func']['info'] = _t('_adm_form_txt_field_checker_func_info_custom');
+                }
+                break;
+        }
+    }
+
+    public static function serializeString($sValue)
+    {
+        if(empty($sValue))
+            return '';
+
+        $aValue = array();
+        @eval("\$aValue = " . $sValue . ";");
+        if(empty($aValue) || !is_array($aValue))
+            return '';
+
+        return serialize($aValue);
+    }
+
+    public static function unserializeString($sValue)
+    {
+        if(empty($sValue))
+            return '';
+
+        $aValue = @unserialize($sValue);
+        if(empty($aValue) || !is_array($aValue))
+            return '';
+
+        return var_export($aValue, true);
+    }
+}
+
+/** @} */

+ 175 - 0
modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevNavigationMenus.php

@@ -0,0 +1,175 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Developer Developer
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxDevNavigationMenus extends BxTemplStudioNavigationMenus
+{
+    protected $oModule;
+
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+
+        $this->_aOptions['actions_single']['export']['attr']['title'] = _t('_bx_dev_nav_btn_menus_gl_export');
+
+        $this->oModule = BxDolModule::getInstance('bx_developer');
+        $this->sUrlViewItems = BX_DOL_URL_STUDIO . 'module.php?name=' . $this->oModule->_oConfig->getName() . '&page=navigation&nav_page=items&nav_module=%s&nav_set=%s';
+    }
+
+    public function performActionAdd()
+    {
+        $sAction = 'add';
+        $sFormObject = $this->oModule->_oConfig->getObject('form_nav_menu');
+        $sFormDisplay = $this->oModule->_oConfig->getObject('form_display_nav_menu_add');
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+        $this->fillInSelects($oForm->aInputs);
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $sObject = uriGenerate($oForm->getCleanValue('object'), 'sys_objects_menu', 'object', ['empty' => 'object']);
+            BxDolForm::setSubmittedValue('object', $sObject, $oForm->aFormAttrs['method']);
+
+            if(($iId = (int)$oForm->insert()) != 0)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_dev_nav_err_menus_create'));
+
+            echoJson($aRes);
+        } else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-nav-menu-create-popup', _t('_bx_dev_nav_txt_menus_create_popup'), $this->oModule->_oTemplate->parseHtmlByName('nav_add_menu.html', array(
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+
+    public function performActionEdit()
+    {
+        $sAction = 'edit';
+        $sFormObject = $this->oModule->_oConfig->getObject('form_nav_menu');
+        $sFormDisplay = $this->oModule->_oConfig->getObject('form_display_nav_menu_edit');
+
+        $aMenu = $this->_getItem('getMenus');
+        if($aMenu === false) {
+            echoJson(array());
+            exit;
+        }
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+        $oForm->aInputs['controls'][0]['value'] = _t('_bx_dev_nav_btn_menus_save');
+        $this->fillInSelects($oForm->aInputs);
+
+        $oForm->initChecker($aMenu);
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($aMenu['id']) !== false)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $aMenu['id']);
+            else
+                $aRes = array('msg' => _t('_bx_dev_nav_err_menus_edit'));
+
+            echoJson($aRes);
+        } else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-nav-menu-edit-popup', _t('_bx_dev_nav_txt_menus_edit_popup', _t($aMenu['title'])), $this->oModule->_oTemplate->parseHtmlByName('nav_add_menu.html', array(
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+
+    public function performActionExport()
+    {
+        $sContentInsert = $sContentDelete = "";
+
+        $aMenu = $this->_getItem('getMenus');
+        if($aMenu === false) {
+            echoJson(array());
+            exit;
+        }
+
+        $sContentInsert .= $this->oModule->_oDb->getQueryInsert('sys_objects_menu', array($aMenu), "Dumping data for '" . $aMenu['object'] . "' menu");
+        $sContentDelete .= $this->oModule->_oDb->getQueryDelete('sys_objects_menu', 'object', array($aMenu), "Deleting data for '" . $aMenu['object'] . "' menu");
+
+        $aSet = array();
+        $this->oDb->getSets(array('type' => 'dump_by_name', 'value' => $aMenu['set_name']), $aSet, false);
+        $sContentInsert .= $this->oModule->_oDb->getQueryInsert('sys_menu_sets', array($aSet), false, array('name'));
+        $sContentDelete .= $this->oModule->_oDb->getQueryDelete('sys_menu_sets', 'set_name', array($aSet), false);
+
+        $aItems = array();
+        $this->oDb->getItems(array('type' => 'by_set_name', 'value' => $aMenu['set_name']), $aItems, false);
+        $sContentInsert .= $this->oModule->_oDb->getQueryInsert('sys_menu_items', $aItems);
+        $sContentDelete .= $this->oModule->_oDb->getQueryDelete('sys_menu_items', 'set_name', array($aSet), false);
+
+        $aFormStructure = array(
+            'form_attrs' => array(),
+            'inputs' => array (
+                'insert' => array(
+                    'type' => 'textarea',
+                    'name' => 'insert',
+                    'caption' => _t('_bx_dev_nav_txt_menus_export_insert'),
+                    'value' => $sContentInsert,
+                ),
+                'delete' => array(
+                    'type' => 'textarea',
+                    'name' => 'delete',
+                    'caption' => _t('_bx_dev_nav_txt_menus_export_delete'),
+                    'value' => $sContentDelete,
+                ),
+                'done' => array (
+                    'type' => 'button',
+                    'name' => 'done',
+                    'value' => _t('_bx_dev_nav_btn_menus_done'),
+                    'attrs' => array(
+                        'onclick' => "$('.bx-popup-applied:visible').dolPopupHide()",
+                    ),
+                )
+            )
+        );
+        $oForm = new BxTemplStudioFormView($aFormStructure);
+
+        $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-nav-menu-export-popup', _t('_bx_dev_nav_txt_menus_export_popup', _t($aMenu['title'])), $this->oModule->_oTemplate->parseHtmlByName('nav_export.html', array(
+            'content' => $oForm->getCode()
+        )));
+
+        echoJson(array('popup' => $sContent));
+    }
+
+    private function fillInSelects(&$aInputs)
+    {
+        $aInputs['module']['values'] = array_merge(array('' => _t('_bx_dev_nav_txt_select_module')), BxDolStudioUtils::getModules());
+        $aInputs['set_name']['values'] = array(
+            array('key' => '', 'value' => _t('_bx_dev_nav_txt_menus_set_name_select'))
+        );
+
+        $aSets = array();
+        $this->oDb->getSets(array('type' => 'all'), $aSets, false);
+        foreach($aSets as $sSet)
+            $aInputs['set_name']['values'][] = array('key' => $sSet['name'], 'value' => _t($sSet['title']));
+
+        $aInputs['template_id']['values'] = array(
+            array('key' => '', 'value' => _t('_bx_dev_nav_txt_menus_template_id_select'))
+        );
+
+        $aTemplates = array();
+        $this->oDb->getTemplates(array('type' => 'all'), $aTemplates, false);
+        foreach($aTemplates as $aTemplate)
+            $aInputs['template_id']['values'][] = array('key' => $aTemplate['id'], 'value' => _t($aTemplate['title']));
+    }
+}
+/** @} */

+ 113 - 0
modules/boonex/developer/updates/13.0.2_13.0.3/source/classes/BxDevNavigationSets.php

@@ -0,0 +1,113 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Developer Developer
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxDevNavigationSets extends BxTemplStudioNavigationSets
+{
+    protected $oModule;
+
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+
+        $this->oModule = BxDolModule::getInstance('bx_developer');
+        $this->sUrlViewItems = BX_DOL_URL_STUDIO . 'module.php?name=' . $this->oModule->_oConfig->getName() . '&page=navigation&nav_page=items&nav_module=%s&nav_set=%s';
+    }
+
+    public function performActionAdd()
+    {
+        $sAction = 'add';
+        $sFormObject = $this->oModule->_oConfig->getObject('form_nav_set');
+        $sFormDisplay = $this->oModule->_oConfig->getObject('form_display_nav_set_add');
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+        $oForm->aInputs['module']['values'] = array_merge(array('' => _t('_bx_dev_nav_txt_select_module')), BxDolStudioUtils::getModules());
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $sName = uriGenerate($oForm->getCleanValue('set_name'), 'sys_menu_sets', 'set_name', ['empty' => 'set']);
+            BxDolForm::setSubmittedValue('set_name', $sName, $oForm->aFormAttrs['method']);
+
+            if($oForm->insert() !== false)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $sName);
+            else
+                $aRes = array('msg' => _t('_bx_dev_nav_err_sets_create'));
+
+            echoJson($aRes);
+        } else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-nav-set-create-popup', _t('_bx_dev_nav_txt_sets_create_popup'), $this->_oTemplate->parseHtmlByName('nav_add_set.html', array(
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+
+    public function performActionEdit()
+    {
+	    $sAction = 'edit';
+	    $sFormObject = $this->oModule->_oConfig->getObject('form_nav_set');
+        $sFormDisplay = $this->oModule->_oConfig->getObject('form_display_nav_set_edit');
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $sId = bx_get('set_name');
+            if(!$sId) {
+                echoJson(array());
+                exit;
+            }
+
+            $aIds = array($sId);
+        }
+
+        $sId = bx_process_input($aIds[0]);
+
+        $aSet = array();
+        $this->oDb->getSets(array('type' => 'by_name', 'value' => $sId), $aSet, false);
+        if(empty($aSet) || !is_array($aSet)) {
+            echoJson(array());
+            exit;
+        }
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+        $oForm->aInputs['module']['values'] = array_merge(array('' => _t('_bx_dev_frm_txt_select_module')), BxDolStudioUtils::getModules());
+        $oForm->aInputs['controls'][0]['value'] = _t('_bx_dev_frm_btn_displays_save');
+
+        $oForm->initChecker($aSet);
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($sId) !== false)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $sId);
+            else
+                $aRes = array('msg' => _t('_bx_dev_nav_err_sets_edit'));
+
+            echoJson($aRes);
+        } else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-nav-set-edit-popup', _t('_bx_dev_nav_txt_sets_edit_popup', _t($aSet['title'])), $this->_oTemplate->parseHtmlByName('nav_add_set.html', array(
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+
+    protected function _getActionDelete ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        return  parent::_getActionDefault($sType, $sKey, $a, false, $isDisabled, $aRow);
+    }
+}
+/** @} */

+ 69 - 0
modules/boonex/developer/updates/13.0.2_13.0.3/source/install/config.php

@@ -0,0 +1,69 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Developer Developer
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_developer',
+    'title' => 'Developer',
+    'note' => 'Developer tools...',
+    'version' => '13.0.3',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/developer/',
+    'home_uri' => 'developer',
+
+    'db_prefix' => 'bx_dev_',
+    'class_prefix' => 'BxDev',
+
+	/**
+     * Category for language keys.
+     */
+    'language_category' => 'BoonEx Developer',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    ),
+    'disable' => array(
+        'execute_sql' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+);
+
+/** @} */

+ 51 - 0
modules/boonex/donations/updates/13.0.2_13.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Donations',
+    'version_from' => '13.0.2',
+    'version_to' => '13.0.3',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/donations/updates/update_13.0.2_13.0.3/',
+    'home_uri' => 'donations_update_1302_1303',
+
+    'module_dir' => 'boonex/donations/',
+    'module_uri' => 'donations',
+
+    'db_prefix' => 'bx_donations_',
+    'class_prefix' => 'BxDonations',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Donations',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/donations/updates/13.0.2_13.0.3/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxDonationsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 6 - 0
modules/boonex/donations/updates/13.0.2_13.0.3/install/sql/enable.sql

@@ -0,0 +1,6 @@
+-- PAGES
+UPDATE `sys_pages_blocks` SET `tabs`='0' WHERE `object`='bx_donations_list' AND `title`='_bx_donations_page_block_title_list';
+
+UPDATE `sys_pages_blocks` SET `tabs`='0' WHERE `object`='bx_donations_list_all' AND `title`='_bx_donations_page_block_title_list_all';
+
+UPDATE `sys_objects_menu` SET `template_id`='26' WHERE `object`='bx_donations_list_submenu';

+ 154 - 0
modules/boonex/donations/updates/13.0.2_13.0.3/source/classes/BxDonationsConfig.php

@@ -0,0 +1,154 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Donations Donations
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxDonationsConfig extends BxBaseModGeneralConfig
+{
+    protected $_oDb;
+    protected $_aHtmlIds;
+
+    protected $_iOwner;
+    protected $_bShowTitle;
+    protected $_bEnableOther;
+    protected $_aBillingTypes;
+    protected $_aPeriodUnits;
+
+    public function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->CNF = array (
+            // module icon
+            'ICON' => 'donate col-blue3',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'entries',
+            'TABLE_ENTRIES_DELETED' => $aModule['db_prefix'] . 'entries_deleted',
+            'TABLE_TYPES' => $aModule['db_prefix'] . 'types',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_NAME' => 'name',
+            'FIELD_TITLE' => 'title',
+            'FIELD_PERIOD' => 'period',
+            'FIELD_PERIOD_UNIT' => 'period_unit',
+            'FIELD_AMOUNT' => 'amount',
+            'FIELD_CUSTOM' => 'custom',
+
+            // page URIs
+            'URL_MAKE' => 'page.php?i=donations-make',
+            'URL_LIST' => 'page.php?i=donations-list',
+            'URL_LIST_ALL' => 'page.php?i=donations-list-all',
+
+            // some params
+            'PARAM_SHOW_TITLE' => 'bx_donations_show_title',
+            'PARAM_ENABLE_OTHER' => 'bx_donations_enable_other',
+            'PARAM_AMOUNT_PRECISION' => 'bx_donations_amount_precision',
+
+            'PARAM_OTHER_NAME' => 'other',
+            'PARAM_OTHER_PERIOD' => 1,
+            'PARAM_OTHER_PERIOD_UNIT' => 'month',
+            'PARAM_OTHER_PRICE_MIN' => 5,
+
+            // objects 
+            'OBJECT_GRID_LIST' => 'bx_donations_list',
+            'OBJECT_GRID_LIST_ALL' => 'bx_donations_list_all',
+            'OBJECT_GRID_TYPES' => 'bx_donations_types',
+            'OBJECT_FORM_TYPE' => 'bx_donations_type',
+            'OBJECT_FORM_TYPE_DISPLAY_ADD' => 'bx_donations_type_add',
+            'OBJECT_FORM_TYPE_DISPLAY_EDIT' => 'bx_donations_type_edit',
+            'OBJECT_FORM_PRELISTS_PERIOD_UNITS' => 'bx_donations_period_units',
+            'OBJECT_MENU_LIST_SUBMENU' => 'bx_donations_list_submenu',
+
+            // email templates
+            'ETEMPLATE_DONATED' => 'bx_donations_donated',
+        );
+
+        $this->_aJsClasses = array(
+            'main' => 'BxDonationsMain',
+            'form' => 'BxDonationsForm',
+        );
+
+        $this->_aJsObjects = array(
+            'main' => 'oBxDonationsMain',
+            'form' => 'oBxDonationsForm',
+        );
+
+        $sHtmlPrefix = str_replace('_', '-', $this->_sName);
+        $this->_aHtmlIds = array(
+            'popup_type' => $sHtmlPrefix . '-popup-type',
+            'menu_billing_types' => $sHtmlPrefix . '-menu-billing_types',
+            'link_billing_type' => $sHtmlPrefix . '-link-billing-',
+        );
+
+        $oPayments = BxDolPayments::getInstance();
+        $this->_iOwner = (int)$oPayments->getOption('site_admin');
+
+        $this->_aBillingTypes = array(
+            BX_DONATIONS_BTYPE_SINGLE,
+            BX_DONATIONS_BTYPE_RECURRING
+        );
+
+        $this->_aPeriodUnits = BxDolForm::getDataItems($this->CNF['OBJECT_FORM_PRELISTS_PERIOD_UNITS']);
+    }
+
+    public function init(&$oDb)
+    {
+        $this->_oDb = &$oDb;
+
+        $this->_bShowTitle = $this->_oDb->getParam($this->CNF['PARAM_SHOW_TITLE']) == 'on';
+        $this->_bEnableOther = $this->_oDb->getParam($this->CNF['PARAM_ENABLE_OTHER']) == 'on';
+    }
+
+    public function getHtmlIds($sKey = '')
+    {
+        if(empty($sKey))
+            return $this->_aHtmlIds;
+
+        return isset($this->_aHtmlIds[$sKey]) ? $this->_aHtmlIds[$sKey] : '';
+    }
+    
+    public function getOwner()
+    {
+    	return $this->_iOwner;
+    }
+
+    public function isShowTitle()
+    {
+        return $this->_bShowTitle;
+    }
+
+    public function isEnableOther()
+    {
+        return $this->_bEnableOther;
+    }
+
+    public function getBillingTypes()
+    {
+        return $this->_aBillingTypes;
+    }
+
+    public function getPeriodUnits()
+    {
+        return $this->_aPeriodUnits;
+    }
+
+    public function getTypeName($sName)
+    {
+        return uriGenerate($sName, $this->CNF['TABLE_TYPES'], $this->CNF['FIELD_NAME'], ['lowercase' => false]);
+    }
+
+    public function getTypeNameCustom()
+    {
+        return $this->getTypeName($this->CNF['PARAM_OTHER_NAME'] . '_' . bx_get_logged_profile_id());
+    }
+}
+
+/** @} */

+ 71 - 0
modules/boonex/donations/updates/13.0.2_13.0.3/source/install/config.php

@@ -0,0 +1,71 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Donations Donations
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_donations',
+    'title' => 'Donations',
+    'note' => 'Donations custom module.',
+    'version' => '13.0.3',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/donations/',
+    'home_uri' => 'donations',
+
+    'db_prefix' => 'bx_donations_',
+    'class_prefix' => 'BxDonations',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Donations',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+);
+
+/** @} */

+ 114 - 0
modules/boonex/donations/updates/13.0.2_13.0.3/source/install/sql/enable.sql

@@ -0,0 +1,114 @@
+SET @sName = 'bx_donations';
+
+
+-- SETTINGS
+SET @iTypeOrder = (SELECT MAX(`order`) FROM `sys_options_types` WHERE `group` = 'modules');
+INSERT INTO `sys_options_types`(`group`, `name`, `caption`, `icon`, `order`) VALUES 
+('modules', @sName, '_bx_donations', 'bx_donations@modules/boonex/donations/|std-icon.svg', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, @sName, '_bx_donations', 10);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+('bx_donations_show_title', '', @iCategId, '_bx_donations_option_show_title', 'checkbox', '', '', '', 1),
+('bx_donations_enable_other', '', @iCategId, '_bx_donations_option_enable_other', 'checkbox', '', '', '', 2),
+('bx_donations_amount_precision', '2', @iCategId, '_bx_donations_option_amount_precision', 'digit', '', '', '', 10);
+
+
+-- PAGE: make
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_donations_make', '_bx_donations_page_title_sys_make', '_bx_donations_page_title_make', @sName, 5, 2147483647, 1, 'donations-make', 'page.php?i=donations-make', '', '', '', 0, 1, 0, '', '');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_donations_make', 1, @sName, '_bx_donations_page_block_title_system_make', '_bx_donations_page_block_title_make', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:12:"bx_donations";s:6:"method";s:14:"get_block_make";}', 0, 1, 1);
+
+-- PAGE: list own
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_donations_list', '_bx_donations_page_title_sys_list', '_bx_donations_page_title_list', @sName, 5, 2147483647, 1, 'donations-list', '', '', '', '', 0, 1, 0, 'BxDonationsPageList', 'modules/boonex/donations/classes/BxDonationsPageList.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `submenu`, `tabs`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_donations_list', 1, @sName, '', '_bx_donations_page_block_title_list', 11, 'bx_donations_list_submenu', 0, 2147483647, 'service', 'a:2:{s:6:"module";s:12:"bx_donations";s:6:"method";s:14:"get_block_list";}', 0, 0, 1, 1);
+
+-- PAGE: list all
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_donations_list_all', '_bx_donations_page_title_sys_list_all', '_bx_donations_page_title_list_all', @sName, 5, 192, 1, 'donations-list-all', '', '', '', '', 0, 1, 0, 'BxDonationsPageList', 'modules/boonex/donations/classes/BxDonationsPageList.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `submenu`, `tabs`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_donations_list_all', 1, @sName, '', '_bx_donations_page_block_title_list_all', 11, 'bx_donations_list_submenu', 0, 192, 'service', 'a:2:{s:6:"module";s:12:"bx_donations";s:6:"method";s:18:"get_block_list_all";}', 0, 0, 1, 0);
+
+
+-- MENU: licenses submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_donations_list_submenu', '_bx_donations_menu_title_list_submenu', 'bx_donations_list_submenu', @sName, 26, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_donations_list_submenu', @sName, '_bx_donations_menu_set_title_list_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_donations_list_submenu', @sName, 'donations-list-all', '_bx_donations_menu_item_title_system_list_submenu_list_all', '_bx_donations_menu_item_title_list_submenu_list_all', 'page.php?i=donations-list-all', '', '_self', '', '', '', 192, 1, 0, 1, 1),
+('bx_donations_list_submenu', @sName, 'donations-list', '_bx_donations_menu_item_title_system_list_submenu_list', '_bx_donations_menu_item_title_list_submenu_list', 'page.php?i=donations-list', '', '_self', '', '', '', 2147483646, 1, 0, 1, 2);
+
+-- MENU: add to site menu
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' AND `active` = 1 AND `order` < 9999 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_site', @sName, 'donations-make', '_bx_donations_menu_item_title_system_make', '_bx_donations_menu_item_title_make', 'page.php?i=donations-make', '', '', 'donate col-blue3', '', 2147483647, 1, 1, IFNULL(@iSiteMenuOrder, 0) + 1);
+
+-- MENU: add to homepage menu
+SET @iHomepageMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_homepage' AND `active` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_homepage', @sName, 'donations-make', '_bx_donations_menu_item_title_system_make', '_bx_donations_menu_item_title_make', 'page.php?i=donations-make', '', '', 'donate col-blue3', '', 2147483647, 1, 1, IFNULL(@iHomepageMenuOrder, 0) + 1);
+
+-- MENU: account dashboard
+SET @iDashboardMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard' LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES
+('sys_account_dashboard', @sName, 'dashboard-donations-list', '_bx_donations_menu_item_title_system_list', '_bx_donations_menu_item_title_list', 'page.php?i=donations-list', '', '', 'donate col-blue3', '', '', 2147483646, 1, 0, 1, @iDashboardMenuOrder + 1);
+
+
+-- GRIDS: types
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_donations_types', 'Sql', 'SELECT * FROM `bx_donations_types` WHERE 1 AND `custom`=''0'' ', 'bx_donations_types', 'id', 'order', 'active', '', 100, NULL, 'start', '', 'name,period,period_unit,amount', 'title', 'like', '', '', 192, 'BxDonationsGridTypes', 'modules/boonex/donations/classes/BxDonationsGridTypes.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_donations_types', 'checkbox', '_sys_select', '1%', 0, 0, '', 1),
+('bx_donations_types', 'order', '', '1%', 0, 0, '', 2),
+('bx_donations_types', 'switcher', '_bx_donations_grid_column_active', '8%', 0, '', '', 3),
+('bx_donations_types', 'name', '_bx_donations_grid_column_name', '20%', 0, 32, '', 4),
+('bx_donations_types', 'title', '_bx_donations_grid_column_title', '20%', 1, 32, '', 5),
+('bx_donations_types', 'amount', '_bx_donations_grid_column_amount', '15%', 0, 8, '', 6),
+('bx_donations_types', 'period', '_bx_donations_grid_column_period', '15%', 0, 8, '', 7),
+('bx_donations_types', 'actions', '', '20%', 0, '', '', 8);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_donations_types', 'independent', 'add', '_bx_donations_grid_action_add', '', 0, 0, 1),
+('bx_donations_types', 'single', 'edit', '_bx_donations_grid_action_edit', 'pencil-alt', 1, 0, 1),
+('bx_donations_types', 'single', 'delete', '_bx_donations_grid_action_delete', 'remove', 1, 1, 2),
+('bx_donations_types', 'bulk', 'delete', '_bx_donations_grid_action_delete', '', 0, 1, 1);
+
+-- GRIDS: entries list
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `show_total_count`, `override_class_name`, `override_class_file`) VALUES
+('bx_donations_list_all', 'Sql', 'SELECT `te`.`id` AS `id`, `te`.`profile_id` AS `profile_id`, `te`.`type_id` AS `type_id`, `tt`.`title` AS `type_title`, `tt`.`amount` AS `type_amount`, `tt`.`period` AS `type_period`, `tt`.`period_unit` AS `type_period_unit`, `te`.`order` AS `transaction`, `te`.`added` AS `added` FROM `bx_donations_entries` AS `te` LEFT JOIN `bx_donations_types` AS `tt` ON `te`.`type_id`=`tt`.`id` WHERE 1 ', 'bx_donations_entries', 'id', 'added', '', '', 20, NULL, 'start', '', 'tt`.`name,tt`.`period,tt`.`period_unit,tt`.`amount,te`.`order', 'tt`.`title', 'like', '', '', 192, 0, 'BxDonationsGridListAll', 'modules/boonex/donations/classes/BxDonationsGridListAll.php'),
+('bx_donations_list', 'Sql', 'SELECT `te`.`id` AS `id`, `te`.`profile_id` AS `profile_id`, `te`.`type_id` AS `type_id`, `tt`.`title` AS `type_title`, `tt`.`amount` AS `type_amount`, `tt`.`period` AS `type_period`, `tt`.`period_unit` AS `type_period_unit`, `te`.`order` AS `transaction`, `te`.`added` AS `added` FROM `bx_donations_entries` AS `te` LEFT JOIN `bx_donations_types` AS `tt` ON `te`.`type_id`=`tt`.`id` WHERE 1 ', 'bx_donations_entries', 'id', 'added', '', '', 20, NULL, 'start', '', 'tt`.`name,tt`.`period,tt`.`period_unit,tt`.`amount,te`.`order', 'tt`.`title', 'like', '', '', 2147483647, 0, 'BxDonationsGridList', 'modules/boonex/donations/classes/BxDonationsGridList.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_donations_list_all', 'profile_id', '_bx_donations_grid_column_title_lst_profile_id', '20%', 0, 0, '', 1),
+('bx_donations_list_all', 'entry', '_bx_donations_grid_column_title_lst_entry', '30%', 0, 0, '', 2),
+('bx_donations_list_all', 'billing_type', '_bx_donations_grid_column_title_lst_billing_type', '10%', 0, 0, '', 3),
+('bx_donations_list_all', 'transaction', '_bx_donations_grid_column_title_lst_transaction', '30%', 0, 32, '', 4),
+('bx_donations_list_all', 'added', '_bx_donations_grid_column_title_lst_added', '10%', 0, 0, '', 5),
+
+('bx_donations_list', 'entry', '_bx_donations_grid_column_title_lst_entry', '45%', 0, 0, '', 1),
+('bx_donations_list', 'billing_type', '_bx_donations_grid_column_title_lst_billing_type', '10%', 0, 0, '', 2),
+('bx_donations_list', 'transaction', '_bx_donations_grid_column_title_lst_transaction', '35%', 0, 32, '', 3),
+('bx_donations_list', 'added', '_bx_donations_grid_column_title_lst_added', '10%', 0, 0, '', 4);
+
+
+-- INJECTIONS
+INSERT INTO `sys_injections` (`name`, `page_index`, `key`, `type`, `data`, `replace`, `active`) VALUES
+(@sName, 0, 'injection_head', 'service', 'a:2:{s:6:"module";s:12:"bx_donations";s:6:"method";s:14:"include_css_js";}', 0, 1);
+
+
+-- EMAIL TEMPLATES
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES 
+(@sName, '_bx_donations_et_txt_name_donated', 'bx_donations_donated', '_bx_donations_et_txt_subject_donated', '_bx_donations_et_txt_body_donated');

+ 51 - 0
modules/boonex/events/updates/13.0.4_13.0.5/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Events',
+    'version_from' => '13.0.4',
+    'version_to' => '13.0.5',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/events/updates/update_13.0.4_13.0.5/',
+    'home_uri' => 'events_update_1304_1305',
+
+    'module_dir' => 'boonex/events/',
+    'module_uri' => 'events',
+
+    'db_prefix' => 'bx_events_',
+    'class_prefix' => 'BxEvents',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Events',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/events/updates/13.0.4_13.0.5/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxEventsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 10 - 0
modules/boonex/events/updates/13.0.4_13.0.5/install/langs/en.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_events_option_enable_subscribe_wo_join"><![CDATA[Allow to mark as Interested without joining (marking as Going)]]></string_add>
+	<string_add name="_bx_events_alert_action_reminder"><![CDATA[reminder]]></string_add>
+    <string_add name="_bx_events_alert_action_reminder_follow_context"><![CDATA[New reminders]]></string_add>
+	<string_add name="_bx_events_txt_ntfs_reminder_1"><![CDATA[Event <b class="bx-ntfs-content-profile">{owner_name}</b> starts in an hour]]></string_add>
+    <string_add name="_bx_events_txt_ntfs_reminder_24"><![CDATA[Event <b class="bx-ntfs-content-profile">{owner_name}</b> starts in 24 hours]]></string_add>
+
+	<string_upd name="_bx_events_form_profile_input_sys_reminder"><![CDATA[Reminder (part of Internal Notifications)]]></string_upd>
+</resources>

+ 15 - 0
modules/boonex/events/updates/13.0.4_13.0.5/install/sql/enable.sql

@@ -0,0 +1,15 @@
+-- SETTINGS
+SET @iCategId = (SELECT `id` FROM `sys_options_categories` WHERE `name`='bx_events' LIMIT 1);
+
+DELETE FROM `sys_options` WHERE `name`='bx_events_enable_subscribe_wo_join';
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+('bx_events_enable_subscribe_wo_join', '', @iCategId, '_bx_events_option_enable_subscribe_wo_join', 'checkbox', '', '', '', 55);
+
+
+-- MENUS
+UPDATE `sys_menu_items` SET `active`='0' WHERE `set_name`='bx_events_menu_manage_tools' AND `name`='delete-with-content';
+
+
+-- GRIDS
+UPDATE `sys_grid_actions` SET `active`='0' WHERE `object`='bx_events_administration' AND `type`='bulk' AND `name`='delete_with_content';
+UPDATE `sys_grid_actions` SET `active`='0' WHERE `object`='bx_events_common' AND `type`='bulk' AND `name`='delete_with_content';

+ 302 - 0
modules/boonex/events/updates/13.0.4_13.0.5/source/classes/BxEventsConfig.php

@@ -0,0 +1,302 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Events Events
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxEventsConfig extends BxBaseModGroupsConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_aMenuItems2MethodsActions = array_merge($this->_aMenuItems2MethodsActions, array(
+            'view-event-profile' => 'checkAllowedView',
+            'edit-event-profile' => 'checkAllowedEdit',
+            'edit-event-cover' => 'checkAllowedChangeCover',
+            'invite-to-event' => 'checkAllowedInvite',
+            'delete-event-profile' => 'checkAllowedDelete',
+            'approve-event-profile' => 'checkAllowedApprove',
+            'ical-export' => 'checkAllowedIcalExport',
+        ));
+
+        $this->CNF = array (
+
+            // module icon
+            'ICON' => 'calendar col-red2',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'data',
+            'TABLE_ENTRIES_FULLTEXT' => 'search_fields',
+            'TABLE_ADMINS' => $aModule['db_prefix'] . 'admins',
+            'TABLE_INVITES' => $aModule['db_prefix'] . 'invites',
+            'TABLE_PRICES' => $aModule['db_prefix'] . 'prices',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => 'author',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => 'changed',
+            'FIELD_PUBLISHED' => 'published',
+            'FIELD_NAME' => 'event_name',
+            'FIELD_TITLE' => 'event_name',
+            'FIELD_TEXT' => 'event_desc',
+            'FIELD_CATEGORY' => 'event_cat',
+            'FIELD_PICTURE' => 'picture',
+            'FIELD_COVER' => 'cover',
+            'FIELD_DATE_START' => 'date_start',
+            'FIELD_DATE_END' => 'date_end',
+            'FIELD_TIMEZONE' => 'timezone',
+            'FIELD_JOIN_CONFIRMATION' => 'join_confirmation',
+            'FIELD_REMINDER' => 'reminder',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_ALLOW_POST_TO' => 'allow_post_to',
+            'FIELD_CF' => 'cf',
+            'FIELD_VIEWS' => 'views',
+            'FIELD_VOTES' => 'votes',
+            'FIELD_COMMENTS' => 'comments',
+            'FIELD_STATUS' => 'status',
+            'FIELD_STATUS_ADMIN' => 'status_admin',
+            'FIELDS_QUICK_SEARCH' => array('event_name'),
+            'FIELD_LOCATION' => 'location',
+            'FIELD_LOCATION_PREFIX' => 'location',
+            'FIELDS_WITH_KEYWORDS' => 'auto', // can be 'auto', array of fields or comma separated string of field names, works only when OBJECT_METATAGS is specified
+            'FIELD_LABELS' => 'labels',
+
+            'FIELD_PRICE_ROLE_ID' => 'role_id',
+            'FIELD_PRICE_NAME' => 'name',
+
+            // page URIs
+            'URI_VIEW_ENTRY' => 'view-event-profile',
+            'URI_EDIT_ENTRY' => 'edit-event-profile',
+            'URI_ENTRIES_BY_CONTEXT' => 'events-context',
+            'URI_EDIT_COVER' => 'edit-event-cover',
+            'URI_JOIN_ENTRY' => 'join-event-profile',
+            'URI_JOINED_ENTRIES' => 'joined-events',
+            'URI_MANAGE_COMMON' => 'events-manage',
+            'URI_FAVORITES_LIST' => 'events-favorites',
+
+            'URL_HOME' => 'page.php?i=events-home',
+            'URL_ENTRY_FANS' => 'page.php?i=event-fans',
+            'URL_MANAGE_COMMON' => 'page.php?i=events-manage',
+            'URL_MANAGE_ADMINISTRATION' => 'page.php?i=events-administration',
+
+            'PARAM_AUTO_APPROVE' => 'bx_events_enable_auto_approve',
+            'PARAM_CHARS_SUMMARY' => 'bx_events_summary_chars',
+            'PARAM_NUM_RSS' => 'bx_events_num_rss',
+            'PARAM_NUM_CONNECTIONS_QUICK' => 'bx_events_num_connections_quick',
+            'PARAM_SEARCHABLE_FIELDS' => 'bx_events_searchable_fields',
+            'PARAM_PUBLIC_SBSD' => 'bx_events_public_subscribed_me',
+            'PARAM_PER_PAGE_BROWSE_SHOWCASE' => 'bx_events_per_page_browse_showcase',
+            'PARAM_PER_PAGE_BROWSE_RECOMMENDED' => 'bx_events_per_page_browse_recommended',
+            'PARAM_MMODE' => 'bx_events_members_mode',
+            'PARAM_PAID_JOIN_ENABLED' => true,
+            'PARAM_RECURRING_RESERVE' => 3, // 3 days for recurring payment to be registered
+            'PARAM_SBS_WO_JOIN' => 'bx_events_enable_subscribe_wo_join',
+            'PARAM_PER_PAGE_FOR_FAVORITES_LISTS' => 'bx_events_per_page_for_favorites_lists',
+            'PARAM_USE_IN' => 'bx_events_internal_notifications',
+
+            // objects
+            'OBJECT_STORAGE' => 'bx_events_pics',
+            'OBJECT_STORAGE_COVER' => 'bx_events_pics',
+            'OBJECT_IMAGES_TRANSCODER_THUMB' => 'bx_events_thumb',
+            'OBJECT_IMAGES_TRANSCODER_ICON' => 'bx_events_icon',
+            'OBJECT_IMAGES_TRANSCODER_AVATAR' => 'bx_events_avatar',
+            'OBJECT_IMAGES_TRANSCODER_AVATAR_BIG' => 'bx_events_avatar_big',
+            'OBJECT_IMAGES_TRANSCODER_PICTURE' => 'bx_events_picture',
+            'OBJECT_IMAGES_TRANSCODER_COVER' => 'bx_events_cover',
+            'OBJECT_IMAGES_TRANSCODER_COVER_THUMB' => 'bx_events_cover_thumb',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => 'bx_events_gallery',
+            'OBJECT_VIEWS' => 'bx_events',
+            'OBJECT_VOTES' => 'bx_events',
+            'OBJECT_SCORES' => 'bx_events',
+            'OBJECT_FAVORITES' => 'bx_events',
+            'OBJECT_FEATURED' => 'bx_events',
+            'OBJECT_COMMENTS' => 'bx_events',
+            'OBJECT_NOTES' => 'bx_events_notes',
+            'OBJECT_REPORTS' => 'bx_events',
+            'OBJECT_METATAGS' => 'bx_events',
+            'OBJECT_CATEGORY' => 'bx_events_cats',
+            'OBJECT_FORM_ENTRY' => 'bx_event',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => 'bx_event_view',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW_FULL' => 'bx_event_view_full', // for "info" tab on view group page
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_event_add',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => 'bx_event_edit',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT_COVER' => 'bx_event_edit_cover',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_event_delete',
+            'OBJECT_FORM_ENTRY_DISPLAY_INVITE' => 'bx_event_invite',
+            'OBJECT_FORM_PRICE' => 'bx_events_price',
+            'OBJECT_FORM_PRICE_DISPLAY_ADD' => 'bx_events_price_add',
+            'OBJECT_FORM_PRICE_DISPLAY_EDIT' => 'bx_events_price_edit',
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_events_view_actions', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_MORE' => 'bx_events_view_actions_more', // actions menu on view entry page for "more" popup
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL' => 'bx_events_view_actions_all', // all actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_events_my', // actions menu on profile entries page
+            'OBJECT_MENU_SUBMENU' => 'bx_events_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => 'bx_events_view_submenu',  // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'events-home', // first item in view entry submenu from main module submenu
+            'OBJECT_MENU_VIEW_ENTRY_META' => 'bx_events_view_meta', // meta menu on view entry page
+            'OBJECT_MENU_SNIPPET_META' => 'bx_events_snippet_meta', // menu for snippet meta info
+            'OBJECT_MENU_MANAGE_TOOLS' => 'bx_events_menu_manage_tools', //manage menu in content administration tools
+            'OBJECT_PAGE_VIEW_ENTRY' => 'bx_events_view_profile',
+            'OBJECT_PAGE_VIEW_ENTRY_CLOSED' => 'bx_events_view_profile_closed',
+            'OBJECT_PRIVACY_VIEW' => 'bx_events_allow_view_to',
+            'OBJECT_PRIVACY_LIST_VIEW' => 'bx_events_allow_view_favorite_list',
+            'OBJECT_PRIVACY_VIEW_NOTIFICATION_EVENT' => 'bx_events_allow_view_notification_to',
+            'OBJECT_PRIVACY_POST' => 'bx_events_allow_post_to',
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_events_administration',
+            'OBJECT_GRID_COMMON' => 'bx_events_common',
+            'OBJECT_GRID_CONNECTIONS' => 'bx_events_fans',
+            'OBJECT_GRID_INVITES' => 'bx_events_invites',
+            'OBJECT_GRID_PRICES_MANAGE' => 'bx_events_prices_manage',
+            'OBJECT_GRID_PRICES_VIEW' => 'bx_events_prices_view',
+            'OBJECT_CONNECTIONS' => 'bx_events_fans',
+            'OBJECT_UPLOADERS_COVER' => array('bx_events_cover_crop'),
+            'OBJECT_UPLOADERS_PICTURE' => array('bx_events_picture_crop'),
+            'OBJECT_PRE_LIST_ROLES' => 'bx_events_roles',
+            'OBJECT_PRE_LIST_PERIOD_UNITS' => 'bx_events_period_units',
+            
+            'BADGES_AVALIABLE' => true,
+            'INVITES_KEYS_LIFETIME' => 86400,
+            'ENABLE_FOR_CONTEXT_IN_MODULES' => array('bx_groups', 'bx_spaces'),
+
+            'EMAIL_INVITATION' => 'bx_events_invitation',
+            'EMAIL_JOIN_REQUEST' => 'bx_events_join_request',
+            'EMAIL_JOIN_CONFIRM' => 'bx_events_join_confirm',
+            'EMAIL_FAN_BECOME_ADMIN' => 'bx_events_fan_become_admin',
+            'EMAIL_ADMIN_BECOME_FAN' => 'bx_events_admin_become_fan',
+            'EMAIL_FAN_REMOVE' => 'bx_events_fan_remove',
+            'EMAIL_FAN_SET_ROLE' => 'bx_events_set_role',
+            'EMAIL_JOIN_REJECT' => 'bx_events_join_reject',
+            'EMAIL_REMINDER' => 'bx_events_reminder',
+
+            'TRIGGER_MENU_PROFILE_VIEW_SUBMENU' => 'trigger_group_view_submenu',
+            'TRIGGER_MENU_PROFILE_SNIPPET_META' => 'trigger_group_snippet_meta',
+            'TRIGGER_MENU_PROFILE_VIEW_ACTIONS' => 'trigger_group_view_actions',
+        	'TRIGGER_PAGE_VIEW_ENTRY' => 'trigger_page_group_view_entry',
+
+            // menu items which visibility depends on custom visibility checking
+            'MENU_ITEM_TO_METHOD' => array (
+                'bx_events_view_actions' => $this->_aMenuItems2MethodsActions,
+                'bx_events_view_actions_more' => $this->_aMenuItems2MethodsActions,
+                'bx_events_view_actions_all' => $this->_aMenuItems2MethodsActions,
+            ),
+
+            // informer messages
+            'INFORMERS' => array (
+                'status' => array (
+                    'name' => 'bx-events-status-not-active',
+                    'map' => array (
+                        BX_PROFILE_STATUS_PENDING => '_bx_events_txt_account_pending',
+                        BX_PROFILE_STATUS_SUSPENDED => '_bx_events_txt_account_suspended',
+                    ),
+                ),
+                'approving' => array (
+                    'name' => 'bx-groups-approving',
+                    'map' => array (
+                        'pending' => array('msg' => '_bx_events_txt_account_pending', 'type' => BX_INFORMER_ALERT),
+                        'hidden' => array('msg' => '_bx_events_txt_status_hidden', 'type' => BX_INFORMER_ERROR),
+                    ),
+                ),
+                'scheduled' => array (
+                    'name' => 'bx-events-scheduled',
+                    'map' => array (
+                        'awaiting' => array('msg' => '_bx_events_txt_scheduled_awaiting', 'type' => BX_INFORMER_ALERT),
+                    ),
+                ),
+            ),
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_events_txt_sample_single',
+            	'txt_sample_single_with_article' => '_bx_events_txt_sample_single_with_article',
+            	'txt_sample_comment_single' => '_bx_events_txt_sample_comment_single',
+                'txt_sample_vote_single' => '_bx_events_txt_sample_vote_single',
+                'txt_sample_score_up_single' => '_bx_events_txt_sample_score_up_single',
+                'txt_sample_score_down_single' => '_bx_events_txt_sample_score_down_single',
+                'txt_private_group' => '_bx_events_txt_private_group',
+                'txt_N_fans' => '_bx_events_txt_N_fans',
+                'txt_ntfs_join_invitation' => '_bx_events_txt_ntfs_join_invitation',
+                'txt_ntfs_join_request' => '_bx_events_txt_ntfs_join_request',
+                'txt_ntfs_fan_added' => '_bx_events_txt_ntfs_fan_added',
+            	'txt_ntfs_timeline_post_common' => '_bx_events_txt_ntfs_timeline_post_common',
+                'option_members_mode_multi_roles' => '_bx_events_option_members_mode_multi_roles',
+                'txt_all_entries_in' => '_bx_events_txt_all_entries_in',
+            	'form_field_author' => '_bx_events_form_profile_input_author',
+                'menu_item_title_befriend_sent' => '_bx_events_menu_item_title_befriend_sent',
+                'menu_item_title_unfriend_cancel_request' => '_bx_events_menu_item_title_unfriend_cancel_request',
+                'menu_item_title_befriend_confirm' => '_bx_events_menu_item_title_befriend_confirm',
+                'menu_item_title_unfriend_reject_request' => '_bx_events_menu_item_title_unfriend_reject_request',
+                'menu_item_title_befriend' => '_bx_events_menu_item_title_befriend',
+                'menu_item_title_unfriend' => '_bx_events_menu_item_title_unfriend',
+                'menu_item_title_subscribe' => '_bx_events_menu_item_title_subscribe',
+                'menu_item_title_unsubscribe' => '_bx_events_menu_item_title_unsubscribe',
+            	'grid_action_err_delete' => '_bx_events_grid_action_err_delete',
+            	'grid_txt_account_manager' => '_bx_events_grid_txt_account_manager',
+                'filter_item_active' => '_bx_events_grid_filter_item_title_adm_active',
+                'filter_item_hidden' => '_bx_events_grid_filter_item_title_adm_hidden',
+            	'filter_item_pending' => '_bx_events_grid_filter_item_title_adm_pending',
+            	'filter_item_suspended' => '_bx_events_grid_filter_item_title_adm_suspended',
+            	'filter_item_select_one_filter1' => '_bx_events_grid_filter_item_title_adm_select_one_filter1',
+                'filter_item_select_one_filter2' => '_bx_events_grid_filter_item_title_adm_select_one_filter2',
+            	'menu_item_manage_my' => '_bx_events_menu_item_title_manage_my',
+                'menu_item_manage_all' => '_bx_events_menu_item_title_manage_all',
+                'menu_item_title_become_fan_sent' => '_bx_events_menu_item_title_become_fan_sent',
+                'menu_item_title_leave_group_cancel_request' => '_bx_events_menu_item_title_leave_group_cancel_request',
+                'menu_item_title_become_fan' => '_bx_events_menu_item_title_become_fan',
+                'menu_item_title_leave_group' => '_bx_events_menu_item_title_leave_group',
+                'menu_item_title_become_fan_sent' => '_bx_events_menu_item_title_become_fan_sent',
+                'menu_item_title_become_fan' => '_bx_events_menu_item_title_become_fan',
+            	'txt_all_entries_by_author' => '_bx_events_page_title_browse_by_author',
+                'txt_all_entries_by_context' => '_bx_events_page_title_browse_by_context',
+                'txt_invitation_popup_title' => '_bx_events_txt_invite_popup_title',
+                'txt_invitation_popup_text' => '_bx_events_txt_invite_popup_text',
+                'txt_invitation_popup_accept_button' => '_bx_events_txt_invite_popup_button_accept',
+                'txt_invitation_popup_decline_button' => '_bx_events_txt_invite_popup_button_decline',
+                'txt_invitation_popup_error_invitation_absent' => '_bx_events_txt_invite_popup_error_invitation_absent',
+                'txt_invitation_popup_error_wrong_user' => '_bx_events_txt_invite_popup_error_invitation_wrong_user',
+                'txt_n_unit' => '_bx_events_txt_n_unit',
+                'txt_buy_title' => '_bx_events_grid_action_title_buy_title',
+                'txt_cart_item_title' => '_bx_events_txt_cart_item_title',
+                'txt_cart_item_title_lifetime' => '_bx_events_txt_cart_item_title_lifetime',
+                'txt_subscribe_title' => '_bx_events_grid_action_title_subscribe_title',
+                'popup_title_price_add' => '_bx_events_popup_title_price_add',
+                'popup_title_price_edit' => '_bx_events_popup_title_price_edit',
+                'msg_performed' => '_bx_events_msg_performed',
+                'err_period_unit' => '_bx_events_form_price_input_err_period_unit',
+                'err_price_duplicate' => '_bx_events_err_price_duplicate',
+                'err_cannot_perform' => '_bx_events_err_cannot_perform',
+            ),
+
+        );
+
+        $this->_aJsClasses = array(
+            'main' => 'BxEventsMain',
+            'entry' => 'BxEventsEntry',
+            'manage_tools' => 'BxEventsManageTools',
+            'invite_popup' => 'BxEventsInvitePopup',
+            'prices' => 'BxEventsPrices'
+        );
+
+        $this->_aJsObjects = array(
+            'main' => 'oBxEventsMain',
+            'entry' => 'oBxEventsEntry',
+            'manage_tools' => 'oBxEventsManageTools',
+            'invite_popup' => 'oBxEventsInvitePopup',
+            'prices' => 'oBxEventsPrices'
+        );
+
+        $this->_aGridObjects = array(
+            'common' => $this->CNF['OBJECT_GRID_COMMON'],
+            'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION']
+        );
+    }
+
+}
+
+/** @} */

+ 190 - 0
modules/boonex/events/updates/13.0.4_13.0.5/source/classes/BxEventsDb.php

@@ -0,0 +1,190 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Events Events
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Groups module database queries
+ */
+class BxEventsDb extends BxBaseModGroupsDb
+{
+    public function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+    }
+
+    public function getContentInfoByIntervalId ($iIntervalId)
+    {
+        $iContentId = $this->getOne("SELECT `event_id` FROM `bx_events_intervals` WHERE `interval_id` = :interval", array(
+            'interval' => $iIntervalId,
+        ));
+        if (!$iContentId)
+            return 0;
+        return $this->getContentInfoById ($iContentId);
+    }
+
+    public function getContentInfoById ($iContentId)
+    {
+        $sQuery = $this->prepare ("SELECT `c`.*, `p`.`account_id`, `p`.`id` AS `profile_id`, `p`.`status` AS `profile_status`, MAX(`i`.`repeat_stop`) AS `repeat_stop` FROM `" . $this->_oConfig->CNF['TABLE_ENTRIES'] . "` AS `c` 
+            INNER JOIN `sys_profiles` AS `p` ON (`p`.`content_id` = `c`.`id` AND `p`.`type` = ?) 
+            LEFT JOIN `bx_events_intervals` as `i` ON (`c`.`id` = `i`.`event_id`)
+            WHERE `c`.`id` = ?
+            GROUP BY `c`.`id`", $this->_oConfig->getName(), $iContentId);
+        return $this->getRow($sQuery);
+    }
+
+    public function deleteIntervalById ($iIntervalId)
+    {
+        return $this->query("DELETE FROM `bx_events_intervals` WHERE `interval_id` = :interval", array(
+            'interval' => $iIntervalId,
+        ));
+    }
+    
+    public function getIntervals ($iContentId) 
+    {
+        return $this->getAllWithKey("SELECT * FROM `bx_events_intervals` WHERE `event_id` = :event_id", 'interval_id', array(
+            'event_id' => $iContentId,
+        ));
+    }
+
+    public function getEntriesByDate($sDateFrom, $sDateTo, $iEventId = 0, $aSQLPart = array())
+    {
+        // validate input data
+        if (false === ($oDateFrom = date_create($sDateFrom, new DateTimeZone('UTC'))))
+            return array();
+        if (false === ($oDateTo = date_create($sDateTo, new DateTimeZone('UTC'))))
+            return array();
+        if ($oDateFrom > $oDateTo)
+            return array();
+
+        $sModule = $this->_oConfig->getName();
+
+        // increase start and end date to cover timezones
+        $oDateFrom = $oDateFrom->sub(new DateInterval("P1D"));
+        $oDateTo = $oDateTo->add(new DateInterval("P1D"));
+
+        // look throught all days in the interval
+        $oDateIter = clone($oDateFrom);
+        $aEntries = array();
+        while ($oDateIter->format('Y-m-d') != $oDateTo->format('Y-m-d')) {
+
+            $oDateMin = date_create($oDateIter->format('Y-m-d') . '00:00:00', new DateTimeZone('UTC'));
+            $oDateMax = date_create($oDateIter->format('Y-m-d') . '23:59:59', new DateTimeZone('UTC'));
+                
+            // get all events for the specific day            
+            $oDateMonthBegin = date_create($oDateIter->format('Y-m-01'), new DateTimeZone('UTC'));
+            $iWeekOfMonth = $oDateIter->format('W') - $oDateMonthBegin->format('W') + 1;
+            $aBindings = array(
+                'timestamp_min' => $oDateMin->getTimestamp(),
+                'timestamp_max' => $oDateMax->getTimestamp(),
+            );
+            $aBindingsRepeating = array(
+                'timestamp_min' => $oDateMin->getTimestamp(),
+                'timestamp_max' => $oDateMax->getTimestamp(),
+                'year_start' => $oDateFrom->format('Y'),
+                'year' => $oDateIter->format('Y'),
+                'month' => $oDateIter->format('n'),
+                'week_of_month' => $iWeekOfMonth > 0 ? $iWeekOfMonth : $oDateIter->format('W') + 1,
+                'day_of_month' => $oDateIter->format('j'),
+                'day_of_week' => $oDateIter->format('N'),
+            );
+            $sJoin = isset($aSQLPart['join']) ? $aSQLPart['join'] : '';
+            $sWhere = isset($aSQLPart['where']) ? $aSQLPart['where'] : '';
+            if ((int)$iEventId) {
+                $aBindings['event'] = (int)$iEventId;
+                $aBindingsRepeating['event'] = (int)$iEventId;
+                $sWhere .= " AND `bx_events_data`.`id` = :event ";
+            }
+
+            // search for regular events
+            $a = $this->getAllWithKey("SELECT DISTINCT `bx_events_data`.`id`, `bx_events_data`.`event_name` AS `title`, `bx_events_data`.`date_start`, `bx_events_data`.`date_end`, `bx_events_data`.`timezone`, `bx_events_data`.`reminder`, 0 AS `repeating`
+                FROM `bx_events_data` $sJoin 
+                WHERE `bx_events_data`.`date_start` >= :timestamp_min AND `bx_events_data`.`date_start` <= :timestamp_max $sWhere
+            ", 'id', $aBindings);
+
+            if ($a)
+                $sWhere .= " AND `bx_events_data`.`id` NOT IN(" . $this->implode_escape(array_keys($a)) . ") ";
+
+            $aRepeating = $this->getAllWithKey("SELECT DISTINCT `bx_events_data`.`id`, `bx_events_data`.`event_name` AS `title`, `bx_events_data`.`date_start`, `bx_events_data`.`date_end`, `bx_events_data`.`timezone`, `bx_events_data`.`reminder`, 1 AS `repeating`
+                FROM `bx_events_data`
+                LEFT JOIN `bx_events_intervals` AS `i` ON (
+                    `bx_events_data`.`id` = `i`.`event_id`
+                    AND
+                    `bx_events_data`.`date_start` < :timestamp_max
+                    AND
+                    (0 = `i`.`repeat_stop` OR `i`.`repeat_stop` >= :timestamp_min)
+                    AND (
+                        (0 = `i`.`repeat_year` OR 0 = (:year - :year_start) % `i`.`repeat_year`)
+                        AND 
+                        (0 = `i`.`repeat_month` OR :month = `i`.`repeat_month`)
+                        AND 
+                        (0 = `i`.`repeat_week_of_month` OR :week_of_month = `i`.`repeat_week_of_month`)
+                        AND 
+                        (0 = `i`.`repeat_day_of_month` OR :day_of_month = `i`.`repeat_day_of_month`)
+                        AND 
+                        (0 = `i`.`repeat_day_of_week` OR :day_of_week = `i`.`repeat_day_of_week`)
+                    )
+                ) $sJoin 
+                WHERE `i`.`interval_id` IS NOT NULL $sWhere
+            ", 'id', $aBindingsRepeating);
+
+            $a = array_merge($aRepeating ? $aRepeating : array(), $a ? $a : array());
+
+            // prepare variables for each event            
+            foreach ($a as $k => $r) {
+                $oDateStart = new DateTime('@' . $r['date_start']);
+                $oDateEnd = new DateTime('@' . $r['date_end']);
+                $oDuration = $oDateStart->diff($oDateEnd);
+
+                if ($r['repeating']) {
+                    // since repeating interval values are stored in specific timezones then we need to convert it
+                    $oTz = new DateTimeZone($r['timezone'] ? $r['timezone'] : 'UTC');
+                    $sHoursStart = $oDateStart->format('H:i:s');
+                    $iSecondsStart = (clone($oDateStart))->setTimezone($oTz)->format('H') * 3600 + $oDateStart->format('i') * 60 +  $oDateStart->format('s');
+                    $iSecondsOffset = $oTz->getOffset($oDateIter);
+
+                    $sCurrentDay = $oDateIter->format('Y-m-d');
+                    if ($iSecondsOffset > 0 && $iSecondsOffset > $iSecondsStart)
+                        $sCurrentDay = (clone($oDateIter))->sub(new DateInterval("P1D"))->format('Y-m-d');
+                    if ($iSecondsOffset < 0 && -$iSecondsOffset > (86400 - $iSecondsStart))
+                        $sCurrentDay = (clone($oDateIter))->add(new DateInterval("P1D"))->format('Y-m-d');
+
+                    $oStart = date_create($sCurrentDay . ' ' . $sHoursStart);
+                    $oEnd = $oStart ? clone($oStart) : null;
+                    $oEnd = $oEnd ? $oEnd->add($oDuration) : null;
+                } 
+                else {
+                    $oStart = $oDateStart;
+                    $oEnd = $oDateEnd;
+                }
+
+                $a[$k]['start'] = $oStart ? $oStart->format('c') : 0;
+                $a[$k]['end'] = $oEnd ? $oEnd->format('c') : 0;
+                $a[$k]['start_utc'] = $oDateStart ? $oDateStart->getTimestamp() : 0;
+                $a[$k]['end_utc'] = $oDateEnd ? $oDateEnd->getTimestamp() : 0;
+                $a[$k]['url'] = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $this->_oConfig->CNF['URI_VIEW_ENTRY'] . '&id=' . $r['id']);
+                if(($oEvent = BxDolProfile::getInstanceByContentAndType($r['id'], $sModule)) !== false)
+                    $a[$k]['extendedProps'] = [
+                        'class' => 'bx-events-calendar-unit',
+                        'card' => $oEvent->getUnit()
+                    ];
+            }
+
+            // merge with all other events
+            $aEntries = array_merge($aEntries, $a);
+
+            // go to the next day
+            $oDateIter = $oDateIter->add(new DateInterval("P1D"));
+        }
+
+        return $aEntries;
+    }
+}
+
+/** @} */

+ 345 - 0
modules/boonex/events/updates/13.0.4_13.0.5/source/classes/BxEventsFormEntry.php

@@ -0,0 +1,345 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Events Events
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Create/Edit Group Form.
+ */
+class BxEventsFormEntry extends BxBaseModGroupsFormEntry
+{
+    protected static $_isCssJsEventsAdded = false;
+
+    protected $_iContentId = 0;
+
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_events';
+        parent::__construct($aInfo, $oTemplate);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if (isset($this->aInputs['reoccurring'])) {
+            $this->aInputs['reoccurring']['ghost_template'] = array (
+                
+                'params' => array(
+                    'nested_form_template' => 'form_ghost_template_wrapper.html',
+                    'db' => array(
+                        'table' => 'bx_events_intervals',
+                        'key' => 'interval_id',
+                        'submit_name' => 'interval_id',
+                    ),
+                ),
+                'inputs' => array (
+                    'interval_id' => array (
+                        'type' => 'hidden',
+                        'name' => 'interval_id[]',
+                        'value' => '{interval_id}',
+                        'caption' => _t('Interval ID'),
+                        'db' => array (
+                            'pass' => 'Int',
+                        ),
+                    ),                
+                    'repeat_year' => array (
+                        'type' => 'select',                    
+                        'name' => 'repeat_year[]',
+                        'value' => '{repeat_year}',
+                        'values' => BxDolForm::getDataItems('bx_events_repeat_year'),
+                        'caption' => _t('_bx_events_form_input_repeat_year'),
+                        'db' => array (
+                            'pass' => 'Int',
+                        ),
+                    ),
+                    'repeat_month' => array (
+                        'type' => 'select',
+                        'name' => 'repeat_month[]',
+                        'value' => '{repeat_month}',
+                        'values' => BxDolForm::getDataItems('bx_events_repeat_month'),
+                        'caption' => _t('_bx_events_form_input_repeat_month'),
+                        'db' => array (
+                            'pass' => 'Int',
+                        ),
+                    ),
+                    'repeat_week_of_month' => array (
+                        'type' => 'select',
+                        'name' => 'repeat_week_of_month[]',
+                        'value' => '{repeat_week_of_month}',
+                        'values' => BxDolForm::getDataItems('bx_events_repeat_week_of_month'),
+                        'caption' => _t('_bx_events_form_input_repeat_week_of_month'),
+                        'db' => array (
+                            'pass' => 'Int',
+                        ),
+                    ),                
+                    'repeat_day_of_month' => array (
+                        'type' => 'select',
+                        'name' => 'repeat_day_of_month[]',
+                        'value' => '{repeat_day_of_month}',
+                        'values' => BxDolForm::getDataItems('bx_events_repeat_day_of_month'),
+                        'caption' => _t('_bx_events_form_input_repeat_day_of_month'),
+                        'db' => array (
+                            'pass' => 'Int',
+                        ),
+                    ),
+                    'repeat_day_of_week' => array (
+                        'type' => 'select',
+                        'name' => 'repeat_day_of_week[]',
+                        'value' => '{repeat_day_of_week}',
+                        'values' => BxDolForm::getDataItems('bx_events_repeat_day_of_week'),
+                        'caption' => _t('_bx_events_form_input_repeat_day_of_week'),
+                        'db' => array (
+                            'pass' => 'Int',
+                        ),
+                    ),
+                    'repeat_stop' => array (
+                        'type' => 'datepicker',
+                        'name' => 'repeat_stop[]',
+                        'value' => '{repeat_stop}',
+                        'caption' => _t('_bx_events_form_input_stop_repeating'),
+                        'db' => array (
+                            'pass' => 'DateTs',
+                        ),
+                    ),
+                ),
+            );
+        }
+
+        if (isset($this->aInputs[$CNF['FIELD_TIMEZONE']]) && !$this->aParams['view_mode']) {
+            $this->aInputs[$CNF['FIELD_TIMEZONE']]['values'] = array_combine(timezone_identifiers_list(), timezone_identifiers_list());
+        }
+
+        if(isset($this->aInputs[$CNF['FIELD_REMINDER']]) && !$this->_oModule->_oConfig->isInternalNotifications())
+            unset($this->aInputs[$CNF['FIELD_REMINDER']]);
+    }
+
+    function getCode($bDynamicMode = false)
+    {
+        $sJsCode = '';
+        if(empty($this->aParams['view_mode']))
+            $sJsCode = $this->_oModule->_oTemplate->getJsCode('entry');
+
+        return $sJsCode . parent::getCode($bDynamicMode);
+    }
+
+    protected function fixTimezone(&$aValues, $bAdd = true)
+    {
+        $sTimezone = 'UTC';
+        if (isset($aValues['timezone']) && $aValues['timezone'])
+            $sTimezone = $aValues['timezone'];
+        elseif (isset($this->aInputs['timezone']['value']) && $this->aInputs['timezone']['value'])
+            $sTimezone = $this->aInputs['timezone']['value'];
+
+        $oTz = new DateTimeZone($sTimezone);
+        $oDateTz = new DateTime("now", $oTz);
+        $iTimeOffset = $oTz->getOffset($oDateTz);
+        $a = array('date_start', 'date_end');
+        foreach ($a as $sField) {
+            if (!isset($aValues[$sField]) && isset($this->aInputs[$sField]['value']) && $this->aInputs[$sField]['value']) {
+                $aValues[$sField] = $this->getCleanValue($sField);
+            }
+            if (isset($aValues[$sField]) && $aValues[$sField] && isset($this->aInputs[$sField]) && isset($this->aInputs[$sField]['db']['pass']) && 'DateTimeTs' == $this->aInputs[$sField]['db']['pass']) {
+                $aValues[$sField] += ($bAdd ? $iTimeOffset : -$iTimeOffset);
+            }
+        }
+    }
+
+    function initChecker ($aValues = array (), $aSpecificValues = array())
+    {        
+        $this->fixTimezone($aValues, true);
+
+        if (isset($aValues[$this->_oModule->_oConfig->CNF['FIELD_ID']]))
+            $this->_iContentId = $aValues[$this->_oModule->_oConfig->CNF['FIELD_ID']];
+        
+        parent::initChecker($aValues, $aSpecificValues);
+        
+        if ($this->isSubmitted ()) {
+            if (isset($this->aInputs['date_start']) && $this->aInputs['date_start']['value'] != '' && isset($this->aInputs['date_end'])){
+                if ($this->aInputs['date_end']['value'] != ''){
+                    if (strtotime($this->aInputs['date_end']['value']) < strtotime($this->aInputs['date_start']['value'])){
+                        $this->aInputs['date_end']['error'] = _t('_bx_events_form_profile_input_date_end_invalid_err');
+                        $this->_isValid = false;       
+                        
+                        $sSubmitName = false;
+                        foreach ($this->aInputs as $k => $a) {
+                            if (isset($a['visible_for_levels']) && !BxDolForm::isVisible($a))
+                                continue;
+
+                            if (empty($a['name']) || 'submit' == $a['type'] || 'reset' == $a['type'] || 'button' == $a['type'] || 'value' == $a['type']) {
+                                if (isset($a['type']) && 'submit' == $a['type'])
+                                    $sSubmitName = $k;
+                                continue;
+                            }
+
+                            if ('input_set' == $a['type'])
+                                foreach ($a as $r)
+                                    if (isset($r['type']) && 'submit' == $r['type'])
+                                        $sSubmitName = $k;
+
+                        }
+                        if ($sSubmitName)
+                            $this->aInputs[$sSubmitName]['error'] = _t('_sys_txt_form_submission_error');
+                        
+                    }
+                }
+                else{
+                    $this->setSubmittedValue('date_end', $this->aInputs['date_start']['value'], BX_DOL_FORM_METHOD_POST);
+                }
+            }
+        }
+        
+    }
+
+    protected function genCustomRowDateEnd (&$aInput)
+    {
+        if ($this->aParams['view_mode'])
+            return $this->_isSameDayEvent() ? '' : $this->genViewRowWrapped($aInput);
+
+        return $this->genRowStandard($aInput);
+    }
+
+    protected function _isSameDayEvent()
+    {
+        $aStartEnd = $this->_getStartEnd();
+        if($aStartEnd === false || (is_array($aStartEnd) && empty($aStartEnd)))
+            return false;
+        else
+            return $aStartEnd['start']->format('Y-m-d') == $aStartEnd['end']->format('Y-m-d');
+    }
+
+    protected function _getStartEnd()
+    {
+        if(!isset($this->aInputs['timezone']['value']) || !isset($this->aInputs['date_start']['value']) || !isset($this->aInputs['date_end']['value']))
+            return false;
+
+        if(empty($this->aInputs['date_start']['value']) && empty($this->aInputs['date_end']['value']))
+            return array();
+
+        $iTimeStart = bx_process_input ($this->aInputs['date_start']['value'], isset($this->aInputs['date_start']['date_filter']) ? $this->aInputs['date_start']['date_filter'] : BX_DATA_DATETIME_TS, false, false);
+        $iTimeEnd = bx_process_input ($this->aInputs['date_end']['value'], isset($this->aInputs['date_end']['date_filter']) ? $this->aInputs['date_end']['date_filter'] : BX_DATA_DATETIME_TS, false, false);
+
+        $oDateStart = date_create("@$iTimeStart");
+        $oDateEnd = date_create("@$iTimeEnd");
+
+        return array('start' => $oDateStart, 'end' => $oDateEnd);
+    }
+    
+    protected function genCustomRowTime (&$aInput)
+    {
+        if (!$this->aParams['view_mode'])
+            return '';
+
+        $aStartEnd = $this->_getStartEnd();
+
+        if ($aStartEnd === false)
+            $aInput['value'] = "Timezone, date start & date end fields are required to display this field";
+        else if(is_array($aStartEnd) && empty($aStartEnd))
+            $aInput['value'] = '';
+        else {
+            if ($aStartEnd['start']->format('Y-m-d') == $aStartEnd['end']->format('Y-m-d'))
+                $aInput['value'] = _t('_bx_events_txt_from_time_to_time', date(getParam('bx_events_time_format'), $aStartEnd['start']->getTimestamp()), date(getParam('bx_events_time_format'), $aStartEnd['end']->getTimestamp()));
+            else
+                $aInput['value'] = '';
+        }
+        return $this->genViewRowWrapped($aInput);
+    }
+ 
+    function genViewRowValue(&$aInput)
+    {
+        if (in_array($aInput['name'], array('date_start', 'date_end'))) {
+
+            $aStartEnd = $this->_getStartEnd();
+            if($aStartEnd === false)
+                return "Timezone, date start & date end fields are required to display this field";
+
+            if(is_array($aStartEnd) && empty($aStartEnd))
+                return null;
+
+            $sFormat = getParam($aStartEnd['start']->format('Y-m-d') == $aStartEnd['end']->format('Y-m-d') ? 'bx_events_short_date_format' : 'bx_events_datetime_format');
+            $oDate = 'date_start' == $aInput['name'] ? $aStartEnd['start'] : $aStartEnd['end'];
+            return date($sFormat, $oDate->getTimestamp());
+        }
+        return parent::genViewRowValue($aInput);
+    }
+
+    protected function genCustomRowReoccurring (&$aInput)
+    {
+        return $this->genRowCustom($aInput, 'genInputReoccurring');
+    }
+
+    protected function genInputReoccurring (&$aInput, $sInfo = '', $sError = '')
+    {
+        $sUniqId = genRndPwd (8, false);
+
+        return $this->oTemplate->parseHtmlByName('form_field_reoccurring.html', array(
+            'info' => $sInfo,
+            'error' => $sError,
+            'uniq_id' => $sUniqId,
+            'js_instance_name' => 'oBxEventsIntervals_' . $sUniqId,
+            'options' => json_encode(array(
+                'uniq_id' => $sUniqId,
+                'js_instance_name' => 'oBxEventsIntervals_' . $sUniqId,
+                'template_ghost' => $this->genGhostTemplate($aInput),
+                'content_id' => $this->_iContentId, 
+            )),
+        ));
+    }
+
+    protected function genCustomViewRowValueTimezone ($aInput)
+    {
+        return $aInput['value'];
+    }
+
+    public function insert ($aValsToAdd = array(), $isIgnore = false)
+    {
+        $this->fixTimezone($aValsToAdd, false);
+
+        $iContentId = parent::insert ($aValsToAdd, $isIgnore);
+
+        if (isset($this->aInputs['reoccurring']) && is_array($this->aInputs['reoccurring']['ghost_template']) && !isset($this->aInputs['reoccurring']['ghost_template']['inputs'])) {
+            foreach ($this->aInputs['reoccurring']['ghost_template'] as $oFormNested) {
+                $oFormNested->insert(array('event_id' => $iContentId));
+            }
+        }
+        
+        return $iContentId;
+    }
+
+    function update ($val, $aValsToAdd = array(), &$aTrackTextFieldsChanges = null)
+    {
+        $this->fixTimezone($aValsToAdd, false);
+
+        $iAffectedRows = parent::update($val, $aValsToAdd, $aTrackTextFieldsChanges);
+
+        if (isset($this->aInputs['reoccurring']) && is_array($this->aInputs['reoccurring']['ghost_template']) && !isset($this->aInputs['reoccurring']['ghost_template']['inputs'])) {
+            foreach ($this->aInputs['reoccurring']['ghost_template'] as $oFormNested) {
+                $aSpecificValues = $oFormNested->getSpecificValues();
+                $iIntervalId = $oFormNested->getSubmittedValue('interval_id', BX_DOL_FORM_METHOD_SPECIFIC, $aSpecificValues);
+                if ($iIntervalId) {
+                    $oFormNested->update($iIntervalId);
+                } else {
+                    $oFormNested->insert(array('event_id' => $this->_iContentId));
+                }
+            }
+        }
+        
+        return $iAffectedRows;
+    }
+    
+    function addCssJs ()
+    {
+        if ((!isset($this->aParams['view_mode']) || !$this->aParams['view_mode']) && !self::$_isCssJsEventsAdded) {
+            $this->oTemplate->addJs(array('moment-timezone-with-data.js', 'entry.js', 'intervals.js'));
+            $this->oTemplate->addCss('informer.css');
+            self::$_isCssJsEventsAdded = true;
+        }  
+
+        parent::addCssJs ();
+    }
+}
+
+/** @} */

+ 572 - 0
modules/boonex/events/updates/13.0.4_13.0.5/source/classes/BxEventsModule.php

@@ -0,0 +1,572 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Events Events
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Events profiles module.
+ */
+class BxEventsModule extends BxBaseModGroupsModule implements iBxDolCalendarService 
+{
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+        
+        $CNF = &$this->_oConfig->CNF;
+        $this->_aSearchableNamesExcept = array_merge($this->_aSearchableNamesExcept, array(
+            $CNF['FIELD_TIMEZONE'],
+            $CNF['FIELD_JOIN_CONFIRMATION'],
+            $CNF['FIELD_REMINDER']
+        ));
+    }
+
+    public function actionCalendarData()
+    {
+        // check permissions
+        $aSQLPart = array();
+        $iContentId = (int)bx_get('event');
+        $iContextId = (int)bx_get('context_id');
+        
+        if ($iContentId) {
+            $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+            if (CHECK_ACTION_RESULT_ALLOWED !== $this->checkAllowedView($aContentInfo)) {
+                $this->_oTemplate->displayAccessDenied();
+                exit;
+            }
+            $aSQLPart = array();
+        }
+        else {
+            $oPrivacy = BxDolPrivacy::getObjectInstance($this->_oConfig->CNF['OBJECT_PRIVACY_VIEW']);
+            if($iContextId){
+                if (!$this->serviceIsEnableForContext($iContextId)){
+                    exit;
+                }
+                else{
+                    $aSQLPart = $oPrivacy ? $oPrivacy->getContentByGroupAsSQLPart(- $iContextId) : array();
+                }
+            }
+            else{
+                $aSQLPart = $oPrivacy ? $oPrivacy->getContentPublicAsSQLPart(0, $oPrivacy->getPartiallyVisiblePrivacyGroups()) : array();
+            }
+        }
+
+        // get entries
+        $aEntries = $this->_oDb->getEntriesByDate(bx_get('start'), bx_get('end'), bx_get('event'), $aSQLPart);
+        
+        bx_alert($this->getName(), 'calendar_data', 0, false, array(
+            'event' => $iContentId,
+            'context_id' => $iContextId,
+            'start' => bx_get('start'),
+            'end' =>  bx_get('end'),
+            'sql_part' => &$aSQLPart,
+            'data' => &$aEntries,
+        ));
+        
+        header('Content-Type: application/json; charset=utf-8');
+        echo json_encode($aEntries);
+    }
+    
+    public function serviceIsIcalExportAvaliable($iContentId)
+    {
+        return true;
+        $aContentInfo = $iContentId ? $this->_oDb->getContentInfoById($iContentId) : false;
+        if ($aContentInfo)
+            return false;
+        
+        return $aContentInfo['date_start'] && $aContentInfo['date_end'];
+    }
+
+    public function serviceGetCalendarEntries($iProfileId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $oConn = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS']);
+        $aData = $oConn->getConnectedContent($iProfileId);
+        $aData2 = array(0);
+        foreach($aData as $iProfileId2){
+            $oProfile = BxDolProfile::getInstance($iProfileId2);
+            array_push($aData2, $oProfile->getContentId());
+        }
+        $aSQLPart['where'] = " AND `bx_events_data`.`id` IN(" . implode(',', $aData2) . ")";
+        return $this->_oDb->getEntriesByDate(bx_get('start'), bx_get('end'), null, $aSQLPart);
+	}
+
+    public function serviceGetSafeServices()
+    {
+        $a = parent::serviceGetSafeServices();
+        return array_merge($a, array (
+            'BrowsePastProfiles' => '',
+            'Calendar' => '',
+        ));
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_events Events
+     * @subsection bx_events-browse Browse
+     * @subsubsection bx_events-browse_upcoming_profiles browse_upcoming_profiles
+     * 
+     * @code bx_srv('bx_events', 'browse_upcoming_profiles', [...]); @endcode
+     * 
+     * Browse upcoming events
+     * 
+     * @param $bDisplayEmptyMsg show "empty" message or not if nothing found
+     * @param $bAjaxPaginate use AJAX paginate or not
+     *
+     * @see BxEventsModule::serviceBrowseUpcomingProfiles
+     */
+    /** 
+     * @ref bx_events-browse_upcoming_profiles "browse_upcoming_profiles"
+     */
+    public function serviceBrowseUpcomingProfiles ($aParams = false)
+    {
+        $bDisplayEmptyMsg = false;
+        if(isset($aParams['empty_message'])) {
+            $bDisplayEmptyMsg = (bool)$aParams['empty_message'];
+            unset($aParams['empty_message']);
+        }
+
+        $bAjaxPaginate = true;
+        if(isset($aParams['ajax_paginate'])) {
+            $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
+            unset($aParams['ajax_paginate']);
+        }
+
+        return $this->_serviceBrowse ('upcoming', $aParams, BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_events Events
+     * @subsection bx_events-browse Browse
+     * @subsubsection bx_events-browse_upcoming_connected_profiles browse_upcoming_connected_profiles
+     * 
+     * @code bx_srv('bx_events', 'browse_upcoming_connected_profiles', [...]); @endcode
+     * 
+     * Browse upcoming connected (followed) events
+     * 
+     * @param $bDisplayEmptyMsg show "empty" message or not if nothing found
+     * @param $bAjaxPaginate use AJAX paginate or not
+     *
+     * @see BxEventsModule::serviceBrowseUpcomingConnectedProfiles
+     */
+    /** 
+     * @ref bx_events-browse_upcoming_connected_profiles "browse_upcoming_connected_profiles"
+     */
+    public function serviceBrowseUpcomingConnectedProfiles ($aParams = false)
+    {
+        if(!is_array($aParams) || empty($aParams['object']) || empty($aParams['profile']))
+            return '';
+
+        $bDisplayEmptyMsg = false;
+        if(isset($aParams['empty_message'])) {
+            $bDisplayEmptyMsg = (bool)$aParams['empty_message'];
+            unset($aParams['empty_message']);
+        }
+
+        $bAjaxPaginate = true;
+        if(isset($aParams['ajax_paginate'])) {
+            $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
+            unset($aParams['ajax_paginate']);
+        }
+
+        $aDefaults = array(
+            'type' => 'content',
+            'mutual' => false,
+            'profile2' => 0
+        );
+
+        return $this->_serviceBrowse ('upcoming_connected', array_merge($aDefaults, $aParams), BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_events Events
+     * @subsection bx_events-browse Browse
+     * @subsubsection bx_events-browse_past_profiles browse_past_profiles
+     * 
+     * @code bx_srv('bx_events', 'browse_past_profiles', [...]); @endcode
+     * 
+     * Browse past events
+     * 
+     * @param $bDisplayEmptyMsg show "empty" message or not if nothing found
+     * @param $bAjaxPaginate use AJAX paginate or not
+     *
+     * @see BxEventsModule::serviceBrowsePastProfiles
+     */
+    /** 
+     * @ref bx_events-browse_past_profiles "browse_past_profiles"
+     */
+    public function serviceBrowsePastProfiles ($bDisplayEmptyMsg = false, $bAjaxPaginate = true)
+    {
+        return $this->_serviceBrowse ('past', false, BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_events Events
+     * @subsection bx_events-browse Browse
+     * @subsubsection bx_events-browse_past_profiles browse_past_profiles_by_params
+     * 
+     * @code bx_srv('bx_events', 'browse_past_profiles_by_params', [...]); @endcode
+     * 
+     * Browse past events
+     * 
+     * @param $aParams array with all parameters
+     *
+     * @see BxEventsModule::serviceBrowsePastProfilesByParams
+     */
+    /** 
+     * @ref bx_events-browse_past_profiles_by_params "browse_past_profiles_by_params"
+     */
+    public function serviceBrowsePastProfilesByParams ($aParams)
+    {
+        $bDisplayEmptyMsg = false;
+        if(isset($aParams['empty_message'])) {
+            $bDisplayEmptyMsg = (bool)$aParams['empty_message'];
+            unset($aParams['empty_message']);
+        }
+
+        $bAjaxPaginate = true;
+        if(isset($aParams['ajax_paginate'])) {
+            $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
+            unset($aParams['ajax_paginate']);
+        }
+        return $this->_serviceBrowse ('past', $aParams, BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_events Events
+     * @subsection bx_events-page_blocks Page Blocks
+     * @subsubsection bx_events-calendar calendar
+     * 
+     * @code bx_srv('bx_events', 'calendar', [...]); @endcode
+     * 
+     * Shows event or events calendar
+     * 
+     * @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.
+     * @param $sTemplate template to use to show calendar, or leave empty for default template, possible options: calendar.html, calendar_compact.html
+     * @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.
+     *
+     * @see BxEventsModule::serviceCalendar
+     */
+    /** 
+     * @ref bx_events-calendar "calendar"
+     */
+    public function serviceCalendar($aData = array(), $sTemplate = 'calendar.html')
+    {
+        if(isset($aData['context_id']) && !$this->serviceIsEnableForContext($aData['context_id']))
+            return '';
+
+        $oCalendar = new BxTemplCalendar([
+            'eventSources' => [
+                bx_append_url_params(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'calendar_data', $aData),
+            ],
+        ], $this->_oTemplate);
+
+        $this->_oTemplate->addCss(['main.css']);
+        return $oCalendar->display($sTemplate);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_events Events
+     * @subsection bx_events-other Other
+     * @subsubsection bx_events-process_reminders process_reminders
+     * 
+     * @code bx_srv('bx_events', 'process_reminders'); @endcode
+     * 
+     * Send remiders to event's participants.
+     *
+     * It must be processed once every hour for the proper processing.
+     * @return nothing
+     *
+     * @see BxEventsModule::serviceProcessReminders
+     */
+    /** 
+     * @ref bx_events-process_reminders "process_reminders"
+     */
+    public function serviceProcessReminders()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iNow = time();
+        $bUseIn = $this->_oConfig->isInternalNotifications();
+        $sModule = $this->getName();
+
+        // get all events for today and tomorrow, since the max reminder is 24 hours
+        $aEntries = $this->_oDb->getEntriesByDate('@' . time(), '@' . (time() + 3600 * getParam('bx_events_reminder_interval')));
+
+        foreach($aEntries as $aEntry) {
+            $aReminders = $bUseIn ? [$aEntry['reminder']] : [24, 1];
+            if(!$aReminders)
+                continue;
+
+            $oEventProfile = BxDolProfile::getInstanceByContentAndType($aEntry[$CNF['FIELD_ID']], $sModule);
+            if(!$oEventProfile)
+                continue;
+
+            $iEventProfileId = $oEventProfile->id();
+            foreach($aReminders as $iReminder) {
+                $iTimestamp = $aEntry['start_utc'] - (3600 * $iReminder);
+                if($iNow <= ($iTimestamp - 3600) || $iNow >= $iTimestamp)
+                    continue;
+
+                if($bUseIn)
+                    $this->sendReminders($aEntry);
+
+                bx_alert($sModule, 'reminder', $aEntry[$CNF['FIELD_ID']], $iEventProfileId, array(
+                    'object_author_id' => $iEventProfileId,
+                    'reminder' => $iReminder
+                ));
+            }
+        }
+    }
+
+    public function serviceGetNotificationsData()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aResults = parent::serviceGetNotificationsData();
+        
+        $sModule = $this->_aModule['name'];
+        $aSettingsTypes = ['follow_context'];
+
+        $aResults['handlers'] = array_merge($aResults['handlers'], [
+            ['group' => $sModule . '_reminder', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'reminder', 'module_name' => $sModule, 'module_method' => 'get_notifications_reminder', 'module_class' => 'Module', 'module_event_privacy' => $CNF['OBJECT_PRIVACY_VIEW_NOTIFICATION_EVENT']],
+        ]);
+
+        $aResults['settings'] = array_merge($aResults['settings'], [
+            ['group' => 'reminder', 'unit' => $sModule, 'action' => 'reminder', 'types' => $aSettingsTypes],
+        ]);
+
+        $aResults['alerts'] = array_merge($aResults['alerts'], [
+            ['unit' => $sModule, 'action' => 'reminder'],
+        ]);
+
+        return $aResults;
+    }
+
+    public function serviceGetNotificationsInsertData($oAlert, $aHandler, $aDataItems)
+    {
+        if($oAlert->sAction != 'reminder' || empty($aDataItems) || !is_array($aDataItems) || empty($oAlert->aExtras['reminder']))
+            return $aDataItems;
+
+        foreach($aDataItems as $iIndex => $aDataItem) {
+            $aContent = [];
+            if(!empty($aDataItem['content']))
+                $aContent = unserialize($aDataItem['content']);
+
+            $aContent['reminder'] = (int)$oAlert->aExtras['reminder'];
+
+            $aDataItems[$iIndex]['content'] = serialize($aContent);
+        }
+
+        return $aDataItems;
+    }
+
+    public function serviceGetNotificationsReminder($aEvent)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!isset($aEvent['content']['reminder']))
+            return [];
+
+        $iContentId = (int)$aEvent['object_id'];
+        $oEventProfile = BxDolProfile::getInstanceByContentAndType((int)$iContentId, $this->getName());
+        if(!$oEventProfile)
+            return [];
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return [];
+
+        return [
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => str_replace(BX_DOL_URL_ROOT, '{bx_url_root}', $oEventProfile->getUrl()),
+            'entry_caption' => $oEventProfile->getDisplayName(),
+            'entry_author' => $oEventProfile->id(),
+            'lang_key' => '_bx_events_txt_ntfs_reminder_' . $aEvent['content']['reminder']
+        ];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_events Events
+     * @subsection bx_events-internal Internal
+     * @subsubsection bx_events-get_timeline_post get_timeline_post
+     *
+     * @code bx_srv('bx_events', 'get_timeline_post', [...]); @endcode
+     * 
+     * Get Timeline post. It's needed for Timeline module.
+     * 
+     * @param $aEvent timeline event array from Timeline module
+     * @return array in special format which is needed specifically for Timeline module to display the data.
+     *
+     * @see BxEventsModule::serviceGetTimelinePost
+     */
+    /** 
+     * @ref bx_events-get_timeline_post "get_timeline_post"
+     */
+    public function serviceGetTimelinePost($aEvent, $aBrowseParams = array())
+    {
+        $a = parent::serviceGetTimelinePost($aEvent, $aBrowseParams);
+        if($a === false)
+            return false;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($aEvent['object_id']);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return $a;
+
+        $CNF = $this->_oConfig->CNF;
+
+        $oDateStart = date_create('@' . $aContentInfo['date_start']);
+        if ($oDateStart)
+            $oDateStart->setTimezone(new DateTimeZone($aContentInfo['timezone'] ? $aContentInfo['timezone'] : 'UTC'));
+
+        $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS']);
+        $sLocationString = $oMetatags ? $oMetatags->locationsString($aContentInfo[$CNF['FIELD_ID']], false) : false;
+
+        $a['content']['raw'] = $this->_oTemplate->parseHtmlByName('timeline_post.html', [
+            'title' => $a['content']['title'],
+            'title_attr' => bx_html_attribute($a['content']['title']),
+            'url' => $a['content']['url'],
+            'bx_if:date' => [
+                'condition' => $oDateStart,
+                'content' => [
+                    'date' => $oDateStart ? bx_time_js($aContentInfo['date_start'], BX_FORMAT_DATE_TIME) : '',
+                    'date_c' => $oDateStart->format('c'),
+            ]],
+            'bx_if:location' => array(
+                'condition' => !!$sLocationString,
+                'content' => array('location' => $sLocationString),
+            ),
+        ]);
+
+        $a['content']['title'] = '';
+        $a['content']['text'] = '';
+
+        return $a;
+    }
+    
+    public function actionIntervals()
+    {
+        $sAction = bx_get('a');
+        $sMethodName = 'subaction' . ucfirst($sAction);
+        if (!method_exists($this, $sMethodName)) {
+            $this->_oTemplate->pageNotFound();
+            return;
+        }
+        $this->$sMethodName();
+    }
+
+    public function subactionRestore($iContentId = 0)
+    {
+        if (!$iContentId)
+            $iContentId = (int)bx_get('c');
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+
+        if (
+            ($aContentInfo && CHECK_ACTION_RESULT_ALLOWED !== $this->checkAllowedEdit ($aContentInfo))
+            ||
+            (!$aContentInfo && CHECK_ACTION_RESULT_ALLOWED !== $this->checkAllowedAdd ())
+        ) {
+            $this->_oTemplate->displayAccessDenied();
+            exit;
+        }
+
+        $a = $this->_oDb->getIntervals($iContentId);
+        foreach ($a as $iIntervalId => $r) {
+            $a[$iIntervalId]['file_id'] = $r['interval_id'];
+            $a[$iIntervalId]['repeat_stop'] = bx_process_output ($r['repeat_stop'], BX_DATA_DATE_TS);
+        }
+
+        if ('json' == bx_get('f')) {
+            header('Content-type: text/html; charset=utf-8');
+            echo json_encode($a);
+        }
+    }
+
+    public function subactionDelete()
+    {
+        header('Content-type: text/html; charset=utf-8');
+
+        $iIntervalId = (int)bx_get('id');
+
+        if (!($aContentInfo = $this->_oDb->getContentInfoByIntervalId($iIntervalId))) {
+            echo _t('_sys_request_page_not_found_cpt');
+        }
+        elseif (CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $this->checkAllowedEdit ($aContentInfo))) {
+            echo $sMsg;
+        } 
+        elseif (!$this->_oDb->deleteIntervalById($iIntervalId)) {
+            echo _t('_sys_txt_error_occured');
+        } 
+        else {
+            echo 'ok';
+        }
+    }
+
+    public function checkAllowedIcalExport ($aDataEntry, $isPerformAction = false)
+    {
+        return $aDataEntry['date_start'] && $aDataEntry['date_end'] ? CHECK_ACTION_RESULT_ALLOWED : _t('_sys_txt_access_denied');
+    }
+
+    /**
+     * Send reminder to event's paritcipants
+     * @param $aContentInfo content info
+     * @return number of sent reminders
+     */ 
+    protected function sendReminders($aContentInfo)
+    {
+        $CNF = $this->_oConfig->CNF;
+
+        $oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS']);
+        if (!$oConnection)
+            return false;
+
+        $oGroupProfile = BxDolProfile::getInstanceByContentAndType($aContentInfo[$CNF['FIELD_ID']], $this->getName());
+        if (!$oGroupProfile)
+            return false;
+
+        $aParticipants = $oConnection->getConnectedInitiators($oGroupProfile->id(), true);
+        if (!$aParticipants)
+            return true;
+
+        $oDateBegin = new DateTime();
+        $oDateBegin->setTimestamp($aContentInfo['start_utc']);
+        $oDateBegin->setTimezone(new DateTimeZone($aContentInfo['timezone'] ? $aContentInfo['timezone'] : 'UTC'));
+        $sEntryBegin = $oDateBegin->format('r');
+        $sEntryBeginShort = date(getParam('bx_events_short_date_format'), $oDateBegin->getTimestamp());
+        $oDateBegin->setTimezone(new DateTimeZone('UTC'));
+        $sEntryBeginUTC = $oDateBegin->format('c');
+
+        $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS']);
+        $sLocationString = $oMetatags->locationsString($aContentInfo[$CNF['FIELD_ID']], false);
+
+        $iCounter = 0;
+        foreach ($aParticipants as $iProfileId) {
+
+            $b = sendMailTemplate($CNF['EMAIL_REMINDER'], 0, $iProfileId, array(
+                'EntryUrl' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]),
+                'EntryTitle' => $aContentInfo['title'],
+                'EntryBegin' => $sEntryBegin,
+                'EntryBeginShort' => $sEntryBeginShort,
+                'EntryBeginUTC' => $sEntryBeginUTC,
+                'EntryLocation' => $sLocationString ? _t('_bx_events_email_reminder_location', $sLocationString) : '',
+            ), BX_EMAIL_NOTIFY);
+
+            $iCounter += $b ? 1 : 0;
+        }
+        return $iCounter;
+    }
+}
+
+/** @} */

+ 152 - 0
modules/boonex/events/updates/13.0.4_13.0.5/source/install/config.php

@@ -0,0 +1,152 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Events Events
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_events',
+    'title' => 'Events',
+    'note' => 'Events functionality.',
+    'version' => '13.0.5',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/events/',
+    'home_uri' => 'events',
+
+    'db_prefix' => 'bx_events_',
+    'class_prefix' => 'BxEvents',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Events',
+
+    /**
+     * Connections.
+     */
+    'connections' => array(
+    	'sys_profiles_friends' => array ('type' => 'profiles'),
+		'sys_profiles_subscriptions' => array ('type' => 'profiles'),
+    ),
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+        'trigger_profile_view_submenu',
+        'trigger_group_view_submenu',
+        'trigger_group_snippet_meta',
+        'trigger_group_view_actions',
+    ),
+
+    /**
+     * Page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_group_view_entry', 
+    ),
+
+	/**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_events_pics'
+    ),
+
+	/**
+     * Transcoders.
+     */
+    'transcoders' => array(
+    	'bx_events_icon', 
+    	'bx_events_thumb', 
+    	'bx_events_avatar', 
+        'bx_events_avatar_big', 
+    	'bx_events_picture', 
+    	'bx_events_cover', 
+    	'bx_events_cover_thumb',
+    	'bx_events_gallery'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_events',
+    	'bx_events_cmts',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'process_connections' => 1,
+        'process_deleted_profiles' => 1,
+    	'update_relations' => 1,        
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+    	'process_menu_triggers' => 1,
+    	'process_page_triggers' => 1,
+    	'process_esearches' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'unregister_transcoders' => 1,
+        'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Connections Section
+     */
+    'relations' => array(
+        'bx_timeline',
+        'bx_notifications',
+    ),
+);
+
+/** @} */

+ 591 - 0
modules/boonex/events/updates/13.0.4_13.0.5/source/install/langs/en.xml

@@ -0,0 +1,591 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string name="_bx_events"><![CDATA[Events]]></string>
+    <string name="_bx_events_cmts"><![CDATA[Events' Comments]]></string>
+
+    <string name="_bx_events_option_enable_auto_approve"><![CDATA[Auto approve an event after creation]]></string>
+    <string name="_bx_events_option_num_connections_quick"><![CDATA[Number of items in friends block]]></string>
+    <string name="_bx_events_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+    <string name="_bx_events_option_num_rss"><![CDATA[Number of items in RSS feed]]></string>
+    <string name="_bx_events_option_time_format"><![CDATA[Time format]]></string>
+    <string name="_bx_events_option_short_date_format"><![CDATA[Short date format]]></string>
+    <string name="_bx_events_option_datetime_format"><![CDATA[Date and time format]]></string>
+    <string name="_bx_events_option_summary_chars"><![CDATA[Number of characters in auto-cropped event summary]]></string>
+    <string name="_bx_events_option_searchable_fields"><![CDATA[Searchable fields]]></string>
+    <string name="_bx_events_option_members_mode"><![CDATA[Special mode for event members]]></string>
+    <string name="_bx_events_option_members_mode_multi_roles"><![CDATA[Multi Roles]]></string>
+    <string name="_bx_events_option_public_subscribed_me"><![CDATA[Public list of interested members]]></string>
+    <string name="_bx_events_option_per_page_for_favorites_lists"><![CDATA[Number of favorite lists per page]]></string>
+    <string name="_bx_events_option_enable_subscribe_wo_join"><![CDATA[Allow to mark as Interested without joining (marking as Going)]]></string>
+    <string name="_bx_events_option_internal_notifications"><![CDATA[Use internal notifications]]></string>
+
+    <string name="_bx_events_form_profile"><![CDATA[Events]]></string>
+    <string name="_bx_events_form_profile_display_add"><![CDATA[Add Event]]></string>
+    <string name="_bx_events_form_profile_display_edit"><![CDATA[Edit Event]]></string>
+    <string name="_bx_events_form_profile_display_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_events_form_profile_display_delete"><![CDATA[Delete Event]]></string>
+    <string name="_bx_events_form_profile_display_view"><![CDATA[View Event]]></string>
+    <string name="_bx_events_form_profile_display_view_full"><![CDATA[Full View Event]]></string>
+    <string name="_bx_events_form_profile_display_invite"><![CDATA[Invite to Event]]></string>
+    <string name="_bx_events_form_profile_input_author"><![CDATA[Author]]></string>
+    <string name="_bx_events_form_profile_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_events_form_profile_input_sys_join_confirm"><![CDATA[Join confirmation]]></string>
+    <string name="_bx_events_form_profile_input_join_confirm"><![CDATA[Approval required to join]]></string>
+    <string name="_bx_events_form_profile_input_sys_allow_view_to"><![CDATA[Visible to]]></string>
+    <string name="_bx_events_form_profile_input_allow_view_to"><![CDATA[Visible to]]></string>
+    <string name="_bx_events_form_profile_input_allow_view_favorite_list"><![CDATA[Visibility]]></string>
+    <string name="_bx_events_form_profile_input_allow_view_to_desc"><![CDATA[Closed - anyone can find the event and see who's in it, only members can see posts. Secret - only members can find the event and see posts.]]></string>
+    <string name="_bx_events_form_profile_input_sys_allow_post_to"><![CDATA[Who can post]]></string>
+    <string name="_bx_events_form_profile_input_allow_post_to"><![CDATA[Who can post]]></string>
+    <string name="_bx_events_form_profile_input_sys_initial_members"><![CDATA[Invite Members]]></string>
+    <string name="_bx_events_form_profile_input_initial_members"><![CDATA[Invite Members]]></string>
+    <string name="_bx_events_form_profile_input_sys_event_name"><![CDATA[Event Name]]></string>
+    <string name="_bx_events_form_profile_input_event_name"><![CDATA[Event Name]]></string>
+    <string name="_bx_events_form_profile_input_event_name_err"><![CDATA[This information is essential. Please, fill in this field.]]></string>
+    <string name="_bx_events_form_profile_input_sys_event_desc"><![CDATA[Description]]></string>
+    <string name="_bx_events_form_profile_input_event_desc"><![CDATA[Description]]></string>
+    <string name="_bx_events_form_profile_input_sys_event_cat"><![CDATA[Category]]></string>
+    <string name="_bx_events_form_profile_input_event_cat"><![CDATA[Category]]></string>
+    <string name="_bx_events_form_profile_input_event_cat_err"><![CDATA[Category field is mandatory]]></string>
+    <string name="_bx_events_form_profile_input_sys_picture"><![CDATA[Event Picture]]></string>
+    <string name="_bx_events_form_profile_input_picture"><![CDATA[Upload New Event Picture]]></string>
+    <string name="_bx_events_form_profile_input_picture_err"><![CDATA[Event picture is mandatory.]]></string>
+    <string name="_bx_events_form_profile_input_sys_cover"><![CDATA[Cover Picture]]></string>
+    <string name="_bx_events_form_profile_input_cover"><![CDATA[Upload New Cover Picture]]></string>
+    <string name="_bx_events_form_profile_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+    <string name="_bx_events_form_profile_input_delete_confirm"><![CDATA[I am sure I want to delete this event]]></string>
+    <string name="_bx_events_form_profile_input_delete_confirm_info"><![CDATA[This action can not be undone.]]></string>
+    <string name="_bx_events_form_profile_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete event.]]></string>
+    <string name="_bx_events_form_profile_input_sys_reoccurring"><![CDATA[Reoccurring]]></string>
+    <string name="_bx_events_form_profile_input_reoccurring"><![CDATA[Reoccurring]]></string>
+    <string name="_bx_events_form_profile_input_reoccurring_add_interval"><![CDATA[Add repeating interval]]></string>
+    <string name="_bx_events_form_profile_input_sys_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_events_form_profile_input_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_events_form_profile_input_sys_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_events_form_profile_input_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_events_form_profile_input_sys_date_published"><![CDATA[Publishing time]]></string>
+    <string name="_bx_events_form_profile_input_date_published"><![CDATA[Publishing time]]></string>
+    <string name="_bx_events_form_profile_input_date_published_info"><![CDATA[Leave empty to publish immediately.]]></string>
+    <string name="_bx_events_form_profile_input_sys_date_start"><![CDATA[Date start]]></string>
+    <string name="_bx_events_form_profile_input_date_start"><![CDATA[Date start]]></string>
+    <string name="_bx_events_form_profile_input_date_start_err"><![CDATA[Start date is mandatory]]></string>
+    <string name="_bx_events_form_profile_input_sys_date_end"><![CDATA[Date end]]></string>
+    <string name="_bx_events_form_profile_input_date_end"><![CDATA[Date end]]></string>    
+    <string name="_bx_events_form_profile_input_date_end_err"><![CDATA[End date is mandatory]]></string>
+    <string name="_bx_events_form_profile_input_date_end_invalid_err"><![CDATA[End date must be must be greater than start date]]></string>
+    <string name="_bx_events_form_profile_input_sys_timezone"><![CDATA[Timezone]]></string>
+    <string name="_bx_events_form_profile_input_timezone"><![CDATA[Timezone]]></string>
+    <string name="_bx_events_form_profile_input_sys_time"><![CDATA[Time]]></string>
+    <string name="_bx_events_form_profile_input_time"><![CDATA[Time]]></string>
+    <string name="_bx_events_form_profile_input_sys_reminder"><![CDATA[Reminder (part of Internal Notifications)]]></string>
+    <string name="_bx_events_form_profile_input_reminder"><![CDATA[Reminder]]></string>
+
+    <string name="_bx_events_form_input_repeat_year"><![CDATA[Repeat year]]></string>
+    <string name="_bx_events_form_input_repeat_month"><![CDATA[Repeat month]]></string>
+    <string name="_bx_events_form_input_repeat_week_of_month"><![CDATA[Repeat week of month]]></string>
+    <string name="_bx_events_form_input_repeat_day_of_month"><![CDATA[Repeat day of month]]></string>
+    <string name="_bx_events_form_input_repeat_day_of_week"><![CDATA[Repeat day of week]]></string>
+    <string name="_bx_events_form_input_stop_repeating"><![CDATA[Stop repeating]]></string>
+
+<string name="_bx_events_form_price"><![CDATA[Price]]></string>
+    <string name="_bx_events_form_price_display_add"><![CDATA[Add]]></string>
+    <string name="_bx_events_form_price_display_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_events_form_price_input_sys_id"><![CDATA[ID]]></string>
+    <string name="_bx_events_form_price_input_sys_role_id"><![CDATA[Role ID]]></string>
+    <string name="_bx_events_form_price_input_sys_name"><![CDATA[Name]]></string>
+    <string name="_bx_events_form_price_input_name"><![CDATA[Name]]></string>
+    <string name="_bx_events_form_price_input_inf_name"><![CDATA[Unique value which will be used in back end and API calls]]></string>
+    <string name="_bx_events_form_price_input_err_name"><![CDATA[You need to enter a unique value here]]></string>
+    <string name="_bx_events_form_price_input_sys_period"><![CDATA[Period]]></string>
+    <string name="_bx_events_form_price_input_period"><![CDATA[Period]]></string>
+    <string name="_bx_events_form_price_input_inf_period"><![CDATA[Use 0 for lifetime]]></string>
+    <string name="_bx_events_form_price_input_sys_period_unit"><![CDATA[Period unit]]></string>
+    <string name="_bx_events_form_price_input_period_unit"><![CDATA[Period unit]]></string>
+    <string name="_bx_events_form_price_input_inf_period_unit"><![CDATA[Leave empty for lifetime level.]]></string>
+    <string name="_bx_events_form_price_input_err_period_unit"><![CDATA[You need to select a period unit here.]]></string>
+    <string name="_bx_events_form_price_input_sys_price"><![CDATA[Price]]></string>
+    <string name="_bx_events_form_price_input_price"><![CDATA[Price]]></string>
+    <string name="_bx_events_form_price_input_inf_price"><![CDATA[Use 0 or leave empty to create free level.]]></string>
+    <string name="_bx_events_form_price_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_events_form_price_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_events_form_price_input_sys_do_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_events_form_price_input_do_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_events_acl_action_create_profile"><![CDATA[Create Event]]></string>
+    <string name="_bx_events_acl_action_use_paid_join"><![CDATA[Use paid join]]></string>
+    <string name="_bx_events_acl_action_delete_profile"><![CDATA[Delete Event]]></string>
+    <string name="_bx_events_acl_action_view_profile"><![CDATA[View Event]]></string>
+    <string name="_bx_events_acl_action_edit_any_profile"><![CDATA[Edit Any Event]]></string>
+    <string name="_bx_events_acl_action_delete_any_profile"><![CDATA[Delete Any Event]]></string>
+    <string name="_bx_events_acl_action_delete_invites"><![CDATA[Delete Invites]]></string>
+
+    <string name="_bx_events_page_title_sys_joined"><![CDATA[Profile Events]]></string>
+    <string name="_bx_events_page_title_joined"><![CDATA[Profile Events]]></string>
+    <string name="_bx_events_page_title_sys_joined_entries"><![CDATA[Profile Events]]></string>
+    <string name="_bx_events_page_title_joined_entries"><![CDATA[Profile Events]]></string>
+    <string name="_bx_events_page_title_sys_entries_in_context"><![CDATA[Events in context]]></string>
+    <string name="_bx_events_page_title_entries_in_context"><![CDATA[Events in {display_name}]]></string>
+    <string name="_bx_events_page_title_sys_create_profile"><![CDATA[Create Event]]></string>
+    <string name="_bx_events_page_title_create_profile"><![CDATA[Create Event]]></string>
+    <string name="_bx_events_page_title_sys_edit_profile"><![CDATA[Edit Event]]></string>
+    <string name="_bx_events_page_title_edit_profile"><![CDATA[Edit Event]]></string>
+    <string name="_bx_events_page_title_sys_edit_profile_cover"><![CDATA[Edit Event Cover]]></string>
+    <string name="_bx_events_page_title_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_events_page_title_sys_delete_profile"><![CDATA[Delete Event]]></string>
+    <string name="_bx_events_page_title_delete_profile"><![CDATA[Delete Event]]></string>
+    <string name="_bx_events_page_title_sys_join_profile"><![CDATA[Join Course]]></string>
+    <string name="_bx_events_page_title_join_profile"><![CDATA[Join Course]]></string>
+    <string name="_bx_events_page_title_sys_view_profile_closed"><![CDATA[View Closed Event]]></string>
+    <string name="_bx_events_page_title_sys_view_profile"><![CDATA[View Event]]></string>
+    <string name="_bx_events_page_title_view_profile"><![CDATA[{display_name}]]></string>
+    <string name="_bx_events_page_title_browse"><![CDATA[Events]]></string>
+    <string name="_bx_events_page_title_browse_by_author"><![CDATA[Events of {display_name}]]></string>
+    <string name="_bx_events_page_title_browse_by_context"><![CDATA[Events in {display_name}]]></string>
+    <string name="_bx_events_page_title_browse_featured"><![CDATA[Featured Events]]></string>
+    <string name="_bx_events_page_title_browse_top"><![CDATA[Top Events]]></string>
+    <string name="_bx_events_page_title_browse_upcoming"><![CDATA[Upcoming Events]]></string>
+    <string name="_bx_events_page_title_browse_past"><![CDATA[Past Events]]></string>
+    <string name="_bx_events_page_title_browse_recent"><![CDATA[New Events]]></string>
+    <string name="_bx_events_page_title_browse_connections"><![CDATA[{0} connections]]></string>
+    <string name="_bx_events_page_title_browse_connections_mutual"><![CDATA[{0} and {1} mutual connections]]></string>
+    <string name="_bx_events_page_title_sys_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_events_page_title_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_events_page_title_sys_group_fans"><![CDATA[Guests]]></string>
+    <string name="_bx_events_page_title_group_fans"><![CDATA[Guests]]></string>
+    <string name="_bx_events_page_title_sys_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_events_page_title_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_events_page_title_sys_profile_info"><![CDATA[Event Info]]></string>
+    <string name="_bx_events_page_title_profile_info"><![CDATA[Info about {display_name}]]></string>
+    <string name="_bx_events_page_title_sys_profile_pricing"><![CDATA[Pricing]]></string>
+    <string name="_bx_events_page_title_profile_pricing"><![CDATA[Pricing]]></string>
+    <string name="_bx_events_page_title_sys_recent"><![CDATA[New Events]]></string>
+    <string name="_bx_events_page_title_recent"><![CDATA[New Events]]></string>
+    <string name="_bx_events_page_title_sys_manage"><![CDATA[Manage Own Events]]></string>
+    <string name="_bx_events_page_title_sys_manage_administration"><![CDATA[Manage All Events]]></string>
+    <string name="_bx_events_page_title_manage"><![CDATA[Manage Events]]></string>
+    <string name="_bx_events_page_title_sys_top"><![CDATA[Top Events]]></string>
+    <string name="_bx_events_page_title_top"><![CDATA[Top Events]]></string>
+    <string name="_bx_events_page_title_sys_upcoming"><![CDATA[Upcoming Events]]></string>
+    <string name="_bx_events_page_title_upcoming"><![CDATA[Upcoming Events]]></string>
+    <string name="_bx_events_page_title_sys_past"><![CDATA[Past Events]]></string>
+    <string name="_bx_events_page_title_past"><![CDATA[Past Events]]></string>
+    <string name="_bx_events_page_title_sys_calendar"><![CDATA[Events Calendar]]></string>
+    <string name="_bx_events_page_title_calendar"><![CDATA[Events Calendar]]></string>
+    <string name="_bx_events_page_title_sys_invite_to_group"><![CDATA[Invite Members to the Event]]></string>
+    <string name="_bx_events_page_title_invite_to_group"><![CDATA[Invite Members to the Event]]></string>
+    <string name="_bx_events_page_title_sys_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_events_page_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_events_page_title_sys_entries_favorites"><![CDATA[Favorites Events]]></string>
+    <string name="_bx_events_page_title_entries_favorites"><![CDATA[Favorites Events]]></string>
+
+    <string name="_bx_events_page_block_title_sys_entries_actions"><![CDATA[Events actions]]></string>
+    <string name="_bx_events_page_block_title_entries_actions"><![CDATA[Events actions]]></string>
+    <string name="_bx_events_page_block_title_entries_in_context"><![CDATA[Events in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_events_page_block_title_sys_entries_in_context"><![CDATA[Events in context]]></string>
+    <string name="_bx_events_page_block_title_calendar_in_context"><![CDATA[Events Calendar in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_events_page_block_title_sys_calendar_in_context"><![CDATA[Events Calendar]]></string>
+    <string name="_bx_events_page_block_title_calendar_for_context"><![CDATA[Events Calendar]]></string>
+    <string name="_bx_events_page_block_title_browse_for_context"><![CDATA[Events in context]]></string>
+    <string name="_bx_events_page_block_title_sys_favorites_entries"><![CDATA[Favorite List]]></string>
+    <string name="_bx_events_page_block_title_favorites_entries"><![CDATA["{title}" List]]></string>
+    <string name="_bx_events_page_block_title_favorites_entries_info"><![CDATA[Info]]></string>
+    <string name="_bx_events_page_block_title_favorites_entries_actions"><![CDATA[Favorites List Actions]]></string>
+    <string name="_bx_events_page_block_title_sys_entries_of_author"><![CDATA[Events of author]]></string>
+    <string name="_bx_events_page_block_title_entries_of_author"><![CDATA[Events by {display_name}]]></string>
+    <string name="_bx_events_page_block_title_favorites_of_author"><![CDATA[Favorite Events]]></string>
+    <string name="_bx_events_page_block_title_sys_favorites_of_author"><![CDATA[Favorite Events]]></string>
+    <string name="_bx_events_page_block_title_sys_joined_entries"><![CDATA[Joined Events]]></string>
+    <string name="_bx_events_page_block_title_joined_entries"><![CDATA[Joined Events]]></string>
+    <string name="_bx_events_page_block_title_create_profile"><![CDATA[Create Event]]></string>
+    <string name="_bx_events_page_block_title_edit_profile"><![CDATA[Edit Event]]></string>
+    <string name="_bx_events_page_block_title_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_events_page_block_title_delete_profile"><![CDATA[Delete Event]]></string>
+    <string name="_bx_events_page_block_title_join_profile"><![CDATA[Join Event]]></string>
+    <string name="_bx_events_page_block_title_profile_info_link"><![CDATA[About <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_events_page_block_title_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_events_page_block_title_system_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_events_page_block_title_system_profile_pricing"><![CDATA[Pricing]]></string>
+    <string name="_bx_events_page_block_title_profile_pricing"><![CDATA[Pricing]]></string>
+    <string name="_bx_events_page_block_title_profile_pricing_link"><![CDATA[Pricing of <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_events_page_block_title_profile_description"><![CDATA[Description]]></string>
+    <string name="_bx_events_page_block_title_profile_friends_link"><![CDATA[Friends of <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_events_page_block_title_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_events_page_block_title_system_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_events_page_block_title_admins"><![CDATA[Administrators]]></string>
+    <string name="_bx_events_page_block_title_fans_link"><![CDATA[Going to <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_events_page_block_title_fans"><![CDATA[Going]]></string>
+    <string name="_bx_events_page_block_title_system_fans"><![CDATA[Going]]></string>
+    <string name="_bx_events_page_block_title_fans_invites"><![CDATA[Invites]]></string>
+    <string name="_bx_events_page_block_title_system_invites"><![CDATA[Invites]]></string>
+    <string name="_bx_events_page_block_title_subscribers_link"><![CDATA[Interested in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_events_page_block_title_subscribers"><![CDATA[Interested]]></string>
+    <string name="_bx_events_page_block_title_system_subscribers"><![CDATA[Interested]]></string>
+    <string name="_bx_events_page_block_title_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_events_page_block_title_entry_reports"><![CDATA[Reports]]></string>
+    <string name="_bx_events_page_block_title_profile_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_events_page_block_title_profile_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_events_page_block_title_featured_profiles"><![CDATA[Featured Events]]></string>
+    <string name="_bx_events_page_block_title_latest_profiles"><![CDATA[New Events]]></string>
+    <string name="_bx_events_page_block_title_system_manage"><![CDATA[Manage Own Events]]></string>
+    <string name="_bx_events_page_block_title_system_manage_administration"><![CDATA[Manage All Events]]></string>
+    <string name="_bx_events_page_block_title_manage"><![CDATA[Manage Events]]></string>
+    <string name="_bx_events_page_block_title_top_profiles"><![CDATA[Top Events]]></string>
+    <string name="_bx_events_page_block_title_joined_profiles"><![CDATA[Joined Events]]></string>
+    <string name="_bx_events_page_block_title_upcoming_profiles"><![CDATA[Upcoming Events]]></string>
+    <string name="_bx_events_page_block_title_past_profiles"><![CDATA[Past Events]]></string>
+    <string name="_bx_events_page_block_title_entry_all_actions"><![CDATA[All Actions]]></string>
+    <string name="_bx_events_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+    <string name="_bx_events_page_block_title_categories"><![CDATA[Event categories]]></string>
+    <string name="_bx_events_page_block_title_calendar"><![CDATA[Events calendar]]></string>
+    <string name="_bx_events_page_block_title_profile_calendar"><![CDATA[Calendar]]></string>
+    <string name="_bx_events_page_block_title_sys_entry_context"><![CDATA[Posted in]]></string>
+    <string name="_bx_events_page_block_title_entry_context"><![CDATA[Posted in]]></string>
+    <string name="_bx_events_page_block_title_entry_location"><![CDATA[Location]]></string>
+    <string name="_bx_events_page_block_title_invite_to_group"><![CDATA[Invite Members to the Event]]></string>
+    <string name="_bx_events_page_block_title_search_form"><![CDATA[Search Form]]></string>
+    <string name="_bx_events_page_block_title_search_results"><![CDATA[Search Results]]></string>
+    <string name="_bx_events_page_block_title_search_form_cmts"><![CDATA[Comments Search Form]]></string>
+    <string name="_bx_events_page_block_title_search_results_cmts"><![CDATA[Comments Search Results]]></string>
+    <string name="_bx_events_page_block_title_sys_featured_entries_view_showcase"><![CDATA[Featured Events (Showcase View)]]></string>
+    <string name="_bx_events_page_block_title_featured_entries_view_showcase"><![CDATA[Featured Events]]></string>
+    <string name="_bx_events_page_block_title_sys_recommended_entries_view_showcase"><![CDATA[Recommended Events (Showcase View)]]></string>
+    <string name="_bx_events_page_block_title_recommended_entries_view_showcase"><![CDATA[Recommended Events]]></string>
+    <string name="_bx_events_page_block_title_sys_cover_block"><![CDATA[Cover]]></string>
+    <string name="_bx_events_page_block_title_cover_block"><![CDATA[Cover]]></string>
+    
+    <string name="_bx_events_menu_title_submenu"><![CDATA[Events Submenu]]></string>
+    <string name="_bx_events_menu_set_title_submenu"><![CDATA[Events Submenu]]></string>
+    <string name="_bx_events_menu_set_title_view_profile_actions"><![CDATA[Event Actions]]></string>
+    <string name="_bx_events_menu_title_view_profile_actions"><![CDATA[Event Actions]]></string>
+    <string name="_bx_events_menu_set_title_view_profile_actions_more"><![CDATA[Event More Actions]]></string>
+    <string name="_bx_events_menu_title_view_profile_actions_more"><![CDATA[Event More Actions]]></string>
+    <string name="_bx_events_menu_title_view_profile_meta"><![CDATA[Event Meta]]></string>
+    <string name="_bx_events_menu_set_title_view_profile_meta"><![CDATA[Event Meta]]></string>
+    <string name="_bx_events_menu_set_title_view_profile_submenu"><![CDATA[View Event Submenu]]></string>
+    <string name="_bx_events_menu_title_view_profile_submenu"><![CDATA[View Event Submenu]]></string>
+    <string name="_bx_events_menu_title_entries_my"><![CDATA[Profile Events Action Menu]]></string>
+    <string name="_bx_events_menu_set_title_entries_my"><![CDATA[Profile Events Menu]]></string>
+    <string name="_bx_events_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_events_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_events_menu_item_title_system_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_events_menu_item_title_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_events_menu_item_title_system_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_events_menu_item_title_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_events_menu_item_title_system_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_events_menu_item_title_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_events_menu_item_title_system_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_events_menu_item_title_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_events_menu_item_title_system_edit_pricing"><![CDATA[Edit Pricing]]></string>
+    <string name="_bx_events_menu_item_title_edit_pricing"><![CDATA[Edit Pricing]]></string>
+    <string name="_bx_events_menu_item_title_system_edit_profile"><![CDATA[Edit Event]]></string>
+    <string name="_bx_events_menu_item_title_edit_profile"><![CDATA[Edit Event]]></string>
+    <string name="_bx_events_menu_item_title_system_delete_profile"><![CDATA[Delete Event]]></string>
+    <string name="_bx_events_menu_item_title_delete_profile"><![CDATA[Delete Event]]></string>
+    <string name="_bx_events_menu_item_title_system_delete_account"><![CDATA[Delete Account]]></string>
+    <string name="_bx_events_menu_item_title_delete_account"><![CDATA[Delete Account]]></string>
+    <string name="_bx_events_menu_item_title_system_profile_type"><![CDATA[Event]]></string>
+    <string name="_bx_events_menu_item_title_profile_type"><![CDATA[Event]]></string>
+    <string name="_bx_events_menu_item_title_system_create_profile"><![CDATA[Event]]></string>
+    <string name="_bx_events_menu_item_title_create_profile"><![CDATA[Event]]></string>
+    <string name="_bx_events_menu_item_title_system_view_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_events_menu_item_title_view_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_events_menu_item_title_system_view_joined_groups"><![CDATA[Events]]></string>
+    <string name="_bx_events_menu_item_title_view_joined_groups"><![CDATA[Events]]></string>
+    <string name="_bx_events_menu_item_title_system_view_fans"><![CDATA[Guests]]></string>
+    <string name="_bx_events_menu_item_title_view_fans"><![CDATA[Guests]]></string>
+    <string name="_bx_events_menu_item_title_system_view_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_events_menu_item_title_view_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_events_menu_item_title_system_view_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_events_menu_item_title_view_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_events_menu_item_title_system_view_profile_view"><![CDATA[Event]]></string>
+    <string name="_bx_events_menu_item_title_view_profile_view"><![CDATA[Event]]></string>
+    <string name="_bx_events_menu_item_title_system_view_profile_more_auto"><![CDATA[More]]></string>
+    <string name="_bx_events_menu_item_title_view_profile_more_auto"><![CDATA[More]]></string>
+    <string name="_bx_events_menu_item_title_system_invite"><![CDATA[Invite]]></string>
+    <string name="_bx_events_menu_item_title_invite"><![CDATA[Invite]]></string>
+
+    <string name="_bx_events_menu_item_title_system_befriend"><![CDATA[Add friend]]></string>
+    <string name="_bx_events_menu_item_title_befriend"><![CDATA[Add friend]]></string>
+    <string name="_bx_events_menu_item_title_befriend_sent"><![CDATA[Add friend (requested)]]></string>
+    <string name="_bx_events_menu_item_title_befriend_confirm"><![CDATA[Accept friend request]]></string>
+    <string name="_bx_events_menu_item_title_system_unfriend"><![CDATA[Unfriend]]></string>
+    <string name="_bx_events_menu_item_title_unfriend"><![CDATA[Unfriend]]></string>
+    <string name="_bx_events_menu_item_title_unfriend_cancel_request"><![CDATA[Cancel friend request]]></string>
+    <string name="_bx_events_menu_item_title_unfriend_reject_request"><![CDATA[Reject friend request]]></string>
+
+    <string name="_bx_events_menu_item_title_system_become_fan"><![CDATA[Join Event]]></string>
+    <string name="_bx_events_menu_item_title_become_fan"><![CDATA[Going]]></string>
+    <string name="_bx_events_menu_item_title_become_fan_sent"><![CDATA[Requested]]></string>
+    <string name="_bx_events_menu_item_title_become_fan_confirm"><![CDATA[Confirm]]></string>
+    <string name="_bx_events_menu_item_title_system_leave_group"><![CDATA[Leave Event]]></string>
+    <string name="_bx_events_menu_item_title_leave_group"><![CDATA[Not going]]></string>
+    <string name="_bx_events_menu_item_title_leave_group_cancel_request"><![CDATA[Cancel]]></string>
+    <string name="_bx_events_menu_item_title_leave_group_reject_request"><![CDATA[Decline]]></string>
+
+<string name="_bx_events_menu_item_title_system_pay_and_join"><![CDATA[Pay & Join]]></string>
+    <string name="_bx_events_menu_item_title_pay_and_join"><![CDATA[Pay & Join]]></string>
+
+    <string name="_bx_events_menu_item_title_system_subscribe"><![CDATA[Follow]]></string>
+    <string name="_bx_events_menu_item_title_subscribe"><![CDATA[Interested]]></string>
+    <string name="_bx_events_menu_item_title_system_view_entries_in_context"><![CDATA[Events]]></string>
+    <string name="_bx_events_menu_item_title_view_entries_in_context"><![CDATA[Events]]></string>
+    <string name="_bx_events_menu_item_title_system_unsubscribe"><![CDATA[Unfollow]]></string>
+    <string name="_bx_events_menu_item_title_unsubscribe"><![CDATA[Not interested]]></string>
+    <string name="_bx_events_menu_item_title_system_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_events_menu_item_title_more_actions"><![CDATA[]]></string>
+    <string name="_bx_events_menu_item_title_system_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_events_menu_item_title_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_events_menu_item_title_system_manage_my_groups"><![CDATA[My events]]></string>
+    <string name="_bx_events_menu_item_title_manage_my_groups"><![CDATA[Events]]></string>
+    <string name="_bx_events_menu_item_title_system_followings"><![CDATA[Events]]></string>
+    <string name="_bx_events_menu_item_title_followings"><![CDATA[Events]]></string>
+    <string name="_bx_events_menu_item_title_system_entries_recent"><![CDATA[New]]></string>
+    <string name="_bx_events_menu_item_title_entries_recent"><![CDATA[New]]></string>
+    <string name="_bx_events_menu_item_title_system_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_events_menu_item_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_events_menu_item_title_system_entries_joined"><![CDATA[Joined]]></string>
+    <string name="_bx_events_menu_item_title_entries_joined"><![CDATA[Joined]]></string>
+    <string name="_bx_events_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_events_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_events_menu_item_title_system_entries_home"><![CDATA[Events]]></string>
+    <string name="_bx_events_menu_item_title_entries_home"><![CDATA[Events]]></string>
+    <string name="_bx_events_menu_item_title_system_admt_groups"><![CDATA[Events]]></string>
+    <string name="_bx_events_menu_item_title_admt_groups"><![CDATA[Events]]></string>
+    <string name="_bx_events_menu_item_title_manage_my"><![CDATA[My Events]]></string>
+    <string name="_bx_events_menu_item_title_manage_all"><![CDATA[All Events]]></string>
+    <string name="_bx_events_menu_item_title_system_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_events_menu_item_title_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_events_menu_item_title_system_entries_upcoming"><![CDATA[Upcoming]]></string>
+    <string name="_bx_events_menu_item_title_entries_upcoming"><![CDATA[Upcoming]]></string>        
+    <string name="_bx_events_menu_item_title_system_entries_past"><![CDATA[Past]]></string>
+    <string name="_bx_events_menu_item_title_entries_past"><![CDATA[Past]]></string>
+    <string name="_bx_events_menu_item_title_system_calendar"><![CDATA[Calendar]]></string>
+    <string name="_bx_events_menu_item_title_calendar"><![CDATA[Calendar]]></string>
+
+    <string name="_bx_events_menu_item_title_system_sm_date_start"><![CDATA[Date start]]></string>
+    <string name="_bx_events_menu_item_title_sm_date_start"><![CDATA[Date start]]></string>
+    <string name="_bx_events_menu_item_title_system_sm_date_end"><![CDATA[Date end]]></string>
+    <string name="_bx_events_menu_item_title_sm_date_end"><![CDATA[Date end]]></string>
+    <string name="_bx_events_menu_item_title_ical_export"><![CDATA[Sync to Calendar]]></string>
+
+    <string name="_bx_events_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+    <string name="_bx_events_grid_filter_item_title_adm_select_one_filter2"><![CDATA[Any Audience]]></string>
+    <string name="_bx_events_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_events_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+    <string name="_bx_events_grid_filter_item_title_adm_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_events_grid_filter_item_title_adm_suspended"><![CDATA[Suspended]]></string>
+    <string name="_bx_events_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_events_grid_column_title_adm_name"><![CDATA[Name]]></string>
+    <string name="_bx_events_grid_column_title_adm_added"><![CDATA[Created]]></string>
+    <string name="_bx_events_grid_column_title_adm_account"><![CDATA[Account]]></string>
+    <string name="_bx_events_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_events_grid_action_title_adm_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_events_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_events_grid_action_title_adm_audit_content"><![CDATA[Audit actions with content]]></string>
+    <string name="_bx_events_grid_action_title_adm_audit_context"><![CDATA[Audit actions in context]]></string>
+    <string name="_bx_events_grid_action_title_adm_clear_reports"><![CDATA[Сlear reports]]></string>
+    <string name="_bx_events_grid_action_err_delete"><![CDATA[Cannot delete the selected event(s).]]></string>
+    <string name="_bx_events_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_events_grid_column_title_name"><![CDATA[Name]]></string>
+    <string name="_bx_events_grid_column_title_role_id"><![CDATA[Role]]></string>
+    <string name="_bx_events_grid_column_title_period"><![CDATA[Period]]></string>
+    <string name="_bx_events_grid_column_title_price"><![CDATA[Price]]></string>
+    <string name="_bx_events_grid_action_title_add"><![CDATA[Add]]></string>
+    <string name="_bx_events_grid_action_title_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_events_grid_action_title_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_events_grid_action_title_buy"><![CDATA[Buy]]></string>
+    <string name="_bx_events_grid_action_title_buy_title"><![CDATA[One-time payment]]></string>
+    <string name="_bx_events_grid_action_title_subscribe"><![CDATA[Subscribe]]></string>
+    <string name="_bx_events_grid_action_title_subscribe_title"><![CDATA[Create a subscription with recurring billing]]></string>
+    <string name="_bx_events_grid_action_title_choose"><![CDATA[Choose]]></string>
+    <string name="_bx_events_grid_action_title_choose_title"><![CDATA[Switch to the level for free]]></string>
+    <string name="_bx_events_popup_title_price_add"><![CDATA[Add Pricing Plan]]></string>
+    <string name="_bx_events_popup_title_price_edit"><![CDATA[Edit Pricing Plan]]></string>
+
+    <string name="_bx_events_chart_growth"><![CDATA[Events: Growth]]></string>
+    <string name="_bx_events_chart_growth_speed"><![CDATA[Events: Growth Speed]]></string>
+
+    <string name="_bx_events_search_extended"><![CDATA[Events Search]]></string>
+    <string name="_bx_events_search_extended_cmts"><![CDATA[Events Comments Search]]></string>
+
+    <string name="_bx_events_txt_all_entries_in"><![CDATA[<a href="{0}">All Events in {1} ({2})</a>]]></string>
+    <string name="_bx_events_txt_account_pending"><![CDATA[This event is pending approval, please wait until it is activated.]]></string>
+    <string name="_bx_events_txt_account_suspended"><![CDATA[This event is suspended.]]></string>
+    <string name="_bx_events_txt_scheduled_awaiting"><![CDATA[Event publishing date is {date_publish_uf}]]></string>
+    <string name="_bx_events_txt_status_hidden"><![CDATA[This event was hidden.]]></string>
+    <string name="_bx_events_txt_N_fans"><![CDATA[{0} members]]></string>
+    <string name="_bx_events_txt_role"><![CDATA[Role]]></string>
+    <string name="_bx_events_txt_sample_single"><![CDATA[event]]></string>
+    <string name="_bx_events_txt_sample_single_with_article"><![CDATA[an event]]></string>
+    <string name="_bx_events_txt_sample_comment_single"><![CDATA[comment to event]]></string>
+    <string name="_bx_events_txt_sample_vote_single"><![CDATA[vote to event]]></string>
+    <string name="_bx_events_txt_sample_score_up_single"><![CDATA[score up vote to event]]></string>
+    <string name="_bx_events_txt_sample_score_down_single"><![CDATA[score down vote to event]]></string>
+    <string name="_bx_events_txt_set_role"><![CDATA[Set Role]]></string>
+    <string name="_bx_events_txt_private_group"><![CDATA[Private event]]></string>
+    <string name="_bx_events_txt_from_time_to_time"><![CDATA[{0} - {1}]]></string>
+    <string name="_bx_events_txt_invite_popup_text"><![CDATA[You have been invited to a event. Click the button below to accept the invitation.]]></string>
+    <string name="_bx_events_txt_invite_popup_title"><![CDATA[Invitation to a event]]></string>
+    <string name="_bx_events_txt_invite_popup_button_accept"><![CDATA[Accept]]></string>
+    <string name="_bx_events_txt_invite_popup_button_decline"><![CDATA[Decline]]></string>
+    <string name="_bx_events_txt_invite_popup_error_invitation_absent"><![CDATA[Sorry, an error has occurred. You can not join this event. The invitation is expired or deleted.]]></string>
+    <string name="_bx_events_txt_invite_popup_error_invitation_wrong_user"><![CDATA[Sorry, an error has occurred. You can not join this event. This invitation cannot be used by you.]]></string>
+    <string name="_bx_events_txt_n_unit"><![CDATA[{0} ({1})]]></string>
+    <string name="_bx_events_txt_cart_item_title"><![CDATA[{0}: {1} ({2} {3})]]></string>
+    <string name="_bx_events_txt_cart_item_title_lifetime"><![CDATA[{0}: {1} (lifetime)]]></string>    
+
+    <string name="_bx_events_msg_performed"><![CDATA[The action was successfully performed.]]></string>
+    <string name="_bx_events_err_price_duplicate"><![CDATA[Similar pricing plan is already exists.]]></string>
+    <string name="_bx_events_err_cannot_perform"><![CDATA[An error appeared. Please report.]]></string>
+
+    <string name="_bx_events_alert_action_fan_added"><![CDATA[member joined]]></string>
+    <string name="_bx_events_txt_ntfs_fan_added"><![CDATA[Event <b class="bx-ntfs-content-profile">{owner_name}</b> has got a member <b class="bx-ntfs-content-entry">{subentry_sample}</b>]]></string>
+    <string name="_bx_events_alert_action_join_invitation_notif"><![CDATA[join invitation]]></string>
+    <string name="_bx_events_alert_action_join_request"><![CDATA[join request]]></string>
+    <string name="_bx_events_alert_action_reminder"><![CDATA[reminder]]></string>
+    <string name="_bx_events_alert_action_reminder_follow_context"><![CDATA[New reminders]]></string>
+    <string name="_bx_events_txt_ntfs_join_invitation"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> event's representative invites <b class="bx-ntfs-content-entry">{subentry_sample}</b> to join event]]></string>
+    <string name="_bx_events_txt_ntfs_join_request"><![CDATA[Event <b class="bx-ntfs-content-profile">{owner_name}</b> has a join request from <b class="bx-ntfs-content-entry">{subentry_sample}</b>]]></string>
+    <string name="_bx_events_txt_ntfs_reminder_1"><![CDATA[Event <b class="bx-ntfs-content-profile">{owner_name}</b> starts in an hour]]></string>
+    <string name="_bx_events_txt_ntfs_reminder_24"><![CDATA[Event <b class="bx-ntfs-content-profile">{owner_name}</b> starts in 24 hours]]></string>
+    <string name="_bx_events_txt_ntfs_timeline_post_common"><![CDATA[New post <b class="bx-ntfs-content-entry">{subentry_sample}</b> in <b class="bx-ntfs-content-profile">{owner_name}</b> event timeline]]></string>
+
+    <string name="_bx_events_privacy_group_closed"><![CDATA[Closed]]></string>
+    <string name="_bx_events_privacy_group_secret"><![CDATA[Secret]]></string>
+
+    <string name="_bx_events_pre_lists_reminder"><![CDATA[Event reminder]]></string>
+    <string name="_bx_events_reminder_none"><![CDATA[Reminder is off]]></string>
+    <string name="_bx_events_reminder_1h"><![CDATA[1 hour]]></string>
+    <string name="_bx_events_reminder_2h"><![CDATA[2 hours]]></string>
+    <string name="_bx_events_reminder_3h"><![CDATA[3 hours]]></string>
+    <string name="_bx_events_reminder_6h"><![CDATA[6 hours]]></string>
+    <string name="_bx_events_reminder_12h"><![CDATA[12 hours]]></string>
+    <string name="_bx_events_reminder_24h"><![CDATA[24 hours]]></string>
+
+    <string name="_bx_events_pre_lists_cats"><![CDATA[Event categories]]></string>
+    <string name="_bx_events_cat_Conference"><![CDATA[Conference]]></string>
+    <string name="_bx_events_cat_Festival"><![CDATA[Festival]]></string>
+    <string name="_bx_events_cat_Fundraiser"><![CDATA[Fundraiser]]></string>
+    <string name="_bx_events_cat_Lecture"><![CDATA[Lecture]]></string>
+    <string name="_bx_events_cat_Market"><![CDATA[Market]]></string>
+    <string name="_bx_events_cat_Meal"><![CDATA[Meal]]></string>
+    <string name="_bx_events_cat_Social_Mixer"><![CDATA[Social Mixer]]></string>
+    <string name="_bx_events_cat_Tour"><![CDATA[Tour]]></string>
+    <string name="_bx_events_cat_Volunteering"><![CDATA[Volunteering]]></string>
+    <string name="_bx_events_cat_Workshop"><![CDATA[Workshop]]></string>
+    <string name="_bx_events_cat_Other"><![CDATA[Other]]></string>
+
+    <string name="_bx_events_pre_lists_roles"><![CDATA[Event roles]]></string>
+    <string name="_bx_events_role_regular"><![CDATA[Regular]]></string>
+    <string name="_bx_events_role_administrator"><![CDATA[Administrator]]></string>
+    <string name="_bx_events_role_moderator"><![CDATA[Moderator]]></string>
+
+    <string name="_bx_events_pre_lists_period_units"><![CDATA[Billing Interval]]></string>
+    <string name="_bx_events_period_unit_day"><![CDATA[day]]></string>
+    <string name="_bx_events_period_unit_week"><![CDATA[week]]></string>
+    <string name="_bx_events_period_unit_month"><![CDATA[month]]></string>
+    <string name="_bx_events_period_unit_year"><![CDATA[year]]></string>
+
+    <string name="_bx_events_pre_lists_repeat_year"><![CDATA[Repeat year]]></string>
+    <string name="_bx_events_cat_repeat_year_every_year"><![CDATA[Every year]]></string>
+    <string name="_bx_events_cat_repeat_year_every_2_years"><![CDATA[Every 2 years]]></string>
+    <string name="_bx_events_cat_repeat_year_every_3_years"><![CDATA[Every 3 years]]></string>
+    <string name="_bx_events_cat_repeat_year_every_4_years"><![CDATA[Every 4 years]]></string>
+
+    <string name="_bx_events_pre_lists_repeat_month"><![CDATA[Repeat month]]></string>
+    <string name="_bx_events_cat_repeat_month_every_month"><![CDATA[Every month]]></string>
+    <string name="_bx_events_cat_repeat_month_jan"><![CDATA[Every January]]></string>
+    <string name="_bx_events_cat_repeat_month_feb"><![CDATA[Every February]]></string>
+    <string name="_bx_events_cat_repeat_month_mar"><![CDATA[Every March]]></string>
+    <string name="_bx_events_cat_repeat_month_apr"><![CDATA[Every April]]></string>
+    <string name="_bx_events_cat_repeat_month_may"><![CDATA[Every May]]></string>
+    <string name="_bx_events_cat_repeat_month_jun"><![CDATA[Every June]]></string>
+    <string name="_bx_events_cat_repeat_month_jul"><![CDATA[Every July]]></string>
+    <string name="_bx_events_cat_repeat_month_aug"><![CDATA[Every August]]></string>
+    <string name="_bx_events_cat_repeat_month_sep"><![CDATA[Every September]]></string>
+    <string name="_bx_events_cat_repeat_month_oct"><![CDATA[Every October]]></string>
+    <string name="_bx_events_cat_repeat_month_nov"><![CDATA[Every November]]></string>
+    <string name="_bx_events_cat_repeat_month_dec"><![CDATA[Every December]]></string>
+
+    <string name="_bx_events_pre_lists_repeat_week_of_month"><![CDATA[Repeat week of the month]]></string>
+    <string name="_bx_events_cat_repeat_week_of_month_every_week"><![CDATA[Every week]]></string>
+    <string name="_bx_events_cat_repeat_week_of_month_first_week_of_month"><![CDATA[Every 1st week of the month]]></string>
+    <string name="_bx_events_cat_repeat_week_of_month_second_week_of_month"><![CDATA[Every 2nd week of the month]]></string>
+    <string name="_bx_events_cat_repeat_week_of_month_third_week_of_month"><![CDATA[Every 3rd week of the month]]></string>
+    <string name="_bx_events_cat_repeat_week_of_month_fourth_week_of_month"><![CDATA[Every 4th week of the month]]></string>
+    <string name="_bx_events_cat_repeat_week_of_month_fifth_week_of_month"><![CDATA[Every 5th week of the month]]></string>
+    <string name="_bx_events_cat_repeat_week_of_month_sixth_week_of_month"><![CDATA[Every 6th week of the month]]></string>
+
+    <string name="_bx_events_pre_lists_repeat_day_of_month"><![CDATA[Repeat day of the month]]></string>
+    <string name="_bx_events_cat_repeat_day_of_month_every_day"><![CDATA[Every day]]></string>
+
+    <string name="_bx_events_pre_lists_repeat_day_of_week"><![CDATA[Repeat day of the week]]></string>
+    <string name="_bx_events_cat_repeat_day_of_week_every_day"><![CDATA[Every day of the week]]></string>
+    <string name="_bx_events_cat_repeat_day_of_week_mon"><![CDATA[Every Monday]]></string>
+    <string name="_bx_events_cat_repeat_day_of_week_tue"><![CDATA[Every Tuesday]]></string>
+    <string name="_bx_events_cat_repeat_day_of_week_wed"><![CDATA[Every Wednesday]]></string>
+    <string name="_bx_events_cat_repeat_day_of_week_thu"><![CDATA[Every Thursday]]></string>
+    <string name="_bx_events_cat_repeat_day_of_week_fri"><![CDATA[Every Friday]]></string>
+    <string name="_bx_events_cat_repeat_day_of_week_sat"><![CDATA[Every Saturday]]></string>
+    <string name="_bx_events_cat_repeat_day_of_week_sun"><![CDATA[Every Sunday]]></string>
+
+    <string name="_bx_events_email_join_request"><![CDATA[Event join request]]></string>
+    <string name="_bx_events_email_join_request_subject"><![CDATA[Request to join your event]]></string>
+    <string name="_bx_events_email_join_request_body"><![CDATA[{email_header}
+<p>New request to join <a href="{EntryUrl}">{EntryTitle}</a> event from <a href="{NewMemberUrl}">{NewMemberDisplayName}</a></p>
+{email_footer}]]></string>
+
+    <string name="_bx_events_email_join_reject"><![CDATA[Event join request was rejected]]></string>
+    <string name="_bx_events_email_join_reject_subject"><![CDATA[Request to join an event was rejected]]></string>
+    <string name="_bx_events_email_join_reject_body"><![CDATA[{email_header}
+<p>Your request to join <a href="{EntryUrl}">{EntryTitle}</a> event was rejected by event admin.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_events_email_join_confirm"><![CDATA[Event join request was confirmed]]></string>
+    <string name="_bx_events_email_join_confirm_subject"><![CDATA[Your request to join an event was confirmed]]></string>
+    <string name="_bx_events_email_join_confirm_body"><![CDATA[{email_header}
+<p>Your request to join <a href="{EntryUrl}">{EntryTitle}</a> event was confirmed by the event admin.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_events_email_fan_remove"><![CDATA[Profile was removed from event participants]]></string>
+    <string name="_bx_events_email_fan_remove_subject"><![CDATA[Your profile was removed from the event]]></string>
+    <string name="_bx_events_email_fan_remove_body"><![CDATA[{email_header}
+<p>Your profile was removed from <a href="{EntryUrl}">{EntryTitle}</a> event by the event admin.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_events_email_fan_become_admin"><![CDATA[Event admin status was granted]]></string>
+    <string name="_bx_events_email_fan_become_admin_subject"><![CDATA[You are an event admin now]]></string>
+    <string name="_bx_events_email_fan_become_admin_body"><![CDATA[{email_header}
+<p>You are an admin of <a href="{EntryUrl}">{EntryTitle}</a> event now.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_events_email_admin_become_fan"><![CDATA[Event admin status was revoked]]></string>
+    <string name="_bx_events_email_admin_become_fan_subject"><![CDATA[Your event admin status was revoked]]></string>
+    <string name="_bx_events_email_admin_become_fan_body"><![CDATA[{email_header}
+<p>Your admin status was revoked from <a href="{EntryUrl}">{EntryTitle}</a> event.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_events_email_invitation"><![CDATA[Invitation to event]]></string>
+    <string name="_bx_events_email_invitation_subject"><![CDATA[Invitation to "{EntryTitle}" event]]></string>
+    <string name="_bx_events_email_invitation_body"><![CDATA[{email_header}
+<p><a href="{InviterUrl}">{InviterDisplayName}</a> invited you to <a href="{EntryUrl}">{EntryTitle} event</a>.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_events_email_set_role"><![CDATA[Event member status was changed]]></string>
+    <string name="_bx_events_email_set_role_subject"><![CDATA[Your event status was changed]]></string>
+    <string name="_bx_events_email_set_role_body"><![CDATA[{email_header}
+<p>Your status in <a href="{EntryUrl}">{EntryTitle}</a> event was changed to <b>{Role}</b>.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_events_email_reminder"><![CDATA[Reminder for the event]]></string>
+    <string name="_bx_events_email_reminder_subject"><![CDATA["{EntryTitle}" event - {EntryBeginShort}]]></string>
+    <string name="_bx_events_email_reminder_body"><![CDATA[{email_header}
+<p class="vevent">
+    <a href="{EntryUrl}" class="summary">{EntryTitle}</a> event reminder:</a><br />
+    Date: <abbr class="dtstart" title="{EntryBeginUTC}">{EntryBegin}</abbr><br />
+    {EntryLocation}
+</p>
+{email_footer}]]></string>
+    <string name="_bx_events_email_reminder_location"><![CDATA[Location: <span class="location">{0}</span>]]></string>
+</resources>

+ 734 - 0
modules/boonex/events/updates/13.0.4_13.0.5/source/install/sql/enable.sql

@@ -0,0 +1,734 @@
+
+-- SETTINGS
+
+SET @iTypeOrder = (SELECT MAX(`order`) FROM `sys_options_types` WHERE `group` = 'modules');
+INSERT INTO `sys_options_types`(`group`, `name`, `caption`, `icon`, `order`) VALUES 
+('modules', 'bx_events', '_bx_events', 'bx_events@modules/boonex/events/|std-icon.svg', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_events', '_bx_events', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+('bx_events_enable_auto_approve', 'on', @iCategId, '_bx_events_option_enable_auto_approve', 'checkbox', '', '', '', 0),
+('bx_events_num_connections_quick', '6', @iCategId, '_bx_events_option_num_connections_quick', 'digit', '', '', '', 10),
+('bx_events_per_page_browse', '24', @iCategId, '_bx_events_option_per_page_browse', 'digit', '', '', '', 11),
+('bx_events_num_rss', '10', @iCategId, '_bx_events_option_num_rss', 'digit', '', '', '', 12),
+('bx_events_per_page_browse_showcase', '32', @iCategId, '_sys_option_per_page_browse_showcase', 'digit', '', '', '', 15),
+('bx_events_per_page_browse_recommended', '10', @iCategId, '_sys_option_per_page_browse_recommended', 'digit', '', '', '', 16),
+('bx_events_per_page_for_favorites_lists', '5', @iCategId, '_bx_events_option_per_page_for_favorites_lists', 'digit', '', '', '', 17),
+('bx_events_time_format', 'H:i', @iCategId, '_bx_events_option_time_format', 'digit', '', '', '', 20),
+('bx_events_short_date_format', 'j/n/Y', @iCategId, '_bx_events_option_short_date_format', 'digit', '', '', '', 22),
+('bx_events_datetime_format', 'j/n/Y H:i', @iCategId, '_bx_events_option_datetime_format', 'digit', '', '', '', 23),
+('bx_events_summary_chars', '700', @iCategId, '_bx_events_option_summary_chars', 'digit', '', '', '', 25),
+('bx_events_searchable_fields', 'event_name,event_desc', @iCategId, '_bx_events_option_searchable_fields', 'list', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:21:"get_searchable_fields";}', '', '', 30),
+('bx_events_members_mode', '', @iCategId, '_bx_events_option_members_mode', 'select', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:24:"get_options_members_mode";}', '', '', 40),
+('bx_events_public_subscribed_me', 'on', @iCategId, '_bx_events_option_public_subscribed_me', 'checkbox', '', '', '', 50),
+('bx_events_enable_subscribe_wo_join', '', @iCategId, '_bx_events_option_enable_subscribe_wo_join', 'checkbox', '', '', '', 55),
+('bx_events_internal_notifications', '', @iCategId, '_bx_events_option_internal_notifications', 'checkbox', '', '', '', 60),
+('bx_events_reminder_interval', '24', @iCategId, '_bx_events_option_reminder_interval', 'select', '24,48', '', '', 70);
+
+-- PAGES
+
+-- PAGE: create profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_create_profile', 'create-event-profile', '_bx_events_page_title_sys_create_profile', '_bx_events_page_title_create_profile', 'bx_events', 5, 2147483647, 1, 'page.php?i=create-event-profile', '', '', '', 0, 1, 0, '', '');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_create_profile', 1, 'bx_events', '_bx_events_page_block_title_create_profile', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:13:\"entity_create\";}', 0, 1, 1);
+
+-- PAGE: view profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_view_profile', 'view-event-profile', '_bx_events_page_title_sys_view_profile', '_bx_events_page_title_view_profile', 'bx_events', 10, 2147483647, 1, 'page.php?i=view-event-profile', '', '', '', 0, 1, 0, 'BxEventsPageEntry', 'modules/boonex/events/classes/BxEventsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `hidden_on`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('bx_events_view_profile', 4, 'bx_events', '', '_bx_events_page_block_title_profile_comments', 11, '', 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 0, 0),
+('bx_events_view_profile', 4, 'bx_events', '', '_bx_events_page_block_title_profile_description', 13, '', 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:17:\"entity_text_block\";}', 0, 0, 1, 0),
+('bx_events_view_profile', 2, 'bx_events', '', '_bx_events_page_block_title_profile_info', 11, '', 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:11:\"entity_info\";}', 0, 0, 1, 0),
+('bx_events_view_profile', 1, 'bx_events', '', '_bx_events_page_block_title_entry_social_sharing', 13, '', 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:21:\"entity_social_sharing\";}', 0, 0, 0, 0),
+('bx_events_view_profile', 1, 'bx_events', '', '_bx_events_page_block_title_entry_all_actions', 13, '', 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:18:"entity_all_actions";}', 0, 0, 0, 0),
+('bx_events_view_profile', 3, 'bx_events', '', '_bx_events_page_block_title_profile_calendar', 11, '', 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:8:\"calendar\";s:6:\"params\";a:2:{i:0;a:1:{s:5:\"event\";s:12:\"{content_id}\";}i:1;s:21:\"calendar_compact.html\";}}', 0, 0, 1, 0),
+('bx_events_view_profile', 3, 'bx_events', '_bx_events_page_block_title_sys_entry_context', '_bx_events_page_block_title_entry_context', 13, '', 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:14:\"entity_context\";}', 0, 0, 1, 1),
+('bx_events_view_profile', 4, 'bx_events', '', '_bx_events_page_block_title_fans', 11, '', 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:4:\"fans\";}', 0, 0, 1, 1),
+('bx_events_view_profile', 4, 'bx_events', '', '_bx_events_page_block_title_admins', 11, '', 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:6:\"admins\";}', 0, 0, 1, 2),
+('bx_events_view_profile', 2, 'bx_events', '', '_bx_events_page_block_title_entry_location', 11, '', 2147483647, 'service', 'a:4:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:13:\"locations_map\";s:6:\"params\";a:2:{i:0;s:9:\"bx_events\";i:1;s:12:\"{content_id}\";}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 0, 0, 1, 1),
+('bx_events_view_profile', 2, 'bx_events', '', '_bx_events_page_block_title_entry_reports', 11, '', 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"events\";s:6:\"method\";s:14:\"entity_reports\";}', 0, 0, 1, 6);
+-- PAGE: view closed profile 
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_view_profile_closed', 'view-event-profile-closed', '_bx_events_page_title_sys_view_profile_closed', '_bx_events_page_title_view_profile', 'bx_events', 10, 2147483647, 1, 'page.php?i=view-event-profile', '', '', '', 0, 1, 0, 'BxEventsPageEntry', 'modules/boonex/events/classes/BxEventsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_events_view_profile_closed', 2, 'bx_events', '', '_bx_events_page_block_title_profile_info', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:11:\"entity_info\";}', 0, 0, 1, 0),
+('bx_events_view_profile_closed', 3, 'bx_events', '', '_bx_events_page_block_title_fans', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:4:\"fans\";}', 0, 0, 1, 0);
+
+-- PAGE: edit profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_edit_profile', 'edit-event-profile', '_bx_events_page_title_sys_edit_profile', '_bx_events_page_title_edit_profile', 'bx_events', 5, 2147483647, 1, 'page.php?i=edit-event-profile', '', '', '', 0, 1, 0, 'BxEventsPageEntry', 'modules/boonex/events/classes/BxEventsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_edit_profile', 1, 'bx_events', '_bx_events_page_block_title_edit_profile', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:11:\"entity_edit\";}', 0, 0, 0);
+
+-- PAGE: edit profile cover
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_edit_profile_cover', 'edit-event-cover', '_bx_events_page_title_sys_edit_profile_cover', '_bx_events_page_title_edit_profile_cover', 'bx_events', 5, 2147483647, 1, 'page.php?i=edit-event-cover', '', '', '', 0, 1, 0, 'BxEventsPageEntry', 'modules/boonex/events/classes/BxEventsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_edit_profile_cover', 1, 'bx_events', '_bx_events_page_block_title_edit_profile_cover', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:17:\"entity_edit_cover\";}', 0, 0, 0);
+
+-- PAGE: invite members
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_invite', 'invite-to-event', '_bx_events_page_title_sys_invite_to_group', '_bx_events_page_title_invite_to_group', 'bx_events', 5, 2147483647, 1, 'page.php?i=invite-to-event', '', '', '', 0, 1, 0, 'BxEventsPageEntry', 'modules/boonex/events/classes/BxEventsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_invite', 1, 'bx_events', '_bx_events_page_block_title_invite_to_group', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:13:\"entity_invite\";}', 0, 0, 0);
+
+-- PAGE: delete profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_delete_profile', 'delete-event-profile', '_bx_events_page_title_sys_delete_profile', '_bx_events_page_title_delete_profile', 'bx_events', 5, 2147483647, 1, 'page.php?i=delete-event-profile', '', '', '', 0, 1, 0, 'BxEventsPageEntry', 'modules/boonex/events/classes/BxEventsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_delete_profile', 1, 'bx_events', '_bx_events_page_block_title_delete_profile', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:13:\"entity_delete\";}', 0, 0, 0);
+
+-- PAGE: join profile
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_join_profile', 'join-event-profile', '_bx_events_page_title_sys_join_profile', '_bx_events_page_title_join_profile', 'bx_events', 5, 2147483647, 1, 'page.php?i=join-event-profile', '', '', '', 0, 1, 0, 'BxEventsPageEntry', 'modules/boonex/events/classes/BxEventsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_join_profile', 1, 'bx_events', '_bx_events_page_block_title_join_profile', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:11:"entity_join";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 0, 0, 0);
+
+-- PAGE: profile info
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_profile_info', 'event-profile-info', '_bx_events_page_title_sys_profile_info', '_bx_events_page_title_profile_info', 'bx_events', 5, 2147483647, 1, 'page.php?i=event-profile-info', '', '', '', 0, 1, 0, 'BxEventsPageEntry', 'modules/boonex/events/classes/BxEventsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `hidden_on`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_events_profile_info', 1, 'bx_events', '', '_bx_events_page_block_title_profile_description', 13, '', 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:17:\"entity_text_block\";}', 0, 0, 1, 0),
+('bx_events_profile_info', 2, 'bx_events', '_bx_events_page_block_title_system_profile_info', '_bx_events_page_block_title_profile_info_link', 11, '', 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:16:\"entity_info_full\";}', 0, 0, 1, 0),
+('bx_events_profile_info', 3, 'bx_events', '', '_bx_events_page_block_title_profile_calendar', 11, '', 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:8:\"calendar\";s:6:\"params\";a:2:{i:0;a:1:{s:5:\"event\";s:12:\"{content_id}\";}i:1;s:21:\"calendar_compact.html\";}}', 0, 0, 1, 0),
+('bx_events_profile_info', 2, 'bx_events', '', '_bx_events_page_block_title_entry_location', 11, '', 2147483647, 'service', 'a:4:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:13:\"locations_map\";s:6:\"params\";a:2:{i:0;s:9:\"bx_events\";i:1;s:12:\"{content_id}\";}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 0, 0, 1, 1);
+
+-- PAGE: manage profile pricing
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_profile_pricing', 'edit-event-pricing', '_bx_events_page_title_sys_profile_pricing', '_bx_events_page_title_profile_pricing', 'bx_events', 5, 2147483647, 1, 'page.php?i=edit-event-pricing', '', '', '', 0, 1, 0, 'BxEventsPageEntry', 'modules/boonex/events/classes/BxEventsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_events_profile_pricing', 1, 'bx_events', '_bx_events_page_block_title_system_profile_pricing', '_bx_events_page_block_title_profile_pricing_link', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:14:"entity_pricing";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 0, 0, 1, 1);
+
+-- PAGE: event fans
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_fans', 'event-fans', '_bx_events_page_title_sys_group_fans', '_bx_events_page_title_group_fans', 'bx_events', 5, 2147483647, 1, 'page.php?i=event-fans', '', '', '', 0, 1, 0, 'BxEventsPageEntry', 'modules/boonex/events/classes/BxEventsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_events_fans', 1, 'bx_events', '_bx_events_page_block_title_system_fans', '_bx_events_page_block_title_fans_link', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:10:"fans_table";}', 0, 0, 1, 1),
+('bx_events_fans', 1, 'bx_events', '_bx_events_page_block_title_system_subscribers', '_bx_events_page_block_title_subscribers_link', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:19:"subscribed_me_table";s:5:"class";s:23:"TemplServiceConnections";}', 0, 0, 1, 2),
+('bx_events_fans', 1, 'bx_events', '_bx_events_page_block_title_system_invites', '_bx_events_page_block_title_fans_invites', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:13:"invites_table";}', 0, 0, 1, 3);
+
+-- PAGE: view entry comments
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_profile_comments', '_bx_events_page_title_sys_profile_comments', '_bx_events_page_title_profile_comments', 'bx_events', 5, 2147483647, 1, 'event-profile-comments', '', '', '', '', 0, 1, 0, 'BxEventsPageEntry', 'modules/boonex/events/classes/BxEventsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_events_profile_comments', 1, 'bx_events', '_bx_events_page_block_title_profile_comments', '_bx_events_page_block_title_profile_comments_link', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 0, 1);
+
+-- PAGE: module home
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_home', '_bx_events_page_title_sys_recent', '_bx_events_page_title_recent', 'bx_events', 5, 2147483647, 1, 'events-home', 'page.php?i=events-home', '', '', '', 0, 1, 0, 'BxEventsPageBrowse', 'modules/boonex/events/classes/BxEventsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_events_home', 1, 'bx_events', '_bx_events_page_block_title_featured_profiles', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:7:"gallery";}}', 0, 1, 0),
+('bx_events_home', 1, 'bx_events', '_bx_events_page_block_title_latest_profiles', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:22:\"browse_recent_profiles\";s:6:"params";a:1:{i:0;b:1;}}', 0, 1, 1),
+('bx_events_home', 1, 'bx_events', '_bx_events_page_block_title_past_profiles', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:20:"browse_past_profiles";s:6:"params";a:1:{i:0;b:0;}}', 0, 1, 2);
+
+-- PAGE: top profiles
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_top', '_bx_events_page_title_sys_top', '_bx_events_page_title_top', 'bx_events', 5, 2147483647, 1, 'events-top', 'page.php?i=events-top', '', '', '', 0, 1, 0, 'BxEventsPageBrowse', 'modules/boonex/events/classes/BxEventsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_top', 1, 'bx_events', '_bx_events_page_block_title_top_profiles', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:19:\"browse_top_profiles\";s:6:"params";a:1:{i:0;b:1;}}', 0, 1, 0);
+
+-- PAGE: entries in context
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_context', 'events-context', '_bx_events_page_title_sys_entries_in_context', '_bx_events_page_title_entries_in_context', 'bx_events', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxEventsPageEntriesInContext', 'modules/boonex/events/classes/BxEventsPageEntriesInContext.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_events_context', 1, 'bx_events', '_bx_events_page_block_title_sys_entries_in_context', '_bx_events_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:14:\"browse_context\";}', 0, 0, 1, 1),
+('bx_events_context', 1, 'bx_events', '_bx_events_page_block_title_sys_calendar_in_context', '_bx_events_page_block_title_calendar_in_context', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:9:"bx_events";s:6:"method";s:8:"calendar";s:12:"ignore_cache";b:1;s:6:"params";a:1:{i:0;a:1:{s:10:"context_id";s:12:"{profile_id}";}}}', 0, 0, 1, 2);
+
+-- PAGE: upcoming profiles
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_upcoming', '_bx_events_page_title_sys_upcoming', '_bx_events_page_title_upcoming', 'bx_events', 5, 2147483647, 1, 'events-upcoming', 'page.php?i=events-upcoming', '', '', '', 0, 1, 0, 'BxEventsPageBrowse', 'modules/boonex/events/classes/BxEventsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_upcoming', 1, 'bx_events', '_bx_events_page_block_title_upcoming_profiles', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:24:"browse_upcoming_profiles";s:6:"params";a:1:{i:0;a:1:{s:13:"empty_message";b:1;}}}', 0, 1, 0);
+
+-- PAGE: past profiles
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_past', '_bx_events_page_title_sys_past', '_bx_events_page_title_past', 'bx_events', 5, 2147483647, 1, 'events-past', 'page.php?i=events-past', '', '', '', 0, 1, 0, 'BxEventsPageBrowse', 'modules/boonex/events/classes/BxEventsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_past', 1, 'bx_events', '_bx_events_page_block_title_past_profiles', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:20:"browse_past_profiles";s:6:"params";a:1:{i:0;b:1;}}', 0, 0, 0);
+
+-- PAGE: calendar
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_calendar', '_bx_events_page_title_sys_calendar', '_bx_events_page_title_calendar', 'bx_events', 5, 2147483647, 1, 'events-calendar', 'page.php?i=events-calendar', '', '', '', 0, 1, 0, 'BxEventsPageCalendar', 'modules/boonex/events/classes/BxEventsPageCalendar.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_calendar', 1, 'bx_events', '_bx_events_page_block_title_calendar', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:8:"calendar";s:12:"ignore_cache";b:1;}', 0, 1, 0);
+
+-- PAGE: search for entries
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_search', '_bx_events_page_title_sys_entries_search', '_bx_events_page_title_entries_search', 'bx_events', 5, 2147483647, 1, 'events-search', 'page.php?i=events-search', '', '', '', 0, 1, 0, 'BxEventsPageBrowse', 'modules/boonex/events/classes/BxEventsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_events_search', 1, 'bx_events', '_bx_events_page_block_title_search_form', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:9:"bx_events";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1),
+('bx_events_search', 1, 'bx_events', '_bx_events_page_block_title_search_results', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:9:"bx_events";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 2),
+('bx_events_search', 1, 'bx_events', '_bx_events_page_block_title_search_form_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:14:"bx_events_cmts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 3),
+('bx_events_search', 1, 'bx_events', '_bx_events_page_block_title_search_results_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:14:"bx_events_cmts";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 4);
+
+-- PAGE: joined profiles
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_joined_events', '_bx_events_page_title_sys_joined', '_bx_events_page_title_joined', 'bx_events', 5, 2147483647, 1, 'events-joined', 'page.php?i=events-joined', '', '', '', 0, 1, 0, 'BxEventsPageBrowse', 'modules/boonex/events/classes/BxEventsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_joined_events', 1, 'bx_events', '_bx_events_page_block_title_joined_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:21:"browse_joined_entries";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;b:1;}}', 0, 1, 0);
+
+
+-- PAGE: module manage own
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_manage', '_bx_events_page_title_sys_manage', '_bx_events_page_title_manage', 'bx_events', 5, 2147483647, 1, 'events-manage', 'page.php?i=events-manage', '', '', '', 0, 1, 0, 'BxEventsPageBrowse', 'modules/boonex/events/classes/BxEventsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_manage', 1, 'bx_events', '_bx_events_page_block_title_system_manage', '_bx_events_page_block_title_manage', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:12:\"manage_tools\";}}', 0, 1, 0);
+
+-- PAGE: module manage all
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_administration', '_bx_events_page_title_sys_manage_administration', '_bx_events_page_title_manage', 'bx_events', 5, 192, 1, 'events-administration', 'page.php?i=events-administration', '', '', '', 0, 1, 0, 'BxEventsPageBrowse', 'modules/boonex/events/classes/BxEventsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_administration', 1, 'bx_events', '_bx_events_page_block_title_system_manage_administration', '_bx_events_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:12:\"manage_tools\";s:6:\"params\";a:1:{i:0;s:14:\"administration\";}}', 0, 1, 0);
+
+-- PAGE: user's events
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_joined', 'joined-events', '_bx_events_page_title_sys_joined_entries', '_bx_events_page_title_joined_entries', 'bx_events', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxEventsPageJoinedEntries', 'modules/boonex/events/classes/BxEventsPageJoinedEntries.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('bx_events_joined', 1, 'bx_events', '_bx_events_page_block_title_sys_entries_actions', '_bx_events_page_block_title_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:18:"my_entries_actions";}', 0, 0, 1, 1),
+('bx_events_joined', 1, 'bx_events', '_bx_events_page_block_title_sys_entries_of_author', '_bx_events_page_block_title_entries_of_author', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:22:"browse_created_entries";}', 0, 0, 0, 2),
+('bx_events_joined', 1, 'bx_events', '_bx_events_page_block_title_sys_favorites_of_author', '_bx_events_page_block_title_favorites_of_author', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:21:"browse_favorite_lists";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";s:6:"params";a:3:{s:9:"unit_view";s:8:"showcase";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1, 2),
+('bx_events_joined', 1, 'bx_events', '_bx_events_page_block_title_sys_joined_entries', '_bx_events_page_block_title_joined_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:21:"browse_joined_entries";s:6:"params";a:2:{i:0;i:0;i:1;b:1;}}', 0, 0, 1, 4);
+
+
+-- PAGE: favorites by list
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_favorites', '_bx_events_page_title_sys_entries_favorites', '_bx_events_page_title_entries_favorites', 'bx_events', 12, 2147483647, 1, 'events-favorites', 'page.php?i=events-favorites', '', '', '', 0, 1, 0, 'BxEventsPageListEntry', 'modules/boonex/events/classes/BxEventsPageListEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_events_favorites', 2, 'bx_events', '_bx_events_page_block_title_sys_favorites_entries', '_bx_events_page_block_title_favorites_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:15:"browse_favorite";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1),
+('bx_events_favorites', 3, 'bx_events', '', '_bx_events_page_block_title_favorites_entries_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:19:"favorites_list_info";}', 0, 0, 0),
+('bx_events_favorites', 3, 'bx_events', '', '_bx_events_page_block_title_favorites_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:22:"favorites_list_actions";}', 0, 0, 1);
+
+
+-- PAGE: add block to homepage
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = 'sys_home' AND `cell_id` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('sys_home', 1, 'bx_events', '', '_bx_events_page_block_title_latest_profiles', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:22:"browse_recent_profiles";}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1),
+('sys_home', 1, 'bx_events', '_bx_events_page_block_title_sys_recommended_entries_view_showcase', '_bx_events_page_block_title_recommended_entries_view_showcase', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:18:"browse_recommended";}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 2);
+
+-- PAGE: service blocks
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = '' AND `cell_id` = 0 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('', 0, 'bx_events', '', '_bx_events_page_block_title_categories', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:15:"categories_list";s:6:"params";a:2:{i:0;s:14:"bx_events_cats";i:1;a:2:{s:10:\"show_empty\";b:1;s:21:\"show_empty_categories\";b:1;}}s:5:"class";s:20:"TemplServiceCategory";}', 1, 1, IFNULL(@iBlockOrder, 0) + 1),
+('', 0, 'bx_events', '_bx_events_page_block_title_sys_featured_entries_view_showcase', '_bx_events_page_block_title_featured_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:15:\"browse_featured\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 2),
+('', 0, 'bx_events', '_bx_events_page_block_title_sys_recommended_entries_view_showcase', '_bx_events_page_block_title_recommended_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:18:\"browse_recommended\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0,  1, IFNULL(@iBlockOrder, 0) + 3),
+('', 0, 'bx_events', '_bx_events_page_block_title_sys_cover_block', '_bx_events_page_block_title_cover_block', 3, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_events\";s:6:\"method\";s:12:\"entity_cover\";}', 0, 1, IFNULL(@iBlockOrder, 0) + 4);
+ 
+ -- PAGES: add page block to profiles modules (trigger* page objects are processed separately upon modules enable/disable)
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`, `active`) VALUES
+('trigger_page_group_view_entry', 2, 'bx_events', '_bx_events_page_block_title_calendar_for_context', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:9:"bx_events";s:6:"method";s:8:"calendar";s:12:"ignore_cache";b:1;s:6:"params";a:1:{i:0;a:1:{s:10:"context_id";s:12:"{profile_id}";}}}', 0, 0, 0, 0),
+('trigger_page_group_view_entry', 4, 'bx_events', '_bx_events_page_block_title_browse_for_context', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:14:"browse_context";s:6:"params";a:1:{s:10:"context_id";s:12:"{profile_id}";}}', 0, 0, 1, 0);
+
+
+-- MENU
+
+-- MENU: add to site menu
+
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' AND `active` = 1 AND `order` < 9999 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_site', 'bx_events', 'events-home', '_bx_events_menu_item_title_system_entries_home', '_bx_events_menu_item_title_entries_home', 'page.php?i=events-home', '', '', 'calendar col-red2', 'bx_events_submenu', 2147483647, 1, 1, IFNULL(@iSiteMenuOrder, 0) + 1);
+
+-- MENU: add to homepage menu
+
+SET @iHomepageMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_homepage' AND `active` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_homepage', 'bx_events', 'events-home', '_bx_events_menu_item_title_system_entries_home', '_bx_events_menu_item_title_entries_home', 'page.php?i=events-home', '', '', 'calendar col-red2', 'bx_events_submenu', 2147483647, 1, 1, IFNULL(@iHomepageMenuOrder, 0) + 1);
+
+-- MENU: add to "add content" menu
+
+SET @iAddMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_add_content_links' AND `active` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_add_content_links', 'bx_events', 'create-event-profile', '_bx_events_menu_item_title_system_create_profile', '_bx_events_menu_item_title_create_profile', 'page.php?i=create-event-profile', '', '', 'calendar col-red2', '', 2147483647, 1, 1, IFNULL(@iAddMenuOrder, 0) + 1);
+
+-- MENU: view actions
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_view_actions', '_bx_events_menu_title_view_profile_actions', 'bx_events_view_actions', 'bx_events', 9, 0, 1, 'BxEventsMenuViewActions', 'modules/boonex/events/classes/BxEventsMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_events_view_actions', 'bx_events', '_bx_events_menu_set_title_view_profile_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_events_view_actions', 'bx_events', 'join-event-profile', '_bx_events_menu_item_title_system_pay_and_join', '_bx_events_menu_item_title_pay_and_join', 'page.php?i=join-event-profile&profile_id={profile_id}', '', '', 'sign-in-alt', '', 0, 2147483647, 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:22:"is_paid_join_avaliable";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 1, 0, 0, 5),
+('bx_events_view_actions', 'bx_events', 'profile-fan-add', '_bx_events_menu_item_title_system_become_fan', '{title_add_fan}', 'javascript:void(0)', 'bx_conn_action(this, \'bx_events_fans\', \'add\', \'{profile_id}\')', '', 'sign-in-alt', '', 0, 2147483647, 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:22:"is_free_join_avaliable";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 1, 0, 0, 5),
+('bx_events_view_actions', 'bx_events', 'profile-subscribe-add', '_bx_events_menu_item_title_system_subscribe', '_bx_events_menu_item_title_subscribe', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_subscriptions\', \'add\', \'{profile_id}\')', '', 'check', '', 0, 2147483647, '', 1, 0, 1, 20),
+('bx_events_view_actions', 'bx_events', 'profile-set-badges', '_sys_menu_item_title_system_set_badges', '_sys_menu_item_title_set_badges', 'javascript:void(0)', 'bx_menu_popup(''sys_set_badges'', window, {}, {module: ''bx_events'', content_id: {content_id}});', '', 'check-circle', '', 0, 192, 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:19:"is_badges_avaliable";}', 1, 0, 1, 30),
+('bx_events_view_actions', 'bx_events', 'ical-export', '', '_bx_events_menu_item_title_ical_export', '{ical_url}', '', '', 'calendar-plus', '', 0, 2147483647, 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:24:"is_ical_export_avaliable";s:6:"params";a:1:{i:0;s:12:"{content_id}";}}', 1, 0, 1, 40),
+('bx_events_view_actions', 'bx_events', 'profile-actions-more', '_bx_events_menu_item_title_system_more_actions', '_bx_events_menu_item_title_more_actions', 'javascript:void(0)', 'bx_menu_popup(''bx_events_view_actions_more'', this, {}, {profile_id:{profile_id}});', '', 'cog', 'bx_events_view_actions_more', 1, 2147483647, '', 1, 0, 1, 9999);
+
+-- MENU: view actions more
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_view_actions_more', '_bx_events_menu_title_view_profile_actions_more', 'bx_events_view_actions_more', 'bx_events', 6, 0, 1, 'BxEventsMenuViewActions', 'modules/boonex/events/classes/BxEventsMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_events_view_actions_more', 'bx_events', '_bx_events_menu_set_title_view_profile_actions_more', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_events_view_actions_more', 'bx_events', 'profile-fan-remove', '_bx_events_menu_item_title_system_leave_group', '{title_remove_fan}', 'javascript:void(0)', 'bx_conn_action(this, \'bx_events_fans\', \'remove\', \'{profile_id}\')', '', 'sign-out-alt', '', 2147483647, '', 1, 0, 10),
+('bx_events_view_actions_more', 'bx_events', 'profile-subscribe-remove', '_bx_events_menu_item_title_system_unsubscribe', '_bx_events_menu_item_title_unsubscribe', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_subscriptions\', \'remove\', \'{profile_id}\')', '', 'check', '', 2147483647, '', 1, 0, 20),
+('bx_events_view_actions_more', 'bx_events', 'edit-event-cover', '_bx_events_menu_item_title_system_edit_cover', '_bx_events_menu_item_title_edit_cover', 'page.php?i=edit-event-cover&id={content_id}', '', '', 'edit', '', 2147483647, '', 1, 0, 30),
+('bx_events_view_actions_more', 'bx_events', 'edit-event-profile', '_bx_events_menu_item_title_system_edit_profile', '_bx_events_menu_item_title_edit_profile', 'page.php?i=edit-event-profile&id={content_id}', '', '', 'pencil-alt', '', 2147483647, '', 1, 0, 40),
+('bx_events_view_actions_more', 'bx_events', 'edit-event-pricing', '_bx_events_menu_item_title_system_edit_pricing', '_bx_events_menu_item_title_edit_pricing', 'page.php?i=edit-event-pricing&profile_id={profile_id}', '', '', 'money-check-alt', '', 2147483647, 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:20:"is_pricing_avaliable";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 1, 0, 41),
+('bx_events_view_actions_more', 'bx_events', 'invite-to-event', '_bx_events_menu_item_title_system_invite', '_bx_events_menu_item_title_invite', 'page.php?i=invite-to-event&id={content_id}', '', '', 'user-friends', '', 2147483647, '', 1, 0, 42),
+('bx_events_view_actions_more', 'bx_events', 'delete-event-profile', '_bx_events_menu_item_title_system_delete_profile', '_bx_events_menu_item_title_delete_profile', 'page.php?i=delete-event-profile&id={content_id}', '', '', 'remove', '', 2147483647, '', 1, 0, 50),
+('bx_events_view_actions_more', 'bx_events', 'approve-event-profile', '_sys_menu_item_title_system_va_approve', '_sys_menu_item_title_va_approve', 'javascript:void(0)', 'javascript:bx_approve(this, ''{module_uri}'', {content_id});', '', 'check', '', 2147483647, '', 1, 0, 60);
+
+-- MENU: all actions menu for view entry 
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_view_actions_all', '_sys_menu_title_view_actions', 'bx_events_view_actions_all', 'bx_events', 15, 0, 1, 'BxEventsMenuViewActionsAll', 'modules/boonex/events/classes/BxEventsMenuViewActionsAll.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_events_view_actions_all', 'bx_events', '_sys_menu_set_title_view_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_events_view_actions_all', 'bx_events', 'join-event-profile', '_bx_events_menu_item_title_system_pay_and_join', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 5),
+('bx_events_view_actions_all', 'bx_events', 'profile-fan-add', '_bx_events_menu_item_title_system_become_fan', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 10),
+('bx_events_view_actions_all', 'bx_events', 'profile-fan-remove', '_bx_events_menu_item_title_system_leave_group', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 20),
+('bx_events_view_actions_all', 'bx_events', 'profile-subscribe-add', '_bx_events_menu_item_title_system_subscribe', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 30),
+('bx_events_view_actions_all', 'bx_events', 'profile-subscribe-remove', '_bx_events_menu_item_title_system_unsubscribe', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 40),
+('bx_events_view_actions_all', 'bx_events', 'profile-set-badges', '_sys_menu_item_title_system_set_badges', '', '', '', '', '', '', '', 0, 192, 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:19:"is_badges_avaliable";}', 1, 0, 50),
+('bx_events_view_actions_all', 'bx_events', 'ical-export', '', '_bx_events_menu_item_title_ical_export', '{ical_url}', '', '', 'calendar-plus', '', '', 0, 2147483647, 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:24:"is_ical_export_avaliable";s:6:"params";a:1:{i:0;s:12:"{content_id}";}}', 1, 0, 60),
+('bx_events_view_actions_all', 'bx_events', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 200),
+('bx_events_view_actions_all', 'bx_events', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 210),
+('bx_events_view_actions_all', 'bx_events', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 220),
+('bx_events_view_actions_all', 'bx_events', 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 230),
+('bx_events_view_actions_all', 'bx_events', 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 240),
+('bx_events_view_actions_all', 'bx_events', 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 250),
+('bx_events_view_actions_all', 'bx_events', 'repost', '_sys_menu_item_title_system_va_repost', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 260),
+('bx_events_view_actions_all', 'bx_events', 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 270),
+('bx_events_view_actions_all', 'bx_events', 'notes', '_sys_menu_item_title_system_va_notes', '_sys_menu_item_title_va_notes', 'javascript:void(0)', 'javascript:bx_get_notes(this,  ''{module_uri}'', {content_id});', '', 'exclamation-triangle', '', '', 0, 2147483647, '', 1, 0, 280),
+('bx_events_view_actions_all', 'bx_events', 'audit', '_sys_menu_item_title_system_va_audit', '_sys_menu_item_title_va_audit', 'page.php?i=dashboard-audit&module=bx_events&content_id={content_id}', '', '', 'history', '', '', 0, 192, '', 1, 0, 290),
+('bx_events_view_actions_all', 'bx_events', 'social-sharing', '_sys_menu_item_title_system_social_sharing', '_sys_menu_item_title_social_sharing', 'javascript:void(0)', 'oBxDolPage.share(this, \'{url_encoded}\')', '', 'share', '', '', 0, 2147483647, '', 1, 0, 300),
+('bx_events_view_actions_all', 'bx_events', 'edit-event-cover', '_bx_events_menu_item_title_system_edit_cover', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 400),
+('bx_events_view_actions_all', 'bx_events', 'edit-event-profile', '_bx_events_menu_item_title_system_edit_profile', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 410),
+('bx_events_view_actions_all', 'bx_events', 'edit-event-pricing', '_bx_events_menu_item_title_system_edit_pricing', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 415),
+('bx_events_view_actions_all', 'bx_events', 'invite-to-event', '_bx_events_menu_item_title_system_invite', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 420),
+('bx_events_view_actions_all', 'bx_events', 'delete-event-profile', '_bx_events_menu_item_title_system_delete_profile', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 430),
+('bx_events_view_actions_all', 'bx_events', 'approve-event-profile', '_sys_menu_item_title_system_va_approve', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 440),
+('bx_events_view_actions_all', 'bx_events', 'more-auto', '_sys_menu_item_title_system_va_more_auto', '_sys_menu_item_title_va_more_auto', 'javascript:void(0)', '', '', 'ellipsis-v', '', '', 0, 2147483647, '', 1, 0, 9999);
+
+-- MENU: meta (counters) menu for view entry
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_view_meta', '_bx_events_menu_title_view_profile_meta', 'bx_events_view_meta', 'bx_events', 15, 0, 1, 'BxEventsMenuViewMeta', 'modules/boonex/events/classes/BxEventsMenuViewMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_events_view_meta', 'bx_events', '_bx_events_menu_set_title_view_profile_meta', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_events_view_meta', 'bx_events', 'members', '_sys_menu_item_title_system_sm_members', '_sys_menu_item_title_sm_members', '', '', '', '', '', 0, 2147483647, '', 1, 0, 10),
+('bx_events_view_meta', 'bx_events', 'subscribers', '_sys_menu_item_title_system_sm_subscribers', '_sys_menu_item_title_sm_subscribers', '', '', '', '', '', 0, 2147483647, '', 1, 0, 20),
+('bx_events_view_meta', 'bx_events', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 0, 2147483647, '', 1, 0, 30),
+('bx_events_view_meta', 'bx_events', 'votes', '_sys_menu_item_title_system_sm_votes', '_sys_menu_item_title_sm_votes', '', '', '', '', '', 0, 2147483647, '', 1, 0, 40),
+('bx_events_view_meta', 'bx_events', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 0, 2147483647, '', 1, 0, 50);
+
+-- MENU: actions menu for my entries
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_my', '_bx_events_menu_title_entries_my', 'bx_events_my', 'bx_events', 9, 0, 1, 'BxEventsMenu', 'modules/boonex/events/classes/BxEventsMenu.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_events_my', 'bx_events', '_bx_events_menu_set_title_entries_my', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_events_my', 'bx_events', 'create-event-profile', '_bx_events_menu_item_title_system_create_profile', '_bx_events_menu_item_title_create_profile', 'page.php?i=create-event-profile', '', '', 'plus', '', 2147483647, 1, 0, 0);
+
+-- MENU: module sub-menu
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_submenu', '_bx_events_menu_title_submenu', 'bx_events_submenu', 'bx_events', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_events_submenu', 'bx_events', '_bx_events_menu_set_title_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_events_submenu', 'bx_events', 'events-home', '_bx_events_menu_item_title_system_entries_recent', '_bx_events_menu_item_title_entries_recent', 'page.php?i=events-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_events_submenu', 'bx_events', 'events-top', '_bx_events_menu_item_title_system_entries_top', '_bx_events_menu_item_title_entries_top', 'page.php?i=events-top', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_events_submenu', 'bx_events', 'events-upcoming', '_bx_events_menu_item_title_system_entries_upcoming', '_bx_events_menu_item_title_entries_upcoming', 'page.php?i=events-upcoming', '', '', '', '', 2147483647, 1, 1, 3),
+('bx_events_submenu', 'bx_events', 'events-past', '_bx_events_menu_item_title_system_entries_past', '_bx_events_menu_item_title_entries_past', 'page.php?i=events-past', '', '', '', '', 2147483647, 1, 1, 4),
+('bx_events_submenu', 'bx_events', 'events-calendar', '_bx_events_menu_item_title_system_calendar', '_bx_events_menu_item_title_calendar', 'page.php?i=events-calendar', '', '', '', '', 2147483647, 1, 1, 5),
+('bx_events_submenu', 'bx_events', 'events-search', '_bx_events_menu_item_title_system_entries_search', '_bx_events_menu_item_title_entries_search', 'page.php?i=events-search', '', '', '', '', 2147483647, 1, 1, 6),
+('bx_events_submenu', 'bx_events', 'events-joined', '_bx_events_menu_item_title_system_entries_joined', '_bx_events_menu_item_title_entries_joined', 'page.php?i=events-joined', '', '', '', '', 2147483647, 1, 1, 7),
+('bx_events_submenu', 'bx_events', 'events-manage', '_bx_events_menu_item_title_system_entries_manage', '_bx_events_menu_item_title_entries_manage', 'page.php?i=events-manage', '', '', '', '', 2147483646, 1, 1, 8);
+
+-- MENU: view submenu
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_view_submenu', '_bx_events_menu_title_view_profile_submenu', 'bx_events_view_submenu', 'bx_events', 18, 0, 1, 'BxEventsMenuView', 'modules/boonex/events/classes/BxEventsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_events_view_submenu', 'bx_events', '_bx_events_menu_set_title_view_profile_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_events_view_submenu', 'bx_events', 'view-event-profile', '_bx_events_menu_item_title_system_view_profile_view', '_bx_events_menu_item_title_view_profile_view', 'page.php?i=view-event-profile&id={content_id}', '', '', 'calendar col-red2', '', '', 0, 2147483647, 1, 0, 1),
+('bx_events_view_submenu', 'bx_events', 'event-profile-info', '_bx_events_menu_item_title_system_view_profile_info', '_bx_events_menu_item_title_view_profile_info', 'page.php?i=event-profile-info&id={content_id}', '', '', 'info-circle col-gray', '', '', 0, 2147483647, 1, 0, 2),
+('bx_events_view_submenu', 'bx_events', 'event-profile-comments', '_bx_events_menu_item_title_system_view_profile_comments', '_bx_events_menu_item_title_view_profile_comments', 'page.php?i=event-profile-comments&id={content_id}', '', '', '', '', '', 0, 2147483647, 0, 0, 3),
+('bx_events_view_submenu', 'bx_events', 'event-fans', '_bx_events_menu_item_title_system_view_fans', '_bx_events_menu_item_title_view_fans', 'page.php?i=event-fans&profile_id={profile_id}', '', '', 'calendar col-blue3', '', '', 0, 2147483647, 1, 0, 4),
+('bx_events_view_submenu', 'bx_events', 'more-auto', '_bx_events_menu_item_title_system_view_profile_more_auto', '_bx_events_menu_item_title_view_profile_more_auto', 'javascript:void(0)', '', '', 'ellipsis-v', '', '', 0, 2147483647, 1, 0, 9999);
+
+-- MENU: custom menu for snippet meta info
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_snippet_meta', '_sys_menu_title_snippet_meta', 'bx_events_snippet_meta', 'bx_events', 15, 0, 1, 'BxEventsMenuSnippetMeta', 'modules/boonex/events/classes/BxEventsMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_events_snippet_meta', 'bx_events', '_sys_menu_set_title_snippet_meta', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `editable`, `order`) VALUES
+('bx_events_snippet_meta', 'bx_events', 'date', '_sys_menu_item_title_system_sm_date', '_sys_menu_item_title_sm_date', '', '', '', '', '', 2147483647, '', 0, 0, 1, 1),
+('bx_events_snippet_meta', 'bx_events', 'date-start', '_bx_events_menu_item_title_system_sm_date_start', '_bx_events_menu_item_title_sm_date_start', '', '', '', '', '', 2147483647, '', 0, 0, 1, 2),
+('bx_events_snippet_meta', 'bx_events', 'date-end', '_bx_events_menu_item_title_system_sm_date_end', '_bx_events_menu_item_title_sm_date_end', '', '', '', '', '', 2147483647, '', 0, 0, 1, 3),
+('bx_events_snippet_meta', 'bx_events', 'category', '_sys_menu_item_title_system_sm_category', '_sys_menu_item_title_sm_category', '', '', '', '', '', 2147483647, '', 0, 0, 1, 5),
+('bx_events_snippet_meta', 'bx_events', 'tags', '_sys_menu_item_title_system_sm_tags', '_sys_menu_item_title_sm_tags', '', '', '', '', '', 2147483647, '', 0, 0, 1, 10),
+('bx_events_snippet_meta', 'bx_events', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 2147483647, '', 0, 0, 1, 15),
+('bx_events_snippet_meta', 'bx_events', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 2147483647, '', 0, 0, 1, 20),
+('bx_events_snippet_meta', 'bx_events', 'members', '_sys_menu_item_title_system_sm_members', '_sys_menu_item_title_sm_members', '', '', '', '', '', 2147483647, '', 1, 0, 1, 25),
+('bx_events_snippet_meta', 'bx_events', 'subscribers', '_sys_menu_item_title_system_sm_subscribers', '_sys_menu_item_title_sm_subscribers', '', '', '', '', '', 2147483647, '', 0, 0, 1, 30),
+('bx_events_snippet_meta', 'bx_events', 'country', '_sys_menu_item_title_system_sm_country', '_sys_menu_item_title_sm_country', '', '', '', '', '', 2147483647, '', 0, 0, 1, 35),
+('bx_events_snippet_meta', 'bx_events', 'country-city', '_sys_menu_item_title_system_sm_country_city', '_sys_menu_item_title_sm_country_city', '', '', '', '', '', 2147483647, '', 0, 0, 1, 40),
+('bx_events_snippet_meta', 'bx_events', 'nl', '_sys_menu_item_title_system_sm_nl', '_sys_menu_item_title_sm_nl', '', '', '', '', '', 2147483647, '', 1, 0, 1, 45),
+('bx_events_snippet_meta', 'bx_events', 'join-paid', '_sys_menu_item_title_system_sm_join_paid', '_sys_menu_item_title_sm_join_paid', '', '', '', '', '', 2147483647, 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:33:"is_paid_join_avaliable_by_content";s:6:"params";a:1:{i:0;s:12:"{content_id}";}}', 1, 0, 1, 50),
+('bx_events_snippet_meta', 'bx_events', 'join', '_sys_menu_item_title_system_sm_join', '_sys_menu_item_title_sm_join', '', '', '', '', '', 2147483647, 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:33:"is_free_join_avaliable_by_content";s:6:"params";a:1:{i:0;s:12:"{content_id}";}}', 1, 0, 1, 55),
+('bx_events_snippet_meta', 'bx_events', 'leave', '_sys_menu_item_title_system_sm_leave', '_sys_menu_item_title_sm_leave', '', '', '', '', '', 2147483647, '', 0, 0, 1, 60),
+('bx_events_snippet_meta', 'bx_events', 'subscribe', '_sys_menu_item_title_system_sm_subscribe', '_sys_menu_item_title_sm_subscribe', '', '', '', '', '', 2147483647, '', 0, 0, 1, 65),
+('bx_events_snippet_meta', 'bx_events', 'unsubscribe', '_sys_menu_item_title_system_sm_unsubscribe', '_sys_menu_item_title_sm_unsubscribe', '', '', '', '', '', 2147483647, '', 0, 0, 1, 70);
+
+-- MENU: profile stats
+SET @iNotifMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name` = 'sys_profile_stats' AND `active` = 1 LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES
+('sys_profile_stats', 'bx_events', 'profile-stats-my-events', '_bx_events_menu_item_title_system_manage_my_groups', '_bx_events_menu_item_title_manage_my_groups', 'page.php?i=joined-events&profile_id={member_id}', '', '_self', 'calendar col-red2', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:41:"get_menu_addon_manage_tools_profile_stats";}', '', 2147483646, 1, 0, @iNotifMenuOrder + 2);
+
+-- MENU: profile followings
+SET @iFollowingsMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_profile_followings' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `collapsed`, `active`, `copyable`, `order`) VALUES 
+('sys_profile_followings', 'bx_events', 'events', '_bx_events_menu_item_title_system_followings', '_bx_events_menu_item_title_followings', 'javascript:void(0)', '', '_self', 'calendar col-red2', '', '', 2147483647, 0, 1, 0, @iFollowingsMenuOrder + 1);
+
+-- MENU: manage tools submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_events_menu_manage_tools', '_bx_events_menu_title_manage_tools', 'bx_events_menu_manage_tools', 'bx_events', 6, 0, 1, 'BxEventsMenuManageTools', 'modules/boonex/events/classes/BxEventsMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_events_menu_manage_tools', 'bx_events', '_bx_events_menu_set_title_manage_tools', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_events_menu_manage_tools', 'bx_events', 'clear-reports', '_bx_cevents_menu_item_title_system_clear_reports', '_bx_events_menu_item_title_clear_reports', 'javascript:void(0)', 'javascript:{js_object}.onClickClearReports({content_id});', '_self', 'eraser', '', 2147483647, 1, 0, 1),
+('bx_events_menu_manage_tools', 'bx_events', 'delete', '_bx_events_menu_item_title_system_delete', '_bx_events_menu_item_title_delete', 'javascript:void(0)', 'javascript:{js_object}.onClickDelete({content_id});', '_self', 'far trash-alt', '', 2147483647, 1, 0, 2),
+('bx_events_menu_manage_tools', 'bx_events', 'delete-with-content', '_bx_events_menu_item_title_system_delete_with_content', '_bx_events_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'far trash-alt', '', 2147483647, 0, 0, 3);
+
+-- MENU: dashboard manage tools
+SET @iManageMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard_manage_tools' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_account_dashboard_manage_tools', 'bx_events', 'events-administration', '_bx_events_menu_item_title_system_admt_groups', '_bx_events_menu_item_title_admt_groups', 'page.php?i=events-administration', '', '_self', 'calendar', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
+
+-- MENU: add menu item to profiles modules (trigger* menu sets are processed separately upon modules enable/disable)
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('trigger_profile_view_submenu', 'bx_events', 'joined-events', '_bx_events_menu_item_title_system_view_joined_groups', '_bx_events_menu_item_title_view_joined_groups', 'page.php?i=joined-events&profile_id={profile_id}', '', '', 'calendar col-red2', '', 2147483647, '', 1, 0, 0),
+('trigger_group_view_submenu', 'bx_events', 'events-context', '_bx_events_menu_item_title_system_view_entries_in_context', '_bx_events_menu_item_title_view_entries_in_context', 'page.php?i=events-context&profile_id={profile_id}', '', '', 'calendar col-red2', '', 2147483647, 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:21:"is_enable_for_context";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 1, 0, 0);
+
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_events', 'create entry', NULL, '_bx_events_acl_action_create_profile', '', 1, 1);
+SET @iIdActionProfileCreate = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_events', 'use paid join', NULL, '_bx_events_acl_action_use_paid_join', '', 1, 1);
+SET @iIdActionUsePaidJoin = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_events', 'delete entry', NULL, '_bx_events_acl_action_delete_profile', '', 1, 1);
+SET @iIdActionProfileDelete = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_events', 'view entry', NULL, '_bx_events_acl_action_view_profile', '', 1, 0);
+SET @iIdActionProfileView = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_events', 'edit any entry', NULL, '_bx_events_acl_action_edit_any_profile', '', 1, 3);
+SET @iIdActionProfileEditAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_events', 'delete any entry', NULL, '_bx_events_acl_action_delete_any_profile', '', 1, 3);
+SET @iIdActionProfileDeleteAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_events', 'delete invites', NULL, '_bx_events_acl_action_delete_invites', '', 1, 3);
+SET @iIdActionProfileDeleteInvites = LAST_INSERT_ID();
+
+SET @iUnauthenticated = 1;
+SET @iAccount = 2;
+SET @iStandard = 3;
+SET @iUnconfirmed = 4;
+SET @iPending = 5;
+SET @iSuspended = 6;
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+
+-- profile create
+(@iAccount, @iIdActionProfileCreate),
+(@iStandard, @iIdActionProfileCreate),
+(@iUnconfirmed, @iIdActionProfileCreate),
+(@iPending, @iIdActionProfileCreate),
+(@iModerator, @iIdActionProfileCreate),
+(@iAdministrator, @iIdActionProfileCreate),
+(@iPremium, @iIdActionProfileCreate),
+
+-- use paid join
+(@iStandard, @iIdActionUsePaidJoin),
+(@iModerator, @iIdActionUsePaidJoin),
+(@iAdministrator, @iIdActionUsePaidJoin),
+(@iPremium, @iIdActionUsePaidJoin),
+
+-- profile delete
+(@iAccount, @iIdActionProfileDelete),
+(@iStandard, @iIdActionProfileDelete),
+(@iUnconfirmed, @iIdActionProfileDelete),
+(@iPending, @iIdActionProfileDelete),
+(@iModerator, @iIdActionProfileDelete),
+(@iAdministrator, @iIdActionProfileDelete),
+(@iPremium, @iIdActionProfileDelete),
+
+-- profile view
+(@iUnauthenticated, @iIdActionProfileView),
+(@iAccount, @iIdActionProfileView),
+(@iStandard, @iIdActionProfileView),
+(@iUnconfirmed, @iIdActionProfileView),
+(@iPending, @iIdActionProfileView),
+(@iModerator, @iIdActionProfileView),
+(@iAdministrator, @iIdActionProfileView),
+(@iPremium, @iIdActionProfileView),
+
+-- any profile edit
+(@iModerator, @iIdActionProfileEditAny),
+(@iAdministrator, @iIdActionProfileEditAny),
+
+-- any profile delete
+(@iAdministrator, @iIdActionProfileDeleteAny),
+
+-- any invites edit
+(@iModerator, @iIdActionProfileDeleteInvites),
+(@iAdministrator, @iIdActionProfileDeleteInvites);
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `module`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_events', 'bx_events', 'bx_events_meta_keywords', 'bx_events_meta_locations', 'bx_events_meta_mentions', '', '');
+
+-- CATEGORY
+INSERT INTO `sys_objects_category` (`object`, `module`, `search_object`, `form_object`, `list_name`, `table`, `field`, `join`, `where`, `override_class_name`, `override_class_file`) VALUES
+('bx_events_cats', 'bx_events', 'bx_events', 'bx_event', 'bx_events_cats', 'bx_events_data', 'event_cat', 'INNER JOIN `sys_profiles` ON (`sys_profiles`.`content_id` = `bx_events_data`.`id` AND `sys_profiles`.`type` = ''bx_events'')', 'AND `sys_profiles`.`status` = ''active''', '', '');
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+('bx_events', '_bx_events', @iSearchOrder + 1, 'BxEventsSearchResult', 'modules/boonex/events/classes/BxEventsSearchResult.php');
+
+-- CONNECTIONS
+INSERT INTO `sys_objects_connection` (`object`, `table`, `profile_initiator`, `profile_content`, `type`, `override_class_name`, `override_class_file`) VALUES
+('bx_events_fans', 'bx_events_fans', 1, 1, 'mutual', '', '');
+
+-- STATS
+SET @iMaxOrderStats = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_statistics`);
+INSERT INTO `sys_statistics` (`module`, `name`, `title`, `link`, `icon`, `query`, `order`) VALUES 
+('bx_events', 'bx_events', '_bx_events', 'page.php?i=events-home', 'calendar col-red2', 'SELECT COUNT(*) FROM `bx_events_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id` = `tp`.`content_id` AND `tp`.`type`=''bx_events'' WHERE 1 AND `tp`.`status`=''active''', @iMaxOrderStats + 1);
+
+-- CHARTS
+SET @iMaxOrderCharts = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_objects_chart`);
+INSERT INTO `sys_objects_chart` (`object`, `title`, `table`, `field_date_ts`, `field_date_dt`, `field_status`, `query`, `active`, `order`, `class_name`, `class_file`) VALUES
+('bx_events_growth', '_bx_events_chart_growth', 'bx_events_data', 'added', '', '', 'SELECT {field_date_formatted} AS `period`, COUNT(*) AS {object} FROM {table} LEFT JOIN `sys_profiles` AS `tp` ON {table}.`id` = `tp`.`content_id` AND `tp`.`type`=''bx_events'' WHERE 1 AND `tp`.`status`=''active'' {where_inteval} GROUP BY `period` ORDER BY {table}.{field_date} ASC', 1, @iMaxOrderCharts + 1, 'BxDolChartGrowth', ''),
+('bx_events_growth_speed', '_bx_events_chart_growth_speed', 'bx_events_data', 'added', '', '', 'SELECT {field_date_formatted} AS `period`, COUNT(*) AS {object} FROM {table} LEFT JOIN `sys_profiles` AS `tp` ON {table}.`id` = `tp`.`content_id` AND `tp`.`type`=''bx_events'' WHERE 1 AND `tp`.`status`=''active'' {where_inteval} GROUP BY `period` ORDER BY {table}.{field_date} ASC', 1, @iMaxOrderCharts + 2, 'BxDolChartGrowthSpeed', '');
+
+-- GRID: connections
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `responsive`, `override_class_name`, `override_class_file`) VALUES
+('bx_events_fans', 'Sql', 'SELECT `p`.`id`, `c`.`added`, `c`.`mutual` FROM `sys_profiles` AS `p` INNER JOIN `sys_accounts` AS `a` ON (`a`.`id` = `p`.`account_id`) {join_connections}', 'sys_profiles', 'id', 'c`.`added', '', '', 10, NULL, 'start', '', 'name,email', '', 'auto', '', '', 2147483647, 0, 'BxEventsGridConnections', 'modules/boonex/events/classes/BxEventsGridConnections.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `params`, `order`) VALUES
+('bx_events_fans', 'name', '_sys_name', '50%', '', 10),
+('bx_events_fans', 'role', '_bx_events_txt_role', '10%', '', 15),
+('bx_events_fans', 'role_added', '_bx_events_txt_role_added', '10%', '', 16),
+('bx_events_fans', 'role_expired', '_bx_events_txt_role_expired', '10%', '', 17),
+('bx_events_fans', 'actions', '', '20%', '', 20);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_events_fans', 'single', 'accept', '_sys_accept', '', 0, 10),
+('bx_events_fans', 'single', 'set_role', '_bx_events_txt_set_role', '', 0, 20),
+('bx_events_fans', 'single', 'set_role_submit', '', '', 0, 21),
+('bx_events_fans', 'single', 'delete', '', 'remove', 1, 40);
+
+-- GRID: invites
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `responsive`, `override_class_name`, `override_class_file`) VALUES
+('bx_events_invites', 'Sql', 'SELECT `bx_events_invites`.`id`, `bx_events_invites`.`invited_profile_id`, `bx_events_invites`.`added`, `bx_events_invites`.`author_profile_id` FROM `sys_profiles` AS `p` INNER JOIN `sys_accounts` AS `a` ON (`a`.`id` = `p`.`account_id`) INNER JOIN `bx_events_invites` ON `bx_events_invites`.`invited_profile_id` = `p`.`id` ', 'bx_events_invites', 'id', 'bx_events_invites`.`added', '', '', 10, NULL, 'start', '', 'name,email', '', 'auto', '', '', 2147483647, 0, 'BxEventsGridInvites', 'modules/boonex/events/classes/BxEventsGridInvites.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `params`, `order`) VALUES
+('bx_events_invites', 'name', '_sys_name', '33%', '', 10),
+('bx_events_invites', 'added', '_sys_added', '33%', '', 20),
+('bx_events_invites', 'actions', '', '34%', '', 30);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_events_invites', 'single', 'delete', '', 'remove', 1, 10);
+
+-- GRIDS: administration
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_events_administration', 'Sql', 'SELECT `td`.*, `td`.`event_name` AS `name`, `ta`.`email` AS `account`, `td`.`added` AS `added_ts`, `tp`.`status` AS `status` FROM `bx_events_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id`=`tp`.`content_id` AND `tp`.`type`=''bx_events'' LEFT JOIN `sys_accounts` AS `ta` ON `tp`.`account_id`=`ta`.`id` WHERE 1 ', 'bx_events_data', 'id', 'added', 'status_admin', '', 20, NULL, 'start', '', 'event_name', '', 'like', 'reports', '', 192, 'BxEventsGridAdministration', 'modules/boonex/events/classes/BxEventsGridAdministration.php'),
+('bx_events_common', 'Sql', 'SELECT `td`.*, `td`.`event_name` AS `name`, `ta`.`email` AS `account`, `td`.`added` AS `added_ts`, `tp`.`status` AS `status` FROM `bx_events_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id`=`tp`.`content_id` AND `tp`.`type`=''bx_events'' LEFT JOIN `sys_accounts` AS `ta` ON `tp`.`account_id`=`ta`.`id` WHERE 1 ', 'bx_events_data', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'event_name', '', 'like', '', '', 2147483647, 'BxEventsGridCommon', 'modules/boonex/events/classes/BxEventsGridCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_events_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_events_administration', 'switcher', '_bx_events_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_events_administration', 'reports', '_sys_txt_reports_title', '5%', 0, '', '', 3),
+('bx_events_administration', 'name', '_bx_events_grid_column_title_adm_name', '25%', 0, '', '', 4),
+('bx_events_administration', 'added_ts', '_bx_events_grid_column_title_adm_added', '20%', 1, '25', '', 5),
+('bx_events_administration', 'account', '_bx_events_grid_column_title_adm_account', '20%', 0, '25', '', 6),
+('bx_events_administration', 'actions', '', '20%', 0, '', '', 7),
+
+('bx_events_common', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_events_common', 'switcher', '_bx_groups_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_events_common', 'name', '_bx_events_grid_column_title_adm_name', '40%', 0, '', '', 3),
+('bx_events_common', 'added_ts', '_bx_events_grid_column_title_adm_added', '30%', 1, '25', '', 4),
+('bx_events_common', 'actions', '', '20%', 0, '', '', 5);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `active`, `order`) VALUES
+('bx_events_administration', 'bulk', 'clear_reports', '_bx_events_grid_action_title_adm_clear_reports', '', 0, 1, 1, 1),
+('bx_events_administration', 'bulk', 'delete', '_bx_events_grid_action_title_adm_delete', '', 0, 1, 1, 2),
+('bx_events_administration', 'bulk', 'delete_with_content', '_bx_events_grid_action_title_adm_delete_with_content', '', 0, 1, 0, 3),
+('bx_events_administration', 'single', 'settings', '_bx_events_grid_action_title_adm_more_actions', 'cog', 1, 0, 1, 2),
+('bx_events_administration', 'single', 'audit_content', '_bx_events_grid_action_title_adm_audit_content', 'search', 1, 0, 1, 3),
+('bx_events_administration', 'single', 'audit_context', '_bx_events_grid_action_title_adm_audit_context', 'search-location', 1, 0, 1, 4),
+
+('bx_events_common', 'bulk', 'delete', '_bx_events_grid_action_title_adm_delete', '', 0, 1, 1, 1),
+('bx_events_common', 'bulk', 'delete_with_content', '_bx_events_grid_action_title_adm_delete_with_content', '', 0, 1, 0, 2),
+('bx_events_common', 'single', 'settings', '_bx_events_grid_action_title_adm_more_actions', 'cog', 1, 0, 1, 1);
+
+-- GRIDS: Pricing
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_events_prices_manage', 'Sql', 'SELECT * FROM `bx_events_prices` WHERE 1 ', 'bx_events_prices', 'id', 'order', '', '', 100, NULL, 'start', '', 'period,period_unit,price', '', 'like', '', '', 2147483647, 'BxEventsGridPricesManage', 'modules/boonex/events/classes/BxEventsGridPricesManage.php'),
+('bx_events_prices_view', 'Sql', 'SELECT * FROM `bx_events_prices` WHERE 1 ', 'bx_events_prices', 'id', 'order', '', '', 100, NULL, 'start', '', 'period,period_unit,price', '', 'like', '', '', 2147483647, 'BxEventsGridPricesView', 'modules/boonex/events/classes/BxEventsGridPricesView.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_events_prices_manage', 'checkbox', '_sys_select', '1%', 0, '', '', 1),
+('bx_events_prices_manage', 'order', '', '1%', 0, '', '', 2),
+('bx_events_prices_manage', 'name', '_bx_events_grid_column_title_name', '38%', 0, 32, '', 3),
+('bx_events_prices_manage', 'price', '_bx_events_grid_column_title_price', '20%', 0, 16, '', 4),
+('bx_events_prices_manage', 'period', '_bx_events_grid_column_title_period', '20%', 0, 16, '', 5),
+('bx_events_prices_manage', 'actions', '', '20%', 0, '', '', 6),
+
+('bx_events_prices_view', 'role_id', '_bx_events_grid_column_title_role_id', '40%', 0, 32, '', 1),
+('bx_events_prices_view', 'price', '_bx_events_grid_column_title_price', '20%', 0, 16, '', 2),
+('bx_events_prices_view', 'period', '_bx_events_grid_column_title_period', '20%', 0, 16, '', 3),
+('bx_events_prices_view', 'actions', '', '20%', 0, '', '', 4);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_events_prices_manage', 'independent', 'add', '_bx_events_grid_action_title_add', '', 0, 0, 1),
+('bx_events_prices_manage', 'single', 'edit', '_bx_events_grid_action_title_edit', 'pencil-alt', 1, 0, 1),
+('bx_events_prices_manage', 'single', 'delete', '_bx_events_grid_action_title_delete', 'remove', 1, 1, 2),
+('bx_events_prices_manage', 'bulk', 'delete', '_bx_events_grid_action_title_delete', '', 0, 1, 1),
+
+('bx_events_prices_view', 'single', 'buy', '_bx_events_grid_action_title_buy', 'cart-plus', 0, 0, 1),
+('bx_events_prices_view', 'single', 'subscribe', '_bx_events_grid_action_title_subscribe', 'credit-card', 0, 0, 2),
+('bx_events_prices_view', 'single', 'choose', '_bx_events_grid_action_title_choose', 'far check-square', 0, 0, 3);
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_events', 'BxEventsAlertsResponse', 'modules/boonex/events/classes/BxEventsAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('bx_timeline', 'post_common', @iHandler),
+('bx_events_pics', 'file_deleted', @iHandler),
+('bx_events_fans', 'connection_added', @iHandler),
+('bx_events_fans', 'connection_removed', @iHandler),
+('profile', 'delete', @iHandler),
+('bx_events', 'fan_added', @iHandler),
+('bx_events', 'join_invitation', @iHandler),
+('bx_events', 'join_request', @iHandler),
+('bx_events', 'join_request_accepted', @iHandler),
+('bx_events', 'timeline_view', @iHandler),
+('bx_events', 'timeline_post', @iHandler),
+('bx_events', 'timeline_delete', @iHandler),
+('bx_events', 'timeline_comment', @iHandler),
+('bx_events', 'timeline_vote', @iHandler),
+('bx_events', 'timeline_score', @iHandler),
+('bx_events', 'timeline_report', @iHandler),
+('bx_events', 'timeline_repost', @iHandler),
+('bx_events', 'timeline_pin', @iHandler),
+('bx_events', 'timeline_promote', @iHandler);
+
+-- PRIVACY 
+INSERT INTO `sys_objects_privacy` (`object`, `module`, `action`, `title`, `default_group`, `spaces`, `table`, `table_field_id`, `table_field_author`, `override_class_name`, `override_class_file`) VALUES
+('bx_events_allow_view_to', 'bx_events', 'view', '_bx_events_form_profile_input_allow_view_to', '3', 'bx_groups,bx_spaces', 'bx_events_data', 'id', 'author', 'BxEventsPrivacy', 'modules/boonex/events/classes/BxEventsPrivacy.php'),
+('bx_events_allow_view_notification_to', 'bx_events', 'view_event', '_bx_events_form_profile_input_allow_view_notification_to', '3', '', 'bx_notifications_events', 'id', 'object_owner_id', 'BxEventsPrivacyNotifications', 'modules/boonex/events/classes/BxEventsPrivacyNotifications.php'),
+('bx_events_allow_post_to', 'bx_events', 'post', '_bx_events_form_profile_input_allow_post_to', 'p', '', 'bx_events_data', 'id', 'author', 'BxEventsPrivacyPost', 'modules/boonex/events/classes/BxEventsPrivacyPost.php'),
+('bx_events_allow_view_favorite_list', 'bx_events', 'view_favorite_list', '_bx_events_form_profile_input_allow_view_favorite_list', '3', '', 'bx_events_favorites_lists', 'id', 'author_id', 'BxEventsPrivacy', 'modules/boonex/events/classes/BxEventsPrivacy.php');
+
+
+-- EMAIL TEMPLATES
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES
+('bx_events', '_bx_events_email_join_request', 'bx_events_join_request', '_bx_events_email_join_request_subject', '_bx_events_email_join_request_body'),
+('bx_events', '_bx_events_email_join_reject', 'bx_events_join_reject', '_bx_events_email_join_reject_subject', '_bx_events_email_join_reject_body'),
+('bx_events', '_bx_events_email_join_confirm', 'bx_events_join_confirm', '_bx_events_email_join_confirm_subject', '_bx_events_email_join_confirm_body'),
+('bx_events', '_bx_events_email_fan_remove', 'bx_events_fan_remove', '_bx_events_email_fan_remove_subject', '_bx_events_email_fan_remove_body'),
+('bx_events', '_bx_events_email_fan_become_admin', 'bx_events_fan_become_admin', '_bx_events_email_fan_become_admin_subject', '_bx_events_email_fan_become_admin_body'),
+('bx_events', '_bx_events_email_admin_become_fan', 'bx_events_admin_become_fan', '_bx_events_email_admin_become_fan_subject', '_bx_events_email_admin_become_fan_body'),
+('bx_events', '_bx_events_email_set_role', 'bx_events_set_role', '_bx_events_email_set_role_subject', '_bx_events_email_set_role_body'),
+('bx_events', '_bx_events_email_invitation', 'bx_events_invitation', '_bx_events_email_invitation_subject', '_bx_events_email_invitation_body'),
+('bx_events', '_bx_events_email_reminder', 'bx_events_reminder', '_bx_events_email_reminder_subject', '_bx_events_email_reminder_body');
+
+-- UPLOADERS
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_events_cover_crop', 1, 'BxEventsUploaderCoverCrop', 'modules/boonex/events/classes/BxEventsUploaderCoverCrop.php'),
+('bx_events_picture_crop', 1, 'BxEventsUploaderPictureCrop', 'modules/boonex/events/classes/BxEventsUploaderPictureCrop.php');
+
+-- CRON
+INSERT INTO `sys_cron_jobs` (`name`, `time`, `class`, `file`, `service_call`) VALUES
+('bx_events_process_reminders', '55 * * * *', 'BxEventsCronProcessReminders', 'modules/boonex/events/classes/BxEventsCronProcessReminders.php', ''),
+('bx_events_pruning', '0 0 * * *', 'BxEventsCronPruning', 'modules/boonex/events/classes/BxEventsCronPruning.php', ''),
+('bx_events_publishing', '* * * * *', 'BxEventsCronPublishing', 'modules/boonex/events/classes/BxEventsCronPublishing.php', '');

+ 16 - 0
modules/boonex/events/updates/13.0.4_13.0.5/source/js/invite_popup.js

@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Events Events
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxEventsInvitePopup(oOptions) {
+    BxBaseModGroupsInvitePopup.call(this, oOptions);
+}
+
+BxEventsInvitePopup.prototype = Object.create(BxBaseModGroupsInvitePopup.prototype);
+BxEventsInvitePopup.prototype.constructor = BxEventsInvitePopup;

+ 3 - 1
modules/boonex/files/template/unit_live_search.html

@@ -4,7 +4,9 @@
             <div class="bx-def-unit-img bx-def-thumb-size bx-def-round-corners bx-def-box bx-def-color-bg-box" style="background-image:url(__thumb_url__);"></div>
         </bx_if:thumb>
         <bx_if:no_thumb>
-            <div class="bx-def-thumb-size bx-def-unit-img bx-def-round-corners bx-def-box bx-def-color-bg-box bx-def-font-align-center"><i class="sys-icon __icon__ bx-def-thumb-size"></i></div>
+            <div class="bx-def-unit-img">
+                <div class="bx-def-unit-img-empty bx-def-thumb-size bx-def-box bg-white dark:bg-gray-700 rounded box-border"><i class="sys-icon __icon__"></i></div>
+            </div>
         </bx_if:no_thumb>
         <div class="bx-def-unit-info bx-def-thumb-size-max-height bx-def-padding-sec-left">
             <div class="bx-def-ui-title">__title__</div>

+ 51 - 0
modules/boonex/files/updates/13.0.4_13.0.5/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Files',
+    'version_from' => '13.0.4',
+    'version_to' => '13.0.5',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/files/updates/update_13.0.4_13.0.5/',
+    'home_uri' => 'files_update_1304_1305',
+
+    'module_dir' => 'boonex/files/',
+    'module_uri' => 'files',
+
+    'db_prefix' => 'bx_files_',
+    'class_prefix' => 'BxFiles',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Files',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/files/updates/13.0.4_13.0.5/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxFilesUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 609 - 0
modules/boonex/files/updates/13.0.4_13.0.5/source/classes/BxFilesModule.php

@@ -0,0 +1,609 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Files Files
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Files module
+ */
+class BxFilesModule extends BxBaseModTextModule
+{
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+
+    public function serviceIsAllowedAddContentToProfile($iGroupProfileId)
+    {
+        if (!$iGroupProfileId || !($oProfile = BxDolProfile::getInstance((int)$iGroupProfileId)))
+            return false;
+
+        if ($iGroupProfileId == bx_get_logged_profile_id())
+            return true;
+
+        return bx_srv($oProfile->getModule(), 'check_allowed_post_in_profile', array($oProfile->getContentId(), $this->getName())) === CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function serviceMyEntriesActions ($iProfileId = 0)
+    {
+        if (!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+
+        if (!$this->serviceIsAllowedAddContentToProfile($iProfileId))
+            return false;
+
+        $oMenu = BxTemplMenu::getObjectInstance($this->_oConfig->CNF['OBJECT_MENU_ACTIONS_MY_ENTRIES']);
+        return $oMenu ? $oMenu->getCode() : false;
+    }
+
+    public function checkAllowedSetThumb ($iContentId = 0)
+    {
+        return _t('_sys_txt_access_denied');
+    }
+
+    public function actionDownload($sToken = '', $iContentId = 0, $sBulk = '')
+    {
+        $CNF = $this->_oConfig->CNF;
+
+        $aFilesToDownload = [$iContentId];
+        if (!empty($sBulk)) {
+            $aFilesToDownload = json_decode($sBulk);
+        }
+
+        if (!is_array($aFilesToDownload)) {
+            $this->_oTemplate->displayPageNotFound();
+            return;
+        }
+
+        $iContentId = reset($aFilesToDownload);
+
+        $aData = $this->_oDb->getContentInfoById((int)$iContentId);
+        if (!$aData) {
+            $this->_oTemplate->displayPageNotFound();
+            return;
+        }
+
+        if (CHECK_ACTION_RESULT_ALLOWED !== $this->checkAllowedView($aData)) {
+            $this->_oTemplate->displayAccessDenied();
+            return;
+        }
+
+        if ($aData['type'] == 'folder' || $aFilesToDownload && count($aFilesToDownload) > 1) {
+            bx_import('BulkDownloader', $this->_aModule);
+            $oDownloader = new BxFilesBulkDownloader($this);
+            $aResult = $oDownloader->createDownloadingJob($aFilesToDownload, $aData[$CNF['FIELD_TITLE']]);
+
+            switch ($aResult['status']) {
+                case BX_FILES_DOWNLOADER_STATUS_TOO_LARGE:
+                    $this->_oTemplate->displayMsg(_t('_bx_files_txt_max_size_reached', _t_format_size(intval(getParam('bx_files_max_bulk_download_size')) * 1024 * 1024)));
+                    break;
+                case BX_FILES_DOWNLOADER_STATUS_DOWNLOADING:
+                    $this->_oTemplate->addJsTranslation('_bx_files_txt_status_downloading_ready_msg');
+                    $this->_oTemplate->displayMsg(['title' => _t('_bx_files_txt_status_downloading'), 'content' => $this->_oTemplate->parseHtmlByName('bulk_downloader_process.html', [
+                        'timeout' => BX_FILES_DOWNLOADER_TIMEOUT_REQUESTS,
+                        'action_url' => BX_DOL_URL_ROOT.$this->_oConfig->getBaseUri().'process_download/'.$aResult['job'],
+                    ])]);
+                    break;
+                case BX_FILES_DOWNLOADER_STATUS_READY:
+                    bx_smart_readfile($aResult['file'], $aResult['filename'], 'application/zip');
+                    break;
+                case BX_FILES_DOWNLOADER_STATUS_EMPTY:
+                default:
+                    $this->_oTemplate->displayPageNotFound();
+                    break;
+            }
+            exit;
+        }
+
+        $aFile = $this->getContentFile($aData);
+        if (!$aFile) {
+            $this->_oTemplate->displayPageNotFound();
+            return;
+        }
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        if (!$oStorage) {
+            $this->_oTemplate->displayErrorOccured();
+            return;
+        }
+
+        if (!$oStorage->download($aFile['remote_id'], $sToken, true)) {
+            $this->_oTemplate->displayErrorOccured();
+            return;
+        }
+        
+        exit;   
+    }
+
+    public function actionProcessDownload($iDownloadingJobId) {
+        if (!$iDownloadingJobId) die;
+
+        $aJob = $this->_oDb->getDownloadingJob($iDownloadingJobId);
+        if (!$aJob || $aJob['owner'] != bx_get_logged_profile_id()) die;
+
+        if ($aJob['result']) {
+            bx_smart_readfile($aJob['result'], $aJob['name'], 'application/zip');
+            exit;
+        }
+
+        bx_import('BulkDownloader', $this->_aModule);
+        $oDownloader = new BxFilesBulkDownloader($this);
+
+        $mRes = $oDownloader->processDownloading($aJob['files']);
+        if ($mRes === BX_FILES_DOWNLOADER_STATUS_DOWNLOADING) {
+            $this->_oDb->updateDownloadingJob($iDownloadingJobId, $aJob['files'], '');
+            echoJson([
+                'status' => 'downloading',
+            ]);
+        } else {
+            $this->_oDb->updateDownloadingJob($iDownloadingJobId, $aJob['files'], $mRes);
+            echoJson([
+                'status' => 'ready',
+            ]);
+        }
+    }
+    
+    public function getContentFile($aData) 
+    {
+        $CNF = $this->_oConfig->CNF;
+
+        if (!isset($aData[$CNF['FIELD_AUTHOR']]) || !isset($aData[$CNF['FIELD_ID']]))
+            return false;
+
+        if (isset($aData['type']) && $aData['type'] == 'folder') {
+            return [
+                'id' => $aData[$CNF['FIELD_ID']],
+                'profile_id' => $aData[$CNF['FIELD_AUTHOR']],
+                'remote_id' => 0,
+                'path' => '',
+                'file_name' => $aData[$CNF['FIELD_TITLE']],
+                'mime_type' => '',
+                'ext' => '',
+                'size' => 0,
+                'added' => $aData[$CNF['FIELD_ADDED']],
+                'modified' => 0,
+                'private' => false,
+                'is_image' => false,
+            ];
+        }
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        if (!$oStorage)
+            return false;
+
+        if (isset($aData[$CNF['FIELD_FILE_ID']]) && $aData[$CNF['FIELD_FILE_ID']])
+            return $this->_addFileFields($oStorage->getFile($aData[$CNF['FIELD_FILE_ID']]));
+        
+        $aGhostFiles = $oStorage->getGhosts ($aData[$CNF['FIELD_AUTHOR']], $aData[$CNF['FIELD_ID']]);
+        if (!$aGhostFiles)
+            return false;
+
+        return $this->_addFileFields(array_pop($aGhostFiles));
+    }
+
+    protected function _addFileFields($aFile) 
+    {
+        if (is_array($aFile))
+            $aFile['is_image'] = in_array($aFile['ext'], array('jpg', 'jpeg', 'png', 'gif', /* when ImageMagick is used - 'tif', 'tiff', 'bmp', 'ico', 'psd' */));
+        return $aFile;
+    }
+
+    public function serviceEntityFilePreview($iContentId = 0)
+    {
+        return $this->_serviceTemplateFunc ('entryFilePreview', $iContentId);
+    }
+
+    public function serviceProcessFilesData($iNumberOfFilesToProcessAtOnce = 3)
+    {
+        $CNF = $this->_oConfig->CNF;
+        
+        if (!defined('BX_SYSTEM_JAVA') || !constant('BX_SYSTEM_JAVA'))
+            return;
+        
+        $a = $this->_oDb->getNotProcessedFiles($iNumberOfFilesToProcessAtOnce);
+        if (!$a)
+            return;
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        if (!$oStorage)
+            return false;
+        
+        foreach ($a as $aContentInfo) {
+            $aFile = $this->getContentFile($aContentInfo);
+            if (!$aFile) {
+                $this->_oDb->updateFileData ($aContentInfo[$CNF['FIELD_ID']], '');
+                continue;
+            }
+
+            $sFileUrl = $oStorage->getFileUrlById($aFile['id']);
+            $sFilePath = BX_DIRECTORY_PATH_TMP . $aFile['remote_id'] . '.' . $aFile['ext'];
+            @file_put_contents($sFilePath, file_get_contents($sFileUrl));
+            if (!file_exists($sFilePath)) {
+                $this->_oDb->updateFileData ($aContentInfo[$CNF['FIELD_ID']], '');
+                continue;
+            }
+            
+            $sCommand = '"' . constant('BX_SYSTEM_JAVA') . '" -Djava.awt.headless=true -jar "' . $this->_oConfig->getHomePath() . 'data/tika-app.jar" --encoding=UTF-8 --text "' . $sFilePath . '"';
+            $sData = `$sCommand`;
+            @unlink($sFilePath);
+
+            $this->_oDb->updateFileData ($aContentInfo[$CNF['FIELD_ID']], $sData);
+        }
+    }
+
+    public function servicePruneDownloadingJobs()
+    {
+        $aFiles = $this->_oDb->deleteOldDownloadingJobs();
+        if ($aFiles) foreach ($aFiles as $sFile) @unlink($sFile);
+    }
+
+    protected function _getContentForTimelinePost($aEvent, $aContentInfo, $aBrowseParams = array())
+    {
+        $aResult = parent::_getContentForTimelinePost($aEvent, $aContentInfo, $aBrowseParams);
+
+        $aFile = $this->getContentFile($aContentInfo);
+        if (!$aFile['is_image']) {
+            $oStorage = BxDolStorage::getObjectInstance($this->_oConfig->CNF['OBJECT_STORAGE']);
+            $sIcon = $oStorage ? $oStorage->getFontIconNameByFileName($aFile['file_name']) : 'far file';
+
+            $aResult['raw'] = $this->_oTemplate->parseHtmlByName('timeline_post.html', array(
+                'title' => $aResult['title'],
+                'title_attr' => bx_html_attribute($aResult['title']),
+                'url' => $aResult['url'],
+                'icon' => $sIcon,
+            ));
+            $aResult['title'] = '';
+        }
+
+        return $aResult;
+    }
+
+    protected function _getImagesForTimelinePost($aEvent, $aContentInfo, $sUrl, $aBrowseParams = array())
+    {
+        $aFile = $this->getContentFile($aContentInfo);
+        if (!$aFile)
+            return array();
+
+        if (!$aFile['is_image'])
+            return array();
+
+        $sPhotoThumb = '';
+        if ($oImagesTranscoder = BxDolTranscoderImage::getObjectInstance($this->_oConfig->CNF['OBJECT_IMAGES_TRANSCODER_GALLERY']))
+            $sPhotoThumb = $oImagesTranscoder->getFileUrl($aFile['id']);
+
+        return array(
+            array('id' => $aFile['id'], 'url' => $sUrl, 'src' => $sPhotoThumb),
+        );
+    }
+
+    public function actionBookmark($iContentId) {
+        if (!$this->isLogged()) return;
+
+        $aFilesToBookmark = [];
+        if ($iContentId) $aFilesToBookmark = [$iContentId];
+        elseif (isset($_POST['bulk'])) $aFilesToBookmark = $_POST['bulk'];
+
+        if ($aFilesToBookmark)
+            foreach ($aFilesToBookmark as $iContentId) {
+                if ($iContentId <= 0) continue;
+
+                $aData = $this->_oDb->getContentInfoById((int)$iContentId);
+                if (!$aData) continue;
+
+                $this->_oDb->bookmarkFile((int)$iContentId, bx_get_logged_profile_id());
+            }
+    }
+
+    public function actionEntryPreview($iContentId) {
+        $aData = $this->_oDb->getContentInfoById((int)$iContentId);
+
+        $sJsCss = '';
+
+        $sPreviewCode = $this->_serviceTemplateFunc ('entryFilePreview', $iContentId);
+
+        // various init scripts could be there, which fail to work properly
+        // because of a fact that it is inside a popup which is at the moment is hidden
+        // so we need a way to postpone that initialization
+        $aScripts = [];
+        $sPreviewCode = preg_replace_callback('/<script>(.*)<\/script>/s', function($aMatch) use (&$aScripts) {
+            $aScripts[] = ['code' => $aMatch[1]];
+            return '';
+        }, $sPreviewCode);
+
+        // if there is a script then most likely it is a text + codemirror initialization, so include it here.
+        if ($aScripts) {
+            $sJsCss .= $this->_oTemplate->addJs('codemirror/codemirror-ext.min.js', true);
+            $sJsCss .= $this->_oTemplate->addCss(BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'codemirror/|codemirror.css', true);
+        }
+
+        $sJsCss .= $this->_oTemplate->addCss('file_handler.css', true);
+
+        $sPopupCode = $this->_oTemplate->parseHtmlByName('entry-popup.html', [
+            'content' => $sPreviewCode,
+            'bx_repeat:init_scripts' => $aScripts,
+        ]);
+
+        echoJson([
+            'popup' => [
+                'html' => PopupBox('bx-files-popup', bx_process_output($aData['title']), $sJsCss.$sPopupCode),
+                'options' => [
+                    'onShow' => 'bx_files_popup_init()',
+                ],
+            ],
+        ]);
+    }
+
+    public function actionEntryInfo($iContentId) {
+        $aData = $this->_oDb->getContentInfoById((int)$iContentId);
+
+        echoJson([
+            'popup' => [
+                'html' => PopupBox('bx-files-popup', bx_process_output($aData['title']), $this->_oTemplate->entryInfoPopup($aData)),
+            ],
+        ]);
+    }
+
+    public function actionEntryEditTitle($iContentId) {
+        $iContentId = intval($iContentId);
+        $aData = $this->_oDb->getContentInfoById($iContentId);
+
+        $CNF = &$this->_oConfig->CNF;
+
+        if (!$aData) {
+            echoJson(['message' => _t('_bx_files_txt_error')]);
+            exit;
+        }
+
+        if ($this->checkAllowedEdit($aData, false) !== CHECK_ACTION_RESULT_ALLOWED) {
+            echoJson(['message' => _t('_bx_files_txt_permission_denied')]);
+            exit;
+        }
+
+        setlocale(LC_ALL,'C.UTF-8'); //otherwise pathinfo returns empty string on a non-latin characters filenames
+
+        if (isset($_POST['title'])) {
+            if ($sNewTitle = bx_get('title')) {
+                $sExt = pathinfo($aData[$CNF['FIELD_TITLE']], PATHINFO_EXTENSION);
+                if ($sExt) $sExt = '.'.$sExt;
+
+                $this->_oDb->updateEntryTitle($iContentId, $sNewTitle.$sExt);
+                $aData = $this->_oDb->getContentInfoById($iContentId);
+                echo bx_process_output($aData[$CNF['FIELD_TITLE']]);
+            }
+            exit;
+        }
+
+
+        $sActionUrl = BX_DOL_URL_ROOT.$this->_oConfig->getBaseUri();
+        echoJson([
+            'eval' => "bx_prompt('"._t('_bx_files_form_entry_input_title')."', '".bx_js_string(pathinfo($aData[$CNF['FIELD_TITLE']], PATHINFO_FILENAME))."', function(val) {                
+                $.post('{$sActionUrl}entry_edit_title/{$iContentId}', {title: val.getValue()}, function(sTitle) {
+                    if (sTitle)
+                        $('.bx-file-entry[file_id=".$aData[$CNF['FIELD_ID']]."] .bx-files-filename a').html(sTitle);
+                });                
+            })",
+        ]);
+    }
+
+    public function actionEntryDelete($iContentId) {
+        $aFilesToDelete = [];
+        if ($iContentId) $aFilesToDelete = [$iContentId];
+        elseif (isset($_POST['bulk'])) $aFilesToDelete = $_POST['bulk'];
+
+        if ($aFilesToDelete)
+            foreach ($aFilesToDelete as $iContentId) {
+                $iContentId = intval($iContentId);
+                if ($iContentId <= 0) continue;
+
+                $aData = $this->_oDb->getContentInfoById($iContentId);
+
+                $CNF = &$this->_oConfig->CNF;
+
+                if (!$aData) {
+                    echoJson(['message' => _t('_bx_files_txt_error')]);
+                    exit;
+                }
+
+                if ($this->checkAllowedDelete($aData, false) !== CHECK_ACTION_RESULT_ALLOWED) {
+                    continue;
+                }
+
+                $this->serviceDeleteEntity($iContentId);
+            }
+
+        if (!isset($_POST['bulk'])) {
+            echoJson([
+                'eval' => "
+                    $('.bx-file-entry[file_id={$iContentId}]').fadeOut();
+                    $(window).trigger('files_browser.update');
+                ",
+            ]);
+        } else {
+            echoJson([]);
+        }
+    }
+
+    public function actionClearGhosts() {
+        if (!isLogged()) die;
+
+        $oStorage = BxDolStorage::getObjectInstance($this->_oConfig->CNF['OBJECT_STORAGE']);
+        if ($oStorage) {
+            $aFiles = $oStorage->getGhosts(bx_get_logged_profile_id(), 0);
+
+            if ($aFiles) foreach ($aFiles as $aFile) {
+                $oStorage->deleteFile($aFile['id']);
+            }
+        }
+    }
+
+    public function actionUploadCompleted() {
+        $iContext = intval(bx_get('context'));
+        $iFolder = intval(bx_get('folder'));
+
+        if (!isLogged()) {
+            echoJson(['message' => _t('_Access denied')]);
+            exit;
+        }
+
+        if ($this->checkAllowedAdd() != CHECK_ACTION_RESULT_ALLOWED || $iContext && !$this->serviceIsAllowedAddContentToProfile($iContext)) {
+            echoJson(['message' => _t('_Access denied')]);
+            exit;
+        }
+
+        $oStorage = BxDolStorage::getObjectInstance($this->_oConfig->CNF['OBJECT_STORAGE']);
+        if ($oStorage) {
+            $iAuthorProfile = bx_get_logged_profile_id();
+            $aFiles = $oStorage->getGhosts($iAuthorProfile, 0);
+
+            if ($aFiles) {
+                $aFilesIDs = [];
+                foreach($aFiles as $aFile) {
+                    $aFilesIDs[] = $aFile['id'];
+                    bx_set('title-'.$aFile['id'], $aFile['file_name'], 'post');
+                }
+                bx_set('attachments', $aFilesIDs, 'post');
+                bx_set('profile_id', $iAuthorProfile, 'post');
+                bx_set('allow_view_to', !$iContext ? BX_DOL_PG_ALL : -$iContext, 'post');
+                bx_set('cf', 1, 'post');
+
+                $oForm = BxDolForm::getObjectInstance($this->_oConfig->CNF['OBJECT_FORM_ENTRY_UPLOAD'], $this->_oConfig->CNF['OBJECT_FORM_ENTRY_DISPLAY_UPLOAD']);
+                $aFiles = $oForm->insert();
+
+                if ($iFolder != 0 && !empty($aFiles))
+                    $this->_oDb->moveFilesToFolder($aFiles, $iFolder);
+            }
+        }
+
+        echoJson(['success' => true]);
+    }
+
+    public function actionCreateFolder() {
+        $iContext = intval(bx_get('context'));
+        $iFolder = intval(bx_get('current_folder'));
+        $sName = trim(bx_get('name'));
+
+        if (!isLogged()) {
+            echoJson(['message' => _t('_Access denied')]);
+            exit;
+        }
+
+        if ($this->checkAllowedAdd() != CHECK_ACTION_RESULT_ALLOWED || $iContext && !$this->serviceIsAllowedAddContentToProfile($iContext)) {
+            echoJson(['message' => _t('_Access denied')]);
+            exit;
+        }
+
+        if (!empty($sName)) {
+            $iAuthor = bx_get_logged_profile_id();
+            // in case it is posted to context make the context profile as an author of an entry
+            // to leave folder in case creator is removed
+            // and to delete folder when context profile is being deleted
+            $this->_oDb->createFolder($iFolder, $iContext ? $iContext : $iAuthor, !$iContext || $iAuthor == $iContext ? BX_DOL_PG_ALL : -$iContext, $sName);
+        }
+
+        echoJson([]);
+        exit;
+    }
+
+    public function actionMoveFiles() {
+        $iContentId = intval(bx_get('file'));
+
+        $aFilesToMove = [];
+        if ($iContentId) $aFilesToMove = [$iContentId];
+        elseif (isset($_POST['bulk'])) $aFilesToMove = $_POST['bulk'];
+
+        $iContentId = reset($aFilesToMove);
+
+        $aData = $this->_oDb->getContentInfoById($iContentId);
+
+        if (!$aData) {
+            echoJson(['message' => _t('_bx_files_txt_error')]);
+            exit;
+        }
+
+        $CNF = &$this->_oConfig->CNF;
+
+        $iContext = $aData[$CNF['FIELD_ALLOW_VIEW_TO']] < 0 ? -$aData[$CNF['FIELD_ALLOW_VIEW_TO']] : $aData[$CNF['FIELD_AUTHOR']];
+
+        if (!isAdmin() && ($this->checkAllowedAdd() != CHECK_ACTION_RESULT_ALLOWED || !$this->serviceIsAllowedAddContentToProfile($iContext))) {
+            echoJson(['message' => _t('_Access denied')]);
+            exit;
+        }
+
+        if (isset($_POST['move_to'])) {
+            $iMoveTo = intval(bx_get('move_to'));
+            if ($iMoveTo) {
+                $aDataMoveTo = $this->_oDb->getContentInfoById($iMoveTo);
+                if (!$aDataMoveTo) {
+                    echoJson(['message' => _t('_bx_files_txt_error')]);
+                    exit;
+                }
+
+                $iContextMoveTo = $aDataMoveTo[$CNF['FIELD_ALLOW_VIEW_TO']] < 0 ? -$aDataMoveTo[$CNF['FIELD_ALLOW_VIEW_TO']] : $aDataMoveTo[$CNF['FIELD_AUTHOR']];
+
+                if (!isAdmin() && ($this->checkAllowedAdd() != CHECK_ACTION_RESULT_ALLOWED || !$this->serviceIsAllowedAddContentToProfile($iContextMoveTo))) {
+                    echoJson(['message' => _t('_Access denied')]);
+                    exit;
+                }
+            }
+
+            $this->_oDb->moveFilesToFolder($aFilesToMove, $iMoveTo);
+
+            echoJson([
+                'eval' => "                        
+                    $(window).trigger('files_browser.update');
+                ",
+            ]);
+            exit;
+        }
+
+        $aFolders = $this->_oDb->getFoldersInContext($iContext);
+        if (!$aFolders) {
+            echoJson(['message' => _t('_bx_files_txt_move_to_nowhere')]);
+            exit;
+        }
+
+        echoJson([
+            'popup' => [
+                'html' => PopupBox('bx-files-popup', _t('_bx_files_txt_move_to'), $this->_oTemplate->getJsTree($aFilesToMove, $aFolders)),
+                'options' => [],
+            ],
+        ]);
+    }
+
+    public function serviceDeleteEntitiesByAuthor ($iProfileId) {
+        $this->_oDb->deleteProfileBookmarks($iProfileId);
+        return parent::serviceDeleteEntitiesByAuthor ($iProfileId);
+    }
+
+    public function serviceDeleteEntity ($iContentId, $sFuncDelete = 'deleteData') {
+        $aData = $this->_oDb->getContentInfoById($iContentId);
+        if ($aData['type'] == 'folder') {
+            $aNestedFiles = $this->_oDb->getFolderFiles($aData[$this->_oConfig->CNF['FIELD_ID']]);
+            if ($aNestedFiles)
+                foreach ($aNestedFiles as $iFile) {
+                    $this->serviceDeleteEntity($iFile);
+                }
+        }
+        parent::serviceDeleteEntity($iContentId, $sFuncDelete);
+    }
+
+    public function serviceBrowseContext ($iProfileId = 0, $aParams = array()) {
+        if(!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if (!$iProfileId)
+            return;
+        // do not show files in context block for persons profiles
+        $oProfile = BxDolProfile::getInstance($iProfileId);
+        if ($oProfile && $oProfile->getModule() == 'bx_persons') return;
+
+        return parent::serviceBrowseContext($iProfileId, $aParams);
+    }
+}
+
+/** @} */

+ 135 - 0
modules/boonex/files/updates/13.0.4_13.0.5/source/install/config.php

@@ -0,0 +1,135 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Files Files
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_files',
+    'title' => 'Files',
+    'note' => 'Basic blogging module.',
+    'version' => '13.0.5',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/files/',
+    'home_uri' => 'files',
+
+    'db_prefix' => 'bx_files_',
+    'class_prefix' => 'BxFiles',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Files',
+
+    /**
+     * List of page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry',
+    ),
+    
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+    	'trigger_profile_view_submenu',
+    	'trigger_group_view_submenu',
+    ),
+
+	/**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_files_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+		'bx_files_preview',
+        'bx_files_gallery',
+    ),
+
+	/**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_files',
+    	'bx_files_cmts',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+        'process_menu_triggers' => 1,
+        'process_page_triggers' => 1,
+    	'process_esearches' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+    	'unregister_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Relations Section
+     */
+    'relations' => array(
+    	'bx_timeline',
+    	'bx_notifications',
+    ),
+
+);
+
+/** @} */

+ 16 - 0
modules/boonex/files/updates/13.0.4_13.0.5/source/template/unit_live_search.html

@@ -0,0 +1,16 @@
+<div class="bx-base-text-unit bx-def-unit bx-def-unit-live-search group flex items-center mb-2 last:mb-0" data-ts="__ts__">
+    <a class="bx-def-box bx-def-box-hor bx-def-box-round-corners bx-def-color-bg-box bx-def-color-bg-box-hover relative items-center w-full p-2 box-border" href="__content_url__">
+        <bx_if:thumb>
+            <div class="bx-def-unit-img bx-def-thumb-size bx-def-round-corners bx-def-box bx-def-color-bg-box" style="background-image:url(__thumb_url__);"></div>
+        </bx_if:thumb>
+        <bx_if:no_thumb>
+            <div class="bx-def-unit-img">
+                <div class="bx-def-unit-img-empty bx-def-thumb-size bx-def-box bg-white dark:bg-gray-700 rounded box-border"><i class="sys-icon __icon__"></i></div>
+            </div>
+        </bx_if:no_thumb>
+        <div class="bx-def-unit-info bx-def-thumb-size-max-height bx-def-padding-sec-left">
+            <div class="bx-def-ui-title">__title__</div>
+            <div class="bx-def-ui-type bx-def-font-meta">__module_name__</div>
+        </div>
+    </a>
+</div>

+ 51 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Discussions',
+    'version_from' => '13.0.5',
+    'version_to' => '13.0.6',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/forum/updates/update_13.0.5_13.0.6/',
+    'home_uri' => 'forum_update_1305_1306',
+
+    'module_dir' => 'boonex/forum/',
+    'module_uri' => 'forum',
+
+    'db_prefix' => 'bx_forum_',
+    'class_prefix' => 'BxForum',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Discussions',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxForumUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 23 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/install/langs/en.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_forum_page_block_title_featured_entries_view_gallery"><![CDATA[Featured Discussions (Gallery view)]]></string_add>
+	<string_add name="_bx_forum_page_block_title_featured_entries_view_extended"><![CDATA[Featured Discussions (Grid view)]]></string_add>
+	<string_add name="_bx_forum_page_block_title_new_entries_view_gallery"><![CDATA[New Discussions (Gallery View)]]></string_add>
+	<string_add name="_bx_forum_page_block_title_new_entries_view_showcase"><![CDATA[New Discussions (Showcase View)]]></string_add>
+	<string_add name="_bx_forum_page_block_title_latest_entries_view_gallery"><![CDATA[Discussions With Recent Posts (Gallery View)]]></string_add>
+	<string_add name="_bx_forum_page_block_title_latest_entries_view_showcase"><![CDATA[Discussions With Recent Posts (Showcase View)]]></string_add>
+	<string_add name="_bx_forum_page_block_title_top_entries_view_gallery"><![CDATA[Top Discussions (Gallery View)]]></string_add>
+	<string_add name="_bx_forum_page_block_title_top_entries_view_showcase"><![CDATA[Top Discussions (Showcase View)]]></string_add>
+	<string_add name="_bx_forum_page_block_title_popular_entries_view_showcase"><![CDATA[Popular Discussions (Showcase View)]]></string_add>
+	<string_add name="_bx_forum_page_block_title_popular_entries_view_gallery"><![CDATA[Popular Discussions (Gallery View)]]></string_add>
+
+	<string_upd name="_bx_forum_page_block_title_new_entries_view_extended"><![CDATA[New Discussions (Grid View)]]></string_upd>
+	<string_upd name="_bx_forum_page_block_title_latest_entries_view_extended"><![CDATA[Discussions With Recent Posts (Grid View)]]></string_upd>
+	<string_upd name="_bx_forum_page_block_title_top_entries_view_extended"><![CDATA[Top Discussions (Grid View)]]></string_upd>
+	<string_upd name="_bx_forum_page_block_title_popular_entries_view_extended"><![CDATA[Popular Discussions (Grid View)]]></string_upd>
+
+	<string_del name="_bx_forum_page_block_title_new_entries_view_full"><![CDATA[New Discussions (Full View)]]></string_del>
+	<string_del name="_bx_forum_page_block_title_latest_entries_view_full"><![CDATA[Discussions With Recent Posts (Full View)]]></string_del>
+	<string_del name="_bx_forum_page_block_title_top_entries_view_full"><![CDATA[Top Discussions (Full View)]]></string_del>
+	<string_del name="_bx_forum_page_block_title_popular_entries_view_full"><![CDATA[Popular Discussions (Full View)]]></string_del>
+</resources>

+ 34 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/install/sql/enable.sql

@@ -0,0 +1,34 @@
+SET @sName = 'bx_forum';
+
+
+-- PAGES
+DELETE FROM `sys_objects_page` WHERE `object` IN ('bx_forum_new', 'bx_forum_top', 'bx_forum_popular', 'bx_forum_updated', 'bx_forum_partaken');
+DELETE FROM `sys_pages_blocks` WHERE `object` IN ('bx_forum_new', 'bx_forum_top', 'bx_forum_popular', 'bx_forum_updated', 'bx_forum_partaken');
+
+UPDATE `sys_pages_blocks` SET `title_system`='_bx_forum_page_block_title_popular_entries_view_extended', `title`='_bx_forum_page_block_title_popular_entries' WHERE `module`=@sName AND `title`='_bx_forum_page_block_title_popular_entries_view_extended';
+UPDATE `sys_pages_blocks` SET `title_system`='_bx_forum_page_block_title_latest_entries_view_gallery', `title`='_bx_forum_page_block_title_latest_entries', `content`='a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:13:\"browse_latest\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:7:\"gallery\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}' WHERE `module`=@sName AND `title`='_bx_forum_page_block_title_latest_entries';
+UPDATE `sys_pages_blocks` SET `title_system`='_bx_forum_page_block_title_new_entries_view_gallery', `title`='_bx_forum_page_block_title_new_entries', `content`='a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:10:\"browse_new\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:7:\"gallery\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}' WHERE `module`=@sName AND `title`='_bx_forum_page_block_title_new_entries';
+UPDATE `sys_pages_blocks` SET `title_system`='_bx_forum_page_block_title_top_entries_view_extended', `title`='_bx_forum_page_block_title_top_entries' WHERE `module`=@sName AND `title`='_bx_forum_page_block_title_top_entries_view_extended';
+
+DELETE FROM `sys_pages_blocks` WHERE `module`=@sName AND `title` IN ('_bx_forum_page_block_title_popular_entries_view_full', '_bx_forum_page_block_title_latest_entries_view_full', '_bx_forum_page_block_title_new_entries_view_full', '_bx_forum_page_block_title_top_entries_view_full');
+
+DELETE FROM `sys_pages_blocks` WHERE `module`=@sName AND `title_system` IN ('_bx_forum_page_block_title_popular_entries_view_showcase', '_bx_forum_page_block_title_popular_entries_view_gallery', '_bx_forum_page_block_title_featured_entries_view_extended', '_bx_forum_page_block_title_featured_entries_view_gallery');
+DELETE FROM `sys_pages_blocks` WHERE `module`=@sName AND `title_system` IN ('_bx_forum_page_block_title_latest_entries_view_extended', '_bx_forum_page_block_title_latest_entries_view_showcase', '_bx_forum_page_block_title_new_entries_view_extended', '_bx_forum_page_block_title_new_entries_view_showcase');
+DELETE FROM `sys_pages_blocks` WHERE `module`=@sName AND `title_system` IN ('_bx_forum_page_block_title_top_entries_view_showcase', '_bx_forum_page_block_title_top_entries_view_gallery', '_bx_forum_page_block_title_partaken_entries');
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = '' AND `cell_id` = 0 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('', 0, @sName, '_bx_forum_page_block_title_popular_entries_view_showcase', '_bx_forum_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:14:\"browse_popular\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 1),
+('', 0, @sName, '_bx_forum_page_block_title_popular_entries_view_gallery', '_bx_forum_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:14:\"browse_popular\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:7:\"gallery\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 2),
+('', 0, @sName, '_bx_forum_page_block_title_featured_entries_view_extended', '_bx_forum_page_block_title_featured_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:15:\"browse_featured\";s:6:\"params\";a:1:{i:0;s:8:\"extended\";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 3),
+('', 0, @sName, '_bx_forum_page_block_title_featured_entries_view_gallery', '_bx_forum_page_block_title_featured_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:15:\"browse_featured\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:7:\"gallery\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 4),
+('', 0, @sName, '_bx_forum_page_block_title_latest_entries_view_extended', '_bx_forum_page_block_title_latest_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:13:\"browse_latest\";s:6:\"params\";a:1:{i:0;s:8:\"extended\";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 5),
+('', 0, @sName, '_bx_forum_page_block_title_latest_entries_view_showcase', '_bx_forum_page_block_title_latest_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:13:\"browse_latest\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 6),
+('', 0, @sName, '_bx_forum_page_block_title_new_entries_view_extended', '_bx_forum_page_block_title_new_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:10:\"browse_new\";s:6:\"params\";a:1:{i:0;s:8:\"extended\";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 7),
+('', 0, @sName, '_bx_forum_page_block_title_new_entries_view_showcase', '_bx_forum_page_block_title_new_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:10:\"browse_new\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 8),
+('', 0, @sName, '_bx_forum_page_block_title_top_entries_view_showcase', '_bx_forum_page_block_title_top_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:10:\"browse_top\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 9),
+('', 0, @sName, '_bx_forum_page_block_title_top_entries_view_gallery', '_bx_forum_page_block_title_top_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:10:\"browse_top\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:7:\"gallery\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 10),
+('', 0, @sName, '_bx_forum_page_block_title_partaken_entries', '_bx_forum_page_block_title_partaken_entries', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:15:"browse_partaken";}', 0, 1, IFNULL(@iBlockOrder, 0) + 11);
+
+
+-- MENUS
+UPDATE `sys_menu_items` SET `title_system`='_sys_menu_item_title_system_sm_scores', `title`='_sys_menu_item_title_sm_scores' WHERE `set_name`='bx_forum_snippet_meta_main' AND `name`='score';

+ 703 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/classes/BxForumGrid.php

@@ -0,0 +1,703 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Forum Forum
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
+
+define('BX_FORUM_FILTER_STATUS_RESOLVED', 1);
+define('BX_FORUM_FILTER_STATUS_UNRESOLVED', 0);
+
+define('BX_FORUM_FILTER_ORDER_RECENT', 'latest');
+define('BX_FORUM_FILTER_ORDER_NEW', 'new');
+define('BX_FORUM_FILTER_ORDER_TOP', 'top');
+define('BX_FORUM_FILTER_ORDER_UPDATED', 'updated');
+define('BX_FORUM_FILTER_ORDER_POPULAR', 'popular');
+define('BX_FORUM_FILTER_ORDER_FEATURED', 'featured');
+define('BX_FORUM_FILTER_ORDER_FAVORITE', 'favorite');
+define('BX_FORUM_FILTER_ORDER_PARTAKEN', 'partaken');
+
+class BxForumGrid extends BxTemplGrid
+{
+    protected $_oModule;
+    protected $_sDefaultSource; 
+    
+    protected $_sFilter1Name;
+    protected $_sFilter1Value;
+    protected $_aFilter1Values;
+    
+    protected $_sFilter2Name;
+    protected $_sFilter2Value;
+    protected $_aFilter2Values;
+    
+    protected $_sFilter3Name;
+    protected $_sFilter3Value;
+    protected $_aFilter3Values;
+    
+    protected $_sParamsDivider;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        $this->_oModule = BxDolModule::getInstance('bx_forum');
+
+        parent::__construct ($aOptions, $oTemplate);
+        
+        $this->_sFilter1Name = 'filter1';
+        $this->_aFilter1Values = array(
+            '' => _t('_bx_forum_grid_filter_resolved_all'),
+            BX_FORUM_FILTER_STATUS_RESOLVED => _t('_bx_forum_grid_filter_resolved_resolved'),
+            BX_FORUM_FILTER_STATUS_UNRESOLVED => _t('_bx_forum_grid_filter_resolved_unresolved'),
+        );
+        
+        $sFilter1 = bx_get($this->_sFilter1Name);
+        if(!empty($sFilter1)) {
+            $this->_sFilter1Value = bx_process_input($sFilter1);
+            $this->_aQueryAppend['filter1'] = $this->_sFilter1Value;
+        }
+        
+        $this->_sFilter2Name = 'filter2';
+        $aBadges = BxDolBadges::getInstance()->getData(['type' => 'by_module', 'module' => $this->_oModule->_aModule['name']]);
+        
+        $this->_aFilter2Values = [];
+        
+        if (count($aBadges) > 0){
+            $this->_aFilter2Values[''] = _t('_bx_forum_grid_filter_badges_all');
+        }
+        
+        foreach($aBadges as $aBadge) {
+            $this->_aFilter2Values[$aBadge['id']] = $aBadge['text'];
+        }
+        
+
+        $sFilter2 = bx_get($this->_sFilter1Name);
+        if(!empty($sFilter2)) {
+            $this->_sFilter2Value = bx_process_input($sFilter2);
+            $this->_aQueryAppend['filter2'] = $this->_sFilter2Value;
+        }
+        
+        $this->_sFilter3Name = 'filter3';
+        $this->_aFilter3Values = array(
+            BX_FORUM_FILTER_ORDER_RECENT => _t('_bx_forum_grid_filter_order_updated'),
+            BX_FORUM_FILTER_ORDER_NEW => _t('_bx_forum_grid_filter_order_new'),
+            BX_FORUM_FILTER_ORDER_TOP => _t('_bx_forum_grid_filter_order_top'),
+            BX_FORUM_FILTER_ORDER_POPULAR => _t('_bx_forum_grid_filter_order_popular'),
+            BX_FORUM_FILTER_ORDER_FEATURED => _t('_bx_forum_grid_filter_order_featured'),
+            BX_FORUM_FILTER_ORDER_FAVORITE => _t('_bx_forum_grid_filter_order_favorite'),
+            BX_FORUM_FILTER_ORDER_PARTAKEN => _t('_bx_forum_grid_filter_order_partaken'),
+        );
+        
+        $sFilter3 = bx_get($this->_sFilter3Name);
+        if(!empty($sFilter3)) {
+            $this->_sFilter1Value = bx_process_input($sFilter3);
+            $this->_aQueryAppend['filter3'] = $this->_sFilter1Value;
+        }
+        
+        $this->_sParamsDivider = '#-#';
+
+        $this->_sDefaultSortingOrder = 'DESC';
+        $this->_sDefaultSource = $this->_aOptions['source'];
+    }
+
+    public function setBrowseParams($aParams)
+    {
+        if(isset($aParams['ajax_paginate'])) {
+            if(!$aParams['ajax_paginate']) {
+                list($sPageLink, $aPageParams) = bx_get_base_url_inline();
+
+                $aPageParams[$this->_aOptions['paginate_get_start']] = '{start}';
+                $this->_aOptions['paginate_url'] = BxDolPermalinks::getInstance()->permalink(bx_append_url_params($sPageLink, $aPageParams, true, ['{start}']));
+            }
+
+            unset($aParams['ajax_paginate']);
+        }
+        
+        if ($aParams['type'])
+            $this->_sFilter3Value = $aParams['type'];
+
+        parent::setBrowseParams($aParams);
+
+    	$sField = 'added';
+    	if(!empty($this->_aBrowseParams['type']))
+            switch($this->_aBrowseParams['type']) {
+                case 'new':
+                case 'index':
+                case 'author':
+                case 'favorite':
+                case 'category':
+                    $sField = 'added';
+                    break;
+
+                case 'featured':
+                    $sField = 'featured';
+                    break;
+
+                case 'latest':
+                    $sField = 'lr_timestamp';
+                    break;
+
+                case 'popular':
+                    $sField = 'views';
+                    break;
+            }
+
+        $this->_aOptions['field_order'] = $sField;
+        $this->_aOptions['paginate_per_page'] = !empty($this->_aBrowseParams['per_page']) ? (int)$this->_aBrowseParams['per_page'] : (int)$this->_oModule->_oDb->getParam('bx_forum_per_page_browse');
+    }
+
+    public function getCode ($isDisplayHeader = true)
+    {
+        $sCode = parent::getCode($isDisplayHeader);
+        if(empty($sCode))
+            return '';
+
+    	return $this->_oModule->_oTemplate->parseHtmlByName('units.html', array(
+            'code' => $sCode,
+            'js_code' => $this->_oModule->_oTemplate->getJsCode('main')
+        ));
+    }
+
+    protected function _getActionAdd ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if($this->_oModule->checkAllowedAdd() !== CHECK_ACTION_RESULT_ALLOWED)
+            return '';
+
+        $sUrl = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $this->_oModule->_oConfig->CNF['URI_ADD_ENTRY']);
+
+        unset($a['attr']['bx_grid_action_independent']);
+        $a['attr'] = array_merge($a['attr'], array(
+    		"onclick" => "window.open('" . $sUrl . "','_self');"
+    	));
+
+        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getRowHead ()
+    {
+    	return array();
+    }
+
+    protected function _getCellDefault ($mixedValue, $sKey, $aField, $aRow)
+    {
+        $aField['attr_cell']['class'] = 'bx-grid-table-cell-' . $sKey;
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellAuthor($mixedValue, $sKey, $aField, $aRow)
+    {
+    	$mixedValue = $this->_oModule->_oTemplate->getEntryAuthor($aRow);
+
+        return self::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+    
+    protected function _getCellCategory($mixedValue, $sKey, $aField, $aRow)
+    {
+        $sIcon = $this->_oModule->_oTemplate->parseHtmlByName('default_category.html', []);
+        $o = BxDolCategory::getObjectInstance('bx_forum_cats');
+        
+        $aCategoryData = $this->_oModule->_oDb->getCategories(array('type' => 'by_category', 'category' => $aRow['cat']));
+
+        if(isset($aCategoryData['icon']))
+            $sIcon = $this->_oTemplate->getImage($aCategoryData['icon'], array('class' => 'sys-icon'));
+        
+        $mixedValue = $this->_oModule->_oTemplate->parseHtmlByName('thumb.html', ['icon' => $sIcon, 'title' => $o->getCategoryTitle($aRow['cat'])]);
+        return self::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+    
+    protected function _getCellRating($mixedValue, $sKey, $aField, $aRow)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $oObject = isset($CNF['OBJECT_SCORES']) ? BxDolScore::getObjectInstance($CNF['OBJECT_SCORES'], $aRow[$CNF['FIELD_ID']], true, $this->_oModule->_oTemplate) : null;
+        $mixedValue = $oObject ? $oObject->getElementInline() : '';
+        
+        return self::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+    
+    protected function _getCellParticipants($mixedValue, $sKey, $aField, $aRow)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+    	$oObject = isset($CNF['OBJECT_COMMENTS']) ? BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], $aRow[$CNF['FIELD_ID']]) : null;
+      
+        $mixedValue = $oObject ? $oObject->getCounter(['show_counter_empty' => true, 'show_counter' => false, 'show_counter_style' => 'simple', 'dynamic_mode' => true, 'show_icon' => false, 'caption_empty' => '']) : '';
+
+        return self::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellText($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = $this->_oModule->_oTemplate->getEntryPreview($aRow, ['show_meta_counters' => false, 'show_meta_reply' => false]);
+
+        return self::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+
+        $this->_oModule->_oTemplate->addJs(array('main.js'));
+        $this->_oModule->_oTemplate->addCss(array('main.css', 'main-media-phone.css', 'main-media-tablet.css', 'main-media-desktop.css'));
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+        
+        if(strpos($sFilter, $this->_sParamsDivider) !== false)
+            list($this->_sFilter1Value, $this->_sFilter2Value, $this->_sFilter3Value, $sFilter) = explode($this->_sParamsDivider, $sFilter);
+
+        $iAuthorId = 0;
+    	if(!empty($this->_aBrowseParams['author'])) {
+            $oProfileAuthor = BxDolProfile::getInstance((int)$this->_aBrowseParams['author']);
+            if($oProfileAuthor)
+                $iAuthorId = $oProfileAuthor->id();
+    	}
+
+        // featured
+        if ($this->_sFilter3Value == BX_FORUM_FILTER_ORDER_FEATURED) {
+            $this->_aBrowseParams['where'] = ['fld' => 'featured', 'val' => 0, 'opr' => '<>'];
+        }
+        
+        // partaken
+        if ($this->_sFilter3Value == BX_FORUM_FILTER_ORDER_PARTAKEN) {
+            $this->_aBrowseParams['select'] = [
+                'tbla' => 'tco', 
+                'fld' => 'cmt_author_id',
+            ];
+
+            $this->_aBrowseParams['join'] = [
+                'tp' => 'LEFT',
+                'tbl1' => 'bx_forum_cmts',
+                'tbl1a' => 'tco',
+                'fld1' => 'cmt_object_id',
+                'tbl2' => 'bx_forum_discussions',
+                'fld2' => 'id'
+            ];
+
+            $this->_aBrowseParams['where'] = ['grp' => true, 'opr' => 'OR', 'cnds' => [[
+                    'tbl' => 'bx_forum_discussions',
+                    'fld' => 'author',
+                    'val' => $iAuthorId, 
+                    'opr' => '='
+                ], [
+                    'tbl' => 'tco', 
+                    'fld' => 'cmt_author_id', 
+                    'val' => $iAuthorId, 
+                    'opr' => '='
+                ]
+            ]];
+
+            $this->_aBrowseParams['group_by'] = [
+                'tbl' => 'bx_forum_discussions', 
+                'fld' => 'id',
+            ];
+        }
+
+        //FAVORITE
+        if ($this->_sFilter3Value == BX_FORUM_FILTER_ORDER_FAVORITE){
+            $oProfile = BxDolProfile:: getInstance(bx_process_input(bx_get('profile_id'), BX_DATA_INT));
+            if(!$oProfile)
+                $oProfile = BxDolProfile::getInstance();
+            if(!$oProfile)
+                return '';
+            
+            $iProfileId = $oProfile->id();
+            $iProfileAuthor = $oProfile->id();
+            $oFavorite = $this->_oModule->getObjectFavorite();
+            if(!$oFavorite->isPublic() && $iProfileAuthor != bx_get_logged_profile_id())
+                return '';
+            
+            $aConditions = $oFavorite->getConditionsTrack($CNF['TABLE_ENTRIES'], 'id', $iProfileAuthor);
+            if(empty($aConditions) || !is_array($aConditions)) 
+                return '';
+
+            $aJoinGroup = array('grp' => true, 'cnds' => array());
+            if(!empty($aConditions['join']))
+                foreach($aConditions['join'] as $aCondition)
+                    $aJoinGroup['cnds'][] = array(
+                        'tp' => $aCondition['type'],
+                        'tbl1' => $aCondition['table'],
+                        'fld1' => $aCondition['onField'],
+                        'tbl2' => $aCondition['mainTable'],
+                        'fld2' => $aCondition['mainField']
+                    );
+
+            $aWhereGroup = array('grp' => true, 'opr' => 'AND', 'cnds' => array());
+            if(!empty($aConditions['restriction']))
+                foreach($aConditions['restriction'] as $aCondition)
+                    $aWhereGroup['cnds'][] = array(
+                        'tbl' => (!empty($aCondition['table']) ? $aCondition['table'] : ''), 
+                        'fld' => $aCondition['field'], 
+                        'val' => $aCondition['value'], 
+                        'opr' => $aCondition['operator']
+                    );
+            
+            $this->_aBrowseParams['author'] = $iProfileId; 
+            $this->_aBrowseParams['join'] = $aJoinGroup;
+            $this->_aBrowseParams['where'] = $aWhereGroup; 
+        }
+        
+    	$sSelectClause = $sJoinClause = $sWhereClause = $sGroupByClause = '';
+
+    	//--- Check status
+    	$sWhereClause .= " AND `{$CNF['TABLE_ENTRIES']}`.`" . $CNF['FIELD_STATUS'] . "`='active'";
+    	$sWhereClause .= " AND `{$CNF['TABLE_ENTRIES']}`.`" . $CNF['FIELD_STATUS_ADMIN'] . "`='active'";
+
+    	//--- Check privacy
+        $bIncludeContexts = isset($this->_aBrowseParams['include_contexts']) && $this->_aBrowseParams['include_contexts'];
+
+        $sPrivacy = $CNF['OBJECT_PRIVACY_VIEW'];
+        $oPrivacy = BxDolPrivacy::getObjectInstance($sPrivacy);
+        $aCondition = $oPrivacy ? $oPrivacy->{'getContentPublic' . ($bIncludeContexts ? 'AndInContext' : '') . 'AsSQLPart'}($iAuthorId) : array();
+        if(isset($aCondition['join']))
+            $sJoinClause .= $aCondition['join'];
+        if(isset($aCondition['where']))
+            $sWhereClause .= $aCondition['where'];
+
+        //--- Check browse params
+        if(!empty($this->_aBrowseParams['select']) && is_array($this->_aBrowseParams['select'])) {
+            $sSelectClauseBrowse = $this->_getSqlSelectFromGroup($this->_aBrowseParams['select']);
+            if(!empty($sSelectClauseBrowse))
+                $sSelectClause .= ", " . $sSelectClauseBrowse;
+        }
+
+        if(!empty($this->_aBrowseParams['join']) && is_array($this->_aBrowseParams['join'])) {
+            $sJoinClauseBrowse = $this->_getSqlJoinFromGroup($this->_aBrowseParams['join']);
+            if(!empty($sJoinClauseBrowse))
+                $sJoinClause .= " " . $sJoinClauseBrowse;
+        }
+
+        if(!empty($this->_aBrowseParams['where']) && is_array($this->_aBrowseParams['where'])) {
+            $sWhereClauseBrowse = $this->_getSqlWhereFromGroup($this->_aBrowseParams['where']);
+            if(!empty($sWhereClauseBrowse))
+                $sWhereClause .= " AND " . $sWhereClauseBrowse;
+        }
+
+        if(!empty($this->_aBrowseParams['group_by']) && is_array($this->_aBrowseParams['group_by'])) {
+            $sGroupByClauseBrowse = $this->_getSqlGroupByFromGroup($this->_aBrowseParams['group_by']);
+            if(!empty($sGroupByClauseBrowse))
+                $sGroupByClause .= " GROUP BY " . $sGroupByClauseBrowse;
+        }
+        
+        $sFilterSql = "";
+
+        // filter by resolved status
+        if(isset($this->_sFilter1Value) && $this->_sFilter1Value != '') {
+            $sWhereClause .= " AND `" . $CNF['TABLE_ENTRIES'] . "`.`" . $CNF['FIELD_RESOLVABLE'] . "` = 1 AND `" . $CNF['TABLE_ENTRIES'] . "`.`" . $CNF['FIELD_RESOLVE'] . "` = " . $this->_sFilter1Value;
+        }
+        
+        // filter out posts of suspended members
+        $sJoinClause .= " INNER JOIN `sys_profiles` AS `p` ON (`p`.`id` = `{$CNF['TABLE_ENTRIES']}`.`{$CNF['FIELD_AUTHOR']}` AND `p`.`status` = 'active') ";
+
+        // filter out posts by content filter
+        $oCf = BxDolContentFilter::getInstance();
+        if($oCf->isEnabled())
+            $sWhereClause .= $oCf->getSQLParts ($CNF['TABLE_ENTRIES'], $CNF['FIELD_CF']);
+
+        // filter by badges
+        if(isset($this->_sFilter2Value) && $this->_sFilter2Value != '') {
+            $aObjects = BxDolBadges::getInstance()->getData(['type' => 'by_module&badge', 'badge_id' => $this->_sFilter2Value, 'module' => $this->_oModule->_aModule['name']]);
+            $sWhereClause .= " AND `" . $CNF['TABLE_ENTRIES'] . "`.`" . $CNF['FIELD_ID'] . "` IN (" . implode(',', $aObjects ) . ")";
+        }
+
+        $this->_aOptions['source'] = sprintf($this->_sDefaultSource, $sSelectClause, $sJoinClause, $sWhereClause, $sGroupByClause);
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+
+    protected function _getDataSqlOrderClause($sOrderByFilter, $sOrderField, $sOrderDir, $bFieldsOnly = false)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(isset($this->_sFilter3Value) && $this->_sFilter3Value != ''){
+            $sOrderField = $this->_aBrowseParams['type'] = $this->_sFilter3Value;
+            if (!empty($this->_aBrowseParams['type']) && $this->_aBrowseParams['type'] != 'partaken'){
+                $this->_aBrowseParams['type'] = $this->_aBrowseParams['type'] = $this->_sFilter3Value;
+            }
+        }
+        
+    	$sOrder = parent::_getDataSqlOrderClause($sOrderByFilter, $sOrderField, $sOrderDir, true);
+                
+        if(!empty($this->_aBrowseParams['type']))
+            switch($this->_aBrowseParams['type']) {
+                case 'top':
+                    $aPartsUp = $aPartsDown = array(0);
+                    if(($oVote = BxDolVote::getObjectInstance($CNF['OBJECT_VOTES'], 0, false)) !== false && $oVote->isEnabled()) {
+                        $aVote = $oVote->getSystemInfo();
+                        if(!empty($aVote['trigger_table']) && !empty($aVote['trigger_field_count']))
+                            $aPartsUp[] = '`' . $aVote['trigger_table'] . '`.`' . $aVote['trigger_field_count'] . '`';
+                    }
+
+                    if(($oReaction = BxDolVote::getObjectInstance($CNF['OBJECT_REACTIONS'], 0, false)) !== false && $oReaction->isEnabled()) {
+                        $aReaction = $oReaction->getSystemInfo();
+                        if(!empty($aReaction['trigger_table']) && !empty($aReaction['trigger_field_count']))
+                            $aPartsUp[] = '`' . $aReaction['trigger_table'] . '`.`' . $aReaction['trigger_field_count'] . '`';
+                    }
+
+                    if(($oScore = BxDolScore::getObjectInstance($CNF['OBJECT_SCORES'], 0, false)) !== false && $oScore->isEnabled()) {
+                        $aScore = $oScore->getSystemInfo();
+                        if(!empty($aScore['trigger_table']) && !empty($aScore['trigger_field_cup']) && !empty($aScore['trigger_field_cdown'])) {
+                            $aPartsUp[] = '`' . $aScore['trigger_table'] . '`.`' . $aScore['trigger_field_cup'] . '`';
+                            $aPartsDown[] = '`' . $aScore['trigger_table'] . '`.`' . $aScore['trigger_field_cdown'] . '`';
+                        }
+                    }
+
+                    $sOrder = pow(10, 8) . ' * ((' . implode(' + ', $aPartsUp) . ') - (' . implode(' + ', $aPartsDown) . ')) / (UNIX_TIMESTAMP() - `' . $this->_aOptions['table'] . '`.`' . $CNF['FIELD_ADDED'] . '`) ' . $this->_sDefaultSortingOrder;
+                    break;
+
+                case 'partaken':
+                    $sOrder = 'MAX(IF(`tco`.`cmt_time`, `tco`.`cmt_time`, `' . $CNF['TABLE_ENTRIES'] . '`.`' . $CNF['FIELD_ADDED'] . '`)) ' . $this->_sDefaultSortingOrder;
+                    break;
+            }           
+
+    	return " ORDER BY `" . $CNF['TABLE_ENTRIES'] . "`.`" . $CNF['FIELD_STICK'] . "` DESC, " . $sOrder;
+    }
+
+    protected function _getSqlSelectFromGroup($aGrp)
+    {
+        if(!isset($aGrp['grp']) || (bool)$aGrp['grp'] !== true)
+            return $this->_getSqlSelectFromCondition($aGrp);
+
+        $sResult = "";
+        if(empty($aGrp['cnds']) || !is_array($aGrp['cnds']))
+            return $sResult;
+
+        $sOprGrp = ", ";
+        foreach($aGrp['cnds'] as $aCnd) {
+            $sResultCnd = $this->_getSqlSelectFromCondition($aCnd);
+            if(!empty($sResultCnd))
+                $sResult .= $sOprGrp . $sResultCnd;
+        }
+
+        return trim($sResult, $sOprGrp);
+    }
+
+    protected function _getSqlSelectFromCondition($aCnd)
+    {
+    	$sResult = "";
+    	if(!isset($aCnd['fld']))
+            return $sResult;
+
+        $sResult = "`" . $aCnd['fld'] . "`";
+        if(!empty($aCnd['tbla']))
+            $sResult = "`" . $aCnd['tbla'] . "`." . $sResult;
+        else if(!empty($aCnd['tbl']))
+            $sResult = "`" . $aCnd['tbl'] . "`." . $sResult;
+
+        return $sResult;
+    }
+
+    protected function _getSqlJoinFromGroup($aGrp)
+    {
+        if(!isset($aGrp['grp']) || (bool)$aGrp['grp'] !== true)
+            return $this->_getSqlJoinFromCondition($aGrp);
+
+        $sResult = "";
+        if(empty($aGrp['cnds']) || !is_array($aGrp['cnds']))
+            return $sResult;
+
+        $sOprGrp = " ";
+        foreach($aGrp['cnds'] as $aCnd) {
+            $sResultCnd = $this->_getSqlJoinFromCondition($aCnd);
+            if(!empty($sResultCnd))
+                $sResult .= $sOprGrp . $sResultCnd;
+        }
+
+        return trim($sResult, $sOprGrp);
+    }
+
+    protected function _getSqlJoinFromCondition($aCnd)
+    {
+    	$sResult = "";
+    	if(!isset($aCnd['tp'], $aCnd['tbl1'], $aCnd['fld1'], $aCnd['fld2']))
+            return $sResult;
+
+        $sTbl1A = $aCnd['tbl1'];
+        if(!empty($aCnd['tbl1a']))
+            $sTbl1A = $aCnd['tbl1a'];
+
+        $sField1 = "`" . $sTbl1A . "`.`" . $aCnd['fld1'] . "`";
+
+        $sField2 = "`" . $aCnd['fld2'] . "`";
+        if(!empty($aCnd['tbl2a']))
+            $sField2 = "`" . $aCnd['tbl2a'] . "`." . $sField2;
+        else if(!empty($aCnd['tbl2']))
+            $sField2 = "`" . $aCnd['tbl2'] . "`." . $sField2;
+
+        return $aCnd['tp'] . " JOIN `" . $aCnd['tbl1'] . "` AS `" . $sTbl1A . "` ON (" . $sField1 . " = " . $sField2 . ")";
+    }
+
+    protected function _getSqlWhereFromGroup($aGrp)
+    {
+        if(!isset($aGrp['grp']) || (bool)$aGrp['grp'] !== true)
+            return $this->_getSqlWhereFromCondition($aGrp);
+
+        $sResult = "";
+        if(!isset($aGrp['opr'], $aGrp['cnds']) || empty($aGrp['cnds']) || !is_array($aGrp['cnds']))
+            return $sResult;
+
+        $sOprGrp = " " . $aGrp['opr'] . " ";
+        foreach($aGrp['cnds'] as $aCnd) {
+            $sMethod = '_getSqlWhereFrom' . (isset($aGrp['grp']) && (bool)$aGrp['grp'] === true ? 'Group' : 'Condition');
+            $sResultCnd = $this->$sMethod($aCnd);
+            if(!empty($sResultCnd))
+                $sResult .= $sOprGrp . $sResultCnd;
+        }
+
+        $sResult = trim($sResult, $sOprGrp);
+        if(!empty($sResult))
+            $sResult = "(" . $sResult . ")";
+
+    	return $sResult;
+    }
+
+    protected function _getSqlWhereFromCondition($aCnd)
+    {
+        $sResult = "";
+        if(!isset($aCnd['fld'], $aCnd['val'], $aCnd['opr']))
+            return $sResult;
+
+        $sMethod = '_getSqlWhereFromCondition' . bx_gen_method_name($aCnd['fld']);
+        if(method_exists($this, $sMethod)) {
+            $mixedResult = $this->$sMethod($aCnd);
+            if(is_array($mixedResult) && isset($mixedResult['fld'], $mixedResult['val'], $mixedResult['opr']))
+                $aCnd = $mixedResult;
+            else
+                return $mixedResult;
+        }
+        
+        $sField = "`" . $aCnd['fld'] . "`";
+        if(!empty($aCnd['tbl']))
+            $sField = "`" . $aCnd['tbl'] . "`." . $sField;
+
+        switch($aCnd['opr']) {
+            case 'IN':
+                if(empty($aCnd['val']) || !is_array($aCnd['val']))
+                    break;
+
+                $sResult .= $sField . " IN (" . $this->_oModule->_oDb->implode_escape($aCnd['val']) . ")";
+                break;
+
+            case 'LIKE':
+                $sResult .= $sField . " LIKE " . $this->_oModule->_oDb->escape('%' . $aCnd['val'] . '%');
+                break;
+
+            default:
+                $sResult .= $sField . " " . $aCnd['opr'] . " " . $this->_oModule->_oDb->escape($aCnd['val']);
+        }
+
+        return $sResult;
+    }
+
+    protected function _getSqlGroupByFromGroup($aGrp)
+    {
+        if(!isset($aGrp['grp']) || (bool)$aGrp['grp'] !== true)
+            return $this->_getSqlGroupByFromCondition($aGrp);
+
+        $sResult = "";
+        if(empty($aGrp['cnds']) || !is_array($aGrp['cnds']))
+            return $sResult;
+
+        $sOprGrp = ", ";
+        foreach($aGrp['cnds'] as $aCnd) {
+            $sResultCnd = $this->_getSqlGroupByFromCondition($aCnd);
+            if(!empty($sResultCnd))
+                $sResult .= $sOprGrp . $sResultCnd;
+        }
+
+        return trim($sResult, $sOprGrp);
+    }
+
+    protected function _getSqlGroupByFromCondition($aCnd)
+    {
+    	$sResult = "";
+    	if(!isset($aCnd['fld']))
+            return $sResult;
+
+        $sResult = "`" . $aCnd['fld'] . "`";
+        if(!empty($aCnd['tbla']))
+            $sResult = "`" . $aCnd['tbla'] . "`." . $sResult;
+        else if(!empty($aCnd['tbl']))
+            $sResult = "`" . $aCnd['tbl'] . "`." . $sResult;
+
+        return $sResult;
+    }
+
+    protected function _getSqlWhereFromConditionAuthorComment($aCnd)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aEntriesIds = $this->_oModule->_oDb->getComments(array('type' => 'entries_author_search', 'author' => $aCnd['val']));
+        if(!empty($aEntriesIds) && is_array($aEntriesIds))
+            return array('tbl' => $CNF['TABLE_ENTRIES'], 'fld' => 'id', 'val' => $aEntriesIds, 'opr' => 'IN');
+
+        return '';
+    }
+
+    protected function _getSqlWhereFromConditionKeywordComment($aCnd)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aEntriesIds = $this->_oModule->_oDb->getComments(array('type' => 'entries_keyword_search', 'keyword' => $aCnd['val']));
+        if(!empty($aEntriesIds) && is_array($aEntriesIds))
+            return array('tbl' => $CNF['TABLE_ENTRIES'], 'fld' => 'id', 'val' => $aEntriesIds, 'opr' => 'IN');
+
+        return '';
+    }
+    
+    protected function _getFilterControls ()
+    {
+        parent::_getFilterControls();
+        return  $this->_getFilterSelectOne($this->_sFilter3Name, $this->_sFilter3Value, $this->_aFilter3Values) . $this->_getFilterSelectOne($this->_sFilter1Name, $this->_sFilter1Value, $this->_aFilter1Values) . (count($this->_aFilter2Values) > 0 ? $this->_getFilterSelectOne($this->_sFilter2Name, $this->_sFilter2Value, $this->_aFilter2Values) : '') . $this->_getSearchInput();
+    }
+    
+    protected function _getSearchInput()
+    {
+        $sJsObject = $this->_oModule->_oConfig->getJsObject('main');
+        $aInputSearch = array(
+            'type' => 'text',
+            'name' => 'search',
+            'attrs' => array(
+                'id' => 'bx-grid-search-' . $this->_sObject,
+                'onKeyup' => 'javascript:$(this).off(\'keyup focusout\'); ' . $sJsObject . '.onChangeFilter(this)',
+                'onBlur' => 'javascript:' . $sJsObject . '.onChangeFilter(this)',
+            )
+        );
+
+        $oForm = new BxTemplFormView(array());
+        return $oForm->genRow($aInputSearch);
+    }
+    
+    protected function _getFilterSelectOne($sFilterName, $sFilterValue, $aFilterValues)
+    {
+        if(empty($sFilterName) || empty($aFilterValues))
+            return '';
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+        $sJsObject = $this->_oModule->_oConfig->getJsObject('main');
+
+        foreach($aFilterValues as $sKey => $sValue)
+            $aFilterValues[$sKey] = _t($sValue);
+
+        $aInputModules = array(
+            'type' => 'select',
+            'name' => $sFilterName,
+            'attrs' => array(
+                'id' => 'bx-grid-' . $sFilterName . '-' . $this->_sObject,
+                'onChange' => 'javascript:' . $sJsObject . '.onChangeFilter(this)'
+            ),
+            'value' => $sFilterValue,
+            'values' => $aFilterValues
+        );
+
+        $oForm = new BxTemplFormView(array());
+        return $oForm->genRow($aInputModules);
+    }
+}
+
+/** @} */

+ 1059 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/classes/BxForumModule.php

@@ -0,0 +1,1059 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Forum Forum
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxForumModule extends BxBaseModTextModule
+{
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+
+    public function sortParticipants ($aParticipants, $iProfileIdLastComment, $iProfileIdAuthor, $iProfileIdCurrent = 0)
+    {
+        if (!$iProfileIdCurrent)
+            $iProfileIdCurrent = bx_get_logged_profile_id();
+
+        $aMoveUp = array($iProfileIdCurrent, $iProfileIdLastComment, $iProfileIdAuthor);
+
+        asort($aParticipants, SORT_NUMERIC);
+
+        foreach ($aMoveUp as $iProfileId) {
+            if (!isset($aParticipants[$iProfileId]))
+                continue;
+
+            $a = array($iProfileId => $aParticipants[$iProfileId]);
+            unset($aParticipants[$iProfileId]);
+            $aParticipants = $a + $aParticipants;
+        }
+
+        return $aParticipants;
+    }
+
+    /**
+     * Action methods
+     */
+    public function actionUpdateStatus($sAction = '', $iContentId = 0)
+    {
+        if(empty($sAction) && bx_get('action') !== false)
+            $sAction = bx_process_input(bx_get('action'));
+
+        if(empty($iContentId) && bx_get('id') !== false)
+            $iContentId = (int)bx_get('id');
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return echoJson(array('code' => 1, 'message' => _t('_bx_forum_err_not_found')));
+
+        $sMethodCheck = 'checkAllowed' . bx_gen_method_name($sAction) . 'AnyEntry';
+        $sResult = $this->$sMethodCheck($aContentInfo);
+        if($sResult !== CHECK_ACTION_RESULT_ALLOWED)
+            return echoJson(array('code' => 2, 'message' => $sResult));
+
+        bx_audit(
+            $iContentId, 
+            $this->getName(), 
+            '_sys_audit_action_' . $sAction,  
+            $this->_prepareAuditParams($aContentInfo, false)
+        );
+        
+        if(!$this->_oDb->updateStatus($sAction, $aContentInfo))
+            return echoJson(array('code' => 3, 'message' => _t('_error occured')));
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        $this->alertAfterEdit($aContentInfo);
+
+        echoJson(array('code' => 0, 'id' => $iContentId, 'reload' => 1));
+    }
+
+    public function actionAjaxGetAuthors()
+    {
+        $aResult = BxDolService::call('system', 'profiles_search', array(bx_get('term')), 'TemplServiceProfiles');
+
+        header('Content-Type:text/javascript; charset=utf-8');
+        echo json_encode($aResult);
+    }
+
+    /**
+     * Service methods
+     */
+
+    public function serviceGetSafeServices()
+    {
+        $a = parent::serviceGetSafeServices();
+        return array_merge($a, array (
+            'BrowseNew' => '',
+            'BrowseLatest' => '',
+            'BrowseTop' => '',
+            'BrowsePopular' => '',
+            'BrowseUpdated' => '',
+            'BrowsePartaken' => '',
+            'BrowseIndex' => '',
+            'Search' => '',
+        ));
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-other Other
+     * @subsubsection bx_forum-get_searchable_fields get_searchable_fields
+     * 
+     * @code bx_srv('bx_forum', 'get_searchable_fields', [...]); @endcode
+     * 
+     * Get searchable fields for Studio settings.
+     * 
+     * @return an array with key-value pairs to be used in settings dropdown field.
+     * 
+     * @see BxForumModule::serviceGetSearchableFields
+     */
+    /** 
+     * @ref bx_forum-get_searchable_fields "get_searchable_fields"
+     */
+    public function serviceGetSearchableFields ($aInputsAdd = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aResult = parent::serviceGetSearchableFields($aInputsAdd);
+        $aResult[$CNF['FIELD_TEXT_COMMENTS']] = _t('_bx_forum_form_entry_input_text_comments');
+
+        return $aResult;
+    }
+
+    /**
+     * Service methods
+     */
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-other Other
+     * @subsubsection bx_forum-get_info get_info
+     * 
+     * @code bx_srv('bx_forum', 'get_info', [...]); @endcode
+     * 
+     * Get content info by content ID. Is used in "Content Info Objects" system.
+     * 
+     * @param $iContentId integer value with content ID.
+     * @param $bSearchableFieldsOnly (optional) boolean value determining all info or "searchable fields" only will be returned.
+     * @return an array with content info. Empty array is returned if something is wrong.
+     * 
+     * @see BxForumModule::serviceGetInfo
+     */
+    /** 
+     * @ref bx_forum-get_info "get_info"
+     */
+    public function serviceGetInfo ($iContentId, $bSearchableFieldsOnly = true)
+    {
+        $aContentInfo = $this->_getFields($iContentId);
+        if(empty($aContentInfo))
+            return array();
+
+        return $aContentInfo;
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_new browse_new
+     * 
+     * @code bx_srv('bx_forum', 'browse_new', [...]); @endcode
+     * 
+     * Get page block with a list of items ordered by newness and represented as table.
+     * 
+     * @param $sUnitView (optional) string with unit view type.
+     * @param $bEmptyMessage (optional) boolean value determining whether an "Empty" message should be returned or not.
+     * @param $bAjaxPaginate (optional) boolean value determining whether an Ajax based pagination should be used or not.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowseNew
+     */
+    /** 
+     * @ref bx_forum-browse_new "browse_new"
+     */
+	public function serviceBrowseNew ($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $bShowHeader = false)
+    {
+    	$sType = 'new';
+
+    	if($sUnitView != 'table')   
+        	return $this->_serviceBrowse($sType, $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+
+        return $this->_serviceBrowseTable(array(
+            'type' => $sType,
+            'empty_message' => $bEmptyMessage,
+            'ajax_paginate' => $bAjaxPaginate
+        ), $bShowHeader);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_latest browse_latest
+     * 
+     * @code bx_srv('bx_forum', 'browse_latest', [...]); @endcode
+     * 
+     * Get page block with a list of items ordered by Recent Posts in them and represented as table.
+     * 
+     * @param $sUnitView (optional) string with unit view type.
+     * @param $bEmptyMessage (optional) boolean value determining whether an "Empty" message should be returned or not.
+     * @param $bAjaxPaginate (optional) boolean value determining whether an Ajax based pagination should be used or not.
+     * @param $bShowHeader (optional) boolean value determining whether a resulting table should have Header section or not.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowseNew
+     */
+    /** 
+     * @ref bx_forum-browse_latest "browse_latest"
+     */
+    public function serviceBrowseLatest($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $bShowHeader = true)
+    {
+        $sType = 'latest';
+
+        if($sUnitView != 'table')
+            return $this->_serviceBrowse($sType, $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+
+        return $this->_serviceBrowseTable(array(
+            'type' => $sType,
+            'empty_message' => $bEmptyMessage, 
+            'ajax_paginate' => $bAjaxPaginate
+        ), $bShowHeader);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_featured browse_featured
+     * 
+     * @code bx_srv('bx_forum', 'browse_featured', [...]); @endcode
+     * 
+     * Get page block with a list of featured items represented as table.
+     * 
+     * @param $sUnitView (optional) string with unit view type.
+     * @param $bEmptyMessage (optional) boolean value determining whether an "Empty" message should be returned or not.
+     * @param $bAjaxPaginate (optional) boolean value determining whether an Ajax based pagination should be used or not.
+     * @param $bShowHeader (optional) boolean value determining whether a resulting table should have Header section or not.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowseFeatured
+     */
+    /** 
+     * @ref bx_forum-browse_featured "browse_featured"
+     */
+    public function serviceBrowseFeatured($sUnitView = false, $bEmptyMessage = false, $bAjaxPaginate = true, $bShowHeader = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$sType = 'featured';
+
+    	if($sUnitView != 'table')
+            return $this->_serviceBrowse($sType, $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+
+        return $this->_serviceBrowseTable(array(
+            'type' => $sType, 
+            'empty_message' => $bEmptyMessage,
+            'ajax_paginate' => $bAjaxPaginate
+        ), $bShowHeader);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_top browse_top
+     * 
+     * @code bx_srv('bx_forum', 'browse_top', [...]); @endcode
+     * 
+     * Get page block with a list of items ordered by a number of comments and represented as table.
+     * 
+     * @param $sUnitView (optional) string with unit view type.
+     * @param $bEmptyMessage (optional) boolean value determining whether an "Empty" message should be returned or not.
+     * @param $bAjaxPaginate (optional) boolean value determining whether an Ajax based pagination should be used or not.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowseTop
+     */
+    /** 
+     * @ref bx_forum-browse_top "browse_top"
+     */
+    public function serviceBrowseTop($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $bShowHeader = true)
+    {
+        $sType = 'top';
+
+        if($sUnitView != 'table')
+            return $this->_serviceBrowse($sType, $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+
+        return $this->_serviceBrowseTable(array(
+            'type' => $sType,
+            'empty_message' => $bEmptyMessage,
+            'ajax_paginate' => $bAjaxPaginate
+        ), $bShowHeader);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_popular browse_popular
+     * 
+     * @code bx_srv('bx_forum', 'browse_popular', [...]); @endcode
+     * 
+     * Get page block with a list of items ordered by a number of views and represented as table.
+     * 
+     * @param $sUnitView (optional) string with unit view type.
+     * @param $bEmptyMessage (optional) boolean value determining whether an "Empty" message should be returned or not.
+     * @param $bAjaxPaginate (optional) boolean value determining whether an Ajax based pagination should be used or not.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowsePopular
+     */
+    /** 
+     * @ref bx_forum-browse_popular "browse_popular"
+     */
+    public function serviceBrowsePopular ($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $bShowHeader = false)
+    {
+        $sType = 'popular';
+
+        if($sUnitView != 'table')
+            return $this->_serviceBrowse($sType, $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+
+        return $this->_serviceBrowseTable(array(
+            'type' => $sType,
+            'empty_message' => $bEmptyMessage,
+            'ajax_paginate' => $bAjaxPaginate
+        ), $bShowHeader);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_updated browse_updated
+     * 
+     * @code bx_srv('bx_forum', 'browse_updated', [...]); @endcode
+     * 
+     * Get page block with a list of updated items represented as table.
+     * 
+     * @param $sUnitView (optional) string with unit view type.
+     * @param $bEmptyMessage (optional) boolean value determining whether an "Empty" message should be returned or not.
+     * @param $bAjaxPaginate (optional) boolean value determining whether an Ajax based pagination should be used or not.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowseUpdated
+     */
+    /** 
+     * @ref bx_forum-browse_updated "browse_updated"
+     */
+    public function serviceBrowseUpdated ($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $bShowHeader = false)
+    {
+        $sType = 'updated';
+
+        if($sUnitView != 'table')
+            return $this->_serviceBrowse($sType, $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+
+        return $this->_serviceBrowseTable(array(
+            'type' => $sType,
+            'empty_message' => $bEmptyMessage,
+            'ajax_paginate' => $bAjaxPaginate
+        ), $bShowHeader);
+    }
+
+        /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_partaken browse_partaken
+     * 
+     * @code bx_srv('bx_forum', 'browse_partaken', [...]); @endcode
+     * 
+     * Get page block with a list of partaken items represented as table.
+     * 
+     * @param $sUnitView (optional) string with unit view type.
+     * @param $bEmptyMessage (optional) boolean value determining whether an "Empty" message should be returned or not.
+     * @param $bAjaxPaginate (optional) boolean value determining whether an Ajax based pagination should be used or not.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowsePartaken
+     */
+    /** 
+     * @ref bx_forum-browse_partaken "browse_partaken"
+     */
+    public function serviceBrowsePartaken ($iProfileId = 0, $aParams = [])
+    {
+        $sType = 'partaken';
+
+        if(!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if(!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        $bEmptyMessage = true;
+        if(isset($aParams['empty_message'])) {
+            $bEmptyMessage = (bool)$aParams['empty_message'];
+            unset($aParams['empty_message']);
+        }
+
+        $bAjaxPaginate = true;
+        if(isset($aParams['ajax_paginate'])) {
+            $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
+            unset($aParams['ajax_paginate']);
+        }
+        
+        $bShowHeader = false;
+        if(isset($aParams['show_header'])) {
+            $bShowHeader = (bool)$aParams['show_header'];
+            unset($aParams['show_header']);
+        }
+
+        if(isset($aParams['unit_view']) && $aParams['unit_view'] != 'table')
+            return $this->_serviceBrowse($sType, array_merge(['author' => $iProfileId], $aParams), BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+
+        return $this->_serviceBrowseTable([
+            'type' => $sType,
+            'author' => $iProfileId,
+            'include_contexts' => isset($aParams['include_contexts']) && $aParams['include_contexts'],
+            'empty_message' => $bEmptyMessage,
+            'ajax_paginate' => $bAjaxPaginate
+        ], $bShowHeader);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_index browse_index
+     * 
+     * @code bx_srv('bx_forum', 'browse_index', [...]); @endcode
+     * 
+     * Get page block for Site's Home page with a list of items ordered by newness and represented as table.
+     * 
+     * @param $sUnitView (optional) string with unit view type.
+     * @param $bEmptyMessage (optional) boolean value determining whether an "Empty" message should be returned or not.
+     * @param $bAjaxPaginate (optional) boolean value determining whether an Ajax based pagination should be used or not.
+     * @param $bShowHeader (optional) boolean value determining whether a resulting table should have Header section or not.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowseIndex
+     */
+    /** 
+     * @ref bx_forum-browse_index "browse_index"
+     */
+    public function serviceBrowseIndex($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $bShowHeader = false)
+    {
+    	$sType = 'index';
+
+    	if($sUnitView != 'table')
+            return $this->_serviceBrowse($sType, $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+
+        return $this->_serviceBrowseTable(array(
+            'type' => $sType,
+            'per_page' => (int)$this->_oDb->getParam('bx_forum_per_page_index'),
+            'empty_message' => $bEmptyMessage,
+            'ajax_paginate' => $bAjaxPaginate
+        ), $bShowHeader);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_author browse_author
+     * 
+     * @code bx_srv('bx_forum', 'browse_author', [...]); @endcode
+     * 
+     * Get page block with a list of items filtered by Author and represented as table.
+     * 
+     * @param $iProfileId (optional) integer value with author ID. If empty value is provided, an attempt to get it from GET/POST arrays will be performed.
+     * @param $aParams (optional) an array of additional params. It's not used for now.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowseAuthor
+     */
+    /** 
+     * @ref bx_forum-browse_author "browse_author"
+     */
+	public function serviceBrowseAuthor ($iProfileId = 0, $aParams = array())
+    {
+        if(!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+
+        if(!$iProfileId)
+            return '';
+
+        $bEmptyMessage = true;
+        if(isset($aParams['empty_message'])) {
+            $bEmptyMessage = (bool)$aParams['empty_message'];
+            unset($aParams['empty_message']);
+        }
+
+        $bAjaxPaginate = true;
+        if(isset($aParams['ajax_paginate'])) {
+            $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
+            unset($aParams['ajax_paginate']);
+        }
+        
+        if(isset($aParams['unit_view']) && $aParams['unit_view'] != 'table')
+            return $this->_serviceBrowse('author', array_merge(array('author' => $iProfileId), $aParams), BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+
+        return $this->_serviceBrowseTable(array(
+        	'type' => 'author', 
+        	'author' => $iProfileId, 
+        	'where' => array('fld' => 'author', 'val' => $iProfileId, 'opr' => '='), 
+        	'per_page' => (int)$this->_oDb->getParam('bx_forum_per_page_profile'),
+        	'empty_message' => $bEmptyMessage,
+        	'ajax_paginate' => $bAjaxPaginate
+        ), false);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_favorite browse_favorite
+     * 
+     * @code bx_srv('bx_forum', 'browse_favorite', [...]); @endcode
+     * 
+     * Get page block with a list of favorited items by some profile and represented as table.
+     * 
+     * @param $iProfileId (optional) integer value with profile ID. If empty value is provided, an attempt to get it from GET/POST arrays will be performed.
+     * @param $aParams (optional) an array of additional params. It's not used for now.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowseFavorite
+     */
+    /** 
+     * @ref bx_forum-browse_favorite "browse_favorite"
+     */
+    public function serviceBrowseFavorite ($iProfileId = 0, $aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $bEmptyMessage = false;
+        if(isset($aParams['empty_message'])) {
+            $bEmptyMessage = (bool)$aParams['empty_message'];
+            unset($aParams['empty_message']);
+        }
+
+        $bAjaxPaginate = true;
+        if(isset($aParams['ajax_paginate'])) {
+            $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
+            unset($aParams['ajax_paginate']);
+        }
+
+        return $this->_serviceBrowseTable(array(
+            'type' => 'favorite', 
+            'per_page' => (int)$this->_oDb->getParam('bx_forum_per_page_profile'),
+            'empty_message' => $bEmptyMessage,
+            'ajax_paginate' => $bAjaxPaginate
+        ), false);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_category browse_category
+     * 
+     * @code bx_srv('bx_forum', 'browse_category', [...]); @endcode
+     * 
+     * Get page block with a list of items filter by some category and represented as table.
+     * 
+     * @param $sUnitView (optional) string with unit view type.
+     * @param $bEmptyMessage (optional) boolean value determining whether an "Empty" message should be returned or not.
+     * @param $bAjaxPaginate (optional) boolean value determining whether an Ajax based pagination should be used or not.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowseCategory
+     */
+    /** 
+     * @ref bx_forum-browse_category "browse_category"
+     */
+    public function serviceBrowseCategory($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $bShowHeader = true)
+    {
+        $sType = 'category';
+        $iCategory = bx_process_input(bx_get('category'), BX_DATA_INT);
+
+        $aCategory = $this->_oDb->getCategories(array('type' => 'by_category', 'category' => $iCategory));
+        if(!empty($aCategory['visible_for_levels']) && !BxDolAcl::getInstance()->isMemberLevelInSet($aCategory['visible_for_levels']))
+            return $bEmptyMessage ? MsgBox(_t('_sys_txt_access_denied')) : '';
+
+        if($sUnitView != 'table')   {
+            $aParams = array('category' => $iCategory);
+            if ($sUnitView)
+                $aParams['unit_view'] = $sUnitView;
+            return $this->_serviceBrowse($sType, $aParams, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+        }
+
+        return $this->_serviceBrowseTable(array(
+            'type' => $sType, 
+            'where' => array('fld' => 'cat', 'val' => $iCategory, 'opr' => '='),
+            'empty_message' => $bEmptyMessage,
+            'ajax_paginate' => $bAjaxPaginate
+        ), $bShowHeader);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_keyword browse_keyword
+     * 
+     * @code bx_srv('bx_forum', 'browse_keyword', [...]); @endcode
+     * 
+     * Get page block with a list of items filter by some keyword and represented as table.
+     * 
+     * @param $sUnitView (optional) string with unit view type.
+     * @param $bEmptyMessage (optional) boolean value determining whether an "Empty" message should be returned or not.
+     * @param $bAjaxPaginate (optional) boolean value determining whether an Ajax based pagination should be used or not.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowseKeyword
+     */
+    /** 
+     * @ref bx_forum-browse_keyword "browse_keyword"
+     */
+    public function serviceBrowseKeyword($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $bShowHeader = false)
+    {
+        $sType = 'keyword';
+        $sKeyword = bx_process_input(bx_get('keyword'));
+
+        if($sUnitView != 'table')   
+            return $this->_serviceBrowse($sType, $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+
+        return $this->_serviceBrowseTable(array(
+            'type' => $sType, 
+            'where' => $this->_getSearchKeywordDescriptor('#' . $sKeyword),
+            'empty_message' => $bEmptyMessage,
+            'ajax_paginate' => $bAjaxPaginate
+        ), $bShowHeader);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-browse_search_results browse_search_results
+     * 
+     * @code bx_srv('bx_forum', 'browse_search_results', [...]); @endcode
+     * 
+     * Get page block with search results by Author(s), Category, Keyword represented as table.
+     * 
+     * @param $sUnitView (optional) string with unit view type.
+     * @param $bEmptyMessage (optional) boolean value determining whether an "Empty" message should be returned or not.
+     * @param $bAjaxPaginate (optional) boolean value determining whether an Ajax based pagination should be used or not.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceBrowseSearchResults
+     */
+    /** 
+     * @ref bx_forum-browse_search_results "browse_search_results"
+     */
+    public function serviceBrowseSearchResults($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true)
+    {
+        $sType = 'search';
+
+        $aAuthors = bx_process_input(bx_get('author'));
+        $iCategory = bx_process_input(bx_get('category'), BX_DATA_INT);
+        $sKeyword = bx_process_input(bx_get('keyword'));
+
+        $aCategory = $this->_oDb->getCategories(array('type' => 'by_category', 'category' => $iCategory));
+        if(!empty($aCategory['visible_for_levels']) && !BxDolAcl::getInstance()->isMemberLevelInSet($aCategory['visible_for_levels']))
+            return $bEmptyMessage ? MsgBox(_t('_sys_txt_access_denied')) : '';
+
+        if($sUnitView != 'table')   
+            return $this->_serviceBrowse('', $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+
+        $aWhereGroupAnd = array('grp' => true, 'opr' => 'AND', 'cnds' => array());
+        if(!empty($aAuthors) && is_array($aAuthors))
+            $aWhereGroupAnd['cnds'][] = $this->_getSearchAuthorDescriptor($aAuthors);
+
+        if(!empty($iCategory))
+            $aWhereGroupAnd['cnds'][] = array('fld' => 'cat', 'val' => $iCategory, 'opr' => '=');
+
+        if(!empty($sKeyword))
+            $aWhereGroupAnd['cnds'][] = $this->_getSearchKeywordDescriptor($sKeyword);
+
+        return $this->_serviceBrowseTable(array(
+            'type' => $sType, 
+            'where' => $aWhereGroupAnd,
+            'empty_message' => $bEmptyMessage,
+            'ajax_paginate' => $bAjaxPaginate
+        ), false);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-other Other
+     * @subsubsection bx_forum-get_discussions_num get_discussions_num
+     * 
+     * @code bx_srv('bx_forum', 'get_discussions_num', [...]); @endcode
+     * 
+     * Get number of discussions for some profile.
+     * 
+     * @param $iProfileId (optional) profile to get discussions for, if omitted then currently logged in profile is used.
+     * @return integer value with a number of discussions.
+     * 
+     * @see BxForumModule::serviceGetDiscussionsNum
+     */
+    /** 
+     * @ref bx_forum-get_discussions_num "get_discussions_num"
+     */
+    public function serviceGetDiscussionsNum ($iProfileId = 0)
+    {
+        if (!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        return $this->_oDb->getEntriesNumByAuthor((int)$iProfileId);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-other Other
+     * @subsubsection bx_forum-get_unreplied_discussions_num get_unreplied_discussions_num
+     * 
+     * @code bx_srv('bx_forum', 'get_unreplied_discussions_num', [...]); @endcode
+     * 
+     * Get number of unreplied discussions for some profile.
+     * 
+     * @param $iProfileId (optional) profile to get unreplied discussions for, if omitted then currently logged is profile is used.
+     * @return integer value with a number of discussions.
+     * 
+     * @see BxForumModule::serviceGetUnrepliedDiscussionsNum
+     */
+    /** 
+     * @ref bx_forum-get_unreplied_discussions_num "get_unreplied_discussions_num"
+     */
+    public function serviceGetUnrepliedDiscussionsNum ($iProfileId = 0)
+    {
+        if (!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        return $this->_oDb->getUnrepliedDiscussionsNum((int)$iProfileId);
+    }
+
+    /**
+     * 
+     */
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-other Other
+     * @subsubsection bx_forum-trigger_comment_post trigger_comment_post
+     * 
+     * @code bx_srv('bx_forum', 'trigger_comment_post', [...]); @endcode
+     * 
+     * Update last comment time and author when new comment was added in the discussion.
+     * 
+     * @param $iContentId integer value with content ID.
+     * @param $iProfileId integer value with profile ID.
+     * @param $iCommentId integer value with comment ID.
+     * @param $iTimestamp (optional) date in UNIX Timestamp format, if omitted then current date is used.
+     * @param $sCommentText (optional) string value with text of comment.
+     * @return boolean value determining where the operation is successful or not.
+     * 
+     * @see BxForumModule::serviceTriggerCommentPost
+     */
+    /** 
+     * @ref bx_forum-trigger_comment_post "trigger_comment_post"
+     */
+    public function serviceTriggerCommentPost ($iContentId, $iProfileId, $iCommentId, $iTimestamp = 0, $sCommentText = '')
+    {
+    	$CNF = $this->_oConfig->CNF;
+
+    	$iContentId = (int)$iContentId;
+        if(!$iContentId)
+            return false;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(!$aContentInfo)
+			return false;
+
+        $oCmts = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], $iContentId);
+        if(!$oCmts)
+            return false;
+
+        if(!$iTimestamp)
+			$iTimestamp = time();
+
+        if(!$this->_oDb->updateLastCommentTimeProfile((int)$iContentId, (int)$iProfileId, $iCommentId, $iTimestamp))
+			return false;
+
+        // send notification to author
+        if($iProfileId != $aContentInfo[$CNF['FIELD_AUTHOR']]) {
+	        $oProfile = BxDolProfile::getInstanceMagic($iProfileId);
+	        if($oProfile) 
+                sendMailTemplate('bx_forum_new_reply', 0, $aContentInfo[$CNF['FIELD_AUTHOR']], array(
+                    'SenderDisplayName' => $oProfile->getDisplayName(),
+                    'SenderUrl' => $oProfile->getUrl(),
+                    'PageUrl' => $oCmts->getItemUrl($iCommentId),
+                    'PageTitle' => $oCmts->getObjectTitle(),
+                    'Message' => $sCommentText,
+                ), BX_EMAIL_NOTIFY);
+        }
+
+        return true;
+    }
+    
+    
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-entity_author entity_author
+     * 
+     * @code bx_srv('bx_forum', 'entity_author', [...]); @endcode
+     * 
+     * Get page block with author.
+     * 
+     * @param $iContentId (optional) content ID. If empty value is provided, an attempt to get it from GET/POST arrays will be performed.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceEntityAuthor
+     */
+    /** 
+     * @ref bx_forum-entity_author "entity_author"
+     */
+    public function serviceEntityAuthor ($iContentId = 0)
+    {
+        return bx_srv('system', 'get_block_author', ['bx_forum', $iContentId], 'TemplServices');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-entity_participants entity_participants
+     * 
+     * @code bx_srv('bx_forum', 'entity_participants', [...]); @endcode
+     * 
+     * Get page block with discussion's collaborators.
+     * 
+     * @param $iContentId (optional) content ID. If empty value is provided, an attempt to get it from GET/POST arrays will be performed.
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceEntityParticipants
+     */
+    /** 
+     * @ref bx_forum-entity_participants "entity_participants"
+     */
+    public function serviceEntityParticipants ($iContentId = 0)
+    {
+        if (!$iContentId)
+            $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if (!$iContentId)
+            return false;
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if (!$aContentInfo)
+            return false;
+
+        return $this->_oTemplate->entryParticipants ($aContentInfo, 5, 'right');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_forum Discussions
+     * @subsection bx_forum-page_blocks Page Blocks
+     * @subsubsection bx_forum-search search
+     * 
+     * @code bx_srv('bx_forum', 'search', [...]); @endcode
+     * 
+     * Get page block with search form.
+     * 
+     * @return HTML string with block content to display on the site or false if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxForumModule::serviceSearch
+     */
+    /** 
+     * @ref bx_forum-search "search"
+     */
+	public function serviceSearch()
+    {
+    	$CNF = $this->_oConfig->CNF;
+    	$oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_SEARCH'], $CNF['OBJECT_FORM_SEARCH_DISPLAY_FULL'], $this->_oTemplate);
+    	$oForm->initChecker();
+
+        return $oForm->getCode();
+    }
+
+    public function checkAllowedSubscribe(&$aDataEntry, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sMsg = $this->checkAllowedView($aDataEntry);
+        if($sMsg !== CHECK_ACTION_RESULT_ALLOWED)
+            return $sMsg;
+
+        return $this->_checkAllowedConnect ($aDataEntry, $isPerformAction, $CNF['OBJECT_CONNECTION_SUBSCRIBERS'], false, false);
+    }
+
+    public function checkAllowedUnsubscribe(&$aDataEntry, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return $this->_checkAllowedConnect ($aDataEntry, $isPerformAction, $CNF['OBJECT_CONNECTION_SUBSCRIBERS'], false, true);
+    }
+
+    public function checkAllowedStickAnyEntry($aDataEntry, $isPerformAction = false)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	if((int)$aDataEntry[$CNF['FIELD_STICK']] != 0)
+    		return false;
+
+		return $this->_checkAllowedAction('stick any entry', $aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedUnstickAnyEntry($aDataEntry, $isPerformAction = false)
+    {
+    	$CNF = $this->_oConfig->CNF;
+
+    	if((int)$aDataEntry[$CNF['FIELD_STICK']] != 1)
+			return false;
+
+    	return $this->_checkAllowedAction('stick any entry', $aDataEntry, $isPerformAction);
+    }
+    
+    public function checkAllowedResolveAnyEntry($aDataEntry, $isPerformAction = false)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	if((int)$aDataEntry[$CNF['FIELD_RESOLVABLE']] != 1 || (int)$aDataEntry[$CNF['FIELD_RESOLVE']] != 0)
+    		return false;
+
+        if($aDataEntry[$CNF['FIELD_AUTHOR']] == bx_get_logged_profile_id())
+            return CHECK_ACTION_RESULT_ALLOWED;
+        
+		return $this->_checkAllowedAction('resolve any entry', $aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedUnresolveAnyEntry($aDataEntry, $isPerformAction = false)
+    {
+    	$CNF = $this->_oConfig->CNF;
+        
+    	if((int)$aDataEntry[$CNF['FIELD_RESOLVABLE']] != 1 || (int)$aDataEntry[$CNF['FIELD_RESOLVE']] != 1)
+			return false;
+        
+        if($aDataEntry[$CNF['FIELD_AUTHOR']] == bx_get_logged_profile_id())
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+    	return $this->_checkAllowedAction('resolve any entry', $aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedLockAnyEntry($aDataEntry, $isPerformAction = false)
+    {
+    	$CNF = $this->_oConfig->CNF;
+
+    	if((int)$aDataEntry[$CNF['FIELD_LOCK']] != 0)
+    		return false;
+
+		return $this->_checkAllowedAction('lock any entry', $aDataEntry, $isPerformAction);
+    }
+
+	public function checkAllowedUnlockAnyEntry($aDataEntry, $isPerformAction = false)
+    {
+    	$CNF = $this->_oConfig->CNF;
+
+    	if((int)$aDataEntry[$CNF['FIELD_LOCK']] != 1)
+    		return false;
+
+		return $this->_checkAllowedAction('lock any entry', $aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedHideAnyEntry($aDataEntry, $isPerformAction = false)
+    {
+    	$CNF = $this->_oConfig->CNF;
+
+    	if($aDataEntry[$CNF['FIELD_STATUS_ADMIN']] == 'hidden')
+    		return false;
+
+		return $this->_checkAllowedAction('hide any entry', $aDataEntry, $isPerformAction);
+    }
+
+	public function checkAllowedUnhideAnyEntry($aDataEntry, $isPerformAction = false)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	if($aDataEntry[$CNF['FIELD_STATUS_ADMIN']] != 'hidden')
+    		return false;
+
+		return $this->_checkAllowedAction('hide any entry', $aDataEntry, $isPerformAction);
+    }
+
+    protected function _checkAllowedConnect (&$aDataEntry, $isPerformAction, $sObjConnection, $isMutual, $isInvertResult)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$this->_iProfileId)
+            return _t('_sys_txt_access_denied');
+
+        $isConnected = BxDolConnection::getObjectInstance($sObjConnection)->isConnected($this->_iProfileId, $aDataEntry[$CNF['FIELD_ID']], $isMutual);
+        if($isInvertResult)
+            $isConnected = !$isConnected;
+
+        return $isConnected ? _t('_sys_txt_access_denied') : CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+	/**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    protected function _checkAllowedAction($sAction, $aDataEntry, $isPerformAction = false)
+    {
+        if($this->_isModerator($isPerformAction))
+			return CHECK_ACTION_RESULT_ALLOWED;
+
+		$aCheck = checkActionModule($this->_iProfileId, $sAction, $this->getName(), $isPerformAction);
+    	if($aCheck[CHECK_ACTION_RESULT] === CHECK_ACTION_RESULT_ALLOWED)
+    		return CHECK_ACTION_RESULT_ALLOWED;
+
+        return _t('_sys_txt_access_denied');
+    }
+
+    protected function _serviceBrowseTable($aParams, $isDisplayHeader = true)
+    {
+        $sGrid = $this->_oConfig->CNF['OBJECT_GRID'];
+        if(!empty($aParams['grid'])) {
+            $sGrid = $aParams['grid'];
+            unset($aParams['grid']);
+        }
+
+        $oGrid = BxDolGrid::getObjectInstance($sGrid);
+        if(!$oGrid)
+            return false;
+        
+        $oGrid->setBrowseParams($aParams);
+        
+        $this->_oTemplate->addJsTranslation(array('_sys_grid_search'));
+        $this->_oTemplate->addCss(array('grid_tools.css'));
+       
+        return $oGrid->getCode($isDisplayHeader);
+    }
+
+    protected function _getSearchAuthorDescriptor($aAutor)
+    {
+        return array('grp' => true, 'opr' => 'OR', 'cnds' => array(
+            array('fld' => 'author', 'val' => $aAutor, 'opr' => 'IN'),
+            array('fld' => 'author_comment', 'val' => $aAutor, 'opr' => 'IN'),
+        ));
+    }
+
+    protected function _getSearchKeywordDescriptor($sKeyword)
+    {
+        return array('grp' => true, 'opr' => 'OR', 'cnds' => array(
+            array('fld' => 'title', 'val' => $sKeyword, 'opr' => 'LIKE'),
+            array('fld' => 'text', 'val' => $sKeyword, 'opr' => 'LIKE'),
+            array('fld' => 'text_comments', 'val' => $sKeyword, 'opr' => 'LIKE')
+        ));
+    }
+}
+
+/** @} */

+ 223 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/classes/BxForumSearchResult.php

@@ -0,0 +1,223 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Forum Forum
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxForumSearchResult extends BxBaseModTextSearchResult
+{
+    function __construct($sMode = '', $aParams = array())
+    {
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent = array(
+            'name' => 'bx_forum',
+            'module_name' => 'bx_forum',
+            'object_metatags' => 'bx_forum',
+            'title' => _t('_bx_forum_page_title_browse'),
+            'table' => 'bx_forum_discussions',
+            'ownFields' => array('id', 'title', 'text', 'thumb', 'author', 'added', 'comments', 'lr_profile_id', 'cat'),
+            'searchFields' => array(),
+            'restriction' => array(
+                'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
+                'cmt_author' => array('value' => '', 'field' => 'cmt_author_id', 'operator' => '=', 'table' => 'bx_forum_cmts'),
+                'category' => array('value' => '', 'field' => 'cat', 'operator' => '='),
+                'featured' => array('value' => '', 'field' => 'featured', 'operator' => '<>'),
+                'status' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
+                'statusAdmin' => array('value' => 'active', 'field' => 'status_admin', 'operator' => '='),
+            ),
+            'paginate' => array('perPage' => getParam('bx_forum_per_page_browse'), 'start' => 0),
+            'sorting' => 'last',
+            'rss' => array(
+                'title' => '',
+                'link' => '',
+                'image' => '',
+                'profile' => 0,
+                'fields' => array (
+                    'Guid' => 'link',
+                    'Link' => 'link',
+                    'Title' => 'title',
+                    'DateTimeUTS' => 'added',
+                    'Desc' => 'text',
+            		'Image' => 'thumb'
+                ),
+            ),
+            'ident' => 'id',
+        );
+
+        $this->sFilterName = 'bx_forum_filter';
+        $this->oModule = $this->getMain();
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        $sSearchFields = getParam($CNF['PARAM_SEARCHABLE_FIELDS']);
+        $this->aCurrent['searchFields'] = !empty($sSearchFields) ? explode(',', $sSearchFields) : '';
+
+        $oProfileAuthor = null;
+
+        switch ($sMode) {
+            case 'author':
+                $oProfileAuthor = BxDolProfile::getInstance((int)$aParams['author']);
+                if (!$oProfileAuthor) {
+                    $this->isError = true;
+                    break;
+                }
+
+                $this->aCurrent['restriction']['author']['value'] = $oProfileAuthor->id();
+                $this->aCurrent['paginate']['perPage'] = getParam('bx_forum_per_page_profile');
+
+                $this->sBrowseUrl = 'page.php?i=' . $CNF['URI_AUTHOR_ENTRIES'] . '&profile_id={profile_id}';
+                $this->aCurrent['title'] = _t('_bx_forum_page_title_browse_by_author');
+                $this->aCurrent['rss']['link'] = 'modules/?r=forum/rss/' . $sMode . '/' . $oProfileAuthor->id();
+                break;
+
+            case 'context':
+                if(!$this->_updateCurrentForContext($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+                
+            case 'favorite':
+                if(!$this->_updateCurrentForFavorite($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'category':
+                    $iCategory = (int)$aParams['category'];
+                    $this->addMarkers(array(
+                        'category_id' => $iCategory,
+                        'category_name' => BxDolCategory::getObjectInstance($CNF['OBJECT_CATEGORY'])->getCategoryTitle($iCategory),
+                    ));
+
+                $this->aCurrent['restriction']['category']['value'] = $iCategory;
+
+                $this->sBrowseUrl = 'page.php?i=' . $CNF['URI_CATEGORY_ENTRIES'] . '&category={category_id}';
+                $this->aCurrent['title'] = _t('_bx_forum_page_title_browse_by_category');
+                $this->aCurrent['rss']['link'] = 'modules/?r=forum/rss/' . $sMode . '/' . $iCategory;
+                break;
+
+            case 'new':
+            case 'public':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_NEW']);
+                $this->aCurrent['title'] = _t('_bx_forum_page_title_browse_new');
+                $this->aCurrent['rss']['link'] = 'modules/?r=forum/rss/' . $sMode;
+                break;
+
+            case 'index':
+                $this->aCurrent['paginate']['perPage'] = getParam('bx_forum_per_page_index');
+
+            case 'latest':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_TOP']);
+                $this->aCurrent['title'] = _t('_bx_forum_page_title_browse_latest');
+                $this->aCurrent['rss']['link'] = 'modules/?r=forum/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'latest';
+                break;
+
+            case 'featured':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_forum_page_title_browse_featured');
+                $this->aCurrent['restriction']['featured']['value'] = '0';
+                $this->aCurrent['rss']['link'] = 'modules/?r=forum/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'featured';
+                break;
+
+            case 'top':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_TOP']);
+                $this->aCurrent['title'] = _t('_bx_forum_page_title_browse_top');
+                $this->aCurrent['rss']['link'] = 'modules/?r=forum/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'top';
+                break;
+
+            case 'popular':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_POPULAR']);
+                $this->aCurrent['title'] = _t('_bx_forum_page_title_browse_popular');
+                $this->aCurrent['rss']['link'] = 'modules/?r=forum/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'popular';
+                break;
+
+            case 'updated':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_UPDATED']);
+                $this->aCurrent['title'] = _t('_bx_forum_page_title_browse_updated');
+                $this->aCurrent['rss']['link'] = 'modules/?r=forum/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'updated';
+                break;
+
+            case 'partaken':
+                $this->aCurrent['restriction']['cmt_author']['value'] = (int)$aParams['author'];
+
+                if(!isset($this->aCurrent['join']))
+                    $this->aCurrent['join'] = array();
+
+                $this->aCurrent['join']['cmts'] = array(
+                    'type' => 'INNER',
+                    'table' => 'bx_forum_cmts',
+                    'mainField' => 'id',
+                    'onField' => 'cmt_object_id',
+                    'joinFields' => array('cmt_author_id'),
+                    'groupTable' => 'bx_forum_discussions',
+                    'groupField' => 'id'
+                );
+
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_PARTAKEN']);
+                $this->aCurrent['title'] = _t('_bx_forum_page_title_browse_partaken');
+                $this->aCurrent['rss']['link'] = 'modules/?r=forum/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'partaken';
+                break;
+
+            case '': // search results
+                $this->checkRestrictionsForContext($sMode, $aParams, $oProfileAuthor);
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_forum');
+                unset($this->aCurrent['paginate']['perPage'], $this->aCurrent['rss']);
+                break;
+
+            default:
+                $sMode = '';
+                $this->isError = true;
+        }
+
+        $this->processReplaceableMarkers($oProfileAuthor);
+
+        $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+        $this->addCustomConditions($CNF, $oProfileAuthor, $sMode, $aParams);
+    }
+
+    function getAlterOrder()
+    {
+        $aSql = array();
+
+        switch ($this->aCurrent['sorting']) {
+            case 'latest':
+                $aSql['order'] = ' ORDER BY `bx_forum_discussions`.`lr_timestamp` DESC';
+                break;
+
+            case 'partaken':
+                $aSql['order'] = ' ORDER BY MAX(`bx_forum_cmts`.`cmt_time`) DESC';
+                break;
+
+            default:
+                $aSql = parent::getAlterOrder();
+        }
+
+        return $aSql;
+    }
+    
+    function displayResultBlock()
+    {
+        if ($this->bShowcaseView) {
+            $this->oModule->_oTemplate->addCss(array('carusel.css'));
+            $this->oModule->_oTemplate->addJs(array('carusel.js'));
+            
+            return $this->oModule->_oTemplate->parseHtmlByName('unaca.html', ['content' => str_replace(['bx-forum-wrapper', 'bx-base-unit-showcase-wrapper'], '' ,str_replace('bx-search-result-block', 'bx-search-result-block unaca-t', parent::displayResultBlock()))]);
+            
+        }
+
+        return parent::displayResultBlock();
+    }
+}
+
+/** @} */

+ 266 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/classes/BxForumTemplate.php

@@ -0,0 +1,266 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Forum Forum
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/*
+ * Module representation.
+ */
+class BxForumTemplate extends BxBaseModTextTemplate
+{
+    /**
+     * Constructor
+     */
+    function __construct(&$oConfig, &$oDb)
+    {
+        $this->MODULE = 'bx_forum';
+        parent::__construct($oConfig, $oDb);
+    }
+
+    public function entryBreadcrumb($aContentInfo, $aTmplVarsItems = array())
+    {
+    	$CNF = &BxDolModule::getInstance($this->MODULE)->_oConfig->CNF;
+
+        $oPermalink = BxDolPermalinks::getInstance();
+        $oCategory = BxDolCategory::getObjectInstance($CNF['OBJECT_CATEGORY']);
+
+    	$aTmplVarsItems = array(array(
+        	'url' => bx_append_url_params($oPermalink->permalink('page.php?i=' . $CNF['URI_CATEGORY_ENTRIES']), array(
+        		'category' => $aContentInfo[$CNF['FIELD_CATEGORY']]
+        	)),
+        	'title' => $oCategory->getCategoryTitle($aContentInfo[$CNF['FIELD_CATEGORY']])
+        ), array(
+        	'url' => $oPermalink->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]),
+        	'title' => bx_process_output($aContentInfo[$CNF['FIELD_TITLE']])
+        ));
+
+    	return parent::entryBreadcrumb($aContentInfo, $aTmplVarsItems);
+    }
+
+    public function entryParticipants($aContentInfo, $iMaxVisible = 2, $sFloat = 'left')
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        $iAuthorId = $aContentInfo[$CNF['FIELD_AUTHOR']];
+        $aParticipants = $this->_oDb->getComments(array('type' => 'author_comments', 'object_id' => $aContentInfo[$CNF['FIELD_ID']]));
+        $aParticipants[$iAuthorId] = !empty($aParticipants[$iAuthorId]) ? $aParticipants[$iAuthorId] + 1 : 1;
+
+        // sort participants: first - current user, second - last replier, third - author, all others sorted by max number of posts
+        $aParticipants = $oModule->sortParticipants($aParticipants, $aContentInfo['lr_profile_id'], $iAuthorId);
+        $iParticipantsNum = count($aParticipants);
+
+        // prepare template variables
+        $aVarsPopup = array (
+            'float' => 'none',
+            'bx_repeat:participants' => array(),
+            'bx_if:participants_more' => array(
+                'condition' => false,
+                'content' => array(),
+            ),
+        );
+        $aVars = array (
+            'float' => $sFloat,
+            'bx_repeat:participants' => array(),
+            'bx_if:participants_more' => array(
+                'condition' => $iParticipantsNum > $iMaxVisible,
+                'content' => array(
+                    'popup' => '',
+                    'title_more' => _t('_bx_forum_more', $iParticipantsNum - $iMaxVisible),
+                    'float' => $sFloat,
+                    'id' => $this->MODULE . '-popup-' . $aContentInfo[$CNF['FIELD_ID']],
+                ),
+            ),
+        );
+        $i = 0;
+        foreach ($aParticipants as $iProfileId => $iComments) {
+            $oProfile = BxDolProfile::getInstanceMagic($iProfileId);
+
+            $aParticipant = array (
+                'id' => $oProfile->id(),
+                'unit' => $oProfile->getUnit(0, array('template' => 'unit_wo_info')),
+                'float' => $sFloat,
+                'class' => $iAuthorId == $iProfileId ? 'bx-forum-participant-author' : '',
+            	'bx_if:replies_count' => array(
+            		'condition' => $iComments > 0,
+            		'content' => array(
+            			'count' => $iComments
+            		)
+            	),
+                'bx_if:last_replier' => array (
+                    'condition' => ($aContentInfo['lr_profile_id'] == $iProfileId),
+                    'content' => array (
+                        'id' => $oProfile->id(),
+                        'title' => bx_html_attribute(_t('_bx_forum_participant_last_replier')),
+                    ),
+                ),
+                'bx_if:author'  => array (
+                    'condition' => $iAuthorId == $iProfileId,
+                    'content' => array (
+                        'id' => $oProfile->id(),
+                        'title' => bx_html_attribute(_t('_bx_forum_participant_author')),
+                    ),
+                ),
+            );
+
+            if ($i < $iMaxVisible)
+                $aVars['bx_repeat:participants'][] = $aParticipant;
+            if ($i >= $iMaxVisible)
+                $aVarsPopup['bx_repeat:participants'][] = $aParticipant;
+
+            ++$i;
+        }
+
+        if ($aVarsPopup['bx_repeat:participants']) {
+            $aVars['bx_if:participants_more']['content']['popup'] = BxTemplFunctions::getInstance()->transBox('', '<div class="bx-def-padding">' . $this->parseHtmlByName('participants.html', $aVarsPopup) . '</div>');
+        }
+
+        return $this->parseHtmlByName('participants.html', $aVars);
+    }
+
+	function getEntryAuthor($aRow)
+    {
+    	$oProfileAuthor = BxDolProfile::getInstanceMagic($aRow['author']);
+
+    	return $this->parseHtmlByName('entry-author.html', array(
+			'unit' => $oProfileAuthor->getUnit(0, array('template' => 'unit_wo_info')),
+    	));
+    }
+
+    function getEntryPreview($aRow, $aParams = [])
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        if($this->_oModule->checkAllowedView($aRow) !== CHECK_ACTION_RESULT_ALLOWED)
+            return $this->parseHtmlByName('entry-preview-private.html', []);
+
+        $oProfileLast = BxDolProfile::getInstanceMagic($aRow['lr_profile_id']);
+
+        $sTitle = $aRow[$CNF['FIELD_TITLE']];
+
+        $aMetas = array('main' => false, 'counters' => false, 'reply' => false);
+        foreach(array_keys($aMetas) as $sMeta) {
+            $sKey = 'OBJECT_MENU_SNIPPET_META_' . strtoupper($sMeta);
+            if(empty($CNF[$sKey]))
+                continue;
+
+            $oMenuMeta = BxDolMenu::getObjectInstance($CNF[$sKey], $this);
+            if(!$oMenuMeta) 
+                continue;
+
+            $oMenuMeta->setContentId($aRow[$CNF['FIELD_ID']]);
+            $sMenuMeta = $oMenuMeta->getCode();
+            if(empty($sMenuMeta))
+                continue;
+
+            $aMetas[$sMeta] = array(
+                'content' => $sMenuMeta
+            );
+        }
+        
+        $oObject = isset($CNF['OBJECT_COMMENTS']) ? BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], $aRow[$CNF['FIELD_ID']]) : null;
+        $sParticipants = $oObject ? $oObject->getCounter(['show_counter_empty' => true, 'show_counter' => false, 'show_counter_style' => 'simple', 'dynamic_mode' => true, 'caption' => '', 'show_icon' => false, 'caption_empty' => '']) : '';
+        
+        $sImage = '';
+        $mixedImage = $this->_getHeaderImage($aRow);
+        if($mixedImage !== false) {
+            if(!empty($mixedImage['object']))
+                $o = BxDolStorage::getObjectInstance($mixedImage['object']);
+            else if(!empty($mixedImage['transcoder']))
+                $o = BxDolTranscoder::getObjectInstance($mixedImage['transcoder']);
+
+            if($o)
+                $sImage = $o->getFileUrlById($mixedImage['id']);
+        }
+
+        return $this->parseHtmlByName('entry-preview.html', array(
+            'bx_if:show_stick' => array(
+                'condition' => (int)$aRow[$CNF['FIELD_STICK']] == 1,
+                'content' => array()
+            ),
+            'bx_if:show_lock' => array(
+                'condition' => (int)$aRow[$CNF['FIELD_LOCK']] == 1,
+                'content' => array()
+            ),
+            'url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aRow[$CNF['FIELD_ID']]),
+            'title' => $sTitle ? $sTitle : _t('_Empty'),
+            'participants' => $sParticipants,
+            'badges' => $this->_oModule->serviceGetBadges($aRow[$CNF['FIELD_ID']]),
+            'image' => $sImage,
+            'bx_if:meta_main' => array(
+                'condition' => $aMetas['main'] !== false && (!isset($aParams['show_meta_main']) || $aParams['show_meta_main']),
+                'content' => $aMetas['main']
+            ),
+            'bx_if:image' => array(
+                'condition' => $sImage != '',
+                'content' => ['image' => $sImage]
+            ),
+            
+            'bx_if:meta_counters' => array(
+                'condition' => $aMetas['counters'] !== false && (!isset($aParams['show_meta_counters']) || $aParams['show_meta_counters']),
+                'content' => $aMetas['counters']
+            ),
+            'bx_if:meta_reply' => array(
+                'condition' => $aMetas['reply'] !== false && (!isset($aParams['show_meta_reply']) || $aParams['show_meta_reply']),
+                'content' => $aMetas['reply']
+            )
+        ));
+    }
+    
+    public function getJsCode($sType, $aParams = array(), $mixedWrap = true)
+    {
+        $CNF = $this->_oModule->_oConfig->CNF;
+        if ($sType == 'main'){
+            $aParams = array_merge(array(
+                'sObjNameGrid' => $CNF['OBJECT_GRID'],
+            ), $aParams);
+        }
+        return parent::getJsCode($sType, $aParams);
+    }
+
+    function getAuthorDesc ($aData, $oProfile)
+    {
+        return '';
+    }
+
+    function getAuthorAddon ($aData, $oProfile)
+    {
+        return '';
+    }
+    
+    protected function getUnit ($aData, $aParams = array())
+    {
+        $aTmplVars = parent::getUnit($aData, $aParams);
+        
+        $CNF = $this->_oModule->_oConfig->CNF;
+        
+        $oCategory = BxDolCategory::getObjectInstance($CNF['OBJECT_CATEGORY']);
+        
+        $sIcon = $this->_oModule->_oTemplate->parseHtmlByName('default_category.html', []);
+        
+        $aCategoryData = $this->_oModule->_oDb->getCategories(array('type' => 'by_category', 'category' => $aData[$CNF['FIELD_CATEGORY']]));
+
+        if(isset($aCategoryData['icon']))
+            $sIcon = $this->getImage($aCategoryData['icon'], array('class' => 'sys-icon'));
+        
+        $oProfile = BxDolProfile::getInstanceMagic($aData[$CNF['FIELD_AUTHOR']]);
+        $aTmplVars['author'] = $oProfile->getUnit();
+        $aTmplVars['category'] = $oCategory->getCategoryTitle($aData[$CNF['FIELD_CATEGORY']]);
+        $aTmplVars['category_icon'] = $sIcon;
+        $aTmplVars['bx_if:thumb']['content']['badges'] = $aTmplVars['badges'];
+        $aTmplVars['bx_if:no_thumb']['content']['badges'] = $aTmplVars['badges'];
+        $aTmplVars['bx_if:no_thumb']['content']['title'] = $aTmplVars['title'];
+        $aTmplVars['bx_if:no_thumb']['content']['summary_attr'] = $aTmplVars['bx_if:thumb']['content']['summary_attr'];
+
+        return $aTmplVars;
+    }
+}
+
+/** @} */

+ 149 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/install/config.php

@@ -0,0 +1,149 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Forum Forum
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_forum',
+    'title' => 'Discussions',
+    'note' => 'Discussions module.',
+    'version' => '13.0.6',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/forum/',
+    'home_uri' => 'forum',
+
+    'db_prefix' => 'bx_forum_',
+    'class_prefix' => 'BxForum',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Discussions',
+    
+    /**
+     * List of page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry',
+    ),
+    
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+    	'trigger_profile_view_submenu',
+        'trigger_group_view_submenu'
+    ),
+
+	/**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_forum_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+        'bx_forum_preview',
+        'bx_forum_gallery',
+        'bx_forum_cover',
+        
+        'bx_forum_preview_photos',
+        'bx_forum_gallery_photos',
+        'bx_forum_view_photos',
+
+        'bx_forum_videos_poster',
+        'bx_forum_videos_poster_preview',
+        'bx_forum_videos_mp4',
+        'bx_forum_videos_mp4_hd',
+        
+        'bx_forum_preview_files',
+        'bx_forum_gallery_files',
+        
+        'bx_forum_preview_cmts',
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_forum',
+    	'bx_forum_cmts',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+	'enable_success' => array(
+    	'process_menu_triggers' => 1,
+        'process_page_triggers' => 1,
+    	'process_esearches' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+    	'unregister_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Relations Section
+     */
+    'relations' => array(
+    	'bx_timeline',
+    	'bx_notifications'
+    ),
+);
+
+/** @} */

+ 451 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/install/langs/en.xml

@@ -0,0 +1,451 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+    <string name="_bx_forum"><![CDATA[Discussions]]></string>
+    <string name="_bx_forum_cmts"><![CDATA[Discussions's Comments]]></string>
+    <string name="_bx_forum_reactions"><![CDATA[Discussions's Reactions]]></string>
+
+    <string name="_bx_forum_option_enable_auto_approve"><![CDATA[Auto approve a discussion after creation]]></string>
+    <string name="_bx_forum_option_summary_chars"><![CDATA[Number of characters in auto-cropped discussion summary]]></string>
+    <string name="_bx_forum_option_plain_summary_chars"><![CDATA[Number of characters in plain discussion description when discussion hasn't thumb]]></string>
+    <string name="_bx_forum_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+    <string name="_bx_forum_option_per_page_index"><![CDATA[Number of items on site home page]]></string>
+    <string name="_bx_forum_option_per_page_profile"><![CDATA[Number of items on profile page]]></string>
+    <string name="_bx_forum_option_rss_num"><![CDATA[Number of items in RSS feed]]></string>
+    <string name="_bx_forum_option_searchable_fields"><![CDATA[Searchable fields for keyword search]]></string>
+    <string name="_bx_forum_option_autosubscribe_created"><![CDATA[Autosubscribe to newly created discussions]]></string>
+    <string name="_bx_forum_option_autosubscribe_replied"><![CDATA[Autosubscribe to replied discussions]]></string>
+    <string name="_bx_forum_option_auto_activation_for_categories"><![CDATA[Auto-Activation For Categories]]></string>
+    <string name="_bx_forum_option_per_page_for_favorites_lists"><![CDATA[Number of favorite lists per page]]></string>
+    <string name="_bx_forum_option_visible_categories"><![CDATA[Number of visible categories]]></string>
+    <string name="_bx_forum_option_visible_hashtags"><![CDATA[Number of visible hashtags]]></string>
+
+    <string name="_bx_forum_form_entry"><![CDATA[Forum]]></string>
+    <string name="_bx_forum_form_entry_display_add"><![CDATA[New discussion]]></string>
+    <string name="_bx_forum_form_entry_display_delete"><![CDATA[Delete discussion]]></string>
+    <string name="_bx_forum_form_entry_display_edit"><![CDATA[Edit discussion]]></string>
+    <string name="_bx_forum_form_entry_display_view"><![CDATA[View discussion]]></string>
+    <string name="_bx_forum_form_entry_input_author"><![CDATA[Author]]></string>
+    <string name="_bx_forum_form_entry_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_forum_form_entry_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_forum_form_entry_input_sys_text"><![CDATA[Text]]></string>
+    <string name="_bx_forum_form_entry_input_text"><![CDATA[Text]]></string>
+    <string name="_bx_forum_form_entry_input_text_err"><![CDATA[Text field can't be empty]]></string>
+    <string name="_bx_forum_form_entry_input_text_comments"><![CDATA[Comments Text]]></string>
+    <string name="_bx_forum_form_entry_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+    <string name="_bx_forum_form_entry_input_delete_confirm"><![CDATA[I am sure I want to delete this discussion]]></string>
+    <string name="_bx_forum_form_entry_input_delete_confirm_info"><![CDATA[This action can not be undone]]></string>
+    <string name="_bx_forum_form_entry_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete the discussion]]></string>
+    <string name="_bx_forum_form_entry_input_sys_attachments"><![CDATA[Attachments]]></string>
+    <string name="_bx_forum_form_entry_input_sys_covers"><![CDATA[Header Image]]></string>
+    <string name="_bx_forum_form_entry_input_covers"><![CDATA[Header Image]]></string>
+    <string name="_bx_forum_form_entry_input_covers_uploader_simple_title"><![CDATA[Upload]]></string>
+    <string name="_bx_forum_form_entry_input_covers_uploader_html5_title"><![CDATA[Upload]]></string>
+    <string name="_bx_forum_form_entry_input_sys_pictures"><![CDATA[Images]]></string>
+    <string name="_bx_forum_form_entry_input_pictures"><![CDATA[]]></string>
+    <string name="_bx_forum_form_entry_input_sys_videos"><![CDATA[Videos]]></string>
+    <string name="_bx_forum_form_entry_input_videos"><![CDATA[]]></string>
+    <string name="_bx_forum_form_entry_input_sys_files"><![CDATA[Files]]></string>
+    <string name="_bx_forum_form_entry_input_files"><![CDATA[]]></string>
+    <string name="_bx_forum_form_entry_input_sys_polls"><![CDATA[Polls]]></string>
+    <string name="_bx_forum_form_entry_input_media"><![CDATA[Media]]></string>
+    <string name="_bx_forum_form_entry_input_sys_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_forum_form_entry_input_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_forum_form_entry_input_allow_view_favorite_list"><![CDATA[Visibility]]></string>
+    <string name="_bx_forum_form_entry_input_picture_use_as_thumb"><![CDATA[Header Image]]></string>
+    <string name="_bx_forum_form_entry_input_sys_date_added"><![CDATA[Added]]></string>
+    <string name="_bx_forum_form_entry_input_date_added"><![CDATA[Added]]></string>
+    <string name="_bx_forum_form_entry_input_sys_date_changed"><![CDATA[Changed]]></string>
+    <string name="_bx_forum_form_entry_input_date_changed"><![CDATA[Changed]]></string>
+    <string name="_bx_forum_form_entry_input_sys_title"><![CDATA[Topic]]></string>
+    <string name="_bx_forum_form_entry_input_title"><![CDATA[Topic]]></string>
+    <string name="_bx_forum_form_entry_input_title_err"><![CDATA[Topic is mandatory]]></string>
+    <string name="_bx_forum_form_entry_input_sys_cat"><![CDATA[Category]]></string>
+    <string name="_bx_forum_form_entry_input_cat"><![CDATA[Category]]></string>
+    <string name="_bx_forum_form_entry_input_cat_err"><![CDATA[Please select category]]></string>
+    <string name="_bx_forum_form_entry_input_sys_multicat"><![CDATA[Categories]]></string>
+    <string name="_bx_forum_form_entry_input_multicat"><![CDATA[Categories]]></string>
+    <string name="_bx_forum_form_entry_input_multicat_err"><![CDATA[Please select category]]></string>
+    <string name="_bx_forum_form_entry_input_resolvable"><![CDATA[Resolvable]]></string>
+    <string name="_bx_forum_form_entry_input_sys_resolvable"><![CDATA[Resolvable]]></string>
+
+    <string name="_bx_forum_form_poll"><![CDATA[Polls]]></string>
+    <string name="_bx_forum_form_poll_display_add"><![CDATA[Add Poll]]></string>
+    <string name="_bx_forum_form_poll_input_sys_text"><![CDATA[Question]]></string>
+    <string name="_bx_forum_form_poll_input_text"><![CDATA[Question]]></string>
+    <string name="_bx_forum_form_poll_input_text_err"><![CDATA[Question is essential. Please, fill in this field]]></string>
+    <string name="_bx_forum_form_poll_input_sys_answers"><![CDATA[Answers]]></string>
+    <string name="_bx_forum_form_poll_input_answers"><![CDATA[Answers]]></string>
+    <string name="_bx_forum_form_poll_input_answers_err"><![CDATA[Poll should have at least 2 non-empty answers.]]></string>
+    <string name="_bx_forum_form_poll_input_answers_add"><![CDATA[Add More]]></string>
+    <string name="_bx_forum_form_poll_input_sys_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_forum_form_poll_input_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_forum_form_poll_input_do_cancel"><![CDATA[Close]]></string>
+
+    <string name="_bx_forum_form_search"><![CDATA[Search]]></string>
+    <string name="_bx_forum_form_search_display_full"><![CDATA[Full Search]]></string>
+    <string name="_bx_forum_form_search_input_sys_author"><![CDATA[Author]]></string>
+    <string name="_bx_forum_form_search_input_author"><![CDATA[Author]]></string>
+    <string name="_bx_forum_form_search_input_sys_category"><![CDATA[Category]]></string>
+    <string name="_bx_forum_form_search_input_category"><![CDATA[Category]]></string>
+    <string name="_bx_forum_form_search_input_sys_keyword"><![CDATA[Keyword]]></string>
+    <string name="_bx_forum_form_search_input_keyword"><![CDATA[Keyword]]></string>
+    <string name="_bx_forum_form_search_input_do_submit"><![CDATA[Search]]></string>
+    <string name="_bx_forum_form_search_input_sys_do_submit"><![CDATA[Search]]></string>
+
+	<string name="_bx_forum_acl_action_create_entry"><![CDATA[Create new discussion]]></string>
+	<string name="_bx_forum_acl_action_delete_entry"><![CDATA[Delete discussion]]></string>
+	<string name="_bx_forum_acl_action_view_entry"><![CDATA[View discussion]]></string>
+	<string name="_bx_forum_acl_action_set_thumb"><![CDATA[Set discussion's cover]]></string>
+	<string name="_bx_forum_acl_action_edit_any_entry"><![CDATA[Edit any discussion]]></string>
+	<string name="_bx_forum_acl_action_delete_any_entry"><![CDATA[Delete any discussion]]></string>
+	<string name="_bx_forum_acl_action_stick_any_entry"><![CDATA[Pin any discussion]]></string>
+	<string name="_bx_forum_acl_action_lock_any_entry"><![CDATA[Lock any discussion]]></string>
+	<string name="_bx_forum_acl_action_hide_any_entry"><![CDATA[Hide any discussion]]></string>
+    <string name="_bx_forum_acl_action_resolve_any_entry"><![CDATA[Mark as answered any discussion]]></string>
+
+	<string name="_bx_forum_page_title_sys_create_entry"><![CDATA[New discussion]]></string>
+	<string name="_bx_forum_page_title_create_entry"><![CDATA[New discussion]]></string>
+	<string name="_bx_forum_page_block_title_create_entry"><![CDATA[New discussion]]></string>
+	<string name="_bx_forum_page_title_sys_edit_entry"><![CDATA[Edit]]></string>
+	<string name="_bx_forum_page_title_edit_entry"><![CDATA[Edit]]></string>
+	<string name="_bx_forum_page_block_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_forum_page_title_sys_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_forum_page_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_forum_page_block_title_delete_entry"><![CDATA[Delete]]></string>
+	<string name="_bx_forum_page_title_sys_view_entry"><![CDATA[View discussion]]></string>
+	<string name="_bx_forum_page_title_view_entry"><![CDATA[{title}]]></string>
+	<string name="_bx_forum_page_block_title_entry_all_actions"><![CDATA[All Actions]]></string>
+	<string name="_bx_forum_page_block_title_entry_attachments"><![CDATA[Attachments]]></string>
+        <string name="_bx_forum_page_block_title_entry_polls"><![CDATA[Polls]]></string>
+	<string name="_bx_forum_page_block_title_entry_text"><![CDATA[Text]]></string>
+    <string name="_bx_forum_page_block_title_entry_author"><![CDATA[Author]]></string>
+    <string name="_bx_forum_page_block_title_entry_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_forum_page_block_title_entry_breadcrumb"><![CDATA[Breadcrumb]]></string>
+    <string name="_bx_forum_page_block_title_entry_comments"><![CDATA[Replies ({0})]]></string>
+	<string name="_bx_forum_page_block_title_entry_reports"><![CDATA[Reports]]></string>
+    <string name="_bx_forum_page_block_title_entry_participants"><![CDATA[Participants]]></string>
+    <string name="_bx_forum_page_block_title_entry_info"><![CDATA[Info]]></string>
+    <string name="_bx_forum_page_title_browse"><![CDATA[Discussions]]></string>
+	<string name="_bx_forum_page_title_search_results"><![CDATA[Discussions matching "{0}"]]></string>
+	<string name="_bx_forum_page_title_browse_by_author"><![CDATA[Discussions of {display_name}]]></string>
+  <string name="_bx_forum_page_title_browse_by_context"><![CDATA[Discussions in {display_name}]]></string>
+	<string name="_bx_forum_page_title_browse_featured"><![CDATA[Featured Discussions]]></string>
+	<string name="_bx_forum_page_title_browse_by_category"><![CDATA[Discussions by {category_name}]]></string>
+	<string name="_bx_forum_page_title_browse_new"><![CDATA[New Discussions]]></string>
+    <string name="_bx_forum_page_title_browse_latest"><![CDATA[Latest Discussions]]></string>
+    <string name="_bx_forum_page_title_browse_top"><![CDATA[Top Discussions]]></string>
+    <string name="_bx_forum_page_title_browse_popular"><![CDATA[Popular Discussions]]></string>
+    <string name="_bx_forum_page_title_browse_updated"><![CDATA[Updated Discussions]]></string>
+    <string name="_bx_forum_page_title_browse_partaken"><![CDATA[Partaken Discussions]]></string>
+    <string name="_bx_forum_page_title_sys_home"><![CDATA[Discussions Home]]></string>
+    <string name="_bx_forum_page_title_home"><![CDATA[Discussions]]></string>
+    <string name="_bx_forum_page_block_title_featured_entries"><![CDATA[Featured Discussions]]></string>
+    <string name="_bx_forum_page_block_title_featured_entries_view_showcase"><![CDATA[Featured Discussions]]></string>
+    <string name="_bx_forum_page_block_title_sys_featured_entries_view_showcase"><![CDATA[Featured Discussions (Showcase view)]]></string>
+    <string name="_bx_forum_page_block_title_featured_entries_view_gallery"><![CDATA[Featured Discussions (Gallery view)]]></string>
+    <string name="_bx_forum_page_block_title_featured_entries_view_extended"><![CDATA[Featured Discussions (Grid view)]]></string>
+    
+    <string name="_bx_forum_page_title_sys_entries_new"><![CDATA[New Discussions]]></string>
+    <string name="_bx_forum_page_title_entries_new"><![CDATA[New Discussions]]></string>
+    <string name="_bx_forum_page_title_sys_entries_top"><![CDATA[Top Discussions]]></string>
+    <string name="_bx_forum_page_title_entries_top"><![CDATA[Top Discussions]]></string>
+    <string name="_bx_forum_page_title_sys_entries_popular"><![CDATA[Popular Discussions]]></string>
+    <string name="_bx_forum_page_title_entries_popular"><![CDATA[Popular Discussions]]></string>
+    <string name="_bx_forum_page_title_sys_entries_updated"><![CDATA[Updated Discussions]]></string>
+    <string name="_bx_forum_page_title_entries_updated"><![CDATA[Updated Discussions]]></string>
+    <string name="_bx_forum_page_block_title_new_entries"><![CDATA[New Discussions]]></string>
+    <string name="_bx_forum_page_block_title_new_entries_view_extended"><![CDATA[New Discussions (Grid View)]]></string>
+    <string name="_bx_forum_page_block_title_new_entries_view_gallery"><![CDATA[New Discussions (Gallery View)]]></string>
+    <string name="_bx_forum_page_block_title_new_entries_view_showcase"><![CDATA[New Discussions (Showcase View)]]></string>
+    <string name="_bx_forum_page_block_title_latest_entries"><![CDATA[Discussions With Recent Posts]]></string>
+    <string name="_bx_forum_page_block_title_home"><![CDATA[Discussions List]]></string>
+    <string name="_bx_forum_page_block_title_latest_entries_view_extended"><![CDATA[Discussions With Recent Posts (Grid View)]]></string>
+    <string name="_bx_forum_page_block_title_latest_entries_view_gallery"><![CDATA[Discussions With Recent Posts (Gallery View)]]></string>
+    <string name="_bx_forum_page_block_title_latest_entries_view_showcase"><![CDATA[Discussions With Recent Posts (Showcase View)]]></string>
+    <string name="_bx_forum_page_block_title_top_entries"><![CDATA[Top Discussions]]></string>
+    <string name="_bx_forum_page_block_title_top_entries_view_extended"><![CDATA[Top Discussions (Grid View)]]></string>
+    <string name="_bx_forum_page_block_title_top_entries_view_gallery"><![CDATA[Top Discussions (Gallery View)]]></string>
+    <string name="_bx_forum_page_block_title_top_entries_view_showcase"><![CDATA[Top Discussions (Showcase View)]]></string>
+    <string name="_bx_forum_page_block_title_popular_entries"><![CDATA[Popular Discussions]]></string>
+    <string name="_bx_forum_page_block_title_popular_entries_view_extended"><![CDATA[Popular Discussions (Grid View)]]></string>
+    <string name="_bx_forum_page_block_title_popular_entries_view_showcase"><![CDATA[Popular Discussions (Showcase View)]]></string>
+    <string name="_bx_forum_page_block_title_popular_entries_view_gallery"><![CDATA[Popular Discussions (Gallery View)]]></string>
+    <string name="_bx_forum_page_block_title_updated_entries"><![CDATA[Updated Discussions]]></string>
+    <string name="_bx_forum_page_block_title_sys_favorites_entries"><![CDATA[Favorite List]]></string>
+    <string name="_bx_forum_page_block_title_favorites_entries"><![CDATA["{title}" List]]></string>
+    <string name="_bx_forum_page_block_title_favorites_entries_info"><![CDATA[Info]]></string>
+    <string name="_bx_forum_page_block_title_favorites_entries_actions"><![CDATA[Favorites List Actions]]></string>
+    <string name="_bx_forum_page_title_sys_entries_categories"><![CDATA[Discussions Categories]]></string>
+    <string name="_bx_forum_page_title_entries_categories"><![CDATA[Discussions Categories]]></string>
+    <string name="_bx_forum_page_block_title_entries_categories"><![CDATA[Discussions Categories]]></string>
+    <string name="_bx_forum_page_title_sys_entries_by_category"><![CDATA[Discussions by category]]></string>
+    <string name="_bx_forum_page_title_entries_by_category"><![CDATA[Discussions by {category_name}]]></string>
+    <string name="_bx_forum_page_block_title_sys_entries_by_category"><![CDATA[Discussions by category]]></string>
+    <string name="_bx_forum_page_block_title_entries_by_category"><![CDATA[{category_name}]]></string>
+    <string name="_bx_forum_page_title_sys_entries_by_keyword"><![CDATA[Discussions by keyword]]></string>
+    <string name="_bx_forum_page_title_entries_by_keyword"><![CDATA[Discussions by {keyword_name}]]></string>
+    <string name="_bx_forum_page_block_title_sys_entries_by_keyword"><![CDATA[Discussions by keyword]]></string>
+    <string name="_bx_forum_page_block_title_entries_by_keyword"><![CDATA[Discussions by {keyword_name}]]></string>
+    <string name="_bx_forum_page_title_sys_entries_of_author"><![CDATA[Discussions of author]]></string>
+    <string name="_bx_forum_page_title_entries_of_author"><![CDATA[Discussions by {display_name}]]></string>
+    <string name="_bx_forum_page_title_sys_entries_in_context"><![CDATA[Discussions in context]]></string>
+    <string name="_bx_forum_page_title_entries_in_context"><![CDATA[Discussions in {display_name}]]></string>
+    <string name="_bx_forum_page_block_title_favorites_of_author"><![CDATA[Favorites by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_forum_page_block_title_sys_favorites_of_author"><![CDATA[Favorites of author]]></string>
+    <string name="_bx_forum_page_block_title_entries_of_author"><![CDATA[Discussions by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_forum_page_block_title_sys_entries_of_author"><![CDATA[Discussions of author]]></string>
+    <string name="_bx_forum_page_block_title_entries_in_context"><![CDATA[Discussions in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_forum_page_block_title_sys_entries_in_context"><![CDATA[Discussions in context]]></string>
+    <string name="_bx_forum_page_block_title_sys_multi_categories_in_context"><![CDATA[Multi categories in context]]></string>
+    <string name="_bx_forum_page_block_title_multi_categories_in_context"><![CDATA[Categories in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_forum_page_block_title_entries_actions"><![CDATA[Discussions actions]]></string>
+    <string name="_bx_forum_page_block_title_sys_entry_context"><![CDATA[Posted in]]></string>
+    <string name="_bx_forum_page_block_title_entry_context"><![CDATA[Posted in]]></string>
+    <string name="_bx_forum_page_block_title_browse_cmts"><![CDATA[Forum's Comments]]></string>
+    <string name="_bx_forum_page_title_sys_manage"><![CDATA[Manage Own]]></string>
+    <string name="_bx_forum_page_title_sys_manage_administration"><![CDATA[Manage All]]></string>
+    <string name="_bx_forum_page_title_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_forum_page_block_title_system_manage"><![CDATA[Manage Own]]></string>
+    <string name="_bx_forum_page_block_title_system_manage_administration"><![CDATA[Manage All]]></string>
+    <string name="_bx_forum_page_block_title_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_forum_page_block_title_popular_keywords"><![CDATA[Popular Hashtags]]></string>
+    <string name="_bx_forum_page_block_title_cats"><![CDATA[Discussions Categories]]></string>
+    <string name="_bx_forum_page_block_title_browse_labels"><![CDATA[Browse Labels]]></string>
+    <string name="_bx_forum_page_block_title_sys_multicats"><![CDATA[Discussions Categories(Multi)]]></string>
+    <string name="_bx_forum_page_block_title_multicats"><![CDATA[Discussions Categories]]></string>
+    <string name="_bx_forum_page_block_title_sys_my_entries"><![CDATA[User Discussions]]></string>
+    <string name="_bx_forum_page_block_title_my_entries"><![CDATA[{display_name} Discussions]]></string>
+    <string name="_bx_forum_page_title_sys_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_forum_page_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_forum_page_title_sys_entries_favorites"><![CDATA[Favorites Discussions]]></string>
+    <string name="_bx_forum_page_title_entries_favorites"><![CDATA[Favorites Discussions]]></string>
+    <string name="_bx_forum_page_block_title_entries_search_form"><![CDATA[Search]]></string>
+    <string name="_bx_forum_page_block_title_entries_search_results"><![CDATA[Search Results]]></string>
+    <string name="_bx_forum_page_block_title_search_form"><![CDATA[Search Form]]></string>
+    <string name="_bx_forum_page_block_title_search_results"><![CDATA[Search Results]]></string>
+    <string name="_bx_forum_page_block_title_search_form_cmts"><![CDATA[Comments Search Form]]></string>
+    <string name="_bx_forum_page_block_title_search_results_cmts"><![CDATA[Comments Search Results]]></string>
+    <string name="_bx_forum_page_title_sys_entries_partaken"><![CDATA[Partaken]]></string>
+    <string name="_bx_forum_page_title_entries_partaken"><![CDATA[Partaken]]></string>
+    <string name="_bx_forum_page_block_title_partaken_entries"><![CDATA[Partaken]]></string>
+
+    <string name="_bx_forum_menu_title_entry_attachments"><![CDATA[Form Attachments]]></string>
+    <string name="_bx_forum_menu_set_title_entry_attachments"><![CDATA[Form Attachments]]></string>
+    <string name="_bx_forum_menu_item_title_system_cpa_photo_simple"><![CDATA[Add Photo (simple)]]></string>
+    <string name="_bx_forum_menu_item_title_cpa_photo_simple"><![CDATA[Add Photo]]></string>
+    <string name="_bx_forum_menu_item_title_system_cpa_photo_html5"><![CDATA[Add Photo (html5)]]></string>
+    <string name="_bx_forum_menu_item_title_cpa_photo_html5"><![CDATA[Add Photos]]></string>
+    <string name="_bx_forum_menu_item_title_system_cpa_video_simple"><![CDATA[Add Video (simple)]]></string>
+    <string name="_bx_forum_menu_item_title_cpa_video_simple"><![CDATA[Add Video]]></string>
+    <string name="_bx_forum_menu_item_title_system_cpa_video_html5"><![CDATA[Add Video (html5)]]></string>
+    <string name="_bx_forum_menu_item_title_cpa_video_html5"><![CDATA[Add Videos]]></string>
+    <string name="_bx_forum_menu_item_title_system_cpa_video_record"><![CDATA[Record Video]]></string>
+    <string name="_bx_forum_menu_item_title_cpa_video_record"><![CDATA[Record Video]]></string>
+    <string name="_bx_forum_menu_item_title_system_cpa_file_simple"><![CDATA[Add File (simple)]]></string>
+    <string name="_bx_forum_menu_item_title_cpa_file_simple"><![CDATA[Add File]]></string>
+    <string name="_bx_forum_menu_item_title_system_cpa_file_html5"><![CDATA[Add File (html5)]]></string>
+    <string name="_bx_forum_menu_item_title_cpa_file_html5"><![CDATA[Add Files]]></string>
+    <string name="_bx_forum_menu_item_title_system_cpa_poll"><![CDATA[Add Poll]]></string>
+    <string name="_bx_forum_menu_item_title_cpa_poll"><![CDATA[Add Poll]]></string>
+    
+    <string name="_bx_forum_menu_item_title_system_add_link"><![CDATA[Add Link]]></string>
+    <string name="_bx_forum_menu_item_title_add_link"><![CDATA[Add Link]]></string>
+    <string name="_bx_forum_form_post_input_link_err_delete"><![CDATA[Cannot remove the link. Please report.]]></string>
+    <string name="_bx_forum_form_post_input_sys_link"><![CDATA[Link]]></string>
+    <string name="_bx_forum_form_post_input_link_alt"><![CDATA[Add Link]]></string>
+    <string name="_bx_forum_form_attach_link"><![CDATA[Attach Link]]></string>
+    <string name="_bx_forum_form_attach_link_display_add"><![CDATA[Attach Link]]></string>
+    <string name="_bx_forum_form_attach_link_input_sys_content_id"><![CDATA[Content Id]]></string>
+    <string name="_bx_forum_form_attach_link_input_sys_url"><![CDATA[Add Link]]></string>
+    <string name="_bx_forum_form_attach_link_input_url_err"><![CDATA[Correct Link is essential. Please, fill in this field.]]></string>
+    <string name="_bx_forum_form_attach_link_input_url"><![CDATA[Add Link]]></string>
+    <string name="_bx_forum_form_attach_link_input_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_forum_form_attach_link_input_sys_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_forum_form_attach_link_input_do_cancel"><![CDATA[Close]]></string>
+    
+
+    <string name="_bx_forum_menu_title_submenu"><![CDATA[Forum Submenu]]></string>
+    <string name="_bx_forum_menu_set_title_submenu"><![CDATA[Forum Submenu]]></string>
+    <string name="_bx_forum_menu_item_title_system_create_entry"><![CDATA[Discussion]]></string>
+    <string name="_bx_forum_menu_item_title_create_entry"><![CDATA[Discussion]]></string>
+    <string name="_bx_forum_menu_item_title_system_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_forum_menu_item_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_forum_menu_item_title_system_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_forum_menu_item_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_forum_menu_item_title_resolve_entry"><![CDATA[Mark as Resolved]]></string>
+    <string name="_bx_forum_menu_item_title_unresolve_entry"><![CDATA[Mark as Unresolved]]></string>
+    <string name="_bx_forum_menu_item_title_system_resolve_entry"><![CDATA[Mark as Resolved]]></string>
+    <string name="_bx_forum_menu_item_title_system_unresolve_entry"><![CDATA[Mark as Unresolved]]></string>
+    <string name="_bx_forum_menu_item_title_system_stick_entry"><![CDATA[Pin]]></string>
+    <string name="_bx_forum_menu_item_title_stick_entry"><![CDATA[Pin]]></string>
+    <string name="_bx_forum_menu_item_title_system_unstick_entry"><![CDATA[Unpin]]></string>
+    <string name="_bx_forum_menu_item_title_unstick_entry"><![CDATA[Unpin]]></string>
+    <string name="_bx_forum_menu_item_title_system_lock_entry"><![CDATA[Lock]]></string>
+    <string name="_bx_forum_menu_item_title_lock_entry"><![CDATA[Lock]]></string>
+    <string name="_bx_forum_menu_item_title_system_unlock_entry"><![CDATA[Unlock]]></string>
+    <string name="_bx_forum_menu_item_title_unlock_entry"><![CDATA[Unlock]]></string>
+    <string name="_bx_forum_menu_item_title_system_hide_entry"><![CDATA[Hide]]></string>
+    <string name="_bx_forum_menu_item_title_hide_entry"><![CDATA[Hide]]></string>
+    <string name="_bx_forum_menu_item_title_system_unhide_entry"><![CDATA[Unhide]]></string>
+    <string name="_bx_forum_menu_item_title_unhide_entry"><![CDATA[Unhide]]></string>
+    <string name="_bx_forum_menu_item_title_system_subscribe"><![CDATA[Subscribe]]></string>
+    <string name="_bx_forum_menu_item_title_subscribe"><![CDATA[Subscribe]]></string>
+    <string name="_bx_forum_menu_item_title_system_unsubscribe"><![CDATA[Unsubscribe]]></string>
+    <string name="_bx_forum_menu_item_title_unsubscribe"><![CDATA[Unsubscribe]]></string>
+    <string name="_bx_forum_menu_item_title_system_more"><![CDATA[More Actions]]></string>
+    <string name="_bx_forum_menu_item_title_more"><![CDATA[]]></string>
+    <string name="_bx_forum_menu_item_title_system_entries_home"><![CDATA[Discussions]]></string>
+    <string name="_bx_forum_menu_item_title_entries_home"><![CDATA[Discussions]]></string>
+    <string name="_bx_forum_menu_item_title_system_entries_partaken"><![CDATA[Partaken]]></string>
+    <string name="_bx_forum_menu_item_title_entries_partaken"><![CDATA[Partaken]]></string>
+    <string name="_bx_forum_menu_item_title_system_entries_public"><![CDATA[Home]]></string>
+    <string name="_bx_forum_menu_item_title_entries_public"><![CDATA[Home]]></string>
+    <string name="_bx_forum_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_forum_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_forum_menu_item_title_system_entries_new"><![CDATA[New]]></string>
+    <string name="_bx_forum_menu_item_title_entries_new"><![CDATA[New]]></string>
+    <string name="_bx_forum_menu_item_title_system_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_forum_menu_item_title_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_forum_menu_item_title_system_entries_categories"><![CDATA[Сategories]]></string>
+    <string name="_bx_forum_menu_item_title_entries_categories"><![CDATA[Сategories]]></string>
+    <string name="_bx_forum_menu_item_title_system_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_forum_menu_item_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_forum_menu_set_title_view_entry"><![CDATA[Discussion Actions]]></string>
+    <string name="_bx_forum_menu_title_view_entry"><![CDATA[Discussion Actions]]></string>
+    <string name="_bx_forum_menu_set_title_view_more"><![CDATA[Discussion More Actions]]></string>
+    <string name="_bx_forum_menu_title_view_more"><![CDATA[Discussion More Actions]]></string>
+    <string name="_bx_forum_menu_item_title_system_view_entries_author"><![CDATA[Discussions]]></string>
+    <string name="_bx_forum_menu_item_title_view_entries_author"><![CDATA[Discussions]]></string>
+    <string name="_bx_forum_menu_item_title_system_view_entries_in_context"><![CDATA[Discussions]]></string>
+    <string name="_bx_forum_menu_item_title_view_entries_in_context"><![CDATA[Discussions]]></string>
+    <string name="_bx_forum_menu_title_entries_my"><![CDATA[My Discussions Action Menu]]></string>
+    <string name="_bx_forum_menu_set_title_entries_my"><![CDATA[My Discussions Menu]]></string>
+    <string name="_bx_forum_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_forum_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_forum_menu_item_title_system_manage_account"><![CDATA[Manage account]]></string>
+    <string name="_bx_forum_menu_item_title_manage_account"><![CDATA[Manage account]]></string>
+    <string name="_bx_forum_menu_item_title_system_admt_discussions"><![CDATA[Discussions]]></string>
+    <string name="_bx_forum_menu_item_title_admt_discussions"><![CDATA[Discussions]]></string>
+    <string name="_bx_forum_menu_item_title_manage_my"><![CDATA[My Discussions]]></string>
+    <string name="_bx_forum_menu_item_title_manage_all"><![CDATA[All Discussions]]></string>
+    <string name="_bx_forum_menu_item_title_system_discussions"><![CDATA[Discussions number]]></string>
+    <string name="_bx_forum_menu_item_title_discussions"><![CDATA[Discussions]]></string>
+    <string name="_bx_forum_lmi_cpt_categories"><![CDATA[Categories]]></string>
+    <string name="_bx_forum_menu_title_snippet_meta_main"><![CDATA[Snippet Meta Info: Main]]></string>
+    <string name="_bx_forum_menu_set_title_snippet_meta_main"><![CDATA[Snippet Meta Info: Main]]></string>
+    <string name="_bx_forum_menu_title_snippet_meta_counters"><![CDATA[Snippet Meta Info: Counters]]></string>
+    <string name="_bx_forum_menu_set_title_snippet_meta_counters"><![CDATA[Snippet Meta Info: Counters]]></string>
+    <string name="_bx_forum_menu_title_snippet_meta_reply"><![CDATA[Snippet Meta Info: Reply]]></string>
+    <string name="_bx_forum_menu_set_title_snippet_meta_reply"><![CDATA[Snippet Meta Info: Reply]]></string>
+    <string name="_bx_forum_menu_item_title_system_sm_reply_text"><![CDATA[Reply text]]></string>
+    <string name="_bx_forum_menu_item_title_sm_reply_text"><![CDATA[Reply text]]></string>
+    <string name="_bx_forum_menu_item_title_system_sm_status"><![CDATA[Status]]></string>
+    <string name="_bx_forum_menu_item_title_sm_status"><![CDATA[Status]]></string>
+    <string name="_bx_forum_menu_item_title_system_sm_badges"><![CDATA[Badges]]></string>
+    <string name="_bx_forum_menu_item_title_sm_badges"><![CDATA[Badges]]></string>
+    <string name="_bx_forum_menu_title_categories"><![CDATA[Categories]]></string>
+  
+
+    <string name="_bx_forum_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+    <string name="_bx_forum_grid_filter_item_title_adm_select_one_filter2"><![CDATA[Any Audience]]></string>
+    <string name="_bx_forum_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_forum_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+    <string name="_bx_forum_grid_filter_item_title_adm_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_forum_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_forum_grid_column_title_adm_title"><![CDATA[Title]]></string>
+    <string name="_bx_forum_grid_column_title_adm_added"><![CDATA[Added]]></string>
+    <string name="_bx_forum_grid_column_title_adm_author"><![CDATA[Author]]></string>
+    <string name="_bx_forum_grid_column_title_title"><![CDATA[Category]]></string>
+    <string name="_bx_forum_grid_column_title_visible_for_levels"><![CDATA[Visible For]]></string>
+    <string name="_bx_forum_grid_column_title_icon"><![CDATA[Icon]]></string>
+    <string name="_bx_forum_grid_action_title_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_forum_grid_action_title_adm_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_forum_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_forum_grid_action_title_adm_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_forum_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_forum_grid_action_title_adm_audit_content"><![CDATA[Audit actions]]></string>
+    <string name="_bx_forum_grid_action_title_add"><![CDATA[New discussion]]></string>
+    <string name="_bx_forum_grid_action_title_show_to"><![CDATA[Show To]]></string>
+    <string name="_bx_forum_grid_column_title_adm_status_admin"><![CDATA[Moderation]]></string>
+    <string name="_bx_forum_grid_action_err_delete"><![CDATA[Cannot delete the selected discussion(s).]]></string>
+    <string name="_bx_forum_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+    <string name="_bx_forum_grid_txt_manage_visibility"><![CDATA[Manage visibility settings.]]></string>
+    <string name="_bx_forum_grid_show_to_popup"><![CDATA[Show category to:]]></string>
+    <string name="_bx_forum_grid_txt_visible_for"><![CDATA[Visible For]]></string>
+    <string name="_bx_forum_grid_txt_visible_for_all"><![CDATA[Anyone]]></string>
+    <string name="_bx_forum_grid_txt_visible_for_levels"><![CDATA[Select Levels]]></string>
+    <string name="_bx_forum_grid_txt_visible_for_selected"><![CDATA[Selected levels]]></string>
+    <string name="_bx_forum_grid_inf_visible_for_levels"><![CDATA[Select user levels that can view this category]]></string>
+    <string name="_bx_forum_grid_err_show_to"><![CDATA[Cannot update category.]]></string>
+    <string name="_bx_forum_grid_edit_popup"><![CDATA[Edit category]]></string>
+    <string name="_bx_forum_grid_err_items_icon_image_remove"><![CDATA[Cannot remove icon image: ]]></string>
+    <string name="_bx_forum_grid_err_items_icon_image"><![CDATA[Cannot process image: ]]></string>
+    <string name="_bx_forum_grid_form_txt_badges_icon"><![CDATA[Icon]]></string>
+    <string name="_bx_forum_grid_form_txt_badges_icon_image"><![CDATA[]]></string>
+    <string name="_bx_forum_grid_form_txt_badges_icon_image_new"><![CDATA[]]></string>
+    <string name="_bx_forum_grid_form_txt_badges_icon_image_old"><![CDATA[Current Icon]]></string>
+    <string name="_bx_forum_grid_form_dsc_badges_icon"><![CDATA[You may use: 1) font icon, 2) Inline SVG code, 3) Emoji]]></string>
+    <string name="_bx_forum_grid_form_dsc_badges_icon_image"><![CDATA[or upload a small image to be displayed near the link.]]></string>
+    <string name="_bx_forum_grid_form_dsc_badges_icon_image_current"><![CDATA[No icon uploaded. Text is used in menu item.]]></string>
+    <string name="_bx_forum_grid_form_btn_badges_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_forum_grid_form_btn_badges_cancel"><![CDATA[Cancel]]></string>
+    
+    <string name="_bx_forum_grid_filter_resolved_all"><![CDATA[Any status]]></string>
+    <string name="_bx_forum_grid_filter_badges_all"><![CDATA[All badges]]></string>
+    <string name="_bx_forum_grid_filter_resolved_resolved"><![CDATA[Resolved]]></string>
+    <string name="_bx_forum_grid_filter_resolved_unresolved"><![CDATA[Unresolved]]></string>
+    
+    <string name="_bx_forum_grid_filter_order_recent"><![CDATA[Recent Posts]]></string>
+    <string name="_bx_forum_grid_filter_order_new"><![CDATA[New]]></string>
+    <string name="_bx_forum_grid_filter_order_top"><![CDATA[Top]]></string>
+    <string name="_bx_forum_grid_filter_order_updated"><![CDATA[Updated]]></string>
+    <string name="_bx_forum_grid_filter_order_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_forum_grid_filter_order_featured"><![CDATA[Featured]]></string>
+    <string name="_bx_forum_grid_filter_order_favorite"><![CDATA[Favorite]]></string>
+    <string name="_bx_forum_grid_filter_order_partaken"><![CDATA[Partaken]]></string>
+    
+    <string name="_bx_forum_grid_btn_save"><![CDATA[Save]]></string>
+    <string name="_bx_forum_grid_btn_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_forum_pre_lists_cats"><![CDATA[Forum categories]]></string>
+    <string name="_bx_forum_cat_General"><![CDATA[General]]></string>
+
+    <string name="_bx_forum_chart_growth"><![CDATA[Discussions: Growth]]></string>
+    <string name="_bx_forum_chart_growth_speed"><![CDATA[Discussions: Growth Speed]]></string>
+
+    <string name="_bx_forum_search_extended"><![CDATA[Discussions Search]]></string>
+    <string name="_bx_forum_search_extended_cmts"><![CDATA[Discussions Comments Search]]></string>
+
+    <string name="_bx_forum_txt_all_categories"><![CDATA[All Categories]]></string>
+    <string name="_bx_forum_txt_msg_status_hidden"><![CDATA[This discussion was hidden.]]></string>
+    <string name="_bx_forum_txt_msg_status_pending"><![CDATA[This discussion is pending approval.]]></string>
+    <string name="_bx_forum_err_not_found"><![CDATA[Discussion wasn't found.]]></string>
+    <string name="_bx_forum_more"><![CDATA[{0} more]]></string>
+    <string name="_bx_forum_participant_author"><![CDATA[author]]></string>
+    <string name="_bx_forum_participant_last_replier"><![CDATA[last replier]]></string>
+    <string name="_bx_forum_txt_entry_locked"><![CDATA[Locked discussion]]></string>
+    <string name="_bx_forum_txt_entry_sticked"><![CDATA[Pinned discussion]]></string>
+    <string name="_bx_forum_txt_sample_comment_single"><![CDATA[comment to discussion]]></string>
+    <string name="_bx_forum_txt_sample_vote_single"><![CDATA[vote to discussion]]></string>
+    <string name="_bx_forum_txt_sample_reaction_single"><![CDATA['{0}' reaction to discussion]]></string>
+    <string name="_bx_forum_txt_sample_score_up_single"><![CDATA[score up vote to discussion]]></string>
+    <string name="_bx_forum_txt_sample_score_down_single"><![CDATA[score down vote to discussion]]></string>
+    <string name="_bx_forum_txt_sample_single"><![CDATA[discussion]]></string>
+    <string name="_bx_forum_txt_sample_single_with_article"><![CDATA[a discussion]]></string>
+
+    <string name="_bx_forum_txt_poll_view_answers"><![CDATA[poll]]></string>
+    <string name="_bx_forum_txt_poll_view_results"><![CDATA[results]]></string>
+    <string name="_bx_forum_txt_poll_answer_vote_do_by"><![CDATA[Voted for]]></string>
+    <string name="_bx_forum_txt_poll_answer_vote_counter"><![CDATA[{0} votes]]></string>
+    <string name="_bx_forum_txt_poll_answer_vote_percent"><![CDATA[({0}%)]]></string>
+
+    <string name="_bx_forum_txt_all_entries_in"><![CDATA[<a href="{0}">All Discussions in {1} ({2})</a>]]></string>
+    <string name="_bx_forum_email_new_reply"><![CDATA[New reply]]></string>
+    <string name="_bx_forum_email_new_reply_subject"><![CDATA[New reply in "{PageTitle}" discussion]]></string>
+    <string name="_bx_forum_email_new_reply_body"><![CDATA[{email_header}
+<p>New reply in <a href="{PageUrl}">{PageTitle}</a> discussion from <a href="{SenderUrl}">{SenderDisplayName}</a>:</p>
+<hr />
+<p>{Message}</p>
+{email_footer}]]></string>
+</resources>

+ 628 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/install/sql/enable.sql

@@ -0,0 +1,628 @@
+SET @sName = 'bx_forum';
+
+
+-- SETTINGS
+SET @iTypeOrder = (SELECT MAX(`order`) FROM `sys_options_types` WHERE `group` = 'modules');
+INSERT INTO `sys_options_types`(`group`, `name`, `caption`, `icon`, `order`) VALUES 
+('modules', @sName, '_bx_forum', 'bx_forum@modules/boonex/forum/|std-icon.svg', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, @sName, '_bx_forum', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_forum_enable_auto_approve', 'on', @iCategId, '_bx_forum_option_enable_auto_approve', 'checkbox', '', '', '', 0),
+('bx_forum_summary_chars', '700', @iCategId, '_bx_forum_option_summary_chars', 'digit', '', '', '', 1),
+('bx_forum_plain_summary_chars', '240', @iCategId, '_bx_forum_option_plain_summary_chars', 'digit', '', '', '', 2),
+('bx_forum_per_page_browse', '12', @iCategId, '_bx_forum_option_per_page_browse', 'digit', '', '', '', 10),
+('bx_forum_per_page_index', '6', @iCategId, '_bx_forum_option_per_page_index', 'digit', '', '', '', 11),
+('bx_forum_per_page_profile', '6', @iCategId, '_bx_forum_option_per_page_profile', 'digit', '', '', '', 12),
+('bx_forum_per_page_for_favorites_lists', '5', @iCategId, '_bx_forum_option_per_page_for_favorites_lists', 'digit', '', '', '', 17),
+('bx_forum_rss_num', '10', @iCategId, '_bx_forum_option_rss_num', 'digit', '', '', '', 20),
+('bx_forum_searchable_fields', 'title,text,text_comments', @iCategId, '_bx_forum_option_searchable_fields', 'list', '', '', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:21:"get_searchable_fields";}', 30),
+('bx_forum_auto_activation_for_categories', 'on', @iCategId, '_bx_forum_option_auto_activation_for_categories', 'checkbox', '', '', '', 35),
+('bx_forum_visible_categories', '10', @iCategId, '_bx_forum_option_visible_categories', 'digit', '', '', '', 40);
+-- ('bx_forum_autosubscribe_created', '', @iCategId, '_bx_forum_option_autosubscribe_created', 'checkbox', '', '', '', 40),
+-- ('bx_forum_autosubscribe_replied', '', @iCategId, '_bx_forum_option_autosubscribe_replied', 'checkbox', '', '', '', 41),
+
+
+
+-- PAGE: create entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_create_entry', '_bx_forum_page_title_sys_create_entry', '_bx_forum_page_title_create_entry', @sName, 5, 2147483647, 1, 'create-discussion', 'page.php?i=create-discussion', '', '', '', 0, 1, 0, 'BxForumPageBrowse', 'modules/boonex/forum/classes/BxForumPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_forum_create_entry', 1, @sName, '_bx_forum_page_block_title_create_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:13:"entity_create";}', 0, 1, 1);
+
+-- PAGE: edit entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_edit_entry', '_bx_forum_page_title_sys_edit_entry', '_bx_forum_page_title_edit_entry', @sName, 5, 2147483647, 1, 'edit-discussion', '', '', '', '', 0, 1, 0, 'BxForumPageEntry', 'modules/boonex/forum/classes/BxForumPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_forum_edit_entry', 1, @sName, '_bx_forum_page_block_title_edit_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:11:"entity_edit";}', 0, 0, 0);
+
+-- PAGE: delete entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_delete_entry', '_bx_forum_page_title_sys_delete_entry', '_bx_forum_page_title_delete_entry', @sName, 5, 2147483647, 1, 'delete-discussion', '', '', '', '', 0, 1, 0, 'BxForumPageEntry', 'modules/boonex/forum/classes/BxForumPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_forum_delete_entry', 1, @sName, '_bx_forum_page_block_title_delete_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:13:"entity_delete";}', 0, 0, 0);
+
+-- PAGE: view entry
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_view_entry', 'view-discussion', '_bx_forum_page_title_sys_view_entry', '_bx_forum_page_title_view_entry', @sName, 12, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxForumPageEntry', 'modules/boonex/forum/classes/BxForumPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_forum_view_entry', 1, @sName,'', '_bx_forum_page_block_title_entry_breadcrumb', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:17:"entity_breadcrumb";}', 0, 0, 1, 1),
+('bx_forum_view_entry', 3, @sName,'', '_bx_forum_page_block_title_entry_author', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:13:"entity_author";}', 0, 0, 1, 1),
+('bx_forum_view_entry', 3, @sName, '_bx_forum_page_block_title_sys_entry_context', '_bx_forum_page_block_title_entry_context', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:14:\"entity_context\";}', 0, 0, 1, 2),
+('bx_forum_view_entry', 3, @sName,'', '_bx_forum_page_block_title_entry_participants', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:19:"entity_participants";}', 0, 0, 1, 3),
+('bx_forum_view_entry', 3, @sName, '', '_bx_forum_page_block_title_entry_info', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:11:\"entity_info\";}', 0, 0, 0, 0),
+('bx_forum_view_entry', 2, @sName,'', '_bx_forum_page_block_title_entry_text', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:17:"entity_text_block";}', 0, 0, 1, 1),
+('bx_forum_view_entry', 1, @sName,'', '_bx_forum_page_block_title_entry_all_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:18:"entity_all_actions";}', 0, 0, 1, 2),
+('bx_forum_view_entry', 2, @sName,'', '_bx_forum_page_block_title_entry_attachments', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:18:"entity_attachments";}', 0, 0, 1, 2),
+('bx_forum_view_entry', 2, @sName, '', '_bx_forum_page_block_title_entry_polls', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:12:"entity_polls";}', 0, 0, 1, 3),
+('bx_forum_view_entry', 2, @sName,'', '_bx_forum_page_block_title_entry_comments', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:15:"entity_comments";}', 0, 0, 1, 4),
+('bx_forum_view_entry', 2, @sName, '', '_bx_forum_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:14:\"entity_reports\";}', 0, 0, 1, 6);
+
+
+-- PAGE: categories
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_categories', 'discussions-categories', '_bx_forum_page_title_sys_entries_categories', '_bx_forum_page_title_entries_categories', @sName, 5, 2147483647, 1, 'page.php?i=discussions-categories', '', '', '', 0, 1, 0, 'BxForumPageBrowse', 'modules/boonex/forum/classes/BxForumPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_forum_categories', 1, @sName, '', '_bx_forum_page_block_title_entries_categories', 13, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:15:"categories_list";s:6:"params";a:2:{i:0;s:13:"bx_forum_cats";i:1;a:1:{s:10:"show_empty";b:1;}}s:5:"class";s:20:"TemplServiceCategory";}', 0, 0, 1, 0);
+
+-- PAGE: entries by category
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_category', 'discussions-category', '_bx_forum_page_title_sys_entries_by_category', '_bx_forum_page_title_entries_by_category', @sName, 1, 2147483647, 1, 'page.php?i=discussions-category', '', '', '', 0, 1, 0, 'BxForumPageBrowse', 'modules/boonex/forum/classes/BxForumPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_forum_category', 2, @sName, '_bx_forum_page_block_title_sys_entries_by_category', '_bx_forum_page_block_title_entries_by_category', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_forum";s:6:"method";s:15:"browse_category";s:6:"params";a:1:{i:0;s:5:"table";}}', 0, 0, 1, 1),
+('bx_forum_category', 1, @sName, '', '_bx_forum_page_block_title_cats', 11, 2147483647, 'menu', 'bx_forum_categories', 0, 0, 1, 1);
+
+-- PAGE: entries by keyword
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_keyword', 'discussions-keyword', '_bx_forum_page_title_sys_entries_by_keyword', '_bx_forum_page_title_entries_by_keyword', @sName, 5, 2147483647, 1, 'page.php?i=discussions-keyword', '', '', '', 0, 1, 0, 'BxForumPageBrowse', 'modules/boonex/forum/classes/BxForumPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_forum_keyword', 1, @sName, '_bx_forum_page_block_title_sys_entries_by_keyword', '_bx_forum_page_block_title_entries_by_keyword', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_forum";s:6:"method";s:14:"browse_keyword";s:6:"params";a:1:{i:0;s:5:"table";}}', 0, 0, 1, 1);
+
+-- PAGE: entries of author
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_author', 'discussions-author', '_bx_forum_page_title_sys_entries_of_author', '_bx_forum_page_title_entries_of_author', @sName, 5, 2147483647, 1, 'page.php?i=discussions-author', '', '', '', 0, 1, 0, 'BxForumPageAuthor', 'modules/boonex/forum/classes/BxForumPageAuthor.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_forum_author', 1, @sName, '', '_bx_forum_page_block_title_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:18:"my_entries_actions";}', 0, 0, 1, 1),
+('bx_forum_author', 1, @sName, '_bx_forum_page_block_title_sys_favorites_of_author', '_bx_forum_page_block_title_favorites_of_author', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_forum";s:6:"method";s:21:"browse_favorite_lists";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";s:6:"params";a:3:{s:9:"unit_view";s:8:"showcase";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1, 2),
+('bx_forum_author', 1, @sName, '_bx_forum_page_block_title_sys_entries_of_author', '_bx_forum_page_block_title_entries_of_author', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:13:"browse_author";}', 0, 0, 1, 3),
+('bx_forum_author', 1, @sName, '_bx_forum_page_block_title_sys_entries_in_context', '_bx_forum_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_forum";s:6:"method";s:14:"browse_context";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";i:0;a:1:{s:13:"empty_message";b:0;}}}', 0, 0, 1, 4);
+
+
+-- PAGE: favorites by list
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_favorites', '_bx_forum_page_title_sys_entries_favorites', '_bx_forum_page_title_entries_favorites', @sName, 12, 2147483647, 1, 'discussions-favorites', 'page.php?i=discussions-favorites', '', '', '', 0, 1, 0, 'BxForumPageListEntry', 'modules/boonex/forum/classes/BxForumPageListEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_forum_favorites', 2, @sName, '_bx_forum_page_block_title_sys_favorites_entries', '_bx_forum_page_block_title_favorites_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_forum";s:6:"method";s:15:"browse_favorite";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1),
+('bx_forum_favorites', 3, @sName, '', '_bx_forum_page_block_title_favorites_entries_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:19:"favorites_list_info";}', 0, 0, 0),
+('bx_forum_favorites', 3, @sName, '', '_bx_forum_page_block_title_favorites_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:22:"favorites_list_actions";}', 0, 0, 1);
+
+
+-- PAGE: entries in context
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_context', 'discussions-context', '_bx_forum_page_title_sys_entries_in_context', '_bx_forum_page_title_entries_in_context', 'bx_forum', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxForumPageAuthor', 'modules/boonex/forum/classes/BxForumPageAuthor.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_forum_context', 1, @sName, '_bx_forum_page_block_title_sys_entries_in_context', '_bx_forum_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:14:\"browse_context\";}', 0, 0, 1, 1),
+('bx_forum_context', 1, @sName, '_bx_forum_page_block_title_sys_multi_categories_in_context', '_bx_forum_page_block_title_multi_categories_in_context', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:29:\"categories_multi_list_context\";}', 0, 0, 0, 2);
+
+-- PAGE: module home
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `cover`, `cover_image`, `type_id`, `layout_id`, `submenu`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `inj_head`, `inj_footer`, `sticky_columns`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_home', 'discussions-home', '_bx_forum_page_title_sys_home', '_bx_forum_page_title_home', @sName, 1, 0, 1, 6, '', 2147483647, 1, 'page.php?i=discussions-home', '', '', '', 0, 1, '', '', 0, 0, 'BxForumPageBrowse', 'modules/boonex/forum/classes/BxForumPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `async`, `cache_lifetime`, `submenu`, `tabs`, `hidden_on`, `visible_for_levels`, `type`, `content`, `help`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_forum_home', 1, @sName, '_bx_forum_page_block_title_sys_featured_entries_view_showcase', '_bx_forum_page_block_title_featured_entries_view_showcase', 0, 0, NULL, '', 0, '', 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:15:\"browse_featured\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', NULL, 0, 1, 1, 0),
+('bx_forum_home', 2, @sName, '', '_bx_forum_page_block_title_cats', 11, 0, NULL, '', 0, 0, 2147483647, 'menu', 'bx_forum_categories', NULL, 0, 1, 1, 0),
+('bx_forum_home', 2, @sName, '_bx_forum_page_block_title_sys_multicats', '_bx_forum_page_block_title_multicats', 11, 0, NULL, '', 0, '', 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:21:\"categories_multi_list\";}', NULL, 0, 1, 0, 1),
+('bx_forum_home', 3, @sName, '', '_bx_forum_page_block_title_home', 11, 0, NULL, '', 0, '', 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:13:\"browse_latest\";s:6:\"params\";a:3:{i:0;s:5:\"table\";i:1;b:1;i:2;b:0;}}', NULL, 0, 1, 1, 1),
+('bx_forum_home', 2, @sName, '', '_bx_forum_page_block_title_browse_labels', 11, 0, NULL, '', 0, '', 2147483647, 'service', 'a:3:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:13:\"browse_labels\";s:5:\"class\";s:20:\"TemplServiceMetatags\";}', NULL, 0, 1, 0, 2),
+('bx_forum_home', 2, @sName, '', '_bx_forum_page_block_title_popular_keywords', 11, 0, NULL, '', 0, '', 2147483647, 'service', 'a:4:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:14:\"keywords_cloud\";s:6:\"params\";a:3:{i:0;s:8:\"bx_forum\";i:1;s:8:\"bx_forum\";i:2;a:1:{s:9:\"menu_view\";b:1;}}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', NULL, 0, 1, 1, 3),
+('bx_forum_home', 2, @sName, '_bx_forum_page_block_title_popular_entries_view_extended', '_bx_forum_page_block_title_popular_entries', 11, 0, NULL, '', 0, '', 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:14:\"browse_popular\";s:6:\"params\";a:1:{i:0;s:8:\"extended\";}}', NULL, 0, 1, 1, 3);
+
+-- PAGE: module search
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_search', 'discussions-search', '_bx_forum_page_title_sys_entries_search', '_bx_forum_page_title_entries_search', @sName, 5, 2147483647, 1, 'page.php?i=discussions-search', '', '', '', 0, 1, 0, 'BxForumPageBrowse', 'modules/boonex/forum/classes/BxForumPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_forum_search', 1, @sName, '', '_bx_forum_page_block_title_entries_search_form', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:6:"search";}', 0, 0, 1, 0),
+('bx_forum_search', 1, @sName, '', '_bx_forum_page_block_title_entries_search_results', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_forum";s:6:"method";s:21:"browse_search_results";s:6:"params";a:1:{i:0;s:5:"table";}}', 0, 0, 1, 1),
+('bx_forum_search', 1, @sName, '', '_bx_forum_page_block_title_search_form', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:8:"bx_forum";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 2),
+('bx_forum_search', 1, @sName, '', '_bx_forum_page_block_title_search_results', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:8:"bx_forum";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 3),
+('bx_forum_search', 1, @sName, '', '_bx_forum_page_block_title_search_form_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:13:"bx_forum_cmts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 4),
+('bx_forum_search', 1, @sName, '', '_bx_forum_page_block_title_search_results_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:13:"bx_forum_cmts";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 5);
+
+-- PAGE: module manage own
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_manage', '_bx_forum_page_title_sys_manage', '_bx_forum_page_title_manage', @sName, 5, 2147483647, 1, 'discussions-manage', 'page.php?i=discussions-manage', '', '', '', 0, 1, 0, 'BxForumPageBrowse', 'modules/boonex/forum/classes/BxForumPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_forum_manage', 1, @sName, '_bx_forum_page_block_title_system_manage', '_bx_forum_page_block_title_manage', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:12:"manage_tools";}}', 0, 1, 0);
+
+-- PAGE: module manage all
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_administration', '_bx_forum_page_title_sys_manage_administration', '_bx_forum_page_title_manage', @sName, 5, 192, 1, 'discussions-administration', 'page.php?i=discussions-administration', '', '', '', 0, 1, 0, 'BxForumPageBrowse', 'modules/boonex/forum/classes/BxForumPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_forum_administration', 1, @sName, '_bx_forum_page_block_title_system_manage_administration', '_bx_forum_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:"module";s:8:"bx_forum";s:6:"method";s:12:"manage_tools";s:6:"params";a:1:{i:0;s:14:"administration";}}', 0, 1, 0);
+
+-- PAGE: add block to homepage
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = 'sys_home' AND `cell_id` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('sys_home', 1, @sName, '_bx_forum_page_block_title_new_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_forum";s:6:"method";s:12:"browse_index";s:6:"params";a:4:{i:0;s:5:"table";i:1;b:0;i:2;b:1;i:3;b:0;}}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1);
+
+-- PAGES: add page block to profiles modules (trigger* page objects are processed separately upon modules enable/disable)
+SET @iPBCellProfile = 2;
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('trigger_page_profile_view_entry', @iPBCellProfile, @sName, '_bx_forum_page_block_title_sys_my_entries', '_bx_forum_page_block_title_my_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_forum";s:6:"method";s:13:"browse_author";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:1:{s:13:"empty_message";b:0;}}}', 0, 0, 0);
+
+
+-- PAGE: service blocks
+ SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = '' AND `cell_id` = 0 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('', 0, @sName, '_bx_forum_page_block_title_popular_entries_view_extended', '_bx_forum_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:14:\"browse_popular\";s:6:\"params\";a:1:{i:0;s:8:\"extended\";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 1),
+('', 0, @sName, '_bx_forum_page_block_title_popular_entries_view_showcase', '_bx_forum_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:14:\"browse_popular\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 2),
+('', 0, @sName, '_bx_forum_page_block_title_popular_entries_view_gallery', '_bx_forum_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:14:\"browse_popular\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:7:\"gallery\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 3),
+
+('', 0, @sName, '_bx_forum_page_block_title_featured_entries_view_extended', '_bx_forum_page_block_title_featured_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:15:\"browse_featured\";s:6:\"params\";a:1:{i:0;s:8:\"extended\";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 4),
+('', 0, @sName, '_bx_forum_page_block_title_featured_entries_view_gallery', '_bx_forum_page_block_title_featured_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:15:\"browse_featured\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:7:\"gallery\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 5),
+
+('', 0, @sName, '_bx_forum_page_block_title_latest_entries_view_extended', '_bx_forum_page_block_title_latest_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:13:\"browse_latest\";s:6:\"params\";a:1:{i:0;s:8:\"extended\";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 6),
+('', 0, @sName, '_bx_forum_page_block_title_latest_entries_view_showcase', '_bx_forum_page_block_title_latest_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:13:\"browse_latest\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 7),
+('', 0, @sName, '_bx_forum_page_block_title_latest_entries_view_gallery', '_bx_forum_page_block_title_latest_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:13:\"browse_latest\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:7:\"gallery\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 8),
+
+('', 0, @sName, '_bx_forum_page_block_title_new_entries_view_extended', '_bx_forum_page_block_title_new_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:10:\"browse_new\";s:6:\"params\";a:1:{i:0;s:8:\"extended\";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 9),
+('', 0, @sName, '_bx_forum_page_block_title_new_entries_view_showcase', '_bx_forum_page_block_title_new_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:10:\"browse_new\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 10),
+('', 0, @sName, '_bx_forum_page_block_title_new_entries_view_gallery', '_bx_forum_page_block_title_new_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:10:\"browse_new\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:7:\"gallery\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 11),
+
+('', 0, @sName, '_bx_forum_page_block_title_top_entries_view_extended', '_bx_forum_page_block_title_top_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:10:\"browse_top\";s:6:\"params\";a:1:{i:0;s:8:\"extended\";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 12),
+('', 0, @sName, '_bx_forum_page_block_title_top_entries_view_showcase', '_bx_forum_page_block_title_top_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:10:\"browse_top\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 13),
+('', 0, @sName, '_bx_forum_page_block_title_top_entries_view_gallery', '_bx_forum_page_block_title_top_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_forum\";s:6:\"method\";s:10:\"browse_top\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:7:\"gallery\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 14),
+
+('', 0, @sName, '_bx_forum_page_block_title_partaken_entries', '_bx_forum_page_block_title_partaken_entries', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:15:"browse_partaken";}', 0, 1, IFNULL(@iBlockOrder, 0) + 15);
+
+
+
+-- MENU: add to site menu
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' AND `active` = 1 AND `order` < 9999 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_site', @sName, 'discussions-home', '_bx_forum_menu_item_title_system_entries_home', '_bx_forum_menu_item_title_entries_home', 'page.php?i=discussions-home', '', '', 'far comments col-blue2', 'bx_forum_submenu', 2147483647, 1, 1, IFNULL(@iSiteMenuOrder, 0) + 1);
+
+-- MENU: add to homepage menu
+SET @iHomepageMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_homepage' AND `active` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_homepage', @sName, 'discussions-home', '_bx_forum_menu_item_title_system_entries_home', '_bx_forum_menu_item_title_entries_home', 'page.php?i=discussions-home', '', '', 'far comments col-blue2', 'bx_forum_submenu', 2147483647, 1, 1, IFNULL(@iHomepageMenuOrder, 0) + 1);
+
+-- MENU: add to "add content" menu
+SET @iAddMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_add_content_links' AND `active` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_add_content_links', @sName, 'create-discussion', '_bx_forum_menu_item_title_system_create_entry', '_bx_forum_menu_item_title_create_entry', 'page.php?i=create-discussion', '', '', 'far comments col-blue2', '', 2147483647, 1, 1, IFNULL(@iAddMenuOrder, 0) + 1);
+
+-- MENU: create post form attachments (link, photo, video, etc)
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_entry_attachments', '_bx_forum_menu_title_entry_attachments', 'bx_forum_entry_attachments', @sName, 23, 0, 1, 'BxForumMenuAttachments', 'modules/boonex/forum/classes/BxForumMenuAttachments.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_forum_entry_attachments', @sName, '_bx_forum_menu_set_title_entry_attachments', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_forum_entry_attachments', @sName, 'photo_simple', '_bx_forum_menu_item_title_system_cpa_photo_simple', '_bx_forum_menu_item_title_cpa_photo_simple', 'javascript:void(0)', 'javascript:{js_object_uploader_photos_simple}.showUploaderForm();', '_self', 'camera', '', '', 2147483647, '', 0, 0, 1, 1),
+('bx_forum_entry_attachments', @sName, 'photo_html5', '_bx_forum_menu_item_title_system_cpa_photo_html5', '_bx_forum_menu_item_title_cpa_photo_html5', 'javascript:void(0)', 'javascript:{js_object_uploader_photos_html5}.showUploaderForm();', '_self', 'camera', '', '', 2147483647, '', 1, 0, 1, 2),
+('bx_forum_entry_attachments', @sName, 'video_simple', '_bx_forum_menu_item_title_system_cpa_video_simple', '_bx_forum_menu_item_title_cpa_video_simple', 'javascript:void(0)', 'javascript:{js_object_uploader_videos_simple}.showUploaderForm();', '_self', 'video', '', '', 2147483647, '', 0, 0, 1, 3),
+('bx_forum_entry_attachments', @sName, 'video_html5', '_bx_forum_menu_item_title_system_cpa_video_html5', '_bx_forum_menu_item_title_cpa_video_html5', 'javascript:void(0)', 'javascript:{js_object_uploader_videos_html5}.showUploaderForm();', '_self', 'video', '', '', 2147483647, '', 1, 0, 1, 4),
+('bx_forum_entry_attachments', @sName, 'video_record_video', '_bx_forum_menu_item_title_system_cpa_video_record', '_bx_forum_menu_item_title_cpa_video_record', 'javascript:void(0)', 'javascript:{js_object_uploader_videos_record_video}.showUploaderForm();', '_self', 'fas circle', '', '', 2147483647, '', 1, 0, 1, 5),
+('bx_forum_entry_attachments', @sName, 'file_simple', '_bx_forum_menu_item_title_system_cpa_file_simple', '_bx_forum_menu_item_title_cpa_file_simple', 'javascript:void(0)', 'javascript:{js_object_uploader_files_simple}.showUploaderForm();', '_self', 'file', '', '', 2147483647, '', 0, 0, 1, 6),
+('bx_forum_entry_attachments', @sName, 'file_html5', '_bx_forum_menu_item_title_system_cpa_file_html5', '_bx_forum_menu_item_title_cpa_file_html5', 'javascript:void(0)', 'javascript:{js_object_uploader_files_html5}.showUploaderForm();', '_self', 'file', '', '', 2147483647, '', 1, 0, 1, 7),
+('bx_forum_entry_attachments', @sName, 'poll', '_bx_forum_menu_item_title_system_cpa_poll', '_bx_forum_menu_item_title_cpa_poll', 'javascript:void(0)', 'javascript:{js_object}.showPollForm(this);', '_self', 'tasks', '', '', 2147483647, '', 1, 0, 1, 8),
+('bx_forum_entry_attachments', @sName, 'add-link', '_bx_forum_menu_item_title_system_add_link', '_bx_forum_menu_item_title_add_link', 'javascript:void(0)', 'javascript:{js_object_link}.showAttachLink(this);', '_self', 'link', '', '', 2147483647, '', 1, 0, 1, 10);
+
+-- MENU: actions menu for view entry 
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_view', '_bx_forum_menu_title_view_entry', 'bx_forum_view', @sName, 9, 0, 1, 'BxForumMenuView', 'modules/boonex/forum/classes/BxForumMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_forum_view', @sName, '_bx_forum_menu_set_title_view_entry', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES
+-- ('bx_forum_view', @sName, 'subscribe-discussion', '_bx_forum_menu_item_title_system_subscribe', '_bx_forum_menu_item_title_subscribe', 'javascript:void(0)', 'bx_conn_action(this, \'bx_forum_subscribers\', \'add\', \'{content_id}\')', '', 'check', '', 0, 2147483647, 1, 0, 1),
+('bx_forum_view', @sName, 'resolve-discussion', '_bx_forum_menu_item_title_system_resolve_entry', '_bx_forum_menu_item_title_resolve_entry', 'javascript:void(0);', '{js_object}.updateStatus(this, \'resolve\', {content_id});', '', 'check-circle', '', 0, 2147483647, 1, 0, 1),
+('bx_forum_view', @sName, 'stick-discussion', '_bx_forum_menu_item_title_system_stick_entry', '_bx_forum_menu_item_title_stick_entry', 'javascript:void(0);', '{js_object}.updateStatus(this, \'stick\', {content_id});', '', 'thumbtack', '', 0, 2147483647, 1, 0, 2),
+('bx_forum_view', @sName, 'lock-discussion', '_bx_forum_menu_item_title_system_lock_entry', '_bx_forum_menu_item_title_lock_entry', 'javascript:void(0);', '{js_object}.updateStatus(this, \'lock\', {content_id});', '', 'lock', '', 0, 2147483647, 1, 0, 3),
+('bx_forum_view', @sName, 'hide-discussion', '_bx_forum_menu_item_title_system_hide_entry', '_bx_forum_menu_item_title_hide_entry', 'javascript:void(0);', '{js_object}.updateStatus(this, \'hide\', {content_id});', '', 'stop-circle', '', 0, 2147483647, 1, 0, 4),
+('bx_forum_view', @sName, 'approve', '_sys_menu_item_title_system_va_approve', '_sys_menu_item_title_va_approve', 'javascript:void(0)', 'javascript:bx_approve(this, ''{module_uri}'', {content_id});', '', 'check', '', 0, 2147483647, 1, 0, 5),
+('bx_forum_view', @sName, 'more', '_bx_forum_menu_item_title_system_more', '_bx_forum_menu_item_title_more', 'javascript:void(0)', 'bx_menu_popup(\'bx_forum_view_more\', this, {}, {id:{content_id}});', '', 'cog', 'bx_forum_view_more', 1, 2147483647, 1, 0, 9999);
+
+-- MENU: view actions more
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_view_more', '_bx_forum_menu_title_view_more', 'bx_forum_view_more', @sName, 6, 0, 1, 'BxForumMenuView', 'modules/boonex/forum/classes/BxForumMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_forum_view_more', @sName, '_bx_forum_menu_set_title_view_more', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+-- ('bx_forum_view_more', @sName, 'unsubscribe-discussion', '_bx_forum_menu_item_title_system_unsubscribe', '_bx_forum_menu_item_title_unsubscribe', 'javascript:void(0)', 'bx_conn_action(this, \'bx_forum_subscribers\', \'remove\', \'{content_id}\')', '', 'check', '', 2147483647, 1, 0, 1),
+('bx_forum_view_more', @sName, 'unresolve-discussion', '_bx_forum_menu_item_title_system_unresolve_entry', '_bx_forum_menu_item_title_unresolve_entry', 'javascript:void(0);', '{js_object}.updateStatus(this, \'unresolve\', {content_id});', '', 'check-circle', '', 2147483647, 1, 0, 1),
+('bx_forum_view_more', @sName, 'unstick-discussion', '_bx_forum_menu_item_title_system_unstick_entry', '_bx_forum_menu_item_title_unstick_entry', 'javascript:void(0);', '{js_object}.updateStatus(this, \'unstick\', {content_id});', '', 'thumbtack', '', 2147483647, 1, 0, 2),
+('bx_forum_view_more', @sName, 'unlock-discussion', '_bx_forum_menu_item_title_system_unlock_entry', '_bx_forum_menu_item_title_unlock_entry', 'javascript:void(0);', '{js_object}.updateStatus(this, \'unlock\', {content_id});', '', 'unlock', '', 2147483647, 1, 0, 3),
+('bx_forum_view_more', @sName, 'unhide-discussion', '_bx_forum_menu_item_title_system_unhide_entry', '_bx_forum_menu_item_title_unhide_entry', 'javascript:void(0);', '{js_object}.updateStatus(this, \'unhide\', {content_id});', '', 'play-circle', '', 2147483647, 1, 0, 4),
+('bx_forum_view_more', @sName, 'edit-discussion', '_bx_forum_menu_item_title_system_edit_entry', '_bx_forum_menu_item_title_edit_entry', 'page.php?i=edit-discussion&id={content_id}', '', '', 'pencil-alt', '', 2147483647, 1, 0, 5),
+('bx_forum_view_more', @sName, 'delete-discussion', '_bx_forum_menu_item_title_system_delete_entry', '_bx_forum_menu_item_title_delete_entry', 'page.php?i=delete-discussion&id={content_id}', '', '', 'remove', '', 2147483647, 1, 0, 6);
+
+-- MENU: all actions menu for view entry 
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_view_actions', '_sys_menu_title_view_actions', 'bx_forum_view_actions', @sName, 15, 0, 1, 'BxForumMenuViewActions', 'modules/boonex/forum/classes/BxForumMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_forum_view_actions', @sName, '_sys_menu_set_title_view_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+-- ('bx_forum_view_actions', @sName, 'subscribe-discussion', '_bx_forum_menu_item_title_system_subscribe', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 10),
+-- ('bx_forum_view_actions', @sName, 'unsubscribe-discussion', '_bx_forum_menu_item_title_system_unsubscribe', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 20),
+('bx_forum_view_actions', @sName, 'resolve-discussion', '_bx_forum_menu_item_title_system_resolve_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 20),
+('bx_forum_view_actions', @sName, 'unresolve-discussion', '_bx_forum_menu_item_title_system_unresolve_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 25),
+('bx_forum_view_actions', @sName, 'stick-discussion', '_bx_forum_menu_item_title_system_stick_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 30),
+('bx_forum_view_actions', @sName, 'unstick-discussion', '_bx_forum_menu_item_title_system_unstick_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 40),
+('bx_forum_view_actions', @sName, 'lock-discussion', '_bx_forum_menu_item_title_system_lock_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 50),
+('bx_forum_view_actions', @sName, 'unlock-discussion', '_bx_forum_menu_item_title_system_unlock_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 60),
+('bx_forum_view_actions', @sName, 'hide-discussion', '_bx_forum_menu_item_title_system_hide_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 70),
+('bx_forum_view_actions', @sName, 'unhide-discussion', '_bx_forum_menu_item_title_system_unhide_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 80),
+('bx_forum_view_actions', @sName, 'edit-discussion', '_bx_forum_menu_item_title_system_edit_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 90),
+('bx_forum_view_actions', @sName, 'delete-discussion', '_bx_forum_menu_item_title_system_delete_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 100),
+('bx_forum_view_actions', @sName, 'approve', '_sys_menu_item_title_system_va_approve', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 100),
+('bx_forum_view_actions', @sName, 'set-badges', '_sys_menu_item_title_system_set_badges', '_sys_menu_item_title_set_badges', 'javascript:void(0)', 'bx_menu_popup(''sys_set_badges'', window, {}, {module: ''bx_forum'', content_id: {content_id}});', '', 'check-circle', '', '', 0, 2147483647, 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:19:"is_badges_avaliable";}', 1, 0, 110),
+('bx_forum_view_actions', @sName, 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 200),
+('bx_forum_view_actions', @sName, 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 210),
+('bx_forum_view_actions', @sName, 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 220),
+('bx_forum_view_actions', @sName, 'reaction', '_sys_menu_item_title_system_va_reaction', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 225),
+('bx_forum_view_actions', @sName, 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 230),
+('bx_forum_view_actions', @sName, 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 240),
+('bx_forum_view_actions', @sName, 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 250),
+('bx_forum_view_actions', @sName, 'repost', '_sys_menu_item_title_system_va_repost', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 260),
+('bx_forum_view_actions', @sName, 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 270),
+('bx_forum_view_actions', @sName, 'notes', '_sys_menu_item_title_system_va_notes', '_sys_menu_item_title_va_notes', 'javascript:void(0)', 'javascript:bx_get_notes(this,  ''{module_uri}'', {content_id});', '', 'exclamation-triangle', '', '', 0, 2147483647, '', 1, 0, 280),
+('bx_forum_view_actions', @sName, 'audit', '_sys_menu_item_title_system_va_audit', '_sys_menu_item_title_va_audit', 'page.php?i=dashboard-audit&module=bx_forum&content_id={content_id}', '', '', 'history', '', '', 0, 192, '', 1, 0, 290),
+('bx_forum_view_actions', @sName, 'social-sharing', '_sys_menu_item_title_system_social_sharing', '_sys_menu_item_title_social_sharing', 'javascript:void(0)', 'oBxDolPage.share(this, \'{url_encoded}\')', '', 'share', '', '', 0, 2147483647, '', 1, 0, 300),
+('bx_forum_view_actions', @sName, 'more-auto', '_sys_menu_item_title_system_va_more_auto', '_sys_menu_item_title_va_more_auto', 'javascript:void(0)', '', '', 'ellipsis-v', '', '', 0, 2147483647, '', 1, 0, 9999);
+
+-- MENU: actions menu for my entries
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_my', '_bx_forum_menu_title_entries_my', 'bx_forum_my', @sName, 9, 0, 1, 'BxForumMenu', 'modules/boonex/forum/classes/BxForumMenu.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_forum_my', @sName, '_bx_forum_menu_set_title_entries_my', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_forum_my', 'bx_forum', 'create-discussion', '_bx_forum_menu_item_title_system_create_entry', '_bx_forum_menu_item_title_create_entry', 'page.php?i=create-discussion', '', '', 'plus', '', 2147483647, 1, 0, 0);
+
+-- MENU: module sub-menu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_submenu', '_bx_forum_menu_title_submenu', 'bx_forum_submenu', @sName, 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_forum_submenu', @sName, '_bx_forum_menu_set_title_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_forum_submenu', @sName, 'discussions-home', '_bx_forum_menu_item_title_system_entries_public', '_bx_forum_menu_item_title_entries_public', 'page.php?i=discussions-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_forum_submenu', @sName, 'discussions-search', '_bx_forum_menu_item_title_system_entries_search', '_bx_forum_menu_item_title_entries_search', 'page.php?i=discussions-search', '', '', '', '', 2147483647, 1, 1, 5),
+('bx_forum_submenu', @sName, 'discussions-manage', '_bx_forum_menu_item_title_system_entries_manage', '_bx_forum_menu_item_title_entries_manage', 'page.php?i=discussions-manage', '', '', '', '', 2147483646, 1, 1, 7);
+
+-- MENU: custom menu for 'main' snippet meta info
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_snippet_meta_main', '_bx_forum_menu_title_snippet_meta_main', 'bx_forum_snippet_meta_main', 'bx_forum', 15, 0, 1, 'BxForumMenuSnippetMeta', 'modules/boonex/forum/classes/BxForumMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_forum_snippet_meta_main', 'bx_forum', '_bx_forum_menu_set_title_snippet_meta_main', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`, `hidden_on_col`) VALUES 
+('bx_forum_snippet_meta_main', 'bx_forum', 'score', '_sys_menu_item_title_system_sm_scores', '_sys_menu_item_title_sm_scores', '', '', '', '', '', 2147483647, 1, 0, 1, 0, 0),
+('bx_forum_snippet_meta_main', 'bx_forum', 'author', '_sys_menu_item_title_system_sm_author', '_sys_menu_item_title_sm_author', '', '', '', '', '', 2147483647, 1, 0, 1, 1, 0),
+('bx_forum_snippet_meta_main', 'bx_forum', 'date', '_sys_menu_item_title_system_sm_date', '_sys_menu_item_title_sm_date', '', '', '', 'clock', '', 2147483647, 1, 0, 1, 2, 0),
+('bx_forum_snippet_meta_main', 'bx_forum', 'category', '_sys_menu_item_title_system_sm_category', '_sys_menu_item_title_sm_category', '', '', '', '', '', 2147483647, 1, 0, 1, 3, 3),
+('bx_forum_snippet_meta_main', 'bx_forum', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', 'comments', '', 2147483647, 1, 0, 1, 4, 3),
+('bx_forum_snippet_meta_main', 'bx_forum', 'status', '_bx_forum_menu_item_title_system_sm_status', '_bx_forum_menu_item_title_sm_status', '', '', '', '', '', 2147483647, 1, 0, 1, 5, 3);
+
+
+-- MENU: custom menu for 'counters' snippet meta info
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_snippet_meta_counters', '_bx_forum_menu_title_snippet_meta_counters', 'bx_forum_snippet_meta_counters', 'bx_forum', 15, 0, 1, 'BxForumMenuSnippetMeta', 'modules/boonex/forum/classes/BxForumMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_forum_snippet_meta_counters', 'bx_forum', '_bx_forum_menu_set_title_snippet_meta_counters', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_forum_snippet_meta_counters', 'bx_forum', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_forum_snippet_meta_counters', 'bx_forum', 'votes', '_sys_menu_item_title_system_sm_votes', '_sys_menu_item_title_sm_votes', '', '', '', '', '', 2147483647, 1, 0, 1, 2),
+('bx_forum_snippet_meta_counters', 'bx_forum', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 2147483647, 1, 0, 1, 3);
+
+-- MENU: custom menu for 'reply' snippet meta info
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_snippet_meta_reply', '_bx_forum_menu_title_snippet_meta_reply', 'bx_forum_snippet_meta_reply', 'bx_forum', 15, 0, 1, 'BxForumMenuSnippetMeta', 'modules/boonex/forum/classes/BxForumMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_forum_snippet_meta_reply', 'bx_forum', '_bx_forum_menu_set_title_snippet_meta_reply', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_forum_snippet_meta_reply', 'bx_forum', 'reply-author', '_sys_menu_item_title_system_sm_author', '_sys_menu_item_title_sm_author', '', '', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_forum_snippet_meta_reply', 'bx_forum', 'reply-date', '_sys_menu_item_title_system_sm_date', '_sys_menu_item_title_sm_date', '', '', '', '', '', 2147483647, 1, 0, 1, 2),
+('bx_forum_snippet_meta_reply', 'bx_forum', 'reply-text', '_bx_forum_menu_item_title_system_sm_reply_text', '_bx_forum_menu_item_title_sm_reply_text', '', '', '', '', '', 2147483647, 1, 0, 1, 3);
+
+
+-- MENU: manage tools submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_menu_manage_tools', '_bx_forum_menu_title_manage_tools', 'bx_forum_menu_manage_tools', 'bx_forum', 6, 0, 1, 'BxForumMenuManageTools', 'modules/boonex/forum/classes/BxForumMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_forum_menu_manage_tools', 'bx_forum', '_bx_forum_menu_set_title_manage_tools', 0);
+
+--INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+--('bx_forum_menu_manage_tools', 'bx_forum', 'delete-with-content', '_bx_forum_menu_item_title_system_delete_with_content', '_bx_forum_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'far trash-alt', '', 128, 1, 0, 0);
+
+-- MENU: profile stats
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES
+('sys_profile_stats', @sName, 'profile-stats-my-forum', '_bx_forum_menu_item_title_system_discussions', '_bx_forum_menu_item_title_discussions', 'page.php?i=discussions-author&profile_id={member_id}', '', '', 'far comments col-blue2', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:19:"get_discussions_num";}', '', 2147483646, 1, 0, 2);
+
+-- MENU: categories
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_forum_categories', '_bx_forum_menu_title_categories', '', 'bx_forum', 21, 0, 1, 'BxForumMenuCategories', 'modules/boonex/forum/classes/BxForumMenuCategories.php');
+
+
+-- MENU: dashboard manage tools
+SET @iManageMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard_manage_tools' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_account_dashboard_manage_tools', @sName, 'discussions-administration', '_bx_forum_menu_item_title_system_admt_discussions', '_bx_forum_menu_item_title_admt_discussions', 'page.php?i=discussions-administration', '', '_self', 'far comments', 'a:2:{s:6:"module";s:8:"bx_forum";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
+
+-- MENU: add menu item to profiles modules (trigger* menu sets are processed separately upon modules enable/disable)
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('trigger_profile_view_submenu', @sName, 'discussions-author', '_bx_forum_menu_item_title_system_view_entries_author', '_bx_forum_menu_item_title_view_entries_author', 'page.php?i=discussions-author&profile_id={profile_id}', '', '', 'far comments col-blue2', '', 2147483647, 1, 0, 0),
+('trigger_group_view_submenu', @sName, 'discussions-context', '_bx_forum_menu_item_title_system_view_entries_in_context', '_bx_forum_menu_item_title_view_entries_in_context', 'page.php?i=discussions-context&profile_id={profile_id}', '', '', 'far comments col-blue2', '', 2147483647, 1, 0, 0);
+
+-- GRIDS: main
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_mode`, `sorting_fields`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+(@sName, 'Sql', 'SELECT `bx_forum_discussions`.*, `bx_forum_cmts`.`cmt_text` AS `cmt_text` %s FROM `bx_forum_discussions` LEFT JOIN `bx_forum_cmts` ON (`bx_forum_cmts`.`cmt_id` = `bx_forum_discussions`.`lr_comment_id`) %s WHERE 1 %s %s', 'bx_forum_discussions', 'id', 'lr_timestamp', '', 10, NULL, 'start', '', 'title,text,text_comments', 'auto', '', 2147483647, 'BxForumGrid', 'modules/boonex/forum/classes/BxForumGrid.php'),
+('bx_forum_favorite', 'Sql', 'SELECT `bx_forum_discussions`.*, `bx_forum_cmts`.`cmt_text` AS `cmt_text` %s FROM `bx_forum_discussions` LEFT JOIN `bx_forum_cmts` ON (`bx_forum_cmts`.`cmt_id` = `bx_forum_discussions`.`lr_comment_id`) %s WHERE 1 %s %s', 'bx_forum_discussions', 'id', 'lr_timestamp', '', 10, NULL, 'start', '', 'title,text,text_comments', 'auto', '', 2147483647, 'BxForumGrid', 'modules/boonex/forum/classes/BxForumGrid.php'),
+('bx_forum_feature', 'Sql', 'SELECT `bx_forum_discussions`.*, `bx_forum_cmts`.`cmt_text` AS `cmt_text` %s FROM `bx_forum_discussions` LEFT JOIN `bx_forum_cmts` ON (`bx_forum_cmts`.`cmt_id` = `bx_forum_discussions`.`lr_comment_id`) %s WHERE 1 %s %s', 'bx_forum_discussions', 'id', 'lr_timestamp', '', 10, NULL, 'start', '', 'title,text,text_comments', 'auto', '', 2147483647, 'BxForumGrid', 'modules/boonex/forum/classes/BxForumGrid.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `params`, `order`) VALUES
+(@sName, 'text', '', '100%', '', 1),
+
+('bx_forum_favorite', 'text', '', '100%', '', 2);
+
+-- GRIDS: moderation tools
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_forum_administration', 'Sql', 'SELECT * FROM `bx_forum_discussions` WHERE 1 ', 'bx_forum_discussions', 'id', 'added', 'status_admin', '', 20, NULL, 'start', '', 'title,text', '', 'like', 'reports', '', 192, 'BxForumGridAdministration', 'modules/boonex/forum/classes/BxForumGridAdministration.php'),
+('bx_forum_common', 'Sql', 'SELECT * FROM `bx_forum_discussions` WHERE 1 ', 'bx_forum_discussions', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'title,text', '', 'like', '', '', 2147483647, 'BxForumGridCommon', 'modules/boonex/forum/classes/BxForumGridCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_forum_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_forum_administration', 'switcher', '_bx_forum_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_forum_administration', 'reports', '_sys_txt_reports_title', '5%', 0, '', '', 3),
+('bx_forum_administration', 'title', '_bx_forum_grid_column_title_adm_title', '25%', 0, '', '', 4),
+('bx_forum_administration', 'added', '_bx_forum_grid_column_title_adm_added', '20%', 1, '25', '', 5),
+('bx_forum_administration', 'author', '_bx_forum_grid_column_title_adm_author', '20%', 0, '25', '', 6),
+('bx_forum_administration', 'actions', '', '20%', 0, '', '', 7),
+
+('bx_forum_common', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_forum_common', 'switcher', '_bx_forum_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_forum_common', 'title', '_bx_forum_grid_column_title_adm_title', '40%', 0, '', '', 3),
+('bx_forum_common', 'added', '_bx_forum_grid_column_title_adm_added', '15%', 1, '25', '', 4),
+('bx_forum_common', 'status_admin', '_bx_forum_grid_column_title_adm_status_admin', '15%', 0, '16', '', 5),
+('bx_forum_common', 'actions', '', '20%', 0, '', '', 6);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_forum_administration', 'bulk', 'delete', '_bx_forum_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_forum_administration', 'bulk', 'clear_reports', '_bx_forum_grid_action_title_adm_clear_reports', '', 0, 1, 2),
+('bx_forum_administration', 'single', 'edit', '_bx_forum_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_forum_administration', 'single', 'delete', '_bx_forum_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_forum_administration', 'single', 'settings', '_bx_forum_grid_action_title_adm_more_actions', 'cog', 1, 0, 3),
+('bx_forum_administration', 'single', 'audit_content', '_bx_forum_grid_action_title_adm_audit_content', 'search', 1, 0, 4),
+('bx_forum_administration', 'single', 'clear_reports', '_bx_forum_grid_action_title_adm_clear_reports', 'eraser', 1, 0, 5),
+
+('bx_forum_common', 'bulk', 'delete', '_bx_forum_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_forum_common', 'single', 'edit', '_bx_forum_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_forum_common', 'single', 'delete', '_bx_forum_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_forum_common', 'single', 'settings', '_bx_forum_grid_action_title_adm_more_actions', 'cog', 1, 0, 3);
+
+-- GRIDS: categories manager
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_mode`, `sorting_fields`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_forum_categories', 'Array', '', '', 'category', '', '', 10, NULL, 'start', '', 'title', 'auto', '', 128, 'BxForumGridCategories', 'modules/boonex/forum/classes/BxForumGridCategories.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `params`, `order`) VALUES
+('bx_forum_categories', 'icon', '_bx_forum_grid_column_title_icon', '10%', '', 1),
+('bx_forum_categories', 'title', '_bx_forum_grid_column_title_title', '50%', '', 2),
+('bx_forum_categories', 'visible_for_levels', '_bx_forum_grid_column_title_visible_for_levels', '20%', '', 3),
+('bx_forum_categories', 'actions', '', '20%', '', 4);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_forum_categories', 'single', 'show_to', '_bx_forum_grid_action_title_show_to', '', 0, 1),
+('bx_forum_categories', 'single', 'edit', '_bx_forum_grid_action_title_adm_edit', 'pencil-alt', 0, 2);
+
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'create entry', NULL, '_bx_forum_acl_action_create_entry', '', 1, 3);
+SET @iIdActionEntryCreate = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'delete entry', NULL, '_bx_forum_acl_action_delete_entry', '', 1, 3);
+SET @iIdActionEntryDelete = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'view entry', NULL, '_bx_forum_acl_action_view_entry', '', 1, 0);
+SET @iIdActionEntryView = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'set thumb', NULL, '_bx_forum_acl_action_set_thumb', '', 1, 3);
+SET @iIdActionSetThumb = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'edit any entry', NULL, '_bx_forum_acl_action_edit_any_entry', '', 1, 3);
+SET @iIdActionEntryEditAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'delete any entry', NULL, '_bx_forum_acl_action_delete_any_entry', '', 1, 3);
+SET @iIdActionEntryDeleteAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'stick any entry', NULL, '_bx_forum_acl_action_stick_any_entry', '', 1, 3);
+SET @iIdActionEntryStickAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'lock any entry', NULL, '_bx_forum_acl_action_lock_any_entry', '', 1, 3);
+SET @iIdActionEntryLockAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'hide any entry', NULL, '_bx_forum_acl_action_hide_any_entry', '', 1, 3);
+SET @iIdActionEntryHideAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'resolve any entry', NULL, '_bx_forum_acl_action_resolve_any_entry', '', 1, 3);
+SET @iIdActionEntryResolveAny = LAST_INSERT_ID();
+
+SET @iUnauthenticated = 1;
+SET @iAccount = 2;
+SET @iStandard = 3;
+SET @iUnconfirmed = 4;
+SET @iPending = 5;
+SET @iSuspended = 6;
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+
+-- entry create
+(@iStandard, @iIdActionEntryCreate),
+(@iModerator, @iIdActionEntryCreate),
+(@iAdministrator, @iIdActionEntryCreate),
+(@iPremium, @iIdActionEntryCreate),
+
+-- entry delete
+(@iStandard, @iIdActionEntryDelete),
+(@iModerator, @iIdActionEntryDelete),
+(@iAdministrator, @iIdActionEntryDelete),
+(@iPremium, @iIdActionEntryDelete),
+
+-- entry view
+(@iUnauthenticated, @iIdActionEntryView),
+(@iAccount, @iIdActionEntryView),
+(@iStandard, @iIdActionEntryView),
+(@iUnconfirmed, @iIdActionEntryView),
+(@iPending, @iIdActionEntryView),
+(@iModerator, @iIdActionEntryView),
+(@iAdministrator, @iIdActionEntryView),
+(@iPremium, @iIdActionEntryView),
+
+-- set entry thumb
+(@iStandard, @iIdActionSetThumb),
+(@iModerator, @iIdActionSetThumb),
+(@iAdministrator, @iIdActionSetThumb),
+(@iPremium, @iIdActionSetThumb),
+
+-- edit any entry
+(@iModerator, @iIdActionEntryEditAny),
+(@iAdministrator, @iIdActionEntryEditAny),
+
+-- delete any entry
+(@iAdministrator, @iIdActionEntryDeleteAny),
+
+-- stick any entry
+(@iModerator, @iIdActionEntryStickAny),
+(@iAdministrator, @iIdActionEntryStickAny),
+
+-- lock any entry
+(@iModerator, @iIdActionEntryLockAny),
+(@iAdministrator, @iIdActionEntryLockAny),
+
+-- hide any entry
+(@iModerator, @iIdActionEntryHideAny),
+(@iAdministrator, @iIdActionEntryHideAny),
+
+-- resolve any entry
+(@iModerator, @iIdActionEntryResolveAny),
+(@iAdministrator, @iIdActionEntryResolveAny);
+
+
+-- PRIVACY 
+INSERT INTO `sys_objects_privacy` (`object`, `module`, `action`, `title`, `default_group`, `table`, `table_field_id`, `table_field_author`, `override_class_name`, `override_class_file`) VALUES
+('bx_forum_allow_view_to', @sName, 'view', '_bx_forum_form_entry_input_allow_view_to', '3', 'bx_forum_discussions', 'id', 'author', '', ''),
+('bx_forum_allow_view_favorite_list', @sName, 'view_favorite_list', '_bx_forum_form_entry_input_allow_view_favorite_list', '3', 'bx_forum_favorites_lists', 'id', 'author_id', '', '');
+
+
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+(@sName, '_bx_forum', @iSearchOrder + 1, 'BxForumSearchResult', 'modules/boonex/forum/classes/BxForumSearchResult.php'),
+('bx_forum_cmts', '_bx_forum_cmts', @iSearchOrder + 2, 'BxForumCmtsSearchResult', 'modules/boonex/forum/classes/BxForumCmtsSearchResult.php');
+
+
+-- CONNECTIONS
+INSERT INTO `sys_objects_connection` (`object`, `table`, `profile_initiator`, `profile_content`, `type`, `override_class_name`, `override_class_file`) VALUES
+('bx_forum_subscribers', 'bx_forum_subscribers', 1, 0, 'one-way', '', '');
+
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `module`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+(@sName, @sName, 'bx_forum_meta_keywords', '', 'bx_forum_meta_mentions', 'BxForumMetatags', 'modules/boonex/forum/classes/BxForumMetatags.php');
+
+
+-- CATEGORY
+INSERT INTO `sys_objects_category` (`object`, `module`, `search_object`, `form_object`, `list_name`, `table`, `field`, `join`, `where`, `override_class_name`, `override_class_file`) VALUES
+('bx_forum_cats', @sName, @sName, @sName, 'bx_forum_cats', 'bx_forum_discussions', 'cat', 'INNER JOIN `sys_profiles` ON (`sys_profiles`.`id` = ABS(`bx_forum_discussions`.`author`))', 'AND `sys_profiles`.`status` = ''active''', 'BxForumCategory', 'modules/boonex/forum/classes/BxForumCategory.php');
+
+
+-- STATS
+SET @iMaxOrderStats = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_statistics`);
+INSERT INTO `sys_statistics` (`module`, `name`, `title`, `link`, `icon`, `query`, `order`) VALUES 
+(@sName, @sName, '_bx_forum', 'page.php?i=discussions-home', 'far comments col-blue2', 'SELECT COUNT(*) FROM `bx_forum_discussions` WHERE 1 AND `status` = ''active'' AND `status_admin` = ''active''', @iMaxOrderStats + 1);
+
+
+-- CHARTS
+SET @iMaxOrderCharts = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_objects_chart`);
+INSERT INTO `sys_objects_chart` (`object`, `title`, `table`, `field_date_ts`, `field_date_dt`, `field_status`, `query`, `active`, `order`, `class_name`, `class_file`) VALUES
+('bx_forum_growth', '_bx_forum_chart_growth', 'bx_forum_discussions', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 1, 'BxDolChartGrowth', ''),
+('bx_forum_growth_speed', '_bx_forum_chart_growth_speed', 'bx_forum_discussions', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 2, 'BxDolChartGrowthSpeed', '');
+
+
+-- UPLOADERS
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_forum_simple', 1, 'BxForumUploaderSimple', 'modules/boonex/forum/classes/BxForumUploaderSimple.php'),
+('bx_forum_html5', 1, 'BxForumUploaderHTML5', 'modules/boonex/forum/classes/BxForumUploaderHTML5.php'),
+('bx_forum_record_video', 1, 'BxForumUploaderRecordVideo', 'modules/boonex/forum/classes/BxForumUploaderRecordVideo.php'),
+('bx_forum_photos_simple', 1, 'BxForumUploaderSimpleAttach', 'modules/boonex/forum/classes/BxForumUploaderSimpleAttach.php'),
+('bx_forum_photos_html5', 1, 'BxForumUploaderHTML5Attach', 'modules/boonex/forum/classes/BxForumUploaderHTML5Attach.php'),
+('bx_forum_videos_simple', 1, 'BxForumUploaderSimpleAttach', 'modules/boonex/forum/classes/BxForumUploaderSimpleAttach.php'),
+('bx_forum_videos_html5', 1, 'BxForumUploaderHTML5Attach', 'modules/boonex/forum/classes/BxForumUploaderHTML5Attach.php'),
+('bx_forum_videos_record_video', 1, 'BxForumUploaderRecordVideoAttach', 'modules/boonex/forum/classes/BxForumUploaderRecordVideoAttach.php'),
+('bx_forum_files_simple', 1, 'BxForumUploaderSimpleAttach', 'modules/boonex/forum/classes/BxForumUploaderSimpleAttach.php'),
+('bx_forum_files_html5', 1, 'BxForumUploaderHTML5Attach', 'modules/boonex/forum/classes/BxForumUploaderHTML5Attach.php');
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+(@sName, 'BxForumAlertsResponse', 'modules/boonex/forum/classes/BxForumAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('profile', 'delete', @iHandler),
+(@sName, 'commentPost', @iHandler),
+(@sName, 'commentUpdated', @iHandler),
+(@sName, 'commentRemoved', @iHandler),
+('bx_forum_files_cmts', 'file_deleted', @iHandler);
+
+
+-- EMAIL TEMPLATES
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES
+(@sName, '_bx_forum_email_new_reply', 'bx_forum_new_reply', '_bx_forum_email_new_reply_subject', '_bx_forum_email_new_reply_body');

+ 54 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/js/carusel.js

@@ -0,0 +1,54 @@
+function initUnaca(){
+     $(".unaca").each(function() {
+        var maxHeight = Math.max.apply(null, $(this).find(".unaca-t > div").map(function () {
+            return $(this).height();
+        }).get());
+        $(this).find(".unaca-t > div").height(maxHeight);
+         
+        checkUnaca($(this));
+         
+    });
+}
+function checkUnaca(unaca){
+    if (unaca.find('.unaca-t > div').last().offset().left < unaca.find('.unaca-t').parent().offset().left + unaca.find('.unaca-t').parent().width())
+        unaca.find('.unaca-c-f').hide();
+    else
+        unaca.find('.unaca-c-f').show();
+
+    if (unaca.find('.unaca-t > div').first().offset().left > 0 )
+
+        unaca.find('.unaca-c-b').hide();
+    else
+        unaca.find('.unaca-c-b').show();
+    
+}
+
+$( window ).resize(function() {
+    initUnaca();
+})    
+$(document).ready(function () {
+    initUnaca();
+    
+    $( ".unaca-c " ).click(function(evt) {
+        
+        var unaca = $(evt.target).parents('.unaca');
+        
+        var i = new Number(unaca.attr('data-slide')); 
+        if ($(evt.target).hasClass('unaca-c-f'))
+            i =  i + 1;
+        else
+            i =  i - 1;
+        
+        unaca.find('.unaca-t').css('transform', 'translateX(-' + (i-1)*100 + '%)'); 
+        
+        setTimeout(function() { 
+            
+            checkUnaca(unaca);
+
+            unaca.find(".unaca-c-f" ).attr('for', 'unaca-a-'+ (i+1));
+            unaca.find(".unaca-c-b" ).attr('for', 'unaca-a-'+ (i-1))
+
+            unaca.find(".unaca-a-n" ).parents('.unaca').attr('data-slide', i);   
+        },400); 
+    }); 
+});

+ 12 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/template/comment_attachments.html

@@ -0,0 +1,12 @@
+<bx_repeat:attached>
+    <div class="__style_prefix__-attached-preview bx-forum-attached-preview bx-def-round-corners bx-def-padding-thd">
+        <bx_if:show_image>
+            <a href="javascript:void(0)" onclick="__js_object__.showImage(event || window.event, this)" data-file-id="__file_id__" data-src="__file__" data-w="__w__" data-h="__h__" title="<bx_text_attribute:_cmt_view_attached_image />">
+                <img class="bg-cover" src="<bx_image_url:spacer.gif />" style="background-image:url(__preview__)" /> __file_name__ <span class="bx-def-font-grayed">__file_size__</span>
+            </a>
+        </bx_if:show_image>
+        <bx_if:show_file>
+            <a href="__file__" title="<bx_text_attribute:_cmt_download_attached_file />"><i class="sys-icon __file_icon__"></i> __file_name__ <span class="bx-def-font-grayed">__file_size__</span></a>
+        </bx_if:show_file>
+    </div>
+</bx_repeat:attached>

+ 115 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/template/css/carusel.css

@@ -0,0 +1,115 @@
+.unaca {
+  margin-left: auto;
+  margin-right: auto;
+  position: relative;
+}
+
+.unaca-a {
+  display: none;
+}
+
+.unaca-cc {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+}
+.unaca-c-b{
+    position: absolute;
+    top: calc(50% - 30px);
+    left:-1rem;
+}
+.unaca-c-f{
+    position: absolute;
+    top: calc(50% - 30px);
+    right:-1rem;
+}
+
+.unaca-c {
+  justify-content: center;
+  transition: 0.3s all;
+    
+  z-index: 1;
+}
+      
+.unaca-c label{
+    height: 48px;
+    width: 48px;
+    display: block;
+    z-index: 100;
+    position: absolute;
+    top:0px;
+    left:0px;
+     cursor: pointer;
+}
+.unaca-c svg{
+    position: absolute;
+    top:0px;
+    left:0px;
+}
+
+.unaca-s {
+    overflow: hidden;
+    width: calc(100% + 1rem);
+    margin-left: -0.5rem;
+    margin-right: -0.5rem;
+}
+
+.unaca-t {
+    font-size: 0;
+     margin-bottom: 0px !important;
+    transition: all 0.3s ease 0s;
+    white-space: nowrap;
+    -webkit-overflow-scrolling: touch;
+    overflow: visible !important;
+    scroll-behavior: smooth;
+    scroll-snap-type: x var(--tw-scroll-snap-strictness);
+    text-align: left !important;
+}
+
+.unaca-t > div {
+    display: inline-flex !important;
+    vertical-align: top !important;
+    white-space: normal !important;
+    width: 25% !important;
+    scroll-snap-align: center;
+}
+.bx-layout-column-wide .unaca-t > div {
+     width: 33.3% !important;
+}
+
+.bx-layout-column-thin .unaca-t > div {
+     width: 100% !important;
+}
+
+.bx-layout-column-half .unaca-t > div {
+     width: 50% !important;
+}
+
+.unaca-t .bx-base-text-unit-showcase {
+    margin: 0;
+    padding: 0.5rem;
+}
+
+.bx-media-phone .unaca-cc {
+    display: none;
+}
+
+.bx-media-phone .unaca-t {
+    overflow-x: auto !important;
+    width: auto;
+}
+.bx-media-phone .unaca-t > div {
+    width: 100% !important;
+}
+
+.bx-media-tablet .unaca-cc {
+    display: none;
+}
+
+.bx-media-tablet .unaca-t {
+    overflow-x: auto !important;
+    width: auto;
+}
+.bx-media-tablet .unaca-t > div {
+    width: 50% !important;
+}

+ 3 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/template/entry-preview-private.html

@@ -0,0 +1,3 @@
+<div class="group flex items-center h-20 hover:bg-gray-50 dark:hover:bg-gray-700/20">
+    <div class="flex flex-wrap p-4 font-semibold text-lg text-gray-400 group-hover:text-gray-600 dark:text-gray-500 dark:group-hover:text-gray-300"><bx_text:_sys_private /></div>
+</div>

+ 27 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/template/unaca.html

@@ -0,0 +1,27 @@
+<div class='unaca' data-slide='1'>
+    <input checked='checked' class='unaca-a unaca-a-p' id='unaca-a-1' name='unaca1' type='radio'>
+    <input  class='unaca-a unaca-a-m' id='unaca-a-2' name='unaca1' type='radio'>
+    <input  class='unaca-a unaca-a-n' id='unaca-a-3' name='unaca1' type='radio'>
+    <input  class='unaca-a unaca-a-n' id='unaca-a-4' name='unaca1' type='radio'>
+    <input  class='unaca-a unaca-a-n' id='unaca-a-5' name='unaca1' type='radio'>
+    <input  class='unaca-a unaca-a-n' id='unaca-a-6' name='unaca1' type='radio'>
+    <input  class='unaca-a unaca-a-n' id='unaca-a-7' name='unaca1' type='radio'>
+    <input  class='unaca-a unaca-a-n' id='unaca-a-8' name='unaca1' type='radio'>
+    <input  class='unaca-a unaca-a-n' id='unaca-a-9' name='unaca1' type='radio'>
+    <input  class='unaca-a unaca-a-n' id='unaca-a-10' name='unaca1' type='radio'>
+    <div class='unaca-cc'>
+        <div class='unaca-c unaca-c-b border h-10 w-10 bg-gray-100 active:bg-gray-300 hover:bg-white dark:bg-gray-700 dark:hover:bg-gray-700/50 dark:active:bg-gray-800 rounded-full border-gray-300 active:border-gray-400 dark:border-gray-600 dark:active:border-gray-700 text-gray-600 hover:text-gray-900 active:text-gray-900 dark:text-gray-300 dark:hover:text-white dark:active:text-gray-200'>
+            <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='currentColor'>
+                <path fill-rule='evenodd' d='M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z' clip-rule='evenodd' />
+            </svg>
+            <label class='unaca-c-b' for='unaca-a-1' style='display: none;'></label>
+        </div>
+        <div class='unaca-c unaca-c-f border h-10 w-10 bg-gray-100 active:bg-gray-300 hover:bg-white dark:bg-gray-700 dark:hover:bg-gray-700/50 dark:active:bg-gray-800 rounded-full border-gray-300 active:border-gray-400 dark:border-gray-600 dark:active:border-gray-700 text-gray-600 hover:text-gray-900 active:text-gray-900 dark:text-gray-300 dark:hover:text-white dark:active:text-gray-200'>
+            <svg xmlns='http://www.w3.org/2000/svg'  viewBox='0 0 20 20' fill='currentColor'>
+                <path fill-rule='evenodd' d='M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z' clip-rule='evenodd' />
+            </svg>
+            <label for='unaca-a-2' class='unaca-c-f'></label>
+        </div>          
+    </div>
+    <div class='unaca-s'>__content__</div>
+</div>

+ 30 - 0
modules/boonex/forum/updates/13.0.5_13.0.6/source/template/unit_gallery.html

@@ -0,0 +1,30 @@
+<div onclick="location.href='__content_url__'" class="__class__ bx-base-text-unit bx-forum-unit bx-base-text-unit-gallery bx-def-gal-unit-size flex flex-col w-full p-2 box-border relative inline-block cursor-pointer">
+    <div class="bg-white dark:bg-gray-800 shadow ring-1 ring-gray-300 dark:ring-gray-700 rounded-md xl:mx-auto h-full">
+        <div class="h-full space-y-4 p-1 pb-4 flex flex-col justify-between">
+            <bx_if:thumb>
+                <a href="__content_url__" title="__summary_attr__">
+                    <img class="flex grow-0 w-full aspect-video overflow-y-auto align-top  object-cover rounded" src="__gallery_url__" alt="">
+                </a>  
+            </bx_if:thumb>
+            <div class="grow-none px-3 mt-4 text-lg leading-tight font-semibold text-gray-700 group-hover:text-gray-900 dark:text-gray-200 dark:group-hover:text-white">
+                <a href="__content_url__" title="__summary_attr__" class=" text-lg leading-tight font-semibold text-gray-600 group-hover:text-gray-900 dark:text-gray-300 dark:group-hover:text-white">__title__</a>
+            </div>               
+            <bx_if:no_thumb>  
+                <div class="grow relative rounded w-full max-w-full sm:aspect-video overflow-hidden font-normal text-sm  text-gray-500 group-hover:text-gray-600 dark:text-gray-400 dark:group-hover:text-gray-300">
+                    <div class="absolute top-auto bottom-0  w-full h-1/4 bg-gradient-to-b from-white/0 to-white dark:from-gray-900/0 dark:to-gray-800"></div>
+                    <div class=" px-3">__summary_plain__</div>
+                </div>
+            </bx_if:no_thumb>
+            <div class="px-3">
+                __badges__
+            </div>
+            <bx_if:meta>
+                <div class="bx-base-general-unit-meta flex grow-0 px-3">
+                    <div class="inline-flex flex-wrap text-xs font-medium">
+                        __meta__
+                    </div>
+                </div>
+            </bx_if:meta>
+        </div>
+    </div>
+</div>

+ 51 - 0
modules/boonex/groups/updates/13.0.3_13.0.4/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Groups',
+    'version_from' => '13.0.3',
+    'version_to' => '13.0.4',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/groups/updates/update_13.0.3_13.0.4/',
+    'home_uri' => 'groups_update_1303_1304',
+
+    'module_dir' => 'boonex/groups/',
+    'module_uri' => 'groups',
+
+    'db_prefix' => 'bx_groups_',
+    'class_prefix' => 'BxGroups',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Groups',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/groups/updates/13.0.3_13.0.4/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxGroupsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 8 - 0
modules/boonex/groups/updates/13.0.3_13.0.4/install/sql/enable.sql

@@ -0,0 +1,8 @@
+-- MENUS
+UPDATE `sys_menu_items` SET `active`='0' WHERE `set_name`='bx_groups_menu_manage_tools' AND `name`='delete-with-content';
+
+
+-- GRIDS
+UPDATE `sys_grid_actions` SET `active`='0' WHERE `object`='bx_groups_administration' AND `type`='bulk' AND `name`='delete_with_content';
+
+UPDATE `sys_grid_actions` SET `active`='0' WHERE `object`='bx_groups_common' AND `type`='bulk' AND `name`='delete_with_content';

+ 152 - 0
modules/boonex/groups/updates/13.0.3_13.0.4/source/install/config.php

@@ -0,0 +1,152 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Groups Groups
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_groups',
+    'title' => 'Groups',
+    'note' => 'Basic group profiles functionality.',
+    'version' => '13.0.4',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/groups/',
+    'home_uri' => 'groups',
+
+    'db_prefix' => 'bx_groups_',
+    'class_prefix' => 'BxGroups',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Groups',
+
+    /**
+     * Connections.
+     */
+    'connections' => array(
+    	'sys_profiles_friends' => array ('type' => 'profiles'),
+		'sys_profiles_subscriptions' => array ('type' => 'profiles'),
+    ),
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+    	'trigger_profile_view_submenu',
+        'trigger_group_view_submenu',
+        'trigger_group_snippet_meta',
+        'trigger_group_view_actions',
+    ),
+
+    /**
+     * Page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_group_view_entry', 
+    ),
+
+	/**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_groups_pics'
+    ),
+
+	/**
+     * Transcoders.
+     */
+    'transcoders' => array(
+    	'bx_groups_icon', 
+    	'bx_groups_thumb', 
+    	'bx_groups_avatar', 
+        'bx_groups_avatar_big', 
+    	'bx_groups_picture', 
+    	'bx_groups_cover', 
+    	'bx_groups_cover_thumb',
+        'bx_groups_gallery'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_groups',
+    	'bx_groups_cmts',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'process_connections' => 1,
+        'process_deleted_profiles' => 1,
+    	'update_relations' => 1,        
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+    	'process_menu_triggers' => 1,
+    	'process_page_triggers' => 1,
+    	'process_esearches' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'unregister_transcoders' => 1,
+        'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Connections Section
+     */
+    'relations' => array(
+        'bx_timeline',
+        'bx_notifications',
+    ),
+);
+
+/** @} */

Некоторые файлы не были показаны из-за большого количества измененных файлов