فهرست منبع

Modules updates.

AntonLV 2 سال پیش
والد
کامیت
d34e672b8e
100فایلهای تغییر یافته به همراه16411 افزوده شده و 0 حذف شده
  1. 51 0
      modules/boonex/accounts/updates/14.0.1_14.0.2/install/config.php
  2. 13 0
      modules/boonex/accounts/updates/14.0.1_14.0.2/install/installer.php
  3. 5 0
      modules/boonex/accounts/updates/14.0.1_14.0.2/install/sql/enable.sql
  4. 787 0
      modules/boonex/accounts/updates/14.0.1_14.0.2/source/classes/BxAccntGridAdministration.php
  5. 71 0
      modules/boonex/accounts/updates/14.0.1_14.0.2/source/install/config.php
  6. 114 0
      modules/boonex/accounts/updates/14.0.1_14.0.2/source/install/sql/enable.sql
  7. 51 0
      modules/boonex/albums/updates/14.0.3_14.0.4/install/config.php
  8. 13 0
      modules/boonex/albums/updates/14.0.3_14.0.4/install/installer.php
  9. 1063 0
      modules/boonex/albums/updates/14.0.3_14.0.4/source/classes/BxAlbumsModule.php
  10. 143 0
      modules/boonex/albums/updates/14.0.3_14.0.4/source/install/config.php
  11. 250 0
      modules/boonex/albums/updates/14.0.3_14.0.4/source/template/css/main.css
  12. 20 0
      modules/boonex/albums/updates/14.0.3_14.0.4/source/template/media-edit.html
  13. 51 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/install/config.php
  14. 26 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/install/installer.php
  15. 4 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/install/langs/en.xml
  16. 8 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/install/sql/enable.sql
  17. 9 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/install/sql/install.sql
  18. 172 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/classes/BxArtificerAlertsResponse.php
  19. 143 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/classes/BxArtificerConfig.php
  20. 137 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/mod_text/css/main.css
  21. 14 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/block_join.html
  22. 34 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/block_login.html
  23. 64 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/css/cover.css
  24. 391 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/css/forms.css
  25. 254 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/css/general.css
  26. 224 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/css/menu.css
  27. 9 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/logo_main.html
  28. 120 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/pt_application.html
  29. 302 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/scripts/BxTemplFunctions.php
  30. 75 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/scripts/BxTemplMenuSidebarSite.php
  31. 82 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/scripts/BxTemplMenuToolbar.php
  32. 68 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/install/config.php
  33. 57 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/install/langs/en.xml
  34. 6 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/install/sql/enable.sql
  35. 61 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/install/sql/install.sql
  36. 173 0
      modules/boonex/artificer/updates/14.0.4_14.0.5/source/js/utils.js
  37. 51 0
      modules/boonex/channels/updates/14.0.3_14.0.4/install/config.php
  38. 29 0
      modules/boonex/channels/updates/14.0.3_14.0.4/install/installer.php
  39. 12 0
      modules/boonex/channels/updates/14.0.3_14.0.4/install/langs/en.xml
  40. 18 0
      modules/boonex/channels/updates/14.0.3_14.0.4/install/sql/enable.sql
  41. 1 0
      modules/boonex/channels/updates/14.0.3_14.0.4/install/sql/install.sql
  42. 194 0
      modules/boonex/channels/updates/14.0.3_14.0.4/source/classes/BxCnlConfig.php
  43. 145 0
      modules/boonex/channels/updates/14.0.3_14.0.4/source/classes/BxCnlDb.php
  44. 663 0
      modules/boonex/channels/updates/14.0.3_14.0.4/source/classes/BxCnlModule.php
  45. 303 0
      modules/boonex/channels/updates/14.0.3_14.0.4/source/classes/BxCnlSearchResult.php
  46. 153 0
      modules/boonex/channels/updates/14.0.3_14.0.4/source/install/config.php
  47. 259 0
      modules/boonex/channels/updates/14.0.3_14.0.4/source/install/langs/en.xml
  48. 422 0
      modules/boonex/channels/updates/14.0.3_14.0.4/source/install/sql/enable.sql
  49. 343 0
      modules/boonex/channels/updates/14.0.3_14.0.4/source/install/sql/install.sql
  50. 51 0
      modules/boonex/classes/updates/14.0.0_14.0.1/install/config.php
  51. 13 0
      modules/boonex/classes/updates/14.0.0_14.0.1/install/installer.php
  52. 152 0
      modules/boonex/classes/updates/14.0.0_14.0.1/source/install/config.php
  53. 47 0
      modules/boonex/classes/updates/14.0.0_14.0.1/source/template/classes_in_context.html
  54. 59 0
      modules/boonex/classes/updates/14.0.0_14.0.1/source/template/css/main.css
  55. 51 0
      modules/boonex/convos/updates/14.0.1_14.0.2/install/config.php
  56. 13 0
      modules/boonex/convos/updates/14.0.1_14.0.2/install/installer.php
  57. 134 0
      modules/boonex/convos/updates/14.0.1_14.0.2/source/classes/BxCnvCmts.php
  58. 104 0
      modules/boonex/convos/updates/14.0.1_14.0.2/source/install/config.php
  59. 51 0
      modules/boonex/courses/updates/14.0.1_14.0.2/install/config.php
  60. 13 0
      modules/boonex/courses/updates/14.0.1_14.0.2/install/installer.php
  61. 284 0
      modules/boonex/courses/updates/14.0.1_14.0.2/source/classes/BxCoursesConfig.php
  62. 152 0
      modules/boonex/courses/updates/14.0.1_14.0.2/source/install/config.php
  63. 51 0
      modules/boonex/credits/updates/14.0.2_14.0.3/install/config.php
  64. 13 0
      modules/boonex/credits/updates/14.0.2_14.0.3/install/installer.php
  65. 59 0
      modules/boonex/credits/updates/14.0.2_14.0.3/install/langs/en.xml
  66. 70 0
      modules/boonex/credits/updates/14.0.2_14.0.3/install/sql/enable.sql
  67. 19 0
      modules/boonex/credits/updates/14.0.2_14.0.3/install/sql/install.sql
  68. 339 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsConfig.php
  69. 448 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsDb.php
  70. 114 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsGrid.php
  71. 114 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsGridHistoryAdministration.php
  72. 39 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsGridHistoryCommon.php
  73. 67 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsGridOrdersAdministration.php
  74. 104 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsGridWithdrawalsAdministration.php
  75. 73 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsGridWithdrawalsCommon.php
  76. 42 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsMenuManage.php
  77. 1471 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsModule.php
  78. 34 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsPageWithdrawals.php
  79. 77 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/install/config.php
  80. 344 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/install/langs/en.xml
  81. 32 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/install/sql/disable.sql
  82. 293 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/install/sql/enable.sql
  83. 213 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/install/sql/install.sql
  84. 16 0
      modules/boonex/credits/updates/14.0.2_14.0.3/source/install/sql/uninstall.sql
  85. 51 0
      modules/boonex/developer/updates/14.0.2_14.0.3/install/config.php
  86. 13 0
      modules/boonex/developer/updates/14.0.2_14.0.3/install/installer.php
  87. 5 0
      modules/boonex/developer/updates/14.0.2_14.0.3/install/sql/install.sql
  88. 69 0
      modules/boonex/developer/updates/14.0.2_14.0.3/source/install/config.php
  89. 730 0
      modules/boonex/developer/updates/14.0.2_14.0.3/source/install/sql/install.sql
  90. 27 0
      modules/boonex/developer/updates/14.0.2_14.0.3/source/template/images/icons/std-icon.svg
  91. 51 0
      modules/boonex/events/updates/14.0.4_14.0.5/install/config.php
  92. 13 0
      modules/boonex/events/updates/14.0.4_14.0.5/install/installer.php
  93. 5 0
      modules/boonex/events/updates/14.0.4_14.0.5/install/sql/enable.sql
  94. 338 0
      modules/boonex/events/updates/14.0.4_14.0.5/source/classes/BxEventsConfig.php
  95. 350 0
      modules/boonex/events/updates/14.0.4_14.0.5/source/classes/BxEventsFormEntry.php
  96. 934 0
      modules/boonex/events/updates/14.0.4_14.0.5/source/classes/BxEventsModule.php
  97. 152 0
      modules/boonex/events/updates/14.0.4_14.0.5/source/install/config.php
  98. 796 0
      modules/boonex/events/updates/14.0.4_14.0.5/source/install/sql/enable.sql
  99. 12 0
      modules/boonex/events/updates/14.0.4_14.0.5/source/template/timeline_post.html
  100. 51 0
      modules/boonex/forum/updates/14.0.2_14.0.3/install/config.php

+ 51 - 0
modules/boonex/accounts/updates/14.0.1_14.0.2/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' => 'Accounts Manager',
+    'version_from' => '14.0.1',
+    'version_to' => '14.0.2',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/accounts/updates/update_14.0.1_14.0.2/',
+    'home_uri' => 'accounts_update_1401_1402',
+
+    'module_dir' => 'boonex/accounts/',
+    'module_uri' => 'accounts',
+
+    'db_prefix' => 'bx_accnt_',
+    'class_prefix' => 'BxAccnt',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Accounts',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/accounts/updates/14.0.1_14.0.2/install/installer.php

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

+ 5 - 0
modules/boonex/accounts/updates/14.0.1_14.0.2/install/sql/enable.sql

@@ -0,0 +1,5 @@
+SET @sName = 'bx_accounts';
+
+
+-- GRIDS
+UPDATE `sys_objects_grid` SET `source`='SELECT `ta`.*, `tp`.`status` AS `status`, `ta`.`active`, `ts`.`date` AS `last_active` FROM `sys_accounts` AS `ta` LEFT JOIN `sys_sessions` AS `ts` ON `ta`.`id`=`ts`.`user_id` LEFT JOIN `sys_profiles` AS `tp` ON `ta`.`id`=`tp`.`account_id` AND `tp`.`type`=''system'' WHERE 1 ', `sorting_fields`='email_confirmed,logged,last_active,added' WHERE `object`='bx_accounts_administration';

+ 787 - 0
modules/boonex/accounts/updates/14.0.1_14.0.2/source/classes/BxAccntGridAdministration.php

@@ -0,0 +1,787 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Accounts Accounts
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+class BxAccntGridAdministration extends BxBaseModProfileGridAdministration
+{
+    protected $_sFilter2Name;
+	protected $_sFilter2Value;
+	protected $_aFilter2Values;
+    
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_accounts';
+        parent::__construct ($aOptions, $oTemplate);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+        $this->_aFilter1Values = array_merge($this->_aFilter1Values, array(
+            'unconfirmed' => $CNF['T']['filter_item_unconfirmed'],
+            'locked' => $CNF['T']['filter_item_locked'],
+            'without_profile' => $CNF['T']['filter_item_without_profile'],
+        ));
+
+        $this->_sFilter2Name = 'filter2';
+        $this->_aFilter2Values = array(
+            'operators' => $CNF['T']['filter_item_operators']
+        );
+
+        $sFilter2 = bx_get($this->_sFilter2Name);
+        if(!empty($sFilter2)) {
+            $this->_sFilter2Value = bx_process_input($sFilter2);
+            $this->_aQueryAppend[$this->_sFilter2Name] = $this->_sFilter2Value;
+        }
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        if(strpos($sFilter, $this->_sParamsDivider) !== false)
+            list($this->_sFilter1Value, $this->_sFilter2Value, $sFilter) = explode($this->_sParamsDivider, $sFilter);
+
+    	if(!empty($this->_sFilter1Value))
+            switch($this->_sFilter1Value) {
+                case 'unconfirmed':
+                    $sCnfnType = getParam('sys_account_confirmation_type');
+                    switch($sCnfnType) {
+                        case 'email':
+                            $this->_aOptions['source'] .= " AND `ta`.`email_confirmed`='0'";
+                            break;
+                        case 'phone':
+                            $this->_aOptions['source'] .= " AND `ta`.`phone_confirmed`='0'";
+                            break;
+                        case 'email_and_phone':
+                            $this->_aOptions['source'] .= " AND (`ta`.`email_confirmed`='0' OR `ta`.`phone_confirmed`='0')";
+                            break;
+                        case 'email_or_phone':
+                            $this->_aOptions['source'] .= " AND (`ta`.`email_confirmed`='0' AND `ta`.`phone_confirmed`='0')";
+                            break;
+                    }
+                    break;
+
+                case 'locked':
+                    $this->_aOptions['source'] .= " AND `ta`.`locked` = 1";
+                    break;
+                
+                case 'without_profile':
+                    $this->_aOptions['source'] .= " AND `ta`.`id` NOT IN (SELECT `account_id` FROM `sys_profiles` WHERE `type` <> 'system')";
+                    break;
+
+                default:
+        	        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `tp`.`status`=?", $this->_sFilter1Value);
+            }
+
+        if(!empty($this->_sFilter2Value))
+        	$this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `ta`.`role` & " . BX_DOL_ROLE_ADMIN ." = " . BX_DOL_ROLE_ADMIN);
+
+        $this->_aOptions['source'] .= " AND `ta`.`email` <> '' ";
+        
+        return parent::_getDataSqlInner($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+    
+    protected function _getFilterControls()
+    {
+        parent::_getFilterControls();
+
+        return  $this->_getFilterSelectOne($this->_sFilter1Name, $this->_sFilter1Value, $this->_aFilter1Values) . $this->_getFilterSelectOne($this->_sFilter2Name, $this->_sFilter2Value, $this->_aFilter2Values) . $this->_getSearchInput();
+    }
+    
+    public function getCode($isDisplayHeader = true)
+    {
+        return $this->_oModule->_oTemplate->getJsCode('main', array(
+        	'aHtmlIds' => $this->_oModule->_oConfig->getHtmlIds()
+        )) . parent::getCode($isDisplayHeader);
+    }
+
+    public function performActionActivate()
+    {
+    	$this->_performActionEnable(true);
+    }
+
+	public function performActionSuspend()
+    {
+    	$this->_performActionEnable(false);
+    }
+
+    public function performActionEditEmail()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $iId = (int)bx_get('id');
+            if(!$iId)
+                return echoJson(array());
+
+            $aIds = array($iId);
+        }
+
+        $iId = $aIds[0];
+        $oAccount = BxDolAccount::getInstance($iId);
+        if(!$oAccount)
+            return echoJson(array());
+
+        $aAccount = $oAccount->getInfo();
+        $sAction = 'edit_email';
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ACCOUNT'], $CNF['OBJECT_FORM_ACCOUNT_DISPLAY_SETTINGS_EMAIL']);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction . '&id=' . $iId;
+        $oForm->initChecker($aAccount);
+
+        if($oForm->isSubmittedAndValid()) {
+            $sEmail = $oForm->getCleanValue('email');
+            if(strcmp($aAccount['email'], $sEmail) !== 0 && BxDolAccountQuery::getInstance()->getIdByEmail($sEmail))
+                return echoJson(array('msg' => _t('_sys_form_account_input_email_uniq_error_loggedin')));
+
+            if($oForm->update($aAccount['id'])) {
+                bx_alert('account', 'edited', $aAccount['id'], BxDolAccount::getInstance()->id(), array('display' => $CNF['OBJECT_FORM_ACCOUNT_DISPLAY_SETTINGS_EMAIL']));
+
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+                
+                $oAccount->doAudit($iId, '_sys_audit_action_account_email_changed', array('old_email' => $oAccount->getEmail(), 'new_email' => $sEmail));
+            }
+            else
+                $aRes = array('msg' => _t('_sys_txt_error_account_update'));
+
+            echoJson($aRes);
+        }
+        else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-account-edit-email-popup', _t('_bx_accounts_form_display_account_settings_email_popup'), $this->_oModule->_oTemplate->parseHtmlByName('edit_email.html', array(
+                'form_id' => $oForm->id,
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+	
+	public function performActionSendMessage()
+    {
+		$sAction = 'send_message';
+		
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds))
+            return echoJson(array());
+		
+		$oForm = BxDolForm::getObjectInstance('bx_accounts_account', 'bx_accounts_send_test');
+        if (!$oForm)
+            return '';
+		
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?' . bx_encode_url_params($_GET, array('_r'));
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+        	$aIdsAffected = array();
+			foreach($aIds as $iId) {
+				if(sendMail(BxDolAccount::getInstance()->getEmail($iId), $oForm->getCleanValue('message_subject'), $oForm->getCleanValue('message_text'), 0, [], BX_EMAIL_MASS, 'text', false, ['From' => "=?UTF-8?B?" . base64_encode(getParam('site_title')) . "?= <" . getParam('site_email_notify') . ">"], false)){
+					$aIdsAffected[] = $iId;
+				}	
+			}
+			
+            echoJson(count($aIdsAffected) > 0 ? array('grid' => $this->getCode(false), 'blink' => $aIdsAffected) : array('msg' => _t($CNF['T']['grid_action_err_perform'])));
+        }
+        else {
+            
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-account-send-message', _t('_bx_accounts_form_display_account_send_message'), $this->_oModule->_oTemplate->parseHtmlByName('manage_item.html', array(
+                'form_id' => $oForm->id,
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+    
+    public function performActionAdd()
+    {
+      
+        $CNF = &$this->_oModule->_oConfig->CNF;
+        $sAction = 'add';
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ACCOUNT'], $CNF['OBJECT_FORM_ACCOUNT_DISPLAY_CREATE']);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+           
+            $iAccountId = $oForm->insert();
+            
+            if (!$iAccountId) {
+                $aRes = array('msg' => _t('_sys_txt_error_account_insert'));
+            }
+            else{
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iAccountId);
+                
+                $oBxTemplAccountForms = new BxTemplAccountForms();
+                
+                $iProfileId = $oBxTemplAccountForms->onAccountCreated($iAccountId, $oForm->isSetPendingApproval(), BX_PROFILE_ACTION_MANUAL, false);
+
+                // perform action
+                BxDolAccount::isAllowedCreate ($iProfileId, true);
+                
+                // check
+                $aModulesProfile = array(); 
+                $aModules = BxDolModuleQuery::getInstance()->getModulesBy(array('type' => 'modules', 'active' => 1));
+                foreach($aModules as $aModule) {
+                    $oModule = BxDolModule::getInstance($aModule['name']);
+                    if($oModule instanceof iBxDolProfileService && BxDolService::call($aModule['name'], 'act_as_profile') === true)
+                        $aModulesProfile[] = $aModule;
+                }
+
+                $sDefaultProfileType = getParam('sys_account_default_profile_type');
+                if(count($aModulesProfile) == 1)
+                    $sProfileModule = $aModulesProfile[0]['name'];
+                else if(!empty($sDefaultProfileType)) 
+                    $sProfileModule = $sDefaultProfileType;
+
+                if (getParam('sys_account_auto_profile_creation') && !empty($sProfileModule)) {
+                    $oAccount = BxDolAccount::getInstance($iAccountId);
+                    $aProfileInfo = BxDolService::call($sProfileModule, 'prepare_fields', array(array(
+                        'author' => $iProfileId,
+                        'name' => $oAccount->getDisplayName(),
+                    )));
+                    $a = BxDolService::call($sProfileModule, 'entity_add', array($iProfileId, $aProfileInfo));
+                    if (isset($a['content']['profile_id']) && (int)$a['content']['profile_id'] > 0){
+                        BxDolAcl::getInstance()->setMembership((int)$a['content']['profile_id'], MEMBERSHIP_ID_STANDARD);
+                    }
+                    echoJson($aRes);
+                }
+            }
+        }
+        else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-account-edit-email-popup', _t('_bx_accounts_form_display_account_create_popup'), $this->_oModule->_oTemplate->parseHtmlByName('create.html', array(
+                'form_id' => $oForm->id,
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+
+    public function performActionExport()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aFields = explode(',', getParam($CNF['PARAM_EXPORT_FIELDS']));
+        if(empty($aFields) || !is_array($aFields))
+            return echoJson(array());
+
+        
+        $aTitles = $aConverters = array();
+        foreach($aFields as $sField) {
+            $aTitles[$sField] = _t('_bx_accnt_txt_field_' . $sField);
+            
+            $sConverter = '_exportFieldConverter' . bx_gen_method_name($sField);
+            if(method_exists($this, $sConverter))
+                $aConverters[$sField] = $sConverter;
+        }
+
+        $sMethod = '_exportTo' . bx_gen_method_name(getParam($CNF['PARAM_EXPORT_TO']));
+        if(!method_exists($this, $sMethod))
+            return echoJson(array());
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds))
+            $aIds = $this->_oModule->_oDb->getAccountIds();
+
+        if(($aFile = $this->$sMethod($aIds, $aFields, $aTitles, $aConverters)) === false)
+            return echoJson(array());
+
+        list($sFilePath, $sFileUrl) = $aFile;
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE_FILES']);
+        if($oStorage && ($iFileId = $oStorage->storeFileFromPath($sFilePath, true, bx_get_logged_profile_id())) !== false) {
+            $sFileUrl = $oStorage->getFileUrlById($iFileId);
+
+            @unlink($sFilePath);
+        }
+
+        return echoJson(array('redirect' => $sFileUrl));
+    }
+    
+    public function performActionConfirm()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+    	$aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds))
+            return echoJson(array());
+
+        $oAccount = BxDolAccount::getInstance();
+
+        $iAffected = 0;
+        $aIdsAffected = array();
+        foreach($aIds as $iId){
+            if (BxDolAccount::isNeedConfirmEmail()) {
+                if($oAccount->updateEmailConfirmed(true, true, $iId)) {
+                    $aIdsAffected[] = $iId;
+                    $iAffected++;  
+                }
+            }
+
+            if (BxDolAccount::isNeedConfirmPhone()){
+                if($oAccount->updatePhoneConfirmed(true, $iId)) {
+                    $aIdsAffected[] = $iId;
+                    $iAffected++;  
+                }
+            }
+        }
+		echoJson($iAffected ? array('grid' => $this->getCode(false), 'blink' => $aIdsAffected) : array('msg' => _t($CNF['T']['grid_action_err_perform'])));
+    }
+    
+    public function performActionResendCemail()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds))
+            return echoJson(array());
+
+        $oAccount = BxDolAccount::getInstance();
+
+        $iAffected = 0;
+        $aIdsAffected = array();
+        foreach($aIds as $iId)
+            if($oAccount->sendConfirmationEmail($iId)) {
+                $aIdsAffected[] = $iId;
+                $iAffected++;  
+            }
+
+        echoJson($iAffected ? array('grid' => $this->getCode(false), 'blink' => $aIdsAffected) : array('msg' => _t($CNF['T']['grid_action_err_perform'])));
+    }
+
+    public function performActionResetPassword()
+    {
+    	$aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds))
+            return echoJson(array());
+
+        $iId = $aIds[0];
+        $oAccount = BxDolAccount::getInstance($iId);
+        if(!$oAccount)
+            return echoJson(array());
+
+        $aRes = array();
+        $sPwd = genRndPwd();
+        if (BxDolAccount::getInstance()->updatePassword($sPwd, $iId)){
+            $sPopupId = $this->_oModule->_oConfig->getHtmlIds('password_popup');
+            $sPopupTitle = _t('_bx_accounts_form_display_account_settings_password_popup');
+            $sPopupContent = $this->_oModule->_oTemplate->parseHtmlByName('reset_password.html', array(
+                'js_object' => $this->_oModule->_oConfig->getJsObject('main'),
+                'html_id_text' => $this->_oModule->_oConfig->getHtmlIds('password_text'),
+                'html_id_button' => $this->_oModule->_oConfig->getHtmlIds('password_button'),
+                'password' => $sPwd,
+            ));
+
+            $aRes = array('popup' => BxTemplStudioFunctions::getInstance()->popupBox($sPopupId, $sPopupTitle, $sPopupContent));
+        }
+        else 
+            $aRes = array('msg' => _t('_bx_accnt_grid_action_err_perform'));
+
+        return echoJson($aRes);
+    }
+
+    public function performActionResendRemail()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds))
+            return echoJson(array());
+
+        $oAccount = BxDolAccount::getInstance();
+
+        $iAffected = 0;
+        $aIdsAffected = array();
+        foreach($aIds as $iId)
+            if($oAccount->sendResetPasswordEmail($iId)) {
+                $aIdsAffected[] = $iId;
+                $iAffected++;  
+            }
+
+        echoJson($iAffected ? array('grid' => $this->getCode(false), 'blink' => $aIdsAffected) : array('msg' => _t($CNF['T']['grid_action_err_perform'])));
+    }
+
+    public function performActionUnlockAccount()
+    {
+    	$aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            echoJson(array());
+            return;
+        }
+
+        $oAccountQuery = BxDolAccountQuery::getInstance();
+        foreach($aIds as $iId) {
+            $oAccount = BxDolAccount::getInstance($iId);
+            if(!$oAccount)
+                continue;
+
+            if ($oAccount->isLocked()){
+                $oAccountQuery->unlockAccount($iId);
+            }
+            
+            $oAccount->doAudit($iId, '_sys_audit_action_account_unlock');
+        }
+
+        return echoJson(array('grid' => $this->getCode(false), 'blink' => $aIds));
+    }
+
+    public function performActionSetOperatorRole()
+    {
+    	$aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds))
+            return echoJson(array());
+        
+        $oUtils = BxDolStudioRolesUtils::getInstance();
+
+        $aRoles = $oUtils->getRoles();
+        if(empty($aRoles) || !is_array($aRoles))
+            return echoJson(array('msg' => _t('_sys_txt_error_occured')));
+
+        $iId = (int)array_shift($aIds);
+
+        $sPopupName = str_replace('_', '-', $this->MODULE) . '-set-role-popup';
+        $sPopupContent = $this->_oModule->_oTemplate->getPopupSetRole($aRoles, $iId, $oUtils->getRole($iId));
+
+        return echoJson(array('popup' => array(
+            'html' => BxTemplFunctions::getInstance()->transBox($sPopupName, $sPopupContent),
+            'options' => array(
+                'closeOnOuterClick' => true,
+                'removeOnClose' => true
+            )
+        )));
+    }
+
+    public function performActionSetOperatorRoleSubmit()
+    {
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds))
+            return echoJson(array());
+
+        $iId = (int)array_shift($aIds);
+        if(!$iId)
+            return echoJson(array('msg' => _t('_sys_txt_error_occured')));
+
+        if(!BxDolStudioRolesUtils::getInstance()->setRole($iId, bx_process_input(bx_get('role'), BX_DATA_INT)))
+            return echoJson(array('msg' => _t('_error occured')));
+
+        echoJson(array('grid' => $this->getCode(false), 'blink' => $iId));
+    }
+
+    public function performActionMakeOperator()
+    {
+    	$this->_performActionChangeRole(3);
+    }
+
+    public function performActionUnmakeOperator()
+    {
+    	$this->_performActionChangeRole(1);
+    }
+
+    protected function _performActionChangeRole($iRole)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds))
+            return echoJson(array());
+
+        $oAccount = BxDolAccount::getInstance();
+        $oUtils = BxDolStudioRolesUtils::getInstance();
+
+        $iAffected = 0;
+        $aIdsAffected = array();
+        foreach($aIds as $iId) {
+            if(!$this->_oModule->_oDb->updateAccount(array('role' => $iRole), array('id' => $iId))) 
+                continue;
+
+            $oUtils->setRole($iId, $iRole == 3 ? BX_DOL_STUDIO_ROLE_OPERATOR : 0);
+
+            $oAccount->doAudit($iId, '_sys_audit_action_account_change_role_to_' . $iRole);
+
+            $aIdsAffected[] = $iId;
+            $iAffected++;
+        }
+
+        echoJson($iAffected ? array('grid' => $this->getCode(false), 'blink' => $aIdsAffected) : array('msg' => _t($CNF['T']['grid_action_err_perform'])));
+    }
+
+    protected function _performActionEnable($isChecked)
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	$aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            echoJson(array());
+            return;
+        }
+        $iAffected = 0;
+        $aIdsAffected = array();
+        foreach($aIds as $iId)
+        	if($this->_enable($iId, $isChecked)) {
+        		$aIdsAffected[] = $iId;
+        		$iAffected++;
+                
+                $oAccount = BxDolAccount::getInstance($iId);
+                $oAccount->doAudit($iId, '_sys_audit_action_account_' . $isChecked ? 'activated' : 'suspended');
+        	}
+
+        echoJson($iAffected ? array('grid' => $this->getCode(false), 'blink' => $aIdsAffected) : array('msg' => _t($CNF['T']['grid_action_err_perform'])));
+    }
+
+    protected function _enable($mixedId, $isChecked)
+    {
+    	$oProfile = BxDolProfile::getInstanceAccountProfile($mixedId);
+    	if(!$oProfile)
+    	    return false;
+
+        $iAction = BX_PROFILE_ACTION_MANUAL;
+        $sMethod = $isChecked ? 'activate' : 'suspend';
+        if(!$oProfile->$sMethod($iAction, 0 ,false))
+            return false;
+
+        sendMailTemplate('t_ChangeStatusAccount' . ucfirst($sMethod), $oProfile->getAccountObject()->id(), $oProfile->id(), array(), BX_EMAIL_SYSTEM);
+        
+        $aProfiles = $oProfile->getAccountObject()->getProfiles();
+        foreach($aProfiles as $aProfile){
+            BxDolProfile::getInstance($aProfile['id'])->$sMethod($iAction, 0 ,false);
+        }
+        
+    	return true;
+    }
+
+    //--- Layout methods ---//
+    protected function _getActionEditEmail($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        return '';
+    }
+    
+    protected function _getCellEmailConfirmed($mixedValue, $sKey, $aField, $aRow)
+    {
+    	$mixedValue = (int)$mixedValue == 1 ? '_Yes' : '_No';
+        return parent::_getCellDefault(_t($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getActionResetPassword($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        return '';
+    }
+
+    protected function _getActionResendRemail($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if($sType == 'single')
+            return '';
+
+        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getActionUnlockAccount($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        return '';
+    }
+
+    protected function _getCellName($mixedValue, $sKey, $aField, $aRow)
+    {
+        $oAccount = BxDolAccount::getInstance($aRow['id']);
+        if ($oAccount)
+            $s = ($aRow['locked'] == 1 ? $this->_oTemplate->parseIcon("lock col-red1") . ' ' : '') . $oAccount->getDisplayName();
+        return parent::_getCellDefault ($s, $sKey, $aField, $aRow);
+    }
+    
+	protected function _getCellProfiles($mixedValue, $sKey, $aField, $aRow)
+    {
+        $s = $this->_oModule->_oTemplate->getProfilesByAccount($aRow);
+
+        return parent::_getCellDefault ($s, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellLogged($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = !empty($mixedValue) ? bx_time_js($mixedValue) : _t('_sys_not_available');
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    } 
+    
+    protected function _getCellLastActive($mixedValue, $sKey, $aField, $aRow)
+    {
+        $iTs = max((int)$mixedValue, (int)$aRow['active']);
+        return parent::_getCellDefault($iTs ? bx_time_js($iTs) : _t('_sys_not_available'), $sKey, $aField, $aRow);
+    } 
+    
+    protected function _getCellAdded($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = !empty($mixedValue) ? bx_time_js($mixedValue) : _t('_sys_not_available');
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    } 
+    
+    protected function _getCellIsConfirmed($mixedValue, $sKey, $aField, $aRow)
+    {
+        $oAccount = BxDolAccount::getInstance($aRow['id']);
+        $s = "";
+        if ($oAccount)
+            $s = $oAccount->getCurrentConfirmationStatusValue();
+        return parent::_getCellDefault(_t('_bx_accnt_grid_confirmation_status_' . $s), $sKey, $aField, $aRow);
+    }
+
+    protected function _isCheckboxDisabled($aRow)
+    {
+        return false;
+    }
+
+	protected function _getContentInfo($iId)
+    {
+    	return BxDolAccountQuery::getInstance()->getInfoById($iId);
+    }
+
+	protected function _doDelete($iId, $aParams = array())
+    {
+        $oAccount = BxDolAccount::getInstance($iId);
+        if($oAccount)
+            return $oAccount->delete(isset($aParams['with_content']) && $aParams['with_content'] === true);
+        
+        return false;
+    }
+    
+    
+
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+        
+        $this->_oTemplate->addJs(array(
+            'main.css'
+        ));
+
+        $this->_oTemplate->addJs(array(
+        	'jquery.form.min.js',
+            'clipboard.min.js',
+            'main.js'
+        ));
+    }
+
+    protected function _isVisibleGrid($a)
+    {
+        if(isAdmin())
+            return true;
+        
+        return parent::_isVisibleGrid($a);
+    }
+
+    protected function _exportToCsv($aIds, $aFields, $aTitles, $aConverters)
+    {
+        $sFileDiv = ';';
+        $sFileName = 'accounts-' . date('Y.m.d') . '.csv';
+        $sFilePath = BX_DIRECTORY_PATH_TMP . $sFileName;
+        $oFileHandler = fopen($sFilePath, 'w');
+        if(!$oFileHandler)
+            return false;
+
+        fputcsv($oFileHandler, $aTitles, $sFileDiv);
+
+        $aFieldsFlip = array_flip($aFields);
+        $oAccountQuery = BxDolAccountQuery::getInstance();
+
+        foreach($aIds as $iId) {
+            $aAccount = $oAccountQuery->getInfoById($iId);
+            if(empty($aAccount) || !is_array($aAccount))
+                continue;
+            
+            $aConvert = array_intersect_key($aConverters, $aAccount);
+            foreach($aConvert as $sField => $sMethod)
+                $aAccount[$sField] = $this->$sMethod($aAccount[$sField]);
+
+            fputcsv($oFileHandler, array_intersect_key($aAccount, $aFieldsFlip), $sFileDiv);
+        }
+
+        fclose($oFileHandler);
+
+        return array($sFilePath, BX_DOL_URL_ROOT . 'tmp/' . $sFileName);
+    }
+
+    protected function _exportToXml($aIds, $aFields, $aTitles, $aConverters)
+    {
+        $sFileName = 'accounts-' . date('Y.m.d') . '.xml';
+        $sFilePath = BX_DIRECTORY_PATH_TMP . $sFileName;
+        $oFileHandler = fopen($sFilePath, 'w');
+        if(!$oFileHandler)
+            return false;
+
+        $aFieldsFlip = array_flip($aFields);
+        $oAccountQuery = BxDolAccountQuery::getInstance();
+
+        $oXML = xmlwriter_open_memory();
+        xmlwriter_set_indent($oXML, 1);
+        xmlwriter_set_indent_string($oXML, '  ');
+        
+        xmlwriter_start_document($oXML, '1.0', 'UTF-8');
+        xmlwriter_start_element($oXML, 'accounts');
+
+        foreach($aIds as $iId) {
+            $aAccount = $oAccountQuery->getInfoById($iId);
+            if(empty($aAccount) || !is_array($aAccount))
+                continue;
+
+            $aConvert = array_intersect_key($aConverters, $aAccount);
+            foreach($aConvert as $sField => $sMethod)
+                $aAccount[$sField] = $this->$sMethod($aAccount[$sField]);
+
+            xmlwriter_start_element($oXML, 'account');
+            $aAccountFields = array_intersect_key($aAccount, $aFieldsFlip);
+            foreach($aAccountFields as $sAccountField => $sAccountValue) {
+                xmlwriter_start_element($oXML, $sAccountField);
+                xmlwriter_write_cdata($oXML, $sAccountValue);
+                xmlwriter_end_element($oXML);
+            }
+            xmlwriter_end_element($oXML);
+        }
+
+        xmlwriter_end_document($oXML);
+
+        fwrite($oFileHandler, xmlwriter_output_memory($oXML));
+        fclose($oFileHandler);
+
+        return array($sFilePath, BX_DOL_URL_ROOT . 'tmp/' . $sFileName);
+    }
+
+    protected function _exportFieldConverterAdded($mixedValue)
+    {
+        return $this->__exportFieldConverterDate($mixedValue);
+    }
+
+    protected function _exportFieldConverterChanged($mixedValue)
+    {
+        return $this->__exportFieldConverterDate($mixedValue);
+    }
+
+    protected function _exportFieldConverterLogged($mixedValue)
+    {
+        return $this->__exportFieldConverterDateTime($mixedValue);
+    }
+
+    protected function _exportFieldConverterLangId($mixedValue)
+    {
+        return $mixedValue ? BxDolLanguages::getInstance()->getLangName($mixedValue) : '';
+    }
+
+    protected function __exportFieldConverterDate($mixedValue)
+    {
+        return date('Y.m.d', $mixedValue);
+    }
+
+    protected function __exportFieldConverterDateTime($mixedValue)
+    {
+        return date('Y.m.d H:i', $mixedValue);
+    }
+}
+
+/** @} */

+ 71 - 0
modules/boonex/accounts/updates/14.0.1_14.0.2/source/install/config.php

@@ -0,0 +1,71 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Accounts Accounts
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_accounts',
+    'title' => 'Accounts Manager',
+    'note' => 'Accounts Manager module.',
+    'version' => '14.0.2',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/accounts/',
+    'home_uri' => 'accounts',
+
+    'db_prefix' => 'bx_accnt_',
+    'class_prefix' => 'BxAccnt',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Accounts',
+
+    /**
+     * 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/accounts/updates/14.0.1_14.0.2/source/install/sql/enable.sql

@@ -0,0 +1,114 @@
+SET @sName = 'bx_accounts';
+
+
+-- 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_accounts', 'bx_accounts@modules/boonex/accounts/|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_accounts', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_accounts_export_to', 'csv', @iCategId, '_bx_accounts_option_export_to', 'select', '', '', 'a:2:{s:6:"module";s:11:"bx_accounts";s:6:"method";s:21:"get_options_export_to";}', 10),
+('bx_accounts_export_fields', 'name,email', @iCategId, '_bx_accounts_option_export_fields', 'list', '', '', 'a:2:{s:6:"module";s:11:"bx_accounts";s:6:"method";s:25:"get_options_export_fields";}', 20);
+
+
+-- PAGE: module administration
+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_accounts_administration', '_bx_accnt_page_title_sys_manage_administration', '_bx_accnt_page_title_manage', @sName, 5, 192, 1, 'accounts-administration', 'page.php?i=accounts-administration', '', '', '', 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_accounts_administration', 1, @sName, '_bx_accnt_page_block_title_system_manage_administration', '_bx_accnt_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:\"module\";s:11:\"bx_accounts\";s:6:\"method\";s:12:\"manage_tools\";s:6:\"params\";a:1:{i:0;s:14:\"administration\";}}', 0, 1, 0);
+
+
+-- 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_accounts_menu_manage_tools', '_bx_accnt_menu_title_manage_tools', 'bx_accounts_menu_manage_tools', @sName, 6, 0, 1, 'BxAccntMenuManageTools', 'modules/boonex/accounts/classes/BxAccntMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_accounts_menu_manage_tools', @sName, '_bx_accnt_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_accounts_menu_manage_tools', @sName, 'edit-email', '_bx_accnt_menu_item_title_system_edit_email', '_bx_accnt_menu_item_title_edit_email', 'javascript:void(0)', 'javascript:{js_object}.onClickEditEmail({content_id}, this);', '_self', '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M227.31,73.37,182.63,28.68a16,16,0,0,0-22.63,0L36.69,152A15.86,15.86,0,0,0,32,163.31V208a16,16,0,0,0,16,16H92.69A15.86,15.86,0,0,0,104,219.31L227.31,96a16,16,0,0,0,0-22.63ZM51.31,160,136,75.31,152.69,92,68,176.68ZM48,179.31,76.69,208H48Zm48,25.38L79.31,188,164,103.31,180.69,120Zm96-96L147.31,64l24-24L216,84.68Z"></path></svg>', '', 192, 1, 0, 1),
+('bx_accounts_menu_manage_tools', @sName, 'resend-cemail', '_bx_accnt_menu_item_title_system_resend_cemail', '_bx_accnt_menu_item_title_resend_cemail', 'javascript:void(0)', 'javascript:{js_object}.onClickResendCemail({content_id}, this);', '_self', '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M231.87,114l-168-95.89A16,16,0,0,0,40.92,37.34L71.55,128,40.92,218.67A16,16,0,0,0,56,240a16.15,16.15,0,0,0,7.93-2.1l167.92-96.05a16,16,0,0,0,.05-27.89ZM56,224a.56.56,0,0,0,0-.12L85.74,136H144a8,8,0,0,0,0-16H85.74L56.06,32.16A.46.46,0,0,0,56,32l168,95.83Z"></path></svg>', '', 192, 1, 0, 2),
+('bx_accounts_menu_manage_tools', @sName, 'confirm', '_bx_accnt_menu_item_title_system_confirm', '_bx_accnt_menu_item_title_confirm', 'javascript:void(0)', 'javascript:{js_object}.onClickConfirm({content_id}, this);', '_self', '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M229.66,77.66l-128,128a8,8,0,0,1-11.32,0l-56-56a8,8,0,0,1,11.32-11.32L96,188.69,218.34,66.34a8,8,0,0,1,11.32,11.32Z"></path></svg>', '', 192, 1, 0, 3),
+('bx_accounts_menu_manage_tools', @sName, 'reset-password', '_bx_accnt_menu_item_title_system_reset_password', '_bx_accnt_menu_item_title_reset_password', 'javascript:void(0)', 'javascript:{js_object}.onClickResetPassword({content_id}, this);', '_self', '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M48,56V200a8,8,0,0,1-16,0V56a8,8,0,0,1,16,0Zm92,54.5L120,117V96a8,8,0,0,0-16,0v21L84,110.5a8,8,0,0,0-5,15.22l20,6.49-12.34,17a8,8,0,1,0,12.94,9.4l12.34-17,12.34,17a8,8,0,1,0,12.94-9.4l-12.34-17,20-6.49A8,8,0,0,0,140,110.5ZM246,115.64A8,8,0,0,0,236,110.5L216,117V96a8,8,0,0,0-16,0v21l-20-6.49a8,8,0,0,0-4.95,15.22l20,6.49-12.34,17a8,8,0,1,0,12.94,9.4l12.34-17,12.34,17a8,8,0,1,0,12.94-9.4l-12.34-17,20-6.49A8,8,0,0,0,246,115.64Z"></path></svg>', '', 192, 1, 0, 4),
+('bx_accounts_menu_manage_tools', @sName, 'resend-remail', '_bx_accnt_menu_item_title_system_resend_remail', '_bx_accnt_menu_item_title_resend_remail', 'javascript:void(0)', 'javascript:{js_object}.onClickResendRemail({content_id}, this);', '_self', '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M184,104v32a8,8,0,0,1-8,8H99.31l10.35,10.34a8,8,0,0,1-11.32,11.32l-24-24a8,8,0,0,1,0-11.32l24-24a8,8,0,0,1,11.32,11.32L99.31,128H168V104a8,8,0,0,1,16,0Zm48-48V200a16,16,0,0,1-16,16H40a16,16,0,0,1-16-16V56A16,16,0,0,1,40,40H216A16,16,0,0,1,232,56ZM216,200V56H40V200H216Z"></path></svg>', '', 192, 1, 0, 5),
+('bx_accounts_menu_manage_tools', @sName, 'unlock-account', '_bx_accnt_menu_item_title_system_unlock_account', '_bx_accnt_menu_item_title_unlock_account', 'javascript:void(0)', 'javascript:{js_object}.onClickUnlockAccount({content_id}, this);', '_self', '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M208,80H96V56a32,32,0,0,1,32-32c15.37,0,29.2,11,32.16,25.59a8,8,0,0,0,15.68-3.18C171.32,24.15,151.2,8,128,8A48.05,48.05,0,0,0,80,56V80H48A16,16,0,0,0,32,96V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V96A16,16,0,0,0,208,80Zm0,128H48V96H208V208Z"></path></svg>', '', 192, 1, 0, 6),
+('bx_accounts_menu_manage_tools', @sName, 'delete', '_bx_accnt_menu_item_title_system_delete', '_bx_accnt_menu_item_title_delete', 'javascript:void(0)', 'javascript:{js_object}.onClickDelete({content_id}, this);', '_self', '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg>', '', 192, 1, 0, 7),
+('bx_accounts_menu_manage_tools', @sName, 'delete-with-content', '_bx_accnt_menu_item_title_system_delete_with_content', '_bx_accnt_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id}, this);', '_self', '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M225,80.4,183.6,39a24,24,0,0,0-33.94,0L31,157.66a24,24,0,0,0,0,33.94l30.06,30.06A8,8,0,0,0,66.74,224H216a8,8,0,0,0,0-16h-84.7L225,114.34A24,24,0,0,0,225,80.4ZM108.68,208H70.05L42.33,180.28a8,8,0,0,1,0-11.31L96,115.31,148.69,168Zm105-105L160,156.69,107.31,104,161,50.34a8,8,0,0,1,11.32,0l41.38,41.38a8,8,0,0,1,0,11.31Z"></path></svg>', '', 192, 1, 0, 8),
+('bx_accounts_menu_manage_tools', @sName, 'make-operator', '_bx_accnt_menu_item_title_system_make_operator', '_bx_accnt_menu_item_title_make_operator', 'javascript:void(0)', 'javascript:{js_object}.onClickMakeOperator({content_id}, this);', '_self', 'wrench', '', 192, 0, 0, 9),
+('bx_accounts_menu_manage_tools', @sName, 'unmake-operator', '_bx_accnt_menu_item_title_system_unmake_operator', '_bx_accnt_menu_item_title_unmake_operator', 'javascript:void(0)', 'javascript:{js_object}.onClickUnmakeOperator({content_id}, this);', '_self', 'wrench', '', 192, 0, 0, 10),
+('bx_accounts_menu_manage_tools', @sName, 'set-operator-role', '_bx_accnt_menu_item_title_system_set_operator_role', '_bx_accnt_menu_item_title_set_operator_role', 'javascript:void(0)', 'javascript:{js_object}.onClickSetOperatorRole({content_id}, this);', '_self', '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M75.19,198.4a8,8,0,0,0,11.21-1.6,52,52,0,0,1,83.2,0,8,8,0,1,0,12.8-9.6A67.88,67.88,0,0,0,155,165.51a40,40,0,1,0-53.94,0A67.88,67.88,0,0,0,73.6,187.2,8,8,0,0,0,75.19,198.4ZM128,112a24,24,0,1,1-24,24A24,24,0,0,1,128,112Zm72-88H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V40A16,16,0,0,0,200,24Zm0,192H56V40H200ZM88,64a8,8,0,0,1,8-8h64a8,8,0,0,1,0,16H96A8,8,0,0,1,88,64Z"></path></svg>', '', 192, 1, 0, 11);
+
+-- 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, 'accounts-administration', '_bx_accnt_menu_item_title_system_admt_accounts', '_bx_accnt_menu_item_title_admt_accounts', 'page.php?i=accounts-administration', '', '_self', 'at', 'a:2:{s:6:"module";s:11:"bx_accounts";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
+
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'edit any entry', NULL, '_bx_accnt_acl_action_edit_any_account', '', 1, 3);
+SET @iIdActionProfileEditAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'delete any entry', NULL, '_bx_accnt_acl_action_delete_any_account', '', 1, 3);
+SET @iIdActionProfileDeleteAny = 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
+
+-- edit any entry 
+(@iModerator, @iIdActionProfileEditAny),
+(@iAdministrator, @iIdActionProfileEditAny),
+
+-- delete any entry 
+(@iAdministrator, @iIdActionProfileDeleteAny);
+
+
+-- 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`, `show_total_count`, `override_class_name`, `override_class_file`) VALUES
+('bx_accounts_administration', 'Sql', 'SELECT `ta`.*, `tp`.`status` AS `status`, `ta`.`active`, `ts`.`date` AS `last_active` FROM `sys_accounts` AS `ta` LEFT JOIN `sys_sessions` AS `ts` ON `ta`.`id`=`ts`.`user_id` LEFT JOIN `sys_profiles` AS `tp` ON `ta`.`id`=`tp`.`account_id` AND `tp`.`type`=''system'' WHERE 1 ', 'sys_accounts', 'id', 'logged', 'status', '', 20, NULL, 'start', '', 'name,email,ip,phone', '', 'like', 'email_confirmed,logged,last_active,added', '', 192, 1, 'BxAccntGridAdministration', 'modules/boonex/accounts/classes/BxAccntGridAdministration.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_accounts_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_accounts_administration', 'switcher', '_bx_accnt_grid_column_title_adm_active', '6%', 0, '', '', 2),
+('bx_accounts_administration', 'name', '_bx_accnt_grid_column_title_adm_name', '12%', 0, '16', '', 3),
+('bx_accounts_administration', 'email', '_bx_accnt_grid_column_title_adm_email', '16%', 0, '16', '', 4),
+('bx_accounts_administration', 'is_confirmed', '_bx_accnt_grid_column_title_adm_is_confirmed', '4%', 0, '', '', 5),
+('bx_accounts_administration', 'profiles', '_bx_accnt_grid_column_title_adm_profiles', '24%', 0, '', '', 6),
+('bx_accounts_administration', 'logged', '_bx_accnt_grid_column_title_adm_logged', '10%', 0, '15', '', 7),
+('bx_accounts_administration', 'last_active', '_bx_accnt_grid_column_title_adm_last_active', '10%', 0, '15', '', 8),
+('bx_accounts_administration', 'added', '_bx_accnt_grid_column_title_adm_added', '10%', 0, '15', '', 9),
+('bx_accounts_administration', 'actions', '', '6%', 0, '', '', 10);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_accounts_administration', 'bulk', 'activate', '_bx_accnt_grid_action_title_adm_activate', '', 0, 0, 1),
+('bx_accounts_administration', 'bulk', 'suspend', '_bx_accnt_grid_action_title_adm_suspend', '', 0, 0, 2),
+('bx_accounts_administration', 'bulk', 'resend_cemail', '_bx_accnt_grid_action_title_adm_resend_cemail', '', 0, 0, 3),
+('bx_accounts_administration', 'bulk', 'resend_remail', '_bx_accnt_grid_action_title_adm_resend_remail', '', 0, 0, 4),
+('bx_accounts_administration', 'bulk', 'confirm', '_bx_accnt_grid_action_title_adm_confirm', '', 0, 0, 5),
+('bx_accounts_administration', 'bulk', 'delete', '_bx_accnt_grid_action_title_adm_delete', '', 0, 1, 6),
+('bx_accounts_administration', 'bulk', 'delete_with_content', '_bx_accnt_grid_action_title_adm_delete_with_content', '', 0, 1, 7),
+('bx_accounts_administration', 'bulk', 'export', '_bx_accnt_grid_action_title_adm_export', '', 0, 0, 8),
+('bx_accounts_administration', 'bulk', 'send_message', '_bx_accnt_grid_action_title_adm_send_message', '', 0, 0, 9),
+('bx_accounts_administration', 'single', 'edit_email', '_bx_accnt_grid_action_title_adm_edit_email', '', 0, 0, 0),
+('bx_accounts_administration', 'single', 'reset_password', '_bx_accnt_grid_action_title_adm_reset_password', '', 0, 0, 0),
+('bx_accounts_administration', 'single', 'resend_remail', '_bx_accnt_grid_action_title_adm_resend_remail', '', 0, 0, 0),
+('bx_accounts_administration', 'single', 'unlock_account', '_bx_accnt_grid_action_title_adm_unlock_account', '', 0, 0, 0),
+('bx_accounts_administration', 'single', 'settings', '_bx_accnt_grid_action_title_adm_more_actions', 'gi-settings.svg', 1, 0, 2),
+('bx_accounts_administration', 'independent', 'add', '_bx_accnt_grid_action_title_adm_more_add', 'gi-add.svg', 0, 0, 0),
+('bx_accounts_administration', 'independent', 'export', '_bx_accnt_grid_action_title_adm_export_all', 'gi-export.svg', 0, 0, 1);

+ 51 - 0
modules/boonex/albums/updates/14.0.3_14.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' => 'Albums',
+    'version_from' => '14.0.3',
+    'version_to' => '14.0.4',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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_14.0.3_14.0.4/',
+    'home_uri' => 'albums_update_1403_1404',
+
+    '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/14.0.3_14.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 BxAlbumsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 1063 - 0
modules/boonex/albums/updates/14.0.3_14.0.4/source/classes/BxAlbumsModule.php

@@ -0,0 +1,1063 @@
+<?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'];
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_albums-media_deleted 'bx_albums', 'media_deleted' - hook on new media deleted from album
+         * - $unit_name - equals `bx_albums`
+         * - $action - equals `media_deleted` 
+         * - $object_id - album_id
+         * - $sender_id - author's profile_id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object_author_id` - [int] confirmation type can be none/phone/email/email_and_phone/email_or_phone
+         *      - `subobject_id` - [int] id for added media
+         *      - `media_id` - [int] id for added media
+         *      - `media_info` - [array] media info
+         * @hook @ref hook-bx_albums-media_deleted
+         */
+        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_absolute_url(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_absolute_url(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_absolute_url($oPermalinks->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iContentId), '{bx_url_root}');
+        $sSubentryUrl = bx_absolute_url($oPermalinks->permalink('page.php?i=' . $CNF['URI_VIEW_MEDIA'] . '&id=' . $iMediaId), '{bx_url_root}');
+        $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_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_MEDIA'] . '&id=' . $aMediaInfo['id']), '{bx_url_root}');
+        $sEntryCaption = isset($aMediaInfo['title']) ? $aMediaInfo['title'] : _t('_bx_albums_media');
+
+        return array(
+            'object_id' => $aMediaInfo['content_id'],
+            '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_absolute_url($oComment->getViewUrl((int)$aEvent['subobject_id'], false), '{bx_url_root}'),
+            '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_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_MEDIA'] . '&id=' . $aMediaInfo['id']), '{bx_url_root}');
+        $sEntryCaption = isset($aMediaInfo['title']) ? $aMediaInfo['title'] : _t('_bx_albums_media');
+
+        return array(
+            'object_id' => $aMediaInfo['content_id'],
+            '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_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_MEDIA'] . '&id=' . $aMediaInfo['id']), '{bx_url_root}');
+        $sEntryCaption = isset($aMediaInfo['title']) ? $aMediaInfo['title'] : _t('_bx_albums_media');
+
+        return array(
+            'object_id' => $aMediaInfo['content_id'],
+            '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;
+        $aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        $aContentInfo = $this->_oDb->getContentInfoById($aMediaInfo['content_id']);
+        if(($sMsg = $this->checkAllowedEdit($aContentInfo)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return echoJson(['msg' => $sMsg]);
+
+        $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_absolute_url(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_absolute_url(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/14.0.3_14.0.4/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' => '14.0.4',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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'
+    ),
+
+);
+
+/** @} */

+ 250 - 0
modules/boonex/albums/updates/14.0.3_14.0.4/source/template/css/main.css

@@ -0,0 +1,250 @@
+/* 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-search-result-block.bx-albums-media .bx-search-result-content {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-wrap: wrap;
+    flex-wrap: wrap;
+
+    margin: -0.5rem;
+}
+
+.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;    
+}

+ 20 - 0
modules/boonex/albums/updates/14.0.3_14.0.4/source/template/media-edit.html

@@ -0,0 +1,20 @@
+<div class="bx-albums-media-edit">
+    <div class="bx-albums-media-edit-cnt bx-def-padding">
+        __form__
+        <script language="javascript">
+            $(document).ready(function () {
+                $("#__form_id__").ajaxForm({ 
+                    dataType: "json",
+                    beforeSubmit: function (formData, jqForm, options) {
+                        bx_loading($("#__form_id__"), true);
+                    },
+                    success: function (oData) {
+                        $(".bx-popup-applied:visible").dolPopupHide();
+
+                        processJsonData(oData);
+                    }
+                });
+            });
+        </script>
+    </div>
+</div>

+ 51 - 0
modules/boonex/artificer/updates/14.0.4_14.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' => 'Artificer',
+    'version_from' => '14.0.4',
+    'version_to' => '14.0.5',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/artificer/updates/update_14.0.4_14.0.5/',
+    'home_uri' => 'artificer_update_1404_1405',
+
+    'module_dir' => 'boonex/artificer/',
+    'module_uri' => 'artificer',
+
+    'db_prefix' => 'bx_artificer_',
+    'class_prefix' => 'BxArtificer',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Artificer Template',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 26 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/install/installer.php

@@ -0,0 +1,26 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxArtificerUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+
+    public function update($aParams)
+    {
+        $aResult = parent::update($aParams);
+        if(!$aResult['result'])
+            return $aResult;
+
+        $oCacheUtilities = BxDolCacheUtilities::getInstance();
+        $oCacheUtilities->clear('css');
+        $oCacheUtilities->clear('template');
+
+        return $aResult;
+    }
+}

+ 4 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/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_artificer_stg_cpt_option_header_search"><![CDATA[Enable floating search bar]]></string_add>
+</resources>

+ 8 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/install/sql/enable.sql

@@ -0,0 +1,8 @@
+SET @sName = 'bx_artificer';
+
+
+-- ALERTS
+SET @iHandler := (SELECT `id` FROM `sys_alerts_handlers` WHERE `name`=@sName LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `unit`='system' AND `action`='save_setting' AND `handler_id`=@iHandler;
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler);

+ 9 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/install/sql/install.sql

@@ -0,0 +1,9 @@
+SET @sName = 'bx_artificer';
+
+
+-- SETTINGS
+SET @iCategoryId = (SELECT `id` FROM `sys_options_categories` WHERE `name`='bx_artificer_system' LIMIT 1);
+
+DELETE FROM `sys_options` WHERE `name`=CONCAT(@sName, '_header_search');
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, CONCAT(@sName, '_header_search'), '_bx_artificer_stg_cpt_option_header_search', 'on', 'checkbox', '', '', '', 12);

+ 172 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/classes/BxArtificerAlertsResponse.php

@@ -0,0 +1,172 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Artificer Artificer template
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+
+class BxArtificerAlertsResponse extends BxBaseModTemplateAlertsResponse
+{
+    public function __construct()
+    {
+        $this->_sModule = 'bx_artificer';
+
+        parent::__construct();
+    }
+
+    protected function _processSystemChangeLogo($oAlert)
+    {
+        $sPrefix = $this->_oModule->_oConfig->getPrefix('option');
+
+        if(!in_array($oAlert->aExtras['option'], ['sys_site_logo', $sPrefix . 'site_logo']))
+            return;
+
+        setParam($sPrefix . 'site_logo_aspect_ratio', '');
+    }
+    
+    protected function _processSystemChangeLogoDark($oAlert)
+    {
+        $sPrefix = $this->_oModule->_oConfig->getPrefix('option');
+
+        if(!in_array($oAlert->aExtras['option'], ['sys_site_logo_dark', $sPrefix . 'site_logo_dark']))
+            return;
+
+        setParam($sPrefix . 'site_logo_dark_aspect_ratio', '');
+    }
+
+    protected function _processSystemChangeMark($oAlert)
+    {
+        $sPrefix = $this->_oModule->_oConfig->getPrefix('option');
+
+        if(!in_array($oAlert->aExtras['option'], ['sys_site_mark', $sPrefix . 'site_mark']))
+            return;
+
+        setParam($sPrefix . 'site_mark_aspect_ratio', '');
+    }
+
+    protected function _processSystemChangeMarkDark($oAlert)
+    {
+        $sPrefix = $this->_oModule->_oConfig->getPrefix('option');
+
+        if(!in_array($oAlert->aExtras['option'], ['sys_site_mark_dark', $sPrefix . 'site_mark_dark']))
+            return;
+
+        setParam($sPrefix . 'site_mark_dark_aspect_ratio', '');
+    }
+
+    protected function _processSystemGetObject($oAlert)
+    {
+        if(!$this->_isActive())
+            return;
+
+        if(empty($oAlert->aExtras['type']))
+            return;
+
+        switch($oAlert->aExtras['type']) {
+            case 'menu':
+                if(!($oAlert->aExtras['object'] instanceof BxBaseModGeneralMenuViewActions))
+                    break;
+
+                $oAlert->aExtras['object']->setShowAsButton(false);
+                break;
+        }
+    }
+
+    protected function _processSystemGetLayoutImages($oAlert)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $sImages = getParam($CNF['PARAM_IMAGES_CUSTOM']);
+        if(!$sImages)
+            return;
+        
+        $aImages = preg_split("/\\r\\n|\\r|\\n/", $sImages);
+        if(empty($aImages) || !is_array($aImages))
+            return;
+
+        foreach($aImages as $sImage) {
+            $aImage = explode('=>', $sImage);
+            if(empty($aImage))
+                continue;
+
+            switch(count($aImage)) {
+                case 2:
+                    list($sName, $sValue) = $aImage;
+
+                    $aCacheItemKeys = ['v'];
+                    $aCacheItemValues = [$sValue];
+                    break;
+
+                case 3:
+                    list($sName, $sValue, $sType) = $aImage;
+
+                    $aCacheItemKeys = ['v', 't'];
+                    $aCacheItemValues = [$sValue, $sType];
+                    break;
+
+                case 4:
+                    list($sName, $sValue, $sType, $sClass) = $aImage;
+
+                    $aCacheItemKeys = ['v', 't', 'c'];
+                    $aCacheItemValues = [$sValue, $sType, $sClass];
+                    break;
+
+                default:
+                    continue 2;
+            }
+
+            $sCacheItemKey = md5(trim($sName));
+            if(!isset($oAlert->aExtras['override_result'][$sCacheItemKey]))
+                continue;
+            
+            foreach($aCacheItemValues as $i => $s)
+                $aCacheItemValues[$i] = trim($s);
+
+            $aCacheItem = array_combine($aCacheItemKeys, $aCacheItemValues);
+
+            if(isset($aCacheItem['t']) && $aCacheItem['t'] == 'im')
+                foreach(['Image', 'Icon'] as $sUrlType) 
+                    if(($sUrl = $this->_oModule->_oTemplate->{'get' . $sUrlType . 'Url'}($aCacheItem['v'])) != '')
+                        $aCacheItem['v'] = $sUrl;
+
+            $oAlert->aExtras['override_result'][$sCacheItemKey] = array_merge($oAlert->aExtras['override_result'][$sCacheItemKey], $aCacheItem);
+        }
+    }
+
+    protected function _processSystemSaveSetting($oAlert)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if($oAlert->aExtras['option'] == $CNF['PARAM_IMAGES_CUSTOM'])
+            BxDolTemplate::getInstance()->clearImagesCache($this->_oModule->_oConfig->getUri());
+    }
+
+    protected function _processProfileUnit($oAlert)
+    {
+        if(!$this->_isActive())
+            return;
+
+        $sModule = $oAlert->aExtras['module'];
+        $oModule = BxDolModule::getInstance($sModule);
+        if(!$oModule)
+            return;
+
+        $sTemplate = !empty($oAlert->aExtras['template']) && is_array($oAlert->aExtras['template']) ? $oAlert->aExtras['template'][0] : $oAlert->aExtras['template'];
+        $sClassSize = $this->_oModule->_oConfig->getThumbSize(isset($oAlert->aExtras['template'][1]) ? $oAlert->aExtras['template'][1] : '', $sTemplate);
+
+        $aTmplVars['class_size'] = $sClassSize;
+        $aTmplVars['bx_if:show_thumb_letter']['content']['class_size'] = $sClassSize;
+        $aTmplVars['bx_if:show_thumb_image']['content']['class_size'] = $sClassSize;
+        
+        $aTmplVars['bx_if:show_thumbnail']['content']['class_size'] = $sClassSize;
+        $aTmplVars['bx_if:show_thumbnail']['content']['bx_if:show_thumb_letter']['content']['class_size'] = $sClassSize;
+        $aTmplVars['bx_if:show_thumbnail']['content']['bx_if:show_thumb_image']['content']['class_size'] = $sClassSize;
+    }
+}
+
+/** @} */

+ 143 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/classes/BxArtificerConfig.php

@@ -0,0 +1,143 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Artificer Artificer template
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+bx_import('BxBaseModTemplateConfig');
+
+class BxArtificerConfig extends BxBaseModTemplateConfig
+{
+    protected $_iLogoDark;
+    protected $_iLogoDarkWidth;
+    protected $_iLogoDarkHeight;
+    protected $_fLogoDarkAspectRatio;
+    protected $_fLogoDarkAspectRatioDefault;
+    protected $_sLogoInline;
+    
+    protected $_iMarkDark;
+    protected $_iMarkDarkWidth;
+    protected $_iMarkDarkHeight;
+    protected $_fMarkDarkAspectRatio;
+    protected $_fMarkDarkAspectRatioDefault;
+    protected $_sMarkInline;
+
+    protected $_sKeyLogoDarkAspectRatio;
+    protected $_sKeyMarkDarkAspectRatio;
+
+    protected $_aReplacements;
+
+    protected $_sThumbSizeDefault;
+    protected $_aThumbSizes;
+    protected $_aThumbSizeByTemplate;
+
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->CNF = array_merge($this->CNF, [
+            // some params
+            'PARAM_IMAGES_CUSTOM' => 'bx_artificer_images_custom',
+        ]);
+
+        $this->_aJsClasses = array_merge($this->_aJsClasses, array(
+            'utils' => 'BxArtificerUtils'
+        ));
+
+        $this->_aJsObjects = array_merge($this->_aJsObjects, array(
+            'utils' => 'oBxArtificerUtils'
+        ));
+
+        $this->_iLogoHeight = 40;
+        $this->_iLogoDarkWidth = 0;
+        $this->_iLogoDarkHeight = $this->_iLogoHeight;
+        $this->_fLogoDarkAspectRatioDefault = BxDolDesigns::$fLogoAspectRatioDefault;
+
+        $this->_iMarkHeight = 40;
+        $this->_iMarkDarkWidth = 0;
+        $this->_iMarkDarkHeight = $this->_iMarkHeight;
+        $this->_fMarkDarkAspectRatioDefault = BxDolDesigns::$fMarkAspectRatioDefault;
+
+        $this->_aPrefixes = [
+            'option' => 'bx_artificer_'
+        ];
+
+        $this->_aReplacements = [
+            'bx-def-margin-sec-neg' => '-m-2',
+        ];
+                
+        $this->_sThumbSizeDefault = 'thumb';
+        $this->_aThumbSizes = [
+            'icon' => 'h-8 w-8',
+            'thumb' => 'h-10 w-10',
+            'ava' => 'h-24 w-24',
+            'ava-big' => 'w-48 h-48'
+        ];
+        $this->_aThumbSizeByTemplate = [
+            'unit_with_cover.html' => 'h-24 w-24' //--- 'ava' size
+        ];
+    }
+    
+    public function init(&$oDb)
+    {
+        parent::init($oDb);
+        $sPrefix = $this->getPrefix('option');
+
+        $this->_sKeyLogoDarkAspectRatio = $sPrefix . 'site_logo_dark_aspect_ratio';
+        $this->_sKeyMarkDarkAspectRatio = $sPrefix . 'site_mark_dark_aspect_ratio';
+
+        $this->_iLogoDark = (int)$this->_oDb->getParam($sPrefix . 'site_logo_dark');
+        $this->_fLogoDarkAspectRatio = (float)$this->_oDb->getParam($this->_sKeyLogoDarkAspectRatio);
+        $this->_sLogoInline = $this->_oDb->getParam($sPrefix . 'site_logo_inline');
+
+        $this->_iMarkDark = (int)$this->_oDb->getParam($sPrefix . 'site_mark_dark');
+        $this->_fMarkDarkAspectRatio = (float)$this->_oDb->getParam($this->_sKeyMarkDarkAspectRatio);
+        $this->_sMarkInline = $this->_oDb->getParam($sPrefix . 'site_mark_inline');
+    }
+
+    public function getColorScheme()
+    {
+        return getParam('bx_artificer_color_scheme');
+    }
+
+    public function getLogoParams()
+    {
+    	$sPrefix = $this->getPrefix('option');
+
+    	return [
+            'logo' => $sPrefix . 'site_logo',
+            'logo_dark' => $sPrefix . 'site_logo_dark',
+            'logo_inline' => $sPrefix . 'site_logo_inline',
+            'mark' => $sPrefix . 'site_mark',
+            'mark_dark' => $sPrefix . 'site_mark_dark',
+            'mark_inline' => $sPrefix . 'site_mark_inline',
+            'logo_alt' => $sPrefix . 'site_logo_alt'
+    	];
+    }
+
+    public function getReplacements()
+    {
+        return $this->_aReplacements;
+    }
+
+    public function getThumbSize($sName = '', $sTemplate = '')
+    {
+        if (empty($sName))
+            $sName = 'thumb';
+        
+        if(!empty($sName) && isset($this->_aThumbSizes[$sName]))
+            return $this->_aThumbSizes[$sName];
+
+        if(!empty($sTemplate) && isset($this->_aThumbSizeByTemplate[$sTemplate]))
+            return $this->_aThumbSizeByTemplate[$sTemplate];
+
+        return $this->_sThumbSizeDefault;
+    }
+}
+
+/** @} */

+ 137 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/mod_text/css/main.css

@@ -0,0 +1,137 @@
+/*-- Unit --*/
+.bx-base-text-unit-cnt {
+    width: 100%;
+}
+.bx-base-text-unit-cover {
+	position: relative;
+}
+.bx-base-text-unit-cover img {
+    position: relative;
+    display: block;
+
+    width: 100%;
+    min-height: 300px;
+    object-fit: cover;
+}
+.bx-base-text-unit-ext .bx-base-text-unit-text {
+    text-align: left;
+}
+
+/*-- Browsing: Search results --*/
+.bx-base-text-unit-gallery-wrapper {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: stretch;
+    align-items: stretch;
+    -webkit-flex-wrap: wrap;
+    flex-wrap: wrap;
+    -webkit-justify-content: flex-start;
+    justify-content: flex-start;
+}
+
+.bx-base-text-unit-gallery-wrapper .bx-base-text-unit-gallery {
+    display: -webkit-flex;
+    display: flex;
+
+    -webkit-flex: 0 0 100%;
+    flex: 0 0 100%;
+
+    overflow:hidden;
+}
+.bx-base-unit-showcase-wrapper .flickity-slider {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: stretch;
+    align-items: stretch;
+    -webkit-flex-wrap: wrap;
+    flex-wrap: wrap;
+    -webkit-justify-content: flex-start;
+    justify-content: flex-start;
+}
+.bx-base-unit-showcase-wrapper .bx-base-text-unit-showcase {
+    margin: 0;
+}
+
+.bx-base-unit-showcase-wrapper.bx-sc-enabled .bx-base-text-unit-showcase {
+    height: calc(100% - 3px);
+}
+
+/*-- MEDIA: phone2 --*/
+.bx-media-phone2 .bx-layout-column-half .bx-base-text-unit-gallery-wrapper .bx-base-text-unit-gallery,
+.bx-media-phone2 .bx-layout-column-thin .bx-base-text-unit-gallery-wrapper .bx-base-text-unit-gallery {
+    -webkit-flex: 0 0 49.8%;
+    flex: 0 0 49.8%;
+}
+
+.bx-media-phone2 .bx-base-unit-showcase-wrapper .bx-base-text-unit-showcase {
+   width:calc(50%);
+}
+
+/*-- MEDIA: tablet2 --*/
+.bx-media-tablet2 .bx-layout-column-wide .bx-base-text-unit-gallery-wrapper .bx-base-text-unit-gallery,
+.bx-media-tablet2 .bx-layout-column-fullwidth .bx-base-text-unit-gallery-wrapper .bx-base-text-unit-gallery,
+.bx-media-tablet2 #sys_search_results .bx-base-text-unit-gallery-wrapper .bx-base-text-unit-gallery {
+    -webkit-flex: 0 0 49.8%;
+    flex: 0 0 49.8%;
+}
+
+.bx-media-tablet2 .bx-layout-column-wide .bx-base-unit-showcase-wrapper .bx-base-text-unit-showcase,
+.bx-media-tablet2 .bx-layout-column-fullwidth .bx-base-unit-showcase-wrapper .bx-base-text-unit-showcase,
+.bx-media-tablet2 #sys_search_results .bx-base-unit-showcase-wrapper .bx-base-text-unit-showcase {
+   width: calc(50%);
+}
+
+/*-- MEDIA: desktop --*/
+.bx-media-desktop .bx-layout-column-wide .bx-base-text-unit-gallery-wrapper .bx-base-text-unit-gallery {
+    -webkit-flex: 0 0 49.8%;
+    flex: 0 0 49.8%;
+}
+.bx-media-desktop #sys_search_results .bx-base-text-unit-gallery-wrapper .bx-base-text-unit-gallery,
+.bx-media-desktop .bx-layout-column-fullwidth .bx-base-text-unit-gallery-wrapper .bx-base-text-unit-gallery {
+    -webkit-flex: 0 0 33.25%;
+    flex: 0 0 33.25%;
+}
+
+.bx-media-desktop .bx-layout-column-thin .bx-base-unit-showcase-wrapper .bx-base-text-unit-showcase {
+   width:calc(100%);
+}
+
+.bx-media-desktop .bx-layout-column-half .bx-base-unit-showcase-wrapper .bx-base-text-unit-showcase,
+.bx-media-desktop .bx-layout-column-wide .bx-base-unit-showcase-wrapper .bx-base-text-unit-showcase {
+   width:calc(50%);
+}
+
+.bx-media-desktop #sys_search_results  .bx-base-unit-showcase-wrapper .bx-base-text-unit-showcase,
+.bx-media-desktop .bx-layout-column-fullwidth  .bx-base-unit-showcase-wrapper .bx-base-text-unit-showcase {
+   width:calc(33.3%);
+}
+
+/*-- Entry: Text block --*/
+.bx-base-text-entity-image img {
+    width: 100%;
+}
+
+/*-- Entry: Actions Menu --*/
+.bx-base-general-entity-actions .bx-menu-custom-hor li.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item {
+    width: 100%;
+    border-color: transparent;
+    border-radius: 0;
+    box-shadow: none;
+}
+.bx-base-general-entity-actions .bx-menu-custom-hor > .bx-menu-item-more-auto > .bx-base-general-entity-action > a > .bx-mi-text {
+    display: none;
+}
+
+/*-- Entry: Author block --*/
+.sys-author-info .sys-author-profile ul.bx-menu-custom.bx-menu-custom-hor {
+    -webkit-flex-wrap: wrap;
+    flex-wrap: wrap;
+    -webkit-align-items: center;
+    align-items: center;
+}
+.sys-author-info .sys-author-profile ul.bx-menu-custom.bx-menu-custom-hor > li {
+    margin-left: 1rem;
+}
+.sys-author-info .sys-author-profile ul.bx-menu-custom.bx-menu-custom-hor > li:first-child {
+    margin-left: 0;
+}

+ 14 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/block_join.html

@@ -0,0 +1,14 @@
+<div class="sys-jf">
+    <bx_if:show_auth>__content__</bx_if:show_auth>
+    <bx_if:show_form>__content__</bx_if:show_form>
+    <bx_if:show_login>
+        <hr class="bx-def-hr my-4" />
+        <div class="sys-jf-login">
+            <a class="bx-btn w-full justify-center text-center" href="__url__"><bx_text:_sys_txt_join_description_action /></a>
+        </div>
+    </bx_if:show_login>
+    <div class="sys-jf-agreement -mx-4">
+        <hr class="bx-def-hr mt-4" />
+        <div class="sys-jf-agreement-cnt pt-4 px-4 text-xs text-gray-500">__agreement__</div>
+    </div>
+</div>

+ 34 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/block_login.html

@@ -0,0 +1,34 @@
+<div class="sys-lf">
+    __custom_html_before__
+    <bx_if:show_auth>__content__</bx_if:show_auth>
+    <bx_if:show_form>__content__</bx_if:show_form>
+    __custom_html_after__
+    <bx_if:show_join>
+        <hr class="bx-def-hr my-4" />
+        <div class="sys-lf-join">
+            <a class="bx-btn w-full justify-center text-center" href="__url__"><bx_text:_sys_txt_login_description_action /></a>
+        </div>
+    </bx_if:show_join>
+    <div class="sys-lf-agreement -mx-4">
+        <hr class="bx-def-hr mt-4" />
+        <div class="sys-lf-agreement-cnt pt-4 px-4 text-xs text-gray-500">__agreement__</div>
+    </div>
+    <bx_if:show_js_code>
+        <script>
+            (bx_login_init_ajax_form = function () {
+                $('#sys-form-login').ajaxForm({
+                    dataType: 'json',
+                    success: function (oData) {
+                        if ('undefined' !== typeof(oData['res']) && 'OK' == oData['res']) {
+                            location.reload();
+                        }
+                        else if ('undefined' !== typeof(oData['form'])) {
+                            $('#sys-form-login').replaceWith(oData['form']);
+                            bx_login_init_ajax_form();
+                        }
+                    }
+                });
+            })();
+        </script>
+    </bx_if:show_js_code>
+</div>

+ 64 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/css/cover.css

@@ -0,0 +1,64 @@
+/*--
+import url(../../../../../../../template/css/cover.css);
+--*/
+
+.bx-cover-wrapper {
+    background-image: url(../images/cover-default.svg);
+    background-repeat: no-repeat;
+    background-position: center center;
+    -webkit-background-size: cover;
+    -moz-background-size: cover;
+    -o-background-size: cover;
+    background-size: cover;
+}
+.dark .bx-cover-wrapper {
+    background-image: url(../images/cover-default-dark.svg);
+}
+.bx-image-edit-buttons{
+    position: absolute;
+    left:1rem;
+    top:1rem;
+    z-index: 100;
+}
+.bx-image-edit-buttons .bx-btn.bx-btn-small{
+    padding: 0.375rem 0.5rem;
+}
+.bx-base-pofile-cover-thumb .bx-image-edit-buttons{
+    display: flex;
+    width: 100%;
+    justify-content: center;
+    left:0px;
+    bottom:1rem;
+    top:auto;
+}
+.bx-image-edit-move{
+    cursor:move;
+    position: relative;
+    z-index: 99;
+}
+.bg-cover{
+    background-size: 100% auto !important;
+}
+.bx-image-edit-move-info{
+    display: flex;
+    align-items: center;
+    position: absolute;
+    opacity: 0.5;
+    background-color: #000;
+    -webkit-backface-visibility: hidden;
+    padding: 0.5rem 1rem;
+    border-radius: 1rem;
+    color:#fff;
+    letter-spacing: 1px;
+}
+.bx-image-edit-move-info i{
+    color:#fff;
+    font-size: 1.25rem;
+    margin-right: 1rem;
+}
+.bx-image-edit-buttons-no-image .bx-image-edit-buttons-edit{
+    display: none;
+}
+.bx-image-edit-buttons .bx-uploader-html5-drop-area{
+    display: none;
+}

+ 391 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/css/forms.css

@@ -0,0 +1,391 @@
+/*--
+import url(../../../../../../../template/css/forms.css);
+--*/
+
+.bx-form-advanced-wrapper .bx-form-section-wrapper:first-child {
+    margin-top:0;
+}
+
+.bx-form-advanced-wrapper .bx-form-section-wrapper:last-child {
+    margin-bottom:0;
+}
+
+.bx-form-advanced-wrapper .bx-form-section-divider:first-child {
+    border: none; 
+    padding: 0; 
+}
+
+.bx-form-advanced-wrapper .bx-form-section-divider:first-child .bx-form-section-content {
+    padding-top:0; 
+}
+
+.bx-form-advanced-wrapper .bx-form-section-divider:last-child .bx-form-section-content {
+    padding-bottom:0;
+}
+
+.bx-form-input-wrapper-pgc {
+    position: relative;
+}
+
+.bx-form-option-info {
+    display: inline-flex;
+    flex-direction: column;
+}
+
+/*-- Section Toggler ---*/
+.bx-form-section-wrapper {
+    position: relative;
+}
+
+.bx-form-section {
+    margin: 0;
+}
+
+.bx-form-section-header .bx-form-section-title {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-flex-wrap: nowrap;
+    flex-wrap: nowrap;
+
+    line-height: 1.25rem;
+    text-transform: uppercase;
+}
+
+.bx-form-section-header .bx-form-section-title .sys-icon {
+    color: inherit !important;
+}
+
+.bx-form-section-header .bx-form-section-title u {
+    cursor: pointer;
+}
+
+.bx-form-section-header .bx-form-section-title span {
+    white-space: nowrap;
+    text-transform: none;
+    font-size: 0.75rem;
+}
+
+.bx-form-section-hidden .bx-form-section-content {
+    display:none;
+}
+
+.bx-form-collapsable .bx-form-section-toggler {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-justify-content: center;
+    justify-content: center;
+
+    width: 1.25rem;
+    height: 1.25rem;
+
+    text-decoration: none;
+
+    -moz-transform: rotate(180deg);
+    -webkit-transform: rotate(180deg);
+    -ms-transform: rotate(180deg);
+    -o-transform: rotate(180deg);
+
+    -webkit-transition: all 0.5s ease;
+    -moz-transition: all 0.5s ease;
+    -ms-transition: all 0.5s ease;
+    -o-transition: all 0.5s ease;
+
+    line-height: 1.25rem;
+}
+
+.bx-form-collapsed .bx-form-section-toggler {
+    -moz-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    -ms-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+}
+
+.bx-form-section-toggler .sys-icon {
+    font-size:0.875rem;
+}
+
+/*--- One Line fields ---*/
+.bx-form-element-wrapper-oneline .bx-form-element {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-flow: row nowrap;
+    flex-flow: row nowrap;
+    -webkit-align-items: flex-start;
+    align-items: flex-start;
+    -webkit-justify-content: flex-start;
+    justify-content: flex-start;
+}
+.bx-form-input-wrapper-submit .bx-btn {
+    float: none;
+}
+.bx-form-input-wrapper-input_set .bx-btn {
+    float: left;
+}
+
+
+/*-- Form field: Password --*/
+.bx-artificer .bx-form-input-wrapper-password > a {
+    position: absolute;
+    z-index: 1000;
+    
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-justify-content: center;
+    justify-content: center;
+
+    top: 0;
+    right: 0;    
+    height: 100%;
+
+    margin: 0 0.5rem;
+}
+.bx-artificer .bx-form-input-password {
+    position: relative;
+
+    -moz-box-sizing: border-box;
+    -ms-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+    box-sizing: border-box;
+
+    width: 100%;
+    height: 100%;
+
+    margin: 0;
+    padding: 0.5rem 0;
+
+    border: 0;
+    background-color: transparent;
+}
+.bx-artificer .bx-form-input-password:focus {
+    border-color: transparent;
+    outline: none;
+    box-shadow: none;
+}
+
+/*-- Form field: Slider/Doublerange --*/
+.bx-form-input-wrapper-slider,
+.bx-form-input-wrapper-doublerange {
+    position: relative;
+}
+.bx-form-input-wrapper-slider .ui-slider,
+.bx-form-input-wrapper-doublerange .ui-slider {
+    position: absolute;
+    top: 0px;
+    right: 0px;
+}
+.bx-form-input-wrapper-slider .ui-slider .ui-slider-handle,
+.bx-form-input-wrapper-doublerange .ui-slider .ui-slider-handle { 
+    z-index: 1;
+}
+
+/*-- Form field: Price --*/
+.bx-form-element .bx-form-value .bx-form-input-wrapper-price {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: stretch;
+    align-items: stretch;
+}
+.bx-form-element .bx-form-value .bx-form-input-wrapper-price span {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+
+    width: auto;
+    border-right-width: 0;
+    border-top-right-radius: 0;
+    border-bottom-right-radius: 0;
+}
+.bx-form-element .bx-form-value .bx-form-input-price:not(:first-child) {
+    border-top-left-radius: 0;
+    border-bottom-left-radius: 0;
+}
+
+
+/*-- Form field: Date/Time Pickers --*/
+.bx-form-datepicker-modal {
+    z-index: 10001 !important;
+}
+
+
+/*-- Form field: Switcher --*/
+.bx-switcher-cont input {
+   display: none !important;
+}
+
+
+/*-- Form field: Checkbox/Radio Set --*/
+.bx-form-input-wrapper-checkbox_set label,
+.bx-artificer .bx-form-input-wrapper-radio_set label {
+    margin-left: 0.5rem;
+    vertical-align: text-bottom;
+}
+
+
+/*--- Form field: File ---*/
+.bx-form-input-wrapper-file .bx-btn {
+    display: inline-block;
+    float: none;
+}
+.bx-form-input-file {
+    position: fixed;
+    top: -1000px;
+
+    border: none;
+    background-color: transparent;
+    visibility: hidden;
+}
+
+
+/*--- Form field: Location ---*/
+.bx-form-element .bx-form-value input,
+.bx-form-element .bx-form-value select {
+    display: inline-block;
+}
+.bx-form-element .bx-form-value .minimized input,
+.bx-form-element .bx-form-value .minimized select {
+    display: block;
+}
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-country,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-zip,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-state,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-city {
+    width:49%;
+}
+.bx-form-element .bx-form-input-location-street {
+    width:83%;
+}
+.bx-form-element .bx-form-input-location-street_number {
+    width:15%;
+}
+.bx-form-element .bx-form-input-location-street_number,
+.bx-form-element .bx-form-input-location-street,
+.bx-form-element .bx-form-input-location-state,
+.bx-form-element .bx-form-input-location-city {
+    margin-bottom: 0.25rem;
+}
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-street,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-state,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-country {
+    margin-left: 0.25rem;
+}
+
+.bx-form-element .bx-form-input-location-cont .bx-form-input-location-status-cont {
+    float:none;
+    width:98%;
+    line-height:normal;
+}
+.bx-form-element .bx-form-input-location-cont.minimized .bx-form-input-location-status-cont {
+    display: flex;
+    flex-direction: column;
+    width: auto;
+}
+.bx-form-element .bx-form-input-location-status {
+    float:left;
+}
+.bx-form-element .bx-form-input-location-copyright {
+    float:right;
+}
+.bx-form-element .bx-form-input-location-cont.minimized .bx-form-input-location-copyright {
+    float: none;
+    margin-top: 0.25rem;
+}
+
+.bx-form-element .bx-form-input-location-auto-cont {
+    display:table;
+}
+.bx-form-element .bx-form-input-location-auto-cont > div {
+    display: table-cell;
+    vertical-align: middle;
+}
+
+
+/*--- Form field: Auto-siggestion ---*/
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) {
+    float: left;
+    padding: 0.125rem 0;
+    height: auto;
+    box-shadow: none;
+    min-height: 2.375rem;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b {
+    display: block;
+    float: left;
+    margin: 0.125rem;
+    padding-right: 1.5rem;
+    border-radius: 1.25rem;
+
+    line-height: 2rem;
+    white-space: nowrap;
+    font-weight: normal;    
+    cursor: pointer;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b.val-wo-icon {
+    padding-left: 1.5rem;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b:hover {
+    opacity: 0.7;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b:after {
+    font-family: 'sys-user', 'sys-user-fal';
+    content: "\f00d";    
+    position:absolute;    
+    padding:0 0.5em;
+    margin-left: 0.5em;
+    font-size:0.7em;
+    font-weight:bold;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels).bx-form-input-disabled b {
+    cursor: default;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels).bx-form-input-disabled b:after{
+    display: none;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) input {
+    float: left;
+    width: auto;
+    margin: 0;
+    padding: 0 0 0 0.5rem;
+    border: 0;
+    box-shadow: none;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) .bx-account-unit-wo-info,
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) .bx-base-pofile-unit-wo-info {
+    display: inline-block;
+    vertical-align: top;
+
+    margin-right: 0.5rem;
+}
+.sys-labels .bx-form-input-text.bx-form-input-autotoken b:first-child {
+    margin-left: 2px !important;
+}
+.sys-labels .bx-form-input-text.bx-form-input-autotoken.bx-form-input-disabled b {
+    height: 2rem;
+    line-height: 2rem;
+}
+
+.select2-container {
+    width:100% !important;
+}
+.bx-form-input-select {
+    -webkit-appearance:none;
+}
+
+/* tiny mce */
+.bx-form-input-wrapper-html .gray-theme.fr-toolbar.fr-top{
+   border-radius: .375rem .375rem 0 0 !important; 
+}
+.bx-form-input-wrapper-html .fr-wrapper{
+    border-radius: 0 0 .375rem .375rem !important; 
+    border-bottom-color: #CCCCCC !important;
+}
+.bx-form-input-wrapper-html .second-toolbar{
+    border-bottom:none !important;
+}
+

+ 254 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/css/general.css

@@ -0,0 +1,254 @@
+/*--
+import url(../../../../../../../template/css/general.css);
+--*/
+
+
+/*--- Toolbar ---*/
+.bx-toolbar-anim {
+    -webkit-transition: all .25s ease-in-out;
+    -moz-transition: all .25s ease-in-out;
+    -o-transition: all .25s ease-in-out;
+    transition: all .25s ease-in-out
+}
+.bx-toolbar-reset {
+    -webkit-transform: translateY(0);
+    -ms-transform: translateY(0);
+    transform: translateY(0)
+}
+.bx-toolbar-up {
+    -webkit-transform: translateY(-100%);
+    -ms-transform: translateY(-100%);
+    transform: translateY(-100%)
+}
+.bx-toolbar-item.bx-ti-logo a:hover {
+    text-decoration: none;
+}
+.bx-toolbar-item.bx-ti-logo .bx-logo-inline svg {
+    max-height: 100%;
+    width: auto;
+}
+.bx-toolbar-item.bx-ti-search .bx-ti-search-button a {
+    text-decoration: none;
+}
+.bx-toolbar-item.bx-ti-search .bx-ti-search-button img {
+    width: 1.5rem;
+    height: 1.5rem;
+}
+.bx-toolbar-item.bx-ti-search .bx-tis-button-hidden {
+    display: none;
+}
+.bx-toolbar-item.bx-ti-search .bx-tis-box-shown {
+    position: absolute;
+    display: block;
+}
+.bx-toolbar-item.bx-ti-search .bx-form-advanced .bx-loading-ajax {
+    top: 0;
+    max-height: 100%;
+}
+.bx-toolbar-item.bx-ti-search .bx-form-advanced-wrapper .bx-form-section-wrapper:first-child {
+    margin-top: 0;
+}
+.bx-toolbar-item.bx-ti-search .sys-search-results-quick {
+    position: absolute;
+    z-index: 10;
+}
+.bx-toolbar-item.bx-ti-search .sys-search-results-quick .bx-btn.sys-agents-ask {
+    margin-bottom: 0.5rem;
+}
+.bx-toolbar-item.bx-ti-search .sys-search-results-quick .bx-btn.sys-agents-ask:last-child {
+    margin-bottom: 0;
+}
+#bx_agents_assistants_ask .bx-popup.bx-popup-width {
+    width: 42rem;
+}
+.bx-agents-popup .cmts {
+    max-height: calc(0.5 * 100vh);
+    overflow-y: auto;
+}
+.bx-agents-popup .cmt-reply {
+    margin-bottom: 0;
+}
+.bx-agents-popup .bx-form-section-content {
+    display: flex;
+}
+.bx-agents-popup .bx-form-section-content > .bx-form-element-wrapper:first-child {
+    flex: 1 1 auto;
+}
+.bx-agents-popup .bx-form-section-content > .bx-form-element-wrapper:last-child {
+    flex: 0 0 auto;
+    margin: 0 0 0 1rem;
+}
+.bx-agents-popup .bx-form-value .bx-form-input-textarea {
+    height: 2.5rem;
+    line-height: 1.25rem;
+}
+.bx-agents-popup .bx-form-value .bx-btn i {
+    height: 1.375rem;
+    line-height: 1.375rem;
+}
+
+
+/*--- Page Content with Cover ---*/
+#bx-content-with-cover-wrapper {
+    opacity: 1;
+    transition: opacity 400ms ease-out;
+}
+#bx-content-with-cover-wrapper.htmx-added {
+    opacity: 0;
+}
+
+
+/*--- Page Submenu ---*/
+.bx-menu-main-bar-cnt {
+    height: 3.25rem;
+}
+
+.bx-menu-main-bar:not(.bx-menu-more-auto) .bx-menu-main-bar-cnt > div {
+    overflow-x: auto;
+}
+
+.bx-menu-main-bar-gap.bx-menu-main-bar-hidden,
+.bx-menu-main-bar-wrapper.bx-menu-main-bar-hidden,
+.bx-menu-main-bar.bx-menu-main-bar-hidden {
+    display: none;
+}
+
+
+/*--- Page Content ---*/
+#bx-content-wrapper.htmx-added {
+    opacity: 0;
+}
+
+#bx-content-wrapper.ltr.htmx-swapping:not(.htmx-added) {
+    opacity: 0;
+    transition: opacity 400ms ease-out;
+    animation: slide-to-right 400ms cubic-bezier(0.37, 0.82, 0.2, 1);
+}
+#bx-content-wrapper.ltr.htmx-settling {
+    opacity: 1;
+    animation: slide-from-left 400ms cubic-bezier(0.37, 0.82, 0.2, 1);
+}
+
+#bx-content-wrapper.rtl.htmx-swapping:not(.htmx-added) {
+    opacity: 0;
+    transition: opacity 400ms ease-out;
+    animation: slide-to-left 400ms cubic-bezier(0.37, 0.82, 0.2, 1);
+}
+#bx-content-wrapper.rtl.htmx-settling {
+    opacity: 1;
+    animation: slide-from-right 400ms cubic-bezier(0.37, 0.82, 0.2, 1);
+}
+
+@keyframes slide-from-right {
+    from { transform: translateX(100%); }
+}
+@keyframes slide-to-right {
+    to { transform: translateX(100%); }
+}
+@keyframes slide-from-left {
+    from { transform: translateX(-100%); }
+}
+@keyframes slide-to-left {
+    to { transform: translateX(-100%); }
+}
+
+
+/*--- Profile Avatar ---*/
+.bx-db-content.bx-content-padding-block .bx-profile-avatar-cnt {
+    margin-left: -0.25rem;
+    margin-right: -0.25rem;
+}
+#bx-profile-switcher .bx-pas-list .bx-def-hr:first-child {
+    display: none;
+}
+
+/*--- Profile Stats ---*/
+.bx-menu-vertical-more-less li.bx-psmi-show-more,
+.bx-menu-vertical-more-less li.bx-psmi-show-less {
+    text-transform: uppercase;
+    font-size: 0.875rem;
+}
+
+.bx-menu-vertical-more-less li.bx-psmi-show-more:hover,
+.bx-menu-vertical-more-less li.bx-psmi-show-less:hover {
+    background-color: transparent;
+}
+
+/*--- Author Info ---*/
+.sys-author-profile .bx-menu-custom.bx-menu-custom-hor > li:first-child .bx-base-general-unit-meta-div {
+    display: none;
+}
+
+/*--- Join/Login Forms ---*/
+.sys-jf .bx-form-advanced .bx-form-element .bx-form-input-submit.bx-btn,
+.sys-lf .bx-form-advanced .bx-form-element .bx-form-input-submit.bx-btn {
+    width: 100%;
+    -webkit-justify-content: center;
+    justify-content: center;
+    text-align: center;
+}
+#bx-form-element-submit_text .bx-form-value {
+    text-align: right;
+}
+
+/*--- Page Type: Application ---*/
+.bx-menu-panel-item .bx-profile-avatar .bx-profile-avatar-cnt {
+    min-height: 2.5rem;
+}
+
+/*--- Create Post Form ---*/
+.sys-cpf-form:not(.sys-cpf-loading) {
+    -webkit-animation: sys-cpf-scale-in 0.4s cubic-bezier(0.37, 0.82, 0.2, 1);
+    animation: sys-cpf-scale-in 0.4s cubic-bezier(0.37, 0.82, 0.2, 1);
+}
+
+@keyframes sys-cpf-scale-in {
+    0% {
+        opacity: 0;
+        transform: scale(0.9);
+    }
+    100% {
+        opacity: 1;
+        transform: scale(1.0);
+    }
+}
+
+@-webkit-keyframes sys-cpf-scale-in {
+    0% {
+        opacity: 0;
+        transform: scale(0.9);
+    }
+    100% {
+        opacity: 1;
+        transform: scale(1.0);
+    }
+}
+
+/* --------------- System objects like Views, Votes, Comments, etc, */
+.sys-action-counter.sys-ac-hidden {
+    display: none;
+}
+.sys-action-counter.sys-action-counter-iconset .sys-ac-link {
+    padding-left: 0.75rem;
+}
+.bx-media-phone .sys-action-counter.sys-action-counter-iconset .sys-ac-link,
+.bx-media-tablet .bx-layout-column-thin .sys-action-counter.sys-action-counter-iconset .sys-ac-link,
+.bx-media-tablet .bx-layout-column-half .sys-action-counter.sys-action-counter-iconset .sys-ac-link {
+    padding-left: 1.0rem;
+}
+.sys-action-counter.sys-action-counter-iconset .bx-def-icon-size {
+    width: 1.5rem;
+    height: 1.5rem;
+}
+.sys-action-counter.sys-action-counter-iconset .bx-base-pofile-unit-wo-info,
+.sys-action-counter.sys-action-counter-iconset .sys-action-counter-icon {
+    margin-left: -0.5rem;
+}
+.bx-media-phone .sys-action-counter.sys-action-counter-iconset .bx-base-pofile-unit-wo-info,
+.bx-media-phone .sys-action-counter.sys-action-counter-iconset .sys-action-counter-icon,
+.bx-media-tablet .bx-layout-column-thin .sys-action-counter.sys-action-counter-iconset .bx-base-pofile-unit-wo-info,
+.bx-media-tablet .bx-layout-column-thin .sys-action-counter.sys-action-counter-iconset .sys-action-counter-icon,
+.bx-media-tablet .bx-layout-column-half .sys-action-counter.sys-action-counter-iconset .bx-base-pofile-unit-wo-info,
+.bx-media-tablet .bx-layout-column-half .sys-action-counter.sys-action-counter-iconset .sys-action-counter-icon {
+    margin-left: -0.75rem;
+}

+ 224 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/css/menu.css

@@ -0,0 +1,224 @@
+/*--
+import url(../../../../../../../template/css/menu.css);
+--*/
+
+ul.bx-menu-hor,
+ul.bx-menu-custom-hor,
+ul.bx-menu-notif,
+ul.bx-menu-verlit,
+ul.bx-menu-ver,
+ul.bx-menu-custom-ver,
+ul.bx-menu-main,
+ul.bx-menu-main-submenu,
+ul.bx-menu-toolbar,
+ul.bx-menu-floating-blocks-wide,
+ul.bx-menu-floating-blocks-big,
+ul.bx-menu-floating-blocks-dash,
+ul.bx-menu-floating-blocks,
+ul.bx-menu-inter,
+ul.bx-menu-inter-vert,
+ul.bx-menu-btns-ver,
+ul.bx-menu-btns-hor,
+ul.bx-menu-btns-icon-hor {
+    padding: 0;
+    margin: 0;
+    list-style: none;
+}
+
+li.bx-mi-aux {}
+li.bx-mi-hidden {
+    display: none;
+}
+
+/* --- Vertical, Vertical lite, Custom Vertical Menus ---*/
+.bx-menu-ver li,
+.bx-menu-verlit li,
+.bx-menu-custom-ver li {
+    margin-top: 1px;
+}
+.bx-menu-ver li:first-child,
+.bx-menu-verlit li:first-child,
+.bx-menu-custom-ver li:first-child {
+    margin-top: 0px;
+}
+
+/*--- Vertical, Vertical lite, Custom Vertical Menus (in Popup) ---*/
+.bx-popup .bx-menu-custom-ver li > span {
+    -webkit-flex: 1 1 auto;
+    -ms-flex: 1 1 auto;
+    flex: 1 1 auto;
+
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-justify-content: space-between;
+    justify-content: space-between;
+}
+.bx-popup .bx-menu-custom-ver li > span .bx-menu-addon {
+    padding-right: 1.0rem;
+}
+
+/* --- Horizontal, Custom Horizontal Menus --- */
+.bx-menu-custom .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item,
+.bx-menu-custom .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item a,
+.bx-menu-custom .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item > span {
+    border-radius: 0;
+}
+
+/*--- Interactive Menu ---*/
+.bx-menu-inter li.bx-menu-inter-hidden,
+.bx-menu-inter-vert li.bx-menu-inter-hidden {
+    display: none;
+}
+
+/*--- Custom Menu with More Auto ---*/
+.bx-menu-main-submenu.bx-menu-more-auto .bx-menu-item.bx-menu-item-more-auto,
+.bx-menu-custom.bx-menu-custom-hor.bx-menu-more-auto .bx-menu-item.bx-menu-item-more-auto {
+    display: none;
+}
+.bx-menu-more-auto .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-item a.p-2,
+.bx-menu-more-auto .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-item a.px-2 {
+    padding-left: 1rem;
+    padding-right: 1rem;
+}
+
+/*--- Page Main menu ---*/
+.bx-menu-main .bx-menu-item.bx-menu-item-more-auto {
+    display: none;
+}
+.bx-menu-main .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item,
+.bx-menu-main .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item a {
+    border-radius: 0;
+}
+
+/*--- Page Submenu ---*/
+.bx-menu-main-submenu {
+    -webkit-justify-content: center;
+    justify-content: center;
+}
+.bx-menu-main-submenu .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item > a {
+    width: 100%;
+    padding: 0.5rem 1.0rem; 
+    text-align: left;
+}
+.bx-menu-main-submenu .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item .bx-mi-underline {
+    display: none;
+}
+
+/*--- Toolbar Menu ---*/
+.bx-menu-toolbar .bx-menu-toolbar-item .bx-menu-item-addon {
+    position: absolute;
+    top: -0.375rem;
+    right: -0.375rem;
+    padding: 0 0.25rem;
+}
+.bx-menu-toolbar .bx-menu-toolbar-item .bx-menu-toolbar-item-unit .bx-base-pofile-unit-online {
+    display: none;
+}
+
+/*--- Account Popup ---*/
+#bx-sliding-menu-account .bx-menu-account-popup .bx-menu-item-addon.bx-def-unit-alert {
+    position: relative;
+    padding: 0 0.25rem;
+}
+#bx-sliding-menu-account .bx-menu-account-popup-profile-create {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-justify-content: center;
+    justify-content: center;
+}
+
+/*--- Add Popup ---*/
+div.bx-popup-menu-main.sys-add-content ul {
+    flex-direction: column;
+}
+
+/*--- Pannel Menu ---*/
+.bx-menu-panel {}
+
+.bx-main-column.bx-mc-narrowed .bx-menu-panel .bx-menu-panel-item .bx-mpi-toggle-hidden {
+    position: absolute;
+    display: none;
+}
+
+.bx-mc-narrowed .bx-menu-panel li .bx-stl-mil {
+    -webkit-justify-content: center;
+    justify-content: center;
+
+    padding-left: 0;
+    padding-right: 0;
+}
+.bx-mc-narrowed .bx-menu-panel li .bx-stl-mii {
+    width: 100%;
+    text-align: center;
+}
+.bx-mc-narrowed .bx-menu-panel li .bx-stl-mii,
+.bx-mc-narrowed .bx-menu-panel li .bx-stl-mii > * {
+    margin: 0;
+}
+.bx-mc-narrowed .bx-menu-panel .bx-def-thumb-size {
+    width: 2rem;
+    height: 2rem;
+}
+.bx-mc-narrowed .bx-menu-panel .bx-profile-avatar-cnt {
+    -webkit-justify-content: center;
+    justify-content: center;
+}
+
+/*--- Footer Menu ---*/
+#bx-menu-footer.bx-menu-hor > li.bx-menu-item-powered_by .sys-icon-svg {
+    width: auto;
+}
+
+/*--- Profile Stats/Followings Menu ---*/
+.bx-db-content .bx-profile-stats .bx-profile-avatar-cnt,
+.bx-db-content .bx-profile-stats .bx-menu-vertical-more-less,
+.bx-db-container:not(.bx-dbc-nopadding) .bx-menu-vertical-more-less,
+.bx-db-container:not(.bx-dbc-nopadding) .bx-menu-profile-followings {
+    margin: -0.75rem;
+}
+.bx-db-container:not(.bx-dbc-notitle) .bx-menu-vertical-more-less,
+.bx-db-container:not(.bx-dbc-notitle) .bx-menu-profile-followings {
+    margin-top: 0;
+}
+
+/*--- Profile Followings Menu ---*/
+.bx-menu-contents .bx-menu-show,
+.bx-menu-ver.bx-menu-multilevel li .bx-menu-show,
+.bx-menu-ver.bx-menu-object-sys_profile_followings li .bx-menu-show {
+    display: none;
+}
+.bx-menu-contents .bx-menu-hide,
+.bx-menu-ver.bx-menu-multilevel li .bx-menu-hide, 
+.bx-menu-ver.bx-menu-object-sys_profile_followings li .bx-menu-hide {
+    display: inline;
+}
+.bx-menu-contents.bx-m-collapsed .bx-menu-show,
+.bx-menu-ver.bx-menu-multilevel li.bx-mi-collapsed .bx-menu-show,
+.bx-menu-ver.bx-menu-object-sys_profile_followings li.bx-mi-collapsed .bx-menu-show {
+    display: inline;
+}
+.bx-menu-contents.bx-m-collapsed .bx-menu-hide,
+.bx-menu-ver.bx-menu-multilevel li.bx-mi-collapsed .bx-menu-hide,
+.bx-menu-ver.bx-menu-object-sys_profile_followings li.bx-mi-collapsed .bx-menu-hide {
+    display: none;
+}
+.bx-menu-ver.bx-menu-multilevel li.bx-mi-collapsed .bx-menu-item-subitems,
+.bx-menu-ver.bx-menu-object-sys_profile_followings li.bx-mi-collapsed .bx-menu-item-subitems {
+    display: none;
+}
+
+/*--- Profiles meta menu ---*/
+.sys-action-counter-icon .sys-icon-image,
+.sys-action-counter-icon .sys-icon{
+    width: 1rem;
+    height: 1rem;
+    font-size: 0.75rem;
+    line-height: 1.1rem;
+    text-align: center;
+}
+.sys-action-counter-icon .sys-icon-image,
+.sys-action-counter-icon .sys-icon.sys-icon-emoji{
+    line-height: 1rem;
+}

+ 9 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/logo_main.html

@@ -0,0 +1,9 @@
+<a __attrs__>
+    <bx_if:show_title><span>__logo__</span></bx_if:show_title>
+    <bx_if:show_logo><img class="__class__" style="__style__" src="__src__" id="__id__" alt="__alt__" /></bx_if:show_logo>
+    <bx_if:show_logo_dark><img class="__class__" style="__style__" src="__src__" id="__id__" alt="__alt__" /></bx_if:show_logo_dark>
+    <bx_if:show_logo_inline><span class="bx-logo-inline __class__" style="height: __height__">__content__</span></bx_if:show_logo_inline>
+    <bx_if:show_mark><img class="__class__" style="__style__" src="__src__" id="__id__" alt="__alt__" /></bx_if:show_mark>
+    <bx_if:show_mark_dark><img class="__class__" style="__style__" src="__src__" id="__id__" alt="__alt__" /></bx_if:show_mark_dark>
+    <bx_if:show_mark_inline><span class="bx-logo-inline __class__" style="height: __height__">__content__</span></bx_if:show_mark_inline>
+</a>

+ 120 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/pt_application.html

@@ -0,0 +1,120 @@
+<bx_include_auto:_header.html />
+<div class="bx-main bx-pt-application <bx_injection:injection_main_class />">
+    <bx_injection:top />
+    <!-- BEG: Navigation -->
+    <nav class="fixed z-30 w-full bg-white border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700">
+        <div class="px-3 py-3 lg:px-5 lg:pl-3">
+            <div class="flex items-center justify-between">
+                <div class="flex flex-1 items-center justify-start">
+                    <!-- Sidebar Toggler -->
+                    <button id="toggleSidebar" aria-expanded="true" aria-controls="sidebar" class="hidden mr-6 bg-gray-100 dark:bg-gray-700/50 text-gray-600 rounded-full cursor-pointer xl:inline hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-white dark:hover:bg-gray-700">
+                      <div class="bx-icon bx-icon-hamburger flex items-center justify-center h-10 w-10">
+                          <bx_image_auto:bars />
+                      </div>
+                    </button>
+                    <button id="toggleSidebarMobile" aria-expanded="true" aria-controls="sidebar" class="mr-2 bg-gray-100 dark:bg-gray-700/50 text-gray-600 rounded-full cursor-pointer xl:hidden hover:text-gray-900 hover:bg-gray-100 focus:bg-gray-100 dark:focus:bg-gray-700 focus:ring-2 focus:ring-gray-100 dark:focus:ring-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
+                      <div id="toggleSidebarMobileHamburger" class="bx-icon bx-icon-hamburger flex items-center justify-center h-10 w-10">
+                          <bx_image_auto:bars />
+                      </div>
+                      <div id="toggleSidebarMobileClose" class="bx-icon bx-icon-close hidden flex items-center justify-center h-10 w-10">
+                        <bx_image_auto:times />
+                      </div>
+                    </button>
+                    <div class="bx-toolbar-items-group relative flex flex-1 items-center justify-start">
+                        <!-- Logo -->
+                        <div id="bx-logo-container" class="bx-toolbar-item bx-ti-left bx-ti-logo flex-none items-center">
+                            <bx_injection:injection_logo_before />
+                            __main_logo__
+                            <bx_injection:injection_logo_after />
+                        </div>
+                        <!-- Menu -->
+                        <div class="bx-toolbar-item bx-ti-menu flex-2 hidden xl:block w-64 ml-4">
+                            <div id="bx-menu-toolbar-1-container" class="bx-toolbar-item bx-ti-menu w-full">
+                                <bx_menu:sys_application />
+                            </div>
+                        </div>
+                        <!-- Search -->
+                        <div class="bx-toolbar-item bx-ti-search flex flex-1 items-center justify-end">
+                            __sys_toolbar_search__
+                        </div>
+                    </div>
+                </div>
+                <div class="flex items-center">
+                    <!-- Members Toolbar -->
+                    <bx_menu:sys_toolbar_member />
+                </div>
+            </div>
+        </div>
+    </nav>
+    <!-- END: Navigation -->
+
+    <div class="bx-main-content flex pt-16 overflow-hidden">
+        <!-- BEG: Sidebar -->
+        <aside id="sidebar" class="bx-main-column narrow fixed top-0 left-0 z-20 hidden xl:flex flex-col flex-shrink-0 w-64 h-full pt-16 duration-75 transition-width" aria-label="Sidebar">
+            <div class="bx-mc-border relative flex flex-col flex-1 min-h-0 max-h-full h-full pt-0 bg-white border-r border-gray-200 dark:bg-gray-800 dark:border-gray-700">
+                <div class="flex flex-col flex-1 py-2 overflow-y-auto">
+                    <div class="bx-mc-cnt flex-1 px-4 space-y-1 bg-white divide-y divide-gray-200 dark:bg-gray-800 dark:divide-gray-700">
+                        <bx_menu:sys_site_panel />
+                    </div>
+                </div>
+                <div class="absolute bottom-0 left-0 justify-center hidden w-full p-4 space-x-4 xl:flex" sidebar-bottom-menu>
+                    <!-- Some button based menu may be here -->
+                </div>
+            </div>
+        </aside>
+        <div class="fixed inset-0 z-10 hidden bg-gray-900/50 dark:bg-gray-900/90" id="sidebarBackdrop"></div>
+        <!-- END: Sidebar -->    
+
+        <!-- BEG: Main Content -->
+        <div id="main-content" class="bx-main-column wide relative w-full h-full overflow-y-auto xl:ml-64">
+            <main>
+                <bx_injection:injection_between_cover_logo />
+                __cover__
+                <bx_injection:injection_between_cover_top_menu />
+                <div id="bx-menu-main-bar-wrapper" class="bx-menu-main-bar-wrapper bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800 __site_submenu_hidden__">
+                    <div id="bx-menu-main-bar" class="bx-menu-main-bar __site_submenu_class__ mx-auto px-4 sm:px-6 lg:px-8 box-border">
+                        <div class="bx-menu-main-bar-cnt -mb-px">
+                            <bx_injection:injection_top_menu_before />
+                            <div class="flex items-center h-full text-center">
+                                <div class="relative flex-1 h-full">
+                                    <div class="absolute w-full h-full">
+                                        <bx_menu:sys_site_submenu />
+                                    </div>
+                                </div>
+                                <div class="flex-none">
+                                    <bx_menu:sys_site_manage />
+                                </div>
+                            </div>
+                            <bx_injection:injection_top_menu_after />
+                        </div>
+                    </div>
+                </div>
+                <bx_injection:injection_between_content_menu />
+                <div id="bx-content-wrapper" class="bx-def-page-width mx-auto">
+                    __informer__
+                    <div class="bx-page-wrapper mx-auto px-3 md:px-4 lg:px-6 box-border">
+                        <div id="bx-content-container" class="bx-content-container">
+                            <div id="bx-content-main" class="bx-content-main my-2 lg:my-3">
+                                <bx_injection:injection_content_before />
+                                __page_main_code__
+                                <bx_injection:injection_content_after />
+                                <bx_injection:banner_bottom />
+                            </div> <!-- #bx-content-main -->
+                            <bx_injection:injection_between_content_footer />
+                        </div> <!-- #bx-content-container -->
+                    </div> <!-- .bx-page-wrapper -->
+                </div> <!-- #bx-content-wrapper -->
+            </main>
+            <footer class="p-4 m-4 bg-white rounded-lg shadow md:flex md:items-center md:justify-between md:p-6 xl:p-8 dark:bg-gray-800">
+                <bx_injection:injection_footer_before />
+                <div id="bx-menu-bottom">
+                    <bx_menu:sys_footer />
+                </div>
+                <bx_injection:injection_footer_after />
+            </footer>
+        </div>
+        <!-- END: Main Content -->
+    </div>
+    <bx_menu:sys_site_action />
+</div> <!-- .bx-main -->
+<bx_include_auto:_footer.html />

+ 302 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/scripts/BxTemplFunctions.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    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+bx_import('BxDolDesigns');
+
+class BxTemplFunctions extends BxBaseFunctions
+{
+    protected $_sModule;
+
+    public function __construct($oTemplate = null)
+    {
+        parent::__construct($oTemplate);
+
+        $this->_sModule = 'bx_artificer';
+    }
+
+    public function getMainLogoDarkUrl()
+    {
+        return BxDolDesigns::getInstance()->getSiteLogoDarkUrl();
+    }
+
+    public function getMainLogoInline()
+    {
+        return BxDolDesigns::getInstance()->getSiteLogoParam('logo_inline');
+    }
+
+    public function getMainMarkDarkUrl()
+    {
+        return BxDolDesigns::getInstance()->getSiteMarkDarkUrl();
+    }
+
+    public function getMainMarkInline()
+    {
+        return BxDolDesigns::getInstance()->getSiteLogoParam('mark_inline');
+    }
+
+    public function getMainLogo($aParams = [])
+    {
+        $oModule = BxDolModule::getInstance($this->_sModule);
+        $oDesigns = BxDolDesigns::getInstance();
+
+        $sTitle = getParam('site_title');
+
+        $sAlt = $oDesigns->getSiteLogoAlt();
+        if(empty($sAlt) && !empty($sTitle))
+            $sAlt = $sTitle;
+        $sAltAttr = bx_html_attribute($sAlt, BX_ESCAPE_STR_QUOTE);
+
+        $aImages = [
+            'logo' => ['uc' => 'Logo', 'gi' => 'logo-generic.svg'], 
+            'logo_dark' => ['uc' => 'LogoDark', 'gi' => 'logo-dark-generic.svg'], 
+            'mark' => ['uc' => 'Mark', 'gi' => 'mark-generic.svg'], 
+            'mark_dark' => ['uc' => 'MarkDark', 'gi' => 'mark-dark-generic.svg'], 
+        ];
+
+        $aTmplVarsImages = [];
+        $bLogo = $bLogoDark = $bMark = $bMarkDark = false;
+        foreach($aImages as $sType => &$aParams)
+            if(($aParams['g'] = false) || ($sFileUrl = $this->{'getMain' . $aParams['uc'] . 'Url'}()) !== false || ($aParams['g'] = (($sType == 'logo' || $aImages['logo']['g']) && ($sFileUrl = $this->_oTemplate->getImageUrl($aParams['gi'])) != ''))) {
+                $iLogoHeight = (int)$oDesigns->{'getSite' . $aParams['uc'] . 'Height'}();
+                $sLogoHeight = $iLogoHeight > 0 ? 'height:' . round($iLogoHeight/16, 3) . 'rem;' : '';
+
+                if(!empty($aParams['g'])) {
+                    list($iDlWidth, $iDlHeight) = bx_get_svg_image_size($sFileUrl);
+                    $fDlAspectRation = $iDlHeight ? $iDlWidth / $iDlHeight : BxDolDesigns::getAspectRatioDefault($sType);
+
+                    $iLogoWidth = $iLogoHeight * $fDlAspectRation;
+                }
+                else
+                    $iLogoWidth = $oDesigns->{'getSite' . $aParams['uc'] . 'Width'}();
+
+                $sLogoWidth = $iLogoWidth > 0 ? 'width:' . round($iLogoWidth/16, 3) . 'rem;' : '';
+
+                $aTmplVarsImages[$sType] = [
+                    'id' => 'bx-' . str_replace('_', '-', $sType),
+                    'src' => $sFileUrl,
+                    'alt' => $sAltAttr,
+                    'class' => '',
+                    'style' => $sLogoWidth . ' ' . $sLogoHeight,
+                ];
+
+                ${'b' . $aParams['uc']} = true;
+            }
+
+        $sLogoInline = $sLogoInlineClass = '';
+        if($aImages['logo']['g'] && ($sLogoInline = $this->getMainLogoInline()) != '') {
+            $bLogo = true;
+            $bLogoDark = false;
+            unset($aTmplVarsImages['logo'], $aTmplVarsImages['logo_dark']);
+        }
+
+        $sMarkInline = $sMarkInlineClass = '';
+        if($aImages['mark']['g'] && ($sMarkInline = $this->getMainMarkInline()) != '') {
+            $bMark = true;
+            $bMarkDark = false;
+            unset($aTmplVarsImages['mark'], $aTmplVarsImages['mark_dark']);
+        }
+
+        if($bLogo) {
+            if($bLogoDark && !$bMark)
+                $aTmplVarsImages['logo']['class'] = 'block dark:hidden';
+            if(!$bLogoDark && $bMark) {
+                $sLogoInlineClass = 'hidden lg:block';
+                if(isset($aTmplVarsImages['logo']))
+                    $aTmplVarsImages['logo']['class'] = $sLogoInlineClass;
+            }
+            if($bLogoDark && $bMark)
+                $aTmplVarsImages['logo']['class'] = 'hidden dark:hidden lg:block'; 
+        }
+
+        if($bLogoDark) {
+            $aTmplVarsImages['logo_dark']['class'] = 'hidden dark:block';
+
+            if($bMark || $bMarkDark)
+                $aTmplVarsImages['logo_dark']['class'] = 'hidden dark:lg:block';
+        }
+
+        if($bMark) {
+            $sMarkInlineClass = 'block lg:hidden';
+            if(isset($aTmplVarsImages['mark']))
+                $aTmplVarsImages['mark']['class'] = $sMarkInlineClass;
+
+            if($bMarkDark)
+                $aTmplVarsImages['mark']['class'] = 'block dark:hidden lg:hidden';
+        }
+
+        if($bMarkDark) {
+            $aTmplVarsImages['mark_dark']['class'] = 'hidden dark:block dark:lg:hidden';
+        }
+
+
+        $aAttrs = [
+            'href' => BX_DOL_URL_ROOT, 
+            'title' => $sAltAttr
+        ];
+        if(!empty($aParams['attrs']) && is_array($aParams['attrs']))
+            $aAttrs = array_merge($aAttrs, $aParams['attrs']);
+
+        $sTmplName = 'logo_main.html';
+        $aTmplVars = [
+            'attrs' => bx_convert_array2attrs($aAttrs),
+            'bx_if:show_title' => [
+                'condition' => !$bLogo && !$sLogoInline,
+                'content' => [
+                    'logo' => $sTitle,
+                ]
+            ],
+            'bx_if:show_logo_inline' => [
+                'condition' => !empty($sLogoInline),
+                'content' => [
+                    'class' => $sLogoInlineClass,
+                    'height' => $oModule->_oConfig->getLogoHeight() . 'px',
+                    'content' => $sLogoInline
+                ]
+            ],
+            'bx_if:show_mark_inline' => [
+                'condition' => !empty($sMarkInline),
+                'content' => [
+                    'class' => $sMarkInlineClass,
+                    'height' => $oModule->_oConfig->getMarkHeight() . 'px',
+                    'content' => $sMarkInline
+                ]
+            ]
+        ];
+
+        foreach($aImages as $sType => $aParams) {
+            if(($sTypeIf = 'bx_if:show_' . $sType) && isset($aTmplVarsImages[$sType]))
+                $aTmplVars[$sTypeIf] = [
+                    'condition' => true,
+                    'content' => $aTmplVarsImages[$sType]
+                ];
+            else 
+                $aTmplVars[$sTypeIf] = [
+                    'condition' => false,
+                    'content' => []
+                ];
+        }
+
+        bx_alert('system', 'get_logo', 0, 0, [
+            'tmpl_name' => &$sTmplName,
+            'tmpl_vars' => &$aTmplVars
+        ]);
+
+        return $this->_oTemplate->parseHtmlByName($sTmplName, $aTmplVars);
+    }
+
+    public function TemplPageAddComponent($sKey)
+    {
+        $mixedResult = false;
+
+        switch($sKey) {
+            case 'sys_header_width':
+                $mixedResult = '';
+                if(getParam('bx_artificer_header_stretched') != 'on')
+                    $mixedResult = parent::TemplPageAddComponent($sKey);
+                break;
+
+            case 'sys_toolbar_search':
+                if(getParam('bx_artificer_header_search') == 'on')
+                    $mixedResult = parent::TemplPageAddComponent($sKey);
+                else
+                    $mixedResult = '';
+                break;
+
+            default:
+                $mixedResult = parent::TemplPageAddComponent($sKey);
+        }
+
+        return $mixedResult;
+    }
+
+    public function getColorSchemeSwitcher()
+    {
+        $oModule = BxDolModule::getInstance($this->_sModule);
+
+        if($oModule->_oConfig->getColorScheme() != 'auto')
+            return '';
+        
+        $aMenu = [
+            ['id' => $this->_sModule . '-css-sun', 'name' => $this->_sModule . '-css-sun', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:oBxArtificerUtils.setColorScheme(1)', 'target' => '_self', 'icon' => 'sun', 'title' => _t('_bx_artificer_txt_color_scheme_light')],
+            ['id' => $this->_sModule . '-css-moon', 'name' => $this->_sModule . '-css-moon', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:oBxArtificerUtils.setColorScheme(2)', 'target' => '_self', 'icon' => 'moon', 'title' => _t('_bx_artificer_txt_color_scheme_dark')],
+            ['id' => $this->_sModule . '-css-desktop', 'name' => $this->_sModule . '-css-desktop', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:oBxArtificerUtils.setColorScheme(0)', 'target' => '_self', 'icon' => 'desktop', 'title' => _t('_bx_artificer_txt_color_scheme_system')],
+        ];
+        $oMenu = new BxTemplMenu(['template' => 'menu_vertical.html', 'menu_id'=> $this->_sModule . '-css-menu', 'menu_items' => $aMenu]);
+
+        return $oModule->_oTemplate->parseHtmlByName('color_scheme_switcher.html', [
+            'popup' => $this->transBox('bx-sb-theme-switcher-menu', $oMenu->getCode(), true)
+        ]);
+    }
+
+    protected function getInjFooterPopupMenus() 
+    {
+        $sContent = '';
+
+        $oSearch = new BxTemplSearch();
+        $oSearch->setLiveSearch(true);
+        $sContent .= $this->_oTemplate->parsePageByName('search.html', array(
+            'search_form' => $oSearch->getForm(BX_DB_CONTENT_ONLY),
+            'results' => $oSearch->getResultsContainer(),
+        ));
+
+        if(isLogged())
+            $sContent .= $this->_oTemplate->getMenu('sys_add_content');
+
+        return $sContent;
+    }
+
+    protected function getInjFooterSidebarSite() 
+    {
+        $oSearch = new BxTemplSearch();
+        $oSearch->setLiveSearch(true);
+        $sSearch = $oSearch->getForm(BX_DB_CONTENT_ONLY);
+
+        $sLogoUrl = $this->getMainLogoUrl();
+        $bLogoUrl = !empty($sLogoUrl);
+
+        $sLogoText = BxDolDesigns::getInstance()->getSiteLogoAlt();
+        if(empty($sLogoText))
+            $sLogoText = getParam('site_title');
+
+        return $this->_oTemplate->parsePageByName('sidebar_site.html', array(
+            'bx_if:show_logo_image' => array(
+                'condition' => $bLogoUrl,
+                'content' => array(
+                    'logo_url' => $sLogoUrl,
+                    'logo_text' => $sLogoText
+                )
+            ),
+            'bx_if:show_logo_text' => array(
+                'condition' => !$bLogoUrl,
+                'content' => array(
+                    'logo_text' => $sLogoText
+                )
+            ),
+            'search_form' => $sSearch,
+        ));
+    }
+
+    protected function getInjFooterSidebarAccount() 
+    {
+        $oProfile = BxDolProfile::getInstance();
+        if(!$oProfile)
+            return '';
+
+        $sMenuAccountPopup = 'sys_account_popup';
+        $oMenuAccountPopup = BxTemplMenu::getObjectInstance($sMenuAccountPopup);
+
+        return $this->_oTemplate->parsePageByName('sidebar_account.html', [
+            'color_scheme_switcher' => $this->getColorSchemeSwitcher(),
+            'ap_menu_object' => $sMenuAccountPopup,
+            'bx_repeat:ap_menu_items' => $oMenuAccountPopup->getMenuItems(),
+        ]);
+    }
+}
+
+/** @} */

+ 75 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/scripts/BxTemplMenuSidebarSite.php

@@ -0,0 +1,75 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolMenu
+ */
+class BxTemplMenuSidebarSite extends BxTemplMenu
+{
+    protected $_sPageUri;
+    protected $_aHideFromMenu;
+
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+
+        list($sPageUrl, $aPageParams) = bx_get_base_url_inline();
+        $this->_sPageUri = !empty($aPageParams['i']) ? $aPageParams['i'] : '';
+
+        $this->_aHideFromMenu = ['search', 'more-auto'];
+    }
+
+    protected function _getMenuItem ($a)
+    {
+        if(in_array($a['name'], $this->_aHideFromMenu))
+            return false;
+
+        $aResult = parent::_getMenuItem($a);
+        if(empty($aResult) || !is_array($aResult))
+            return $aResult;
+
+        $aTmplVarsSubmenu = [];
+        $bTmplVarsSubmenu = !empty($aResult['submenu_object']);
+        if($bTmplVarsSubmenu) {
+            $aResult['bx_if:onclick'] = [
+                'condition' => true,
+                'content' => [
+                    'onclick' => "javascript:return bx_sidebar_dropdown_toggle(this)"
+            ]];
+            $aResult['class_add'] .= ' bx-si-dropdown-has';
+
+            if(($oSubmenu = BxDolMenu::getObjectInstance($aResult['submenu_object'])) !== false) {
+                $aSubmenuItems = $oSubmenu->getMenuItemsRaw();
+                if($oSubmenu->isHtmx() && !$this->_isSelected($a) && !array_key_exists($this->_sPageUri, $aSubmenuItems))
+                    $oSubmenu->setHtmx(false);
+
+                $aTmplVarsSubmenu['bx_repeat:submenu_items'] = $oSubmenu->getMenuItems();
+            }
+        }
+
+        $aResult['bx_if:show_arrow'] = [
+            'condition' => false && $bTmplVarsSubmenu,
+            'content' => [true],
+        ];
+
+        $aResult['bx_if:show_line'] = [
+            'condition' => true,
+            'content' => [true],
+        ];
+
+        $aResult['bx_if:show_submenu'] = [
+            'condition' => $bTmplVarsSubmenu,
+            'content' => $aTmplVarsSubmenu,
+        ];
+
+        return $aResult;
+    }
+}
+
+/** @} */

+ 82 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/data/template/system/scripts/BxTemplMenuToolbar.php

@@ -0,0 +1,82 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolMenu
+ */
+class BxTemplMenuToolbar extends BxBaseMenuToolbar
+{
+    protected $_aHideFromSiteToolbar;
+    protected $_aHideFromMemberToolbar;
+
+    protected $_bSiteToolbar;    
+
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+
+        $this->_aHideFromSiteToolbar = ['search'];
+        $this->_aHideFromMemberToolbar = [];
+
+        $this->_bSiteToolbar = $this->_sObject == 'sys_toolbar_site';
+    }
+
+    protected function _getMenuItem ($a)
+    {
+        if(in_array($a['hidden_on'], [7, 15])) 
+            return false;
+
+        //--- Update '[Main Menu]' from Site Toolbar
+        if($this->_bSiteToolbar && $a['name'] == 'main-menu')
+            $a['onclick'] = '';
+
+    	//--- Hide '[Search]' from Site Toolbar
+        if($this->_bSiteToolbar && in_array($a['name'], $this->_aHideFromSiteToolbar))
+            return false;
+
+        //--- Hide '[+ Add]' from Member Toolbar
+        if(!$this->_bSiteToolbar && in_array($a['name'], $this->_aHideFromMemberToolbar))
+            return false;
+
+        $a = parent::_getMenuItem ($a);
+        if($a === false)
+            return $a;
+
+        $a['class_add_a'] = '';
+        switch ($a['name']) {
+            case 'main-menu':
+                $a['class_add_a'] = ' bx-sidebar-site-trigger';
+                $a['link'] = 'javascript:void(0)';
+                $a['onclick'] = '';
+                break;
+
+            case 'account':
+                $a['class_add_a'] = ' bx-sidebar-account-trigger';
+                $a['link'] = 'javascript:void(0)';
+                $a['onclick'] = '';
+                break;
+
+            case 'add-content':
+                $a['class_add'] = str_replace('bx-def-media-phone-hide', '',  $a['class_add']);
+
+                if(isset($a['bx_if:onclick']['content']['onclick']))
+                    $a['bx_if:onclick']['content']['onclick'] = str_replace('bx_menu_slide_inline', 'bx_menu_popup_inline', $a['bx_if:onclick']['content']['onclick']);
+                break;
+
+            case 'notifications-preview':
+                if(isset($a['bx_if:onclick']['content']['onclick']))
+                    $a['bx_if:onclick']['content']['onclick'] = str_replace(["bx_menu_slide", "'site', "], ['bx_menu_popup'], $a['bx_if:onclick']['content']['onclick']);
+                break;
+        }
+
+        return $a;
+    }
+}
+
+/** @} */

+ 68 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/install/config.php

@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Artificer Artificer template
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_TEMPLATE,
+    'name' => 'bx_artificer',
+    'title' => 'Artificer',
+    'note' => 'Design template',
+    'version' => '14.0.5',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/artificer/',
+    'home_uri' => 'artificer',
+
+    'db_prefix' => 'bx_artificer_',
+    'class_prefix' => 'BxArtificer',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Artificer Template',
+
+    /**
+     * 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(),
+);
+
+/** @} */

+ 57 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/install/langs/en.xml

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string name="_bx_artificer_wgt_cpt"><![CDATA[Artificer]]></string>
+
+    <!-- Settings -->
+    <string name="_bx_artificer_stg_cpt_type"><![CDATA[Artificer]]></string>
+
+    <string name="_bx_artificer_stg_cpt_category_system"><![CDATA[General]]></string>
+    <string name="_bx_artificer_stg_cpt_option_switcher_name"><![CDATA[Name in Template Switcher]]></string>	
+    <string name="_bx_artificer_stg_cpt_option_page_width"><![CDATA[Page Width]]></string>
+    <string name="_bx_artificer_stg_cpt_option_header_stretched"><![CDATA[Stretched Header]]></string>
+    <string name="_bx_artificer_stg_cpt_option_header_search"><![CDATA[Enable floating search bar]]></string>
+    <string name="_bx_artificer_stg_cpt_option_color_scheme"><![CDATA[Color Scheme]]></string>
+    <string name="_bx_artificer_stg_cpt_option_color_scheme_auto"><![CDATA[Auto with switcher]]></string>
+    <string name="_bx_artificer_stg_cpt_option_color_scheme_light_only"><![CDATA[Light mode only]]></string>
+    <string name="_bx_artificer_stg_cpt_option_color_scheme_dark_only"><![CDATA[Dark mode only]]></string>
+    <string name="_bx_artificer_stg_cpt_option_use_htmx"><![CDATA[Use HTMX in Top menu and Page submenu (experimental)]]></string>
+    
+
+    <string name="_bx_artificer_stg_cpt_category_styles_custom"><![CDATA[Custom Styles]]></string>
+    <string name="_bx_artificer_stg_cpt_option_styles_custom"><![CDATA[Custom Styles]]></string>
+    <string name="_bx_artificer_stg_cpt_option_images_custom"><![CDATA[Custom Images]]></string>
+    <string name="_bx_artificer_stg_cpt_option_images_custom_inf"><![CDATA[Each line represents an image. Line format: <b>name</b> => <b>value</b> => <b>type</b> => <b>class</b><br />Where <b>type</b> and/or <b>class</b> may be omitted. Available types are <b>ic</b> - icon (Font Awesome), <b>im</b> - image (file name or URL), <b>sc</b> - source code (SVG).<br />Don't forget to clear template cache (if it's enabled) to see the changes.]]></string>
+
+    <!-- Pages -->
+    <string name="_bx_artificer_page_block_title_splash"><![CDATA[Splash]]></string>
+    <string name="_bx_artificer_page_block_title_splash_lite"><![CDATA[Explore]]></string>
+
+    <!-- Menus -->
+    <string name="_bx_artificer_lmi_cpt_styles"><![CDATA[Styles]]></string>
+
+    <string name="_bx_artificer_menu_template_title_sidebar_site"><![CDATA[Site Sidebar Navigation]]></string>
+    <string name="_bx_artificer_menu_title_sidebar_site"><![CDATA[Site Sidebar Navigation]]></string>
+
+    <!-- Other -->
+    <string name="_bx_artificer_txt_close_sidebar"><![CDATA[Close sidebar]]></string>
+
+    <string name="_bx_artificer_txt_color_scheme_light"><![CDATA[Light]]></string>
+    <string name="_bx_artificer_txt_color_scheme_dark"><![CDATA[Dark]]></string>
+    <string name="_bx_artificer_txt_color_scheme_system"><![CDATA[System]]></string>
+
+    <string name="_bx_artificer_txt_splash_welcome_l1"><![CDATA[Welcome to]]></string>
+    <string name="_bx_artificer_txt_splash_welcome_l2"><![CDATA[the community]]></string>
+    <string name="_bx_artificer_txt_splash_welcome_l3"><![CDATA[The best social media network for people to connect, collaborate, share content and inspire each other.]]></string>
+    <string name="_bx_artificer_txt_splash_welcome_l4"><![CDATA[Powered by <a class="font-medium underline" href="https://una.io">UNA Community Management System</a>.]]></string>
+    <string name="_bx_artificer_txt_splash_welcome_a1"><![CDATA[Create Account]]></string>
+    <string name="_bx_artificer_txt_splash_welcome_a2"><![CDATA[Login]]></string>
+    <string name="_bx_artificer_txt_splash_stats_l1"><![CDATA[We rise by helping others]]></string>
+    <string name="_bx_artificer_txt_splash_stats_l2"><![CDATA[Make new friends, follow interesting creators and stay in touch with your community.]]></string>
+    <string name="_bx_artificer_txt_splash_stats_c1"><![CDATA[members]]></string>
+    <string name="_bx_artificer_txt_splash_stats_c2"><![CDATA[posts]]></string>
+    <string name="_bx_artificer_txt_splash_stats_c3"><![CDATA[comments]]></string>
+    <string name="_bx_artificer_txt_splash_login_title"><![CDATA[Log in to your account]]></string>
+    <string name="_bx_artificer_txt_splash_login_join"><![CDATA[Create New Account]]></string>
+    <string name="_bx_artificer_txt_splash_login_agreement"><![CDATA[By logging in, you agree to our <a href="{0}" class="font-medium text-gray-900 dark:text-white hover:underline">Terms of use</a> and <a href="{1}" class="dark:text-white font-medium text-gray-900 hover:underline">Privacy policy</a>.]]></string>
+    
+</resources>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 6 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/install/sql/enable.sql


+ 61 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/install/sql/install.sql

@@ -0,0 +1,61 @@
+SET @sName = 'bx_artificer';
+
+
+-- SETTINGS
+INSERT INTO `sys_options_types`(`group`, `name`, `caption`, `icon`, `order`) VALUES 
+('templates', @sName, '_bx_artificer_stg_cpt_type', 'bx_artificer@modules/boonex/artificer/|std-icon.svg', 2);
+SET @iTypeId = LAST_INSERT_ID();
+
+-- SETTINGS: Artificer template System
+INSERT INTO `sys_options_categories`(`type_id`, `name`, `caption`, `order`) VALUES 
+(@iTypeId, CONCAT(@sName, '_system'), '_bx_artificer_stg_cpt_category_system', 10);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, CONCAT(@sName, '_switcher_title'), '_bx_artificer_stg_cpt_option_switcher_name', 'Artificer', 'digit', '', '', '', 1), 
+(@iCategoryId, CONCAT(@sName, '_color_scheme'), '_bx_artificer_stg_cpt_option_color_scheme', 'auto', 'select', 'a:2:{s:6:"module";s:12:"bx_artificer";s:6:"method";s:24:"get_options_color_scheme";}', '', '', 2),
+
+(@iCategoryId, CONCAT(@sName, '_page_width'), '_bx_artificer_stg_cpt_option_page_width', '1280', 'digit', '', '', '', 10),
+(@iCategoryId, CONCAT(@sName, '_header_stretched'), '_bx_artificer_stg_cpt_option_header_stretched', '', 'checkbox', '', '', '', 11),
+(@iCategoryId, CONCAT(@sName, '_header_search'), '_bx_artificer_stg_cpt_option_header_search', 'on', 'checkbox', '', '', '', 12),
+
+(@iCategoryId, CONCAT(@sName, '_use_htmx'), '_bx_artificer_stg_cpt_option_use_htmx', '', 'checkbox', '', '', '', 30);
+
+-- SETTINGS: Artificer template Custom Styles
+INSERT INTO `sys_options_categories`(`type_id`, `name`, `caption`, `order`) VALUES 
+(@iTypeId, CONCAT(@sName, '_styles_custom'), '_bx_artificer_stg_cpt_category_styles_custom', 20);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, CONCAT(@sName, '_styles_custom'), '_bx_artificer_stg_cpt_option_styles_custom', '', 'text', '', '', '', 1),
+(@iCategoryId, CONCAT(@sName, '_images_custom'), '_bx_artificer_stg_cpt_option_images_custom', '', 'text', '', '', '', 10);
+
+-- SETTINGS: Artificer template Site Logo
+SET @iSystemCategoryId = (SELECT IFNULL(`id`, @iCategoryId) FROM `sys_options_categories` WHERE `name`='system' LIMIT 1);
+SET @iSystemCategoryOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_options` WHERE `category_id`=@iSystemCategoryId LIMIT 1);
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iSystemCategoryId, CONCAT(@sName, '_site_logo'), '', '0', 'digit', '', '', '', @iSystemCategoryOrder + 1),
+(@iSystemCategoryId, CONCAT(@sName, '_site_logo_aspect_ratio'), '', '', 'digit', '', '', '', @iSystemCategoryOrder + 2),
+(@iSystemCategoryId, CONCAT(@sName, '_site_logo_dark'), '', '0', 'digit', '', '', '', @iSystemCategoryOrder + 3),
+(@iSystemCategoryId, CONCAT(@sName, '_site_logo_dark_aspect_ratio'), '', '', 'digit', '', '', '', @iSystemCategoryOrder + 4),
+(@iSystemCategoryId, CONCAT(@sName, '_site_logo_inline'), '', '', 'text', '', '', '', @iSystemCategoryOrder + 5),
+(@iSystemCategoryId, CONCAT(@sName, '_site_logo_alt'), '', '', 'text', '', '', '', @iSystemCategoryOrder + 6),
+
+(@iSystemCategoryId, CONCAT(@sName, '_site_mark'), '', '0', 'digit', '', '', '', @iSystemCategoryOrder + 10),
+(@iSystemCategoryId, CONCAT(@sName, '_site_mark_aspect_ratio'), '', '', 'digit', '', '', '', @iSystemCategoryOrder + 11),
+(@iSystemCategoryId, CONCAT(@sName, '_site_mark_dark'), '', '0', 'digit', '', '', '', @iSystemCategoryOrder + 12),
+(@iSystemCategoryId, CONCAT(@sName, '_site_mark_dark_aspect_ratio'), '', '', 'digit', '', '', '', @iSystemCategoryOrder + 13),
+(@iSystemCategoryId, CONCAT(@sName, '_site_mark_inline'), '', '', 'text', '', '', '', @iSystemCategoryOrder + 14);
+
+
+-- STUDIO PAGE & WIDGET
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, @sName, '', '', 'bx_artificer@modules/boonex/artificer/|std-icon.svg');
+SET @iPageId = LAST_INSERT_ID();
+
+SET @iParentPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name`='home');
+SET @iParentPageOrder = (SELECT MAX(`order`) FROM `sys_std_pages_widgets` WHERE `page_id`=@iParentPageId);
+INSERT INTO `sys_std_widgets`(`page_id`, `module`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, @sName, 'appearance', CONCAT('{url_studio}design.php?name=', @sName), '', 'bx_artificer@modules/boonex/artificer/|std-icon.svg', '_bx_artificer_wgt_cpt', '', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_actions";s:6:"params";a:0:{}s:5:"class";s:18:"TemplStudioDesigns";}');
+INSERT INTO `sys_std_pages_widgets`(`page_id`, `widget_id`, `order`) VALUES
+(@iParentPageId, LAST_INSERT_ID(), @iParentPageOrder + 1);

+ 173 - 0
modules/boonex/artificer/updates/14.0.4_14.0.5/source/js/utils.js

@@ -0,0 +1,173 @@
+function BxArtificerUtils(oOptions)
+{
+    this._sActionUri = oOptions.sActionUri;
+    this._sActionUrl = oOptions.sActionUrl;
+    this._sObject = oOptions.sObject;
+    this._aHtmlIds = undefined == oOptions.aHtmlIds ? {} : oOptions.aHtmlIds;  
+    this._sColorScheme = undefined == oOptions.sColorScheme ? 'auto' : oOptions.sColorScheme;
+
+    if(htmx != undefined)
+        htmx.on('htmx:afterSwap', function(evt) {
+            var oTarget = $(evt.target);
+            if(oTarget.attr('id') == 'bx-content-preload')
+                return;
+
+            oTarget.bxProcessHtml();
+        });
+
+    this.init();
+}
+
+BxArtificerUtils.prototype.init = function()
+{
+    var $this = this;
+
+    switch(this._sColorScheme) {
+        case 'auto':
+            window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
+                $this.setColorSchemeIcon();
+                $this.setColorSchemeHtml();
+                $this.onColorSchemeChange();
+            });
+            break;
+
+        case 'light_only':
+            this.setColorScheme(1);
+            break;
+
+        case 'dark_only':
+            this.setColorScheme(2);
+            break;
+    }    
+
+    this.setColorSchemeHtml();
+
+    $(document).ready(function() {
+        $this.setColorSchemeIcon();
+        $this.onColorSchemeChange();
+    });
+};
+
+BxArtificerUtils.prototype.setColorScheme = function(iCode)
+{
+    switch(iCode) {
+        case 0:
+            localStorage.removeItem('theme');
+            break;
+
+        case 1:
+            localStorage.theme = 'sun'
+            break;
+
+        case 2:
+            localStorage.theme = 'dark'
+            break;
+    }
+
+    this.setColorSchemeIcon();
+    this.setColorSchemeHtml();
+    this.onColorSchemeChange(iCode);
+};
+
+BxArtificerUtils.prototype.isColorSchemeDark = function()
+{
+    return localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches);
+};
+
+BxArtificerUtils.prototype.setColorSchemeHtml = function()
+{
+    if(this.isColorSchemeDark())
+        $('html').addClass('dark')
+    else
+        $('html').removeClass('dark')
+};
+
+BxArtificerUtils.prototype.setColorSchemeIcon = function() 
+{
+    if(this.isColorSchemeDark())
+        $('.bx-sb-theme-switcher .sys-icon').addClass('moon').removeClass('sun');
+    else
+        $('.bx-sb-theme-switcher .sys-icon').addClass('sun').removeClass('moon');
+};
+
+BxArtificerUtils.prototype.onColorSchemeChange = function(iCode) 
+{
+    if(typeof glOnColorSchemeChange === 'undefined' || !(glOnColorSchemeChange instanceof Array)) 
+        return;
+
+    if(typeof iCode === 'undefined' || !iCode)
+        iCode = this.isColorSchemeDark() ? 2 : 1;
+
+    for(var i = 0; i < glOnColorSchemeChange.length; i++)
+        if(typeof glOnColorSchemeChange[i] === "function")
+            glOnColorSchemeChange[i](iCode);
+};
+
+BxArtificerUtils.prototype.getColorSchemeMenu = function() {
+    $('#bx-sb-theme-switcher-menu').dolPopup({
+        pointer: {
+            el: $('.bx-sb-theme-switcher')
+        },
+        moveToDocRoot: true,
+        cssClass: 'bx-popup-menu'
+    });
+};
+
+BxArtificerUtils.prototype.getAddContentMenu = function(sMenu, e, sPosition) {
+    $('.bx-popup-applied:visible').dolPopupHide();
+
+    var sSidebar = 'account';
+    if(bx_sidebar_active(sSidebar))
+        bx_sidebar_toggle(sSidebar);
+
+    bx_menu_popup_inline(sMenu, e, {});
+};
+
+BxArtificerUtils.prototype.getNotificationsMenu = function(sMenu, e, sPosition, oOptions) {
+    $('.bx-popup-applied:visible').dolPopupHide();
+
+    var sSidebar = 'account';
+    if(bx_sidebar_active(sSidebar))
+        bx_sidebar_toggle(sSidebar);
+
+    oOptions = $.extend({}, {pointer: {align:'right'}, cssClass: ''}, oOptions);
+
+    bx_menu_popup(sMenu, e, oOptions);
+};
+
+BxArtificerUtils.prototype.mmenuClickAl = function(oElement) {
+    var sClass = 'bx-menu-tab-active';
+    var oItem = $(oElement).parent().addClass(sClass);
+
+    oItem.siblings().removeClass(sClass);
+    oItem.siblings('.bx-menu-item-more-auto').find('li').removeClass(sClass);
+
+    oItem.parents('li:first').siblings().removeClass(sClass);
+    if(oItem.parents('.bx-popup-applied.bx-popup-menu'))
+        $('.bx-popup-applied:visible').dolPopupHide();
+};
+
+BxArtificerUtils.prototype.submenuClickBl = function(oElement) {
+    var oItems = $(oElement).parents('ul:first').find('li');
+    var iPosNew = oItems.index($(oElement).parent());
+    var iPosOld = oItems.index($(oElement).parent().siblings('.bx-menu-tab-active'));
+
+    var sClassAdd = iPosOld > iPosNew ? 'ltr' : 'rtl';
+    $('#bx-content-wrapper').addClass(sClassAdd);
+};
+
+BxArtificerUtils.prototype.submenuClickAl = function(oElement) {
+    var sClass = 'bx-menu-tab-active';
+    var oItem = $(oElement).parent().addClass(sClass);
+
+    oItem.siblings().removeClass(sClass);
+    oItem.siblings('.bx-menu-item-more-auto').find('li').removeClass(sClass);
+
+    oItem.parents('li:first').siblings().removeClass(sClass);
+    if(oItem.parents('.bx-popup-applied.bx-popup-menu'))
+        $('.bx-popup-applied:visible').dolPopupHide();
+
+    var sSidebar = 'site';
+    if(bx_sidebar_active(sSidebar))
+        bx_sidebar_toggle(sSidebar);
+};

+ 51 - 0
modules/boonex/channels/updates/14.0.3_14.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' => 'Channels',
+    'version_from' => '14.0.3',
+    'version_to' => '14.0.4',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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_14.0.3_14.0.4/',
+    'home_uri' => 'channels_update_1403_1404',
+
+    '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(),
+);

+ 29 - 0
modules/boonex/channels/updates/14.0.3_14.0.4/install/installer.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxCnlUpdater extends BxDolStudioUpdater
+{
+    public function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+
+    public function actionExecuteSql($sOperation)
+    {
+        if($sOperation == 'install') {
+            if(!$this->oDb->isFieldExists('bx_cnl_data', 'lc_id'))
+                $this->oDb->query("ALTER TABLE `bx_cnl_data` ADD `lc_id` int(11) NOT NULL default '0' AFTER `channel_name`");
+            if(!$this->oDb->isFieldExists('bx_cnl_data', 'lc_date'))
+                $this->oDb->query("ALTER TABLE `bx_cnl_data` ADD `lc_date` int(11) NOT NULL default '0' AFTER `lc_id`");
+            if(!$this->oDb->isFieldExists('bx_cnl_data', 'contents'))
+                $this->oDb->query("ALTER TABLE `bx_cnl_data` ADD `contents` int(11) NOT NULL default '0' AFTER `lc_date`");
+
+            if(!$this->oDb->isFieldExists('bx_cnl_content', 'date'))
+        }           $this->oDb->query("ALTER TABLE `bx_cnl_content` ADD `date` int(11) NOT NULL default '0' AFTER `module_name`");
+
+        return parent::actionExecuteSql($sOperation);
+    }
+}

+ 12 - 0
modules/boonex/channels/updates/14.0.3_14.0.4/install/langs/en.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_channels_option_browse_active_n_posts"><![CDATA[Browse Active: Min number of new posts in channel during the period of time]]></string_add>
+	<string_add name="_bx_channels_option_browse_active_x_hours"><![CDATA[Browse Active: The period of time to count new posts in channel]]></string_add>
+	<string_add name="_bx_channels_option_browse_trending_x_hours"><![CDATA[Browse Trending: The period of time to count new posts in channel]]></string_add>
+	<string_add name="_bx_channels_page_title_browse_active"><![CDATA[Active Channels]]></string_add>
+	<string_add name="_bx_channels_page_title_browse_trending"><![CDATA[Trending Channels]]></string_add>
+	<string_add name="_bx_channels_page_block_title_sys_active_entries"><![CDATA[Active Channels]]></string_add>
+	<string_add name="_bx_channels_page_block_title_active_entries"><![CDATA[Active Channels]]></string_add>
+	<string_add name="_bx_channels_page_block_title_sys_trending_entries"><![CDATA[Trending Channels]]></string_add>
+	<string_add name="_bx_channels_page_block_title_trending_entries"><![CDATA[Trending Channels]]></string_add>
+</resources>

+ 18 - 0
modules/boonex/channels/updates/14.0.3_14.0.4/install/sql/enable.sql

@@ -0,0 +1,18 @@
+SET @sName = 'bx_channels';
+
+
+-- OPTIONS
+SET @iCategId = (SELECT `id` FROM `sys_options_categories` WHERE `name`='bx_channels' LIMIT 1);
+DELETE FROM `sys_options` WHERE `name` IN ('bx_channels_browse_active_n_posts', 'bx_channels_browse_active_x_hours', 'bx_channels_browse_trending_x_hours');
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `extra`, `check`, `check_params`, `check_error`, `order`) VALUES
+('bx_channels_browse_active_n_posts', '1', @iCategId, '_bx_channels_option_browse_active_n_posts', 'digit', '', '', '', '', 20),
+('bx_channels_browse_active_x_hours', '24', @iCategId, '_bx_channels_option_browse_active_x_hours', 'digit', '', '', '', '', 21),
+('bx_channels_browse_trending_x_hours', '24', @iCategId, '_bx_channels_option_browse_trending_x_hours', 'digit', '', '', '', '', 23);
+
+
+-- PAGES
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = '' AND `cell_id` = 0 ORDER BY `order` DESC LIMIT 1);
+DELETE FROM `sys_pages_blocks` WHERE `module`='bx_channels' AND `title_system` IN ('_bx_channels_page_block_title_sys_active_entries', '_bx_channels_page_block_title_sys_trending_entries');
+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_active_entries', '_bx_channels_page_block_title_active_entries', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:13:\"browse_active\";}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 1),
+('', 0, 'bx_channels', '_bx_channels_page_block_title_sys_trending_entries', '_bx_channels_page_block_title_trending_entries', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:15:\"browse_trending\";}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 2);

+ 1 - 0
modules/boonex/channels/updates/14.0.3_14.0.4/install/sql/install.sql

@@ -0,0 +1 @@
+SET @sName = 'bx_channels';

+ 194 - 0
modules/boonex/channels/updates/14.0.3_14.0.4/source/classes/BxCnlConfig.php

@@ -0,0 +1,194 @@
+<?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_COVER_POSITION' => 'cover_data',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_CF' => 'cf',
+            'FIELD_VIEWS' => 'views',
+            'FIELD_COMMENTS' => 'comments',
+            'FIELD_STATUS' => 'status',
+            'FIELD_STATUS_ADMIN' => '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_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',
+
+            // some params
+            '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',
+            'PARAM_BROWSE_ACTIVE_N_POSTS' => 'bx_channels_browse_active_n_posts',
+            'PARAM_BROWSE_ACTIVE_X_HOURS' => 'bx_channels_browse_active_x_hours',
+            'PARAM_BROWSE_TRENDING_X_HOURS' => 'bx_channels_browse_trending_x_hours',
+
+            // 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_MANAGE_VIEW_ENTRY' => '',
+            '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_PAGE_JOINED_ENTRY' => 'bx_channels_join_profile',
+            '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;
+    }
+}
+
+/** @} */

+ 145 - 0
modules/boonex/channels/updates/14.0.3_14.0.4/source/classes/BxCnlDb.php

@@ -0,0 +1,145 @@
+<?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 module database queries
+ */
+class BxCnlDb extends BxBaseModGroupsDb
+{
+    public function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+    }
+
+    public function getChannelIdByName($sName)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return $this->getOne("SELECT `" . $CNF['FIELD_ID'] . "` FROM `" . $CNF['TABLE_ENTRIES'] . "` WHERE `" . $CNF['FIELD_NAME'] . "` = :name", array(
+            'name' => $sName,
+        ));
+    }
+
+    public function getChannelInfoByName($sName)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return $this->getRow("SELECT `c`.*, `p`.`account_id`, `p`.`id` AS `profile_id`, `a`.`email` AS `profile_email`, `a`.`ip` AS `profile_ip`, `p`.`status` AS `profile_status` FROM `" . $CNF['TABLE_ENTRIES'] . "` AS `c` INNER JOIN `sys_profiles` AS `p` ON (`p`.`content_id` = `c`.`id` AND `p`.`type` = :type) INNER JOIN `sys_accounts` AS `a` ON (`p`.`account_id` = `a`.`id`) WHERE `c`.`channel_name` = :name", array(
+            'type' => $this->_oConfig->getName(),
+            'name' => $sName,
+        ));
+    }
+
+    public function addContentToChannel($iContentId, $iCnlId, $sModuleName, $iAuthorId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iNow = time();
+        if(!$this->query("INSERT INTO `" . $CNF['TABLE_CONTENT'] . "` (`content_id`, `cnl_id`, `author_id`, `module_name`, `date`) VALUES (:content_id, :cnl_id, :author_id, :module_name, :date)", [
+            'content_id' => $iContentId,
+            'cnl_id' => $iCnlId,
+            'module_name' => $sModuleName,
+            'author_id' => $iAuthorId,
+            'date' => $iNow
+        ]))
+            return 0;
+
+        $iCnlContentId = $this->lastId();
+
+        $this->query("UPDATE `" . $CNF['TABLE_ENTRIES'] . "` SET `lc_id`=:lc_id, `lc_date`=:lc_date, `contents`=:contents WHERE `" . $CNF['FIELD_ID'] . "`=:id", [
+            'lc_id' => $iCnlContentId,
+            'lc_date' => $iNow,
+            'contents' => (int)$this->getOne("SELECT COUNT(*) FROM `" . $CNF['TABLE_CONTENT'] . "` WHERE `cnl_id`=:cnl_id LIMIT 1", ['cnl_id' => $iCnlId]),
+            'id' => $iCnlId
+        ]);
+
+        return $iCnlContentId;
+    }
+    
+    public function checkContentInChannel($iContentId, $iCnlId, $sModuleName, $iAuthorId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $aBindings = array(
+            'content_id' => $iContentId,
+            'cnl_id' => $iCnlId,
+            'module_name' => $sModuleName,
+            'author_id' => $iAuthorId,
+        );
+        return $this->getOne("SELECT COUNT(*) FROM `" . $CNF['TABLE_CONTENT'] . "` WHERE `content_id` = :content_id AND `module_name` = :module_name  AND `cnl_id` = :cnl_id AND `author_id` =:author_id", $aBindings);
+    }
+    
+    public function getContentById($iId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return $this->getRow("SELECT * FROM `" . $CNF['TABLE_CONTENT'] . "` WHERE `id` = :id LIMIT 1", array(
+            'id' => $iId
+        ));
+    }
+    
+    public function getDataByContent($iContentId, $sModuleName)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $aBindings = array(
+            'content_id' => $iContentId,
+            'module_name' => $sModuleName
+        );
+        return $this->getAll("SELECT `id`, `author_id`, `cnl_id` FROM `" . $CNF['TABLE_CONTENT'] . "` WHERE `content_id` = :content_id AND `module_name` = :module_name", $aBindings);
+    }
+    
+    public function removeContentFromChannel($iContentId, $sModuleName)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aBindings = [
+            'content_id' => $iContentId,
+            'module_name' => $sModuleName
+        ];
+
+        $aContents = $this->getAll("SELECT * FROM `" . $CNF['TABLE_CONTENT'] . "` WHERE `content_id` = :content_id AND `module_name` = :module_name", $aBindings);
+        if(empty($aContents) || !is_array($aContents))
+            return;
+
+        $this->query("DELETE FROM `" . $CNF['TABLE_CONTENT'] . "` WHERE `content_id` = :content_id AND `module_name` = :module_name", $aBindings);
+
+        foreach($aContents as $aContent) {
+            $iCnlId = (int)$aContent['cnl_id'];
+
+            $aLatest = $this->getRow("SELECT * FROM `" . $CNF['TABLE_CONTENT'] . "` WHERE `cnl_id`=:cnl_id ORDER BY `date` DESC LIMIT 1", [
+                'cnl_id' => $iCnlId
+            ]);
+
+            $iLcId = $iLcDate = 0;
+            if(!empty($aLatest) && is_array($aLatest)) {
+                $iLcId = (int)$aLatest['id'];
+                $iLcDate = (int)$aLatest['date'];
+            }
+
+            $this->query("UPDATE `" . $CNF['TABLE_ENTRIES'] . "` SET `lc_id`=:lc_id, `lc_date`=:lc_date, `contents`=:contents WHERE `" . $CNF['FIELD_ID'] . "`=:id", [
+                'lc_id' => $iLcId,
+                'lc_date' => $iLcDate,
+                'contents' => (int)$this->getOne("SELECT COUNT(*) FROM `" . $CNF['TABLE_CONTENT'] . "` WHERE `cnl_id`=:cnl_id LIMIT 1", ['cnl_id' => $iCnlId]),
+                'id' => $iCnlId
+            ]);
+        }
+    }
+	
+    public function removeChannelContent($iChannelId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $this->query("DELETE FROM `" . $CNF['TABLE_CONTENT'] . "` WHERE `cnl_id` = :channel_id", [
+            'channel_id' => $iChannelId
+        ]);
+    }
+}
+
+/** @} */

+ 663 - 0
modules/boonex/channels/updates/14.0.3_14.0.4/source/classes/BxCnlModule.php

@@ -0,0 +1,663 @@
+<?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 $iSenderId - action's sender (author) id.
+     */
+    function processHashtag($sHashtag, $sModuleName, $iContentId, $iSenderId = 0)
+    {
+        $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;
+
+        $iAuthorId = 0;
+        if(($sModuleMethod = 'act_as_profile') && bx_is_srv($sModuleName, $sModuleMethod) && ($oAuthor = BxDolProfile::getInstanceByContentAndType($iContentId, $sModuleName)) !== false)
+            $iAuthorId = $oAuthor->id();
+        else if(($sModuleMethod = 'get_author') && bx_is_srv($sModuleName, $sModuleMethod))
+            $iAuthorId = abs(bx_srv($sModuleName, $sModuleMethod, [$iContentId]));
+        if(empty($iAuthorId) && !empty($iSenderId))
+            $iAuthorId = $iSenderId;
+
+        $aCheck = checkActionModule($iAuthorId, '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($iAuthorId, '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();
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_channels-hashtag_added 'bx_channels', 'hashtag_added' - hook on found hashtag in content
+         * - $unit_name - equals `bx_channels`
+         * - $action - equals `hashtag_added` 
+         * - $object_id - content_id in channel
+         * - $sender_id - channel profile_id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object_author_id` - [int] profile_id for content's author
+         *      - `privacy_view` - [string] equal - channel_profile_id
+         *      - `subobject_id` - [int]  content_id in channel
+         *      - `content_module` - [string] module name for content
+         *      - `content_id` - [int] content_id
+         *      - `content_author_id` - [int] equal with object_author_id
+         *      - `timeline_group` - [array] parameters for group event in timeline  ['by' => $sModuleName . '_' . $iAuthorId . '_' . $iContentId, 'field' => 'owner_id']
+         * @hook @ref hook-bx_channels-hashtag_added
+         */
+        bx_alert($this->_aModule['name'], 'hashtag_added', $iId, $iCnlProfileId, array(
+            'object_author_id' => $iAuthorId, 
+            'privacy_view' => -$iCnlProfileId,
+            'subobject_id' => $iId,
+            'content_module' => $sModuleName,
+            'content_id' => $iContentId,
+            'content_author_id' => $iAuthorId,
+            'timeline_group' => array(
+                'by' => $sModuleName . '_' . $iAuthorId . '_' . $iContentId,
+                'field' => 'owner_id'
+            )
+        ));
+
+        $aParams = [
+            'object_author_id' => $iAuthorId, 
+            'privacy_view' => -$iCnlProfileId, 
+            'subobject_id' => $iId,
+            'content_module' => $sModuleName,
+            'content_id' => $iContentId,
+            'content_author_id' => $iAuthorId
+        ];
+        /**
+         * @hooks
+         * @hookdef hook-system-prepare_alert_params 'system', 'prepare_alert_params' - hook to override alert (hook) params
+         * - $unit_name - equals `system`
+         * - $action - equals `prepare_alert_params`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `unit` - [string] unit name
+         *      - `action` - [string] equals to 'hashtag_added_notif'
+         *      - `object_id` - [int] object id
+         *      - `sender_id` - [int] action performer profile id
+         *      - `extras` - [array] by ref, extra params array as key&value pairs, can be overridden in hook processing
+         * @hook @ref hook-system-prepare_alert_params
+         */
+        bx_alert('system', 'prepare_alert_params', 0, 0, [
+            'unit'=> $this->_aModule['name'], 
+            'action' => 'hashtag_added_notif', 
+            'object_id' => $mixedCnlId, 
+            'sender_id' => $iCnlProfileId, 
+            'extras' => &$aParams
+        ]);
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_channels-hashtag_added_notif 'bx_channels', 'hashtag_added_notif' - hook on after found hashtag in content
+         * - $unit_name - equals `bx_channels`
+         * - $action - equals `hashtag_added_notif` 
+         * - $object_id - channel id
+         * - $sender_id - channel profile_id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object_author_id` - [int] profile_id for content's author
+         *      - `privacy_view` - [string] equal - channel_profile_id
+         *      - `subobject_id` - [int]  content_id in channel
+         *      - `content_module` - [string] module name for content
+         *      - `content_id` - [int] content_id
+         *      - `content_author_id` - [int] equal with object_author_id
+         * @hook @ref hook-bx_channels-hashtag_added_notif
+         */
+        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)){
+                /**
+                 * @hooks
+                 * @hookdef hook-bx_channels-hashtag_deleted 'bx_channels', 'hashtag_deleted' - hook on before delete content from channel
+                 * - $unit_name - equals `bx_channels`
+                 * - $action - equals `hashtag_deleted` 
+                 * - $object_id - content id in channel
+                 * - $sender_id - channel profile_id
+                 * @hook @ref hook-bx_channels-hashtag_deleted
+                 */
+                bx_alert($this->_aModule['name'], 'hashtag_deleted', $aRow['id'], $iProfileInfo['id']);
+                 /**
+                 * @hooks
+                 * @hookdef hook-bx_channels-hashtag_deleted_notif 'bx_channels', 'hashtag_deleted_notif' - hook on before delete content from channel
+                 * - $unit_name - equals `bx_channels`
+                 * - $action - equals `hashtag_deleted_notif` 
+                 * - $object_id - channel id
+                 * - $sender_id - channel profile_id
+                 * - $extra_params - array of additional params with the following array keys:
+                 *      - `subobject_id` - [int] content id in channel
+                 * @hook @ref hook-bx_channels-hashtag_deleted_notif
+                 */
+                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 = [])
+    {
+        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') {
+            $sModule = 'system';
+            $sClass = 'TemplCmtsServices';
+        }
+
+        if(!BxDolRequest::serviceExists($sModule, 'get_timeline_post', $sClass))
+            return false;
+
+        $iContentId = (int)$aEventContent['content_id'];
+        $iContentAuthor = 0;
+        if(bx_is_srv($sModule, 'get_author', $sClass))
+            $iContentAuthor = bx_srv($sModule, 'get_author', [$iContentId], $sClass);
+
+        /**
+         * Prepare fake event array (only mandatory parameters) to get
+         * necessary data (related to an 'original' event with hashtag/label) 
+         * from associated content module.
+         */
+        $iOwnerId = $aEvent['owner_id'];
+        $mixedObjectPrivacyView = BX_DOL_PG_ALL;
+        if($iContentAuthor > 0) {
+            $iOwnerId = (int)$aEventContent['author_id'];
+            if(bx_is_srv($sModule, 'get_privacy_view', $sClass)) {
+                $mixedAllowViewTo = bx_srv($sModule, 'get_privacy_view', [$iContentId]);
+                if($mixedAllowViewTo !== false)
+                    $mixedObjectPrivacyView = $mixedAllowViewTo;
+
+                if(is_numeric($mixedAllowViewTo) && (int)$mixedAllowViewTo < 0)
+                    $iOwnerId = abs($mixedAllowViewTo);
+            }
+        }
+
+        $aResult = bx_srv($sModule, 'get_timeline_post', [[
+            '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, [
+            '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'] = bx_absolute_url(str_replace(BX_DOL_URL_ROOT, '', $this->serviceGetLink($aContentEvent['cnl_id'])), '{bx_url_root}');
+            return $aRv;
+        }
+
+        return '';
+    }
+
+    public function serviceBrowseActive ($bDisplayEmptyMsg = false, $bAjaxPaginate = false)
+    {
+        return $this->_serviceBrowse ('active', false, BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
+    }
+
+    public function serviceBrowseTrending ($bDisplayEmptyMsg = false, $bAjaxPaginate = false)
+    {
+        return $this->_serviceBrowse ('trending', false, BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
+    }
+
+    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_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iContentId)),
+                    'followers' => $oConnection -> getConnectedInitiatorsCount($iProfileId),
+                    'id' => $iProfileId,
+                    'icon' => $oProfile -> getThumb()
+                ));
+        }
+
+        return $aVars;
+    }
+}
+
+/** @} */

+ 303 - 0
modules/boonex/channels/updates/14.0.3_14.0.4/source/classes/BxCnlSearchResult.php

@@ -0,0 +1,303 @@
+<?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 BxCnlSearchResult extends BxBaseModGroupsSearchResult
+{
+    function __construct($sMode = '', $aParams = false)
+    {
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent = array(
+            'name' => 'bx_channels',
+            'module_name' => 'bx_channels',
+            'object_metatags' => 'bx_channels',
+            'title' => _t('_bx_channels_page_title_browse'),
+            'table' => 'sys_profiles',
+            'tableSearch' => 'bx_cnl_data',
+            'ownFields' => array(),
+            'searchFields' => array(),
+            'restriction' => array(
+                'account_id' => array('value' => '', 'field' => 'account_id', 'operator' => '='),
+                'perofileStatus' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
+                'perofileType' => array('value' => 'bx_channels', 'field' => 'type', 'operator' => '='),
+                'owner' => array('value' => '', 'field' => 'author', 'operator' => '=', 'table' => 'bx_cnl_data'),
+                'featured' => array('value' => '', 'field' => 'featured', 'operator' => '<>', 'table' => 'bx_cnl_data'),
+                'status' => array('value' => 'active', 'field' => 'status', 'operator' => '=', 'table' => 'bx_cnl_data'),
+                'statusAdmin' => array('value' => 'active', 'field' => 'status_admin', 'operator' => '=', 'table' => 'bx_cnl_data'),
+            ),
+            'join' => array (
+                'profile' => array(
+                    'type' => 'INNER',
+                    'table' => 'bx_cnl_data',
+                    'mainField' => 'content_id',
+                    'onField' => 'id',
+                    'joinFields' => array('id', 'channel_name', 'picture', 'cover', 'added', 'author', 'allow_view_to'),
+                ),
+                'account' => array(
+                    'type' => 'INNER',
+                    'table' => 'sys_accounts',
+                    'mainField' => 'account_id',
+                    'onField' => 'id',
+                    'joinFields' => array(),
+                ),
+            ),
+            'paginate' => array('perPage' => getParam('bx_channels_per_page_browse'), 'start' => 0),
+            'sorting' => 'last',
+            'rss' => array(
+                'title' => '',
+                'link' => '',
+                'image' => '',
+                'profile' => 0,
+                'fields' => array (
+                    'Guid' => 'link',
+                    'Link' => 'link',
+                    'Title' => 'channel_name',
+                    'DateTimeUTS' => 'added',
+                    'Desc' => 'channel_name',
+                    'Image' => 'picture',
+                ),
+            ),
+            'ident' => 'id'
+        );
+
+        $this->sFilterName = 'bx_cnl_data_filter';
+        $this->oModule = $this->getMain();
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        $sSearchFields = getParam($CNF['PARAM_SEARCHABLE_FIELDS']);
+        $this->aCurrent['searchFields'] = !empty($sSearchFields) ? explode(',', $sSearchFields) : '';
+
+        $oJoinedProfile = null;
+        $bProcessConditionsForPrivateContent = true;
+        switch ($sMode) {
+            case 'created_entries':
+                if(!$this->_setAuthorConditions($sMode, $aParams, $oJoinedProfile)) {
+                    $this->isError = true;
+                    break;
+                }
+                break;
+
+            case 'connections':
+                if ($this->_setConnectionsConditions($aParams)) {
+                    $bProcessConditionsForPrivateContent = false;
+                    $oProfile = BxDolProfile::getInstance($aParams['profile']);
+                    $oProfile2 = isset($aParams['profile2']) ? BxDolProfile::getInstance($aParams['profile2']) : null;
+
+                    if (isset($aParams['type']) && $aParams['type'] == 'common' && $oProfile && $oProfile2)
+                        $this->aCurrent['title'] = _t('_bx_channels_page_title_browse_connections_mutual', $oProfile->getDisplayName(), $oProfile2->getDisplayName());
+                    elseif ((!isset($aParams['type']) || $aParams['type'] != 'common') && $oProfile)
+                        $this->aCurrent['title'] = _t('_bx_channels_page_title_browse_connections', $oProfile->getDisplayName());
+
+                    $this->aCurrent['rss']['link'] = 'modules/?r=channels/rss/' . $sMode . '/' . $aParams['object'] . '/' . $aParams['type'] . '/' . (int)$aParams['profile'] . '/' . (int)$aParams['profile2'] . '/' . (int)$aParams['mutual'];
+                }
+                break;
+                
+            case 'followed_entries':
+                $oJoinedProfile = BxDolProfile::getInstance((int)$aParams['joined_profile']);
+                if (!$oJoinedProfile) {
+                    $this->isError = true;
+                    break;
+                }
+
+                $bProcessConditionsForPrivateContent = false;
+
+                $this->aCurrent['join']['subscriptions'] = array(
+                    'type' => 'INNER',
+                    'table' => 'sys_profiles_conn_subscriptions',
+                    'mainField' => 'id',
+                    'onField' => 'content',
+                    'joinFields' => array('initiator'),
+                );
+
+                $this->aCurrent['restriction']['subscriptions'] = array('value' => $oJoinedProfile->id(), 'field' => 'initiator', 'operator' => '=', 'table' => 'sys_profiles_conn_subscriptions');
+                break;
+
+            case 'favorite':
+                if(!$this->_setFavoriteConditions($sMode, $aParams, $oJoinedProfile)) {
+                    $this->isError = true;
+                    break;
+                }
+                break;
+
+            case 'recent':
+                $this->aCurrent['rss']['link'] = 'modules/?r=channels/rss/' . $sMode;
+                $this->aCurrent['title'] = _t('_bx_channels_page_title_browse_recent');
+                $this->aCurrent['sorting'] = 'last';
+                $this->sBrowseUrl = 'page.php?i=channels-home';
+                break;
+
+            case 'featured':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_channels_page_title_browse_featured');
+                $this->aCurrent['restriction']['featured']['value'] = '0';
+                $this->aCurrent['rss']['link'] = 'modules/?r=channels/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'featured';
+                break;
+
+            case 'recommended':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_channels_page_title_browse_recommended');
+                $this->aCurrent['restriction']['featured']['value'] = '0';
+                $this->aCurrent['rss']['link'] = 'modules/?r=channels/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'recommended';
+                $this->_setConditionsForRecommended();
+                break;
+                
+            case 'top':
+                $this->aCurrent['rss']['link'] = 'modules/?r=channels/rss/' . $sMode;
+                $this->aCurrent['title'] = _t('_bx_channels_page_title_browse_top');
+                $this->aCurrent['sorting'] = 'top';
+                $this->sBrowseUrl = 'page.php?i=channels-top';
+                break;
+            
+            case 'active':
+                $this->aCurrent['join']['contents'] = [
+                    'type' => 'INNER',
+                    'table' => $CNF['TABLE_CONTENT'],
+                    'mainTable' => 'bx_cnl_data',
+                    'mainField' => 'id',
+                    'onField' => 'cnl_id',
+                    'joinFields' => [],
+                    'groupTable' => 'bx_cnl_data',
+                    'groupField' => 'id',
+                    'groupHaving' => 'COUNT(`' . $CNF['TABLE_CONTENT'] . '`.`cnl_id`) >= ' . (int)getParam($CNF['PARAM_BROWSE_ACTIVE_N_POSTS'])
+                ];
+                $this->aCurrent['restriction'] = array_merge($this->aCurrent['restriction'], [
+                    'contents_period' => [
+                        'value' => time() - 3600 * (int)getParam($CNF['PARAM_BROWSE_ACTIVE_X_HOURS']), 
+                        'field' => 'date', 
+                        'operator' => '>=',
+                        'table' => $CNF['TABLE_CONTENT']
+                    ]
+                ]);
+
+                $this->aCurrent['rss']['link'] = 'modules/?r=channels/rss/' . $sMode;
+                $this->aCurrent['title'] = _t('_bx_channels_page_title_browse_active');
+                $this->aCurrent['sorting'] = 'active';
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                break;
+
+            case 'trending':
+                $this->aCurrent['join']['contents'] = [
+                    'type' => 'INNER',
+                    'table' => $CNF['TABLE_CONTENT'],
+                    'mainTable' => 'bx_cnl_data',
+                    'mainField' => 'id',
+                    'onField' => 'cnl_id',
+                    'joinFields' => ['cnl_id'],
+                    'operator' => 'COUNT', 
+                    'groupTable' => 'bx_cnl_data',
+                    'groupField' => 'id',
+                    'groupHaving' => 'COUNT(`' . $CNF['TABLE_CONTENT'] . '`.`cnl_id`) > 0'
+                ];
+                $this->aCurrent['restriction'] = array_merge($this->aCurrent['restriction'], [
+                    'contents_period' => [
+                        'value' => time() - 3600 * (int)getParam($CNF['PARAM_BROWSE_TRENDING_X_HOURS']), 
+                        'field' => 'date', 
+                        'operator' => '>=',
+                        'table' => $CNF['TABLE_CONTENT']
+                    ]
+                ]);
+                $this->aCurrent['rss']['link'] = 'modules/?r=channels/rss/' . $sMode;
+                $this->aCurrent['title'] = _t('_bx_channels_page_title_browse_trending');
+                $this->aCurrent['sorting'] = 'trending';
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                break;
+
+            case 'level':
+                $this->aCurrent['join']['level'] = array(
+                    'type' => 'INNER',
+                    'table' => 'sys_labels',
+                    'mainTable' => 'bx_cnl_data',
+                    'mainField' => 'channel_name',
+                    'onField' => 'value',
+                    'joinFields' => array('value'),
+                );
+                $this->aCurrent['restriction']['level'] = array('value' => $aParams['level'], 'field' => 'level', 'operator' => '=', 'table' => 'sys_labels');
+                $this->aCurrent['sorting'] = 'level';
+                $this->sBrowseUrl = 'page.php?i=channels-toplevel';
+                break;
+
+            case '': // search results
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_channels');
+                unset($this->aCurrent['paginate']['perPage'], $this->aCurrent['rss']);
+                break;
+
+            default:
+                $this->isError = true;
+        }
+
+        if ($bProcessConditionsForPrivateContent) {
+            $this->addConditionsForPrivateContent($CNF, $oJoinedProfile);
+
+            $this->addCustomConditions($CNF, $oJoinedProfile, $sMode, $aParams);
+        }
+
+        $this->sCenterContentUnitSelector = false;
+    }
+
+    function getAlterOrder()
+    {
+        $aResult = [];
+
+        switch ($this->aCurrent['sorting']) {
+            case 'none':
+                break;
+
+            case 'featured':
+                $aResult = ['order' => ' ORDER BY `bx_cnl_data`.`featured` DESC'];
+                break;
+
+            case 'recommended':
+                $aResult = ['order' => ' ORDER BY RAND()'];
+                break;
+
+            case 'top':
+                $aResult = ['order' => ' ORDER BY `bx_cnl_data`.`views` DESC'];
+                break;
+
+            case 'active':
+                $aResult = ['order' => ' ORDER BY `bx_cnl_data`.`lc_date` DESC'];
+                break;
+
+            case 'trending':
+                $aResult = ['order' => ' ORDER BY `contents_new` DESC'];
+                break;
+
+            case 'level':
+                $aResult = ['order' => ' ORDER BY `bx_cnl_data`.`channel_name` DESC'];
+                break;
+
+            case 'last':
+            default:
+                $aResult = ['order' => ' ORDER BY `bx_cnl_data`.`added` DESC'];
+        }
+
+        return $aResult;
+    }
+
+    function _getPseud ()
+    {
+        return [
+            'id' => 'id',
+            'channel_name' => 'channel_name',
+            'added' => 'added',
+            'author' => 'author',
+            'picture' => 'picture',
+
+            'contents_new' => 'cnl_id_count'
+        ];
+    }
+}
+
+/** @} */

+ 153 - 0
modules/boonex/channels/updates/14.0.3_14.0.4/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' => '14.0.4',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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',
+    ),
+);
+
+/** @} */

+ 259 - 0
modules/boonex/channels/updates/14.0.3_14.0.4/source/install/langs/en.xml

@@ -0,0 +1,259 @@
+<?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_option_browse_active_n_posts"><![CDATA[Browse Active: Min number of new posts in channel during the period of time]]></string>
+    <string name="_bx_channels_option_browse_active_x_hours"><![CDATA[Browse Active: The period of time to count new posts in channel]]></string>
+    <string name="_bx_channels_option_browse_trending_x_hours"><![CDATA[Browse Trending: The period of time to count new posts in channel]]></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_active"><![CDATA[Active Channels]]></string>
+        <string name="_bx_channels_page_title_browse_trending"><![CDATA[Trending 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_active_entries"><![CDATA[Active Channels]]></string>
+    <string name="_bx_channels_page_block_title_active_entries"><![CDATA[Active Channels]]></string>
+    <string name="_bx_channels_page_block_title_sys_trending_entries"><![CDATA[Trending Channels]]></string>
+    <string name="_bx_channels_page_block_title_trending_entries"><![CDATA[Trending 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>

+ 422 - 0
modules/boonex/channels/updates/14.0.3_14.0.4/source/install/sql/enable.sql

@@ -0,0 +1,422 @@
+
+-- 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_browse_active_n_posts', '1', @iCategId, '_bx_channels_option_browse_active_n_posts', 'digit', '', '', '', '', 20),
+('bx_channels_browse_active_x_hours', '24', @iCategId, '_bx_channels_option_browse_active_x_hours', 'digit', '', '', '', '', 21),
+('bx_channels_browse_trending_x_hours', '24', @iCategId, '_bx_channels_option_browse_trending_x_hours', 'digit', '', '', '', '', 23),
+('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: 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_active_entries', '_bx_channels_page_block_title_active_entries', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:13:\"browse_active\";}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 3),
+('', 0, 'bx_channels', '_bx_channels_page_block_title_sys_trending_entries', '_bx_channels_page_block_title_trending_entries', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_channels\";s:6:\"method\";s:15:\"browse_trending\";}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 4),
+('', 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) + 5);
+
+-- 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-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', '', 0, 2147483647, 1, 0, 1, 21),
+('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', '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', '', 192, 1, 0, 20),
+('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`, `persistent`, `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, 1, 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', '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', '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_channels_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_profile` 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_admin', '', 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');

+ 343 - 0
modules/boonex/channels/updates/14.0.3_14.0.4/source/install/sql/install.sql

@@ -0,0 +1,343 @@
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+-- TABLE: PROFILES
+CREATE TABLE IF NOT EXISTS `bx_cnl_data` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `author` int(10) unsigned NOT NULL,
+  `added` int(11) NOT NULL,
+  `changed` int(11) NOT NULL,
+  `picture` int(11) NOT NULL,
+  `cover` int(11) NOT NULL,
+  `cover_data` varchar(50) NOT NULL,
+  `channel_name` varchar(191) NOT NULL,
+  `lc_id` int(11) NOT NULL default '0',
+  `lc_date` int(11) NOT NULL default '0',
+  `contents` int(11) NOT NULL default '0',
+  `views` int(11) NOT NULL default '0',
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `score` int(11) NOT NULL default '0',
+  `sc_up` int(11) NOT NULL default '0',
+  `sc_down` int(11) NOT NULL default '0',
+  `favorites` int(11) NOT NULL default '0',
+  `comments` int(11) NOT NULL default '0',
+  `reports` int(11) NOT NULL default '0',
+  `featured` int(11) NOT NULL default '0',
+  `cf` int(11) NOT NULL default '1',
+  `allow_view_to` varchar(255) DEFAULT '3',
+  `status` enum('active','awaiting','hidden') NOT NULL DEFAULT 'active',
+  `status_admin` enum('active','hidden','pending') NOT NULL DEFAULT 'active',
+  PRIMARY KEY (`id`),
+  UNIQUE INDEX channel_name (`channel_name`),
+  FULLTEXT KEY `search_fields` (`channel_name`)
+);
+
+-- TABLE: items
+CREATE TABLE IF NOT EXISTS `bx_cnl_content` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `content_id` int(11) NOT NULL,
+  `cnl_id` int(11) NOT NULL,
+  `author_id` int(11) NOT NULL,
+  `module_name` varchar(19) NOT NULL,
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`)
+);
+
+-- TABLE: STORAGES & TRANSCODERS
+CREATE TABLE `bx_cnl_pics` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` bigint(20) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE `bx_cnl_pics_resized` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` bigint(20) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+-- TABLE: comments
+CREATE TABLE IF NOT EXISTS `bx_cnl_cmts` (
+  `cmt_id` int(11) NOT NULL AUTO_INCREMENT,
+  `cmt_parent_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_vparent_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_object_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_author_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_level` int(11) NOT NULL DEFAULT '0',
+  `cmt_text` text NOT NULL,
+  `cmt_mood` tinyint(4) NOT NULL DEFAULT '0',
+  `cmt_rate` int(11) NOT NULL DEFAULT '0',
+  `cmt_rate_count` int(11) NOT NULL DEFAULT '0',
+  `cmt_time` int(11) unsigned NOT NULL DEFAULT '0',
+  `cmt_replies` int(11) NOT NULL DEFAULT '0',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  `cmt_cf` int(11) NOT NULL default '1',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_cnl_cmts_notes` (
+  `cmt_id` int(11) NOT NULL AUTO_INCREMENT,
+  `cmt_parent_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_vparent_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_object_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_author_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_level` int(11) NOT NULL DEFAULT '0',
+  `cmt_text` text NOT NULL,
+  `cmt_mood` tinyint(4) NOT NULL DEFAULT '0',
+  `cmt_rate` int(11) NOT NULL DEFAULT '0',
+  `cmt_rate_count` int(11) NOT NULL DEFAULT '0',
+  `cmt_time` int(11) unsigned NOT NULL DEFAULT '0',
+  `cmt_replies` int(11) NOT NULL DEFAULT '0',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+-- TABLE: VIEWS
+CREATE TABLE `bx_cnl_views_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `viewer_id` int(11) NOT NULL default '0',
+  `viewer_nip` int(11) unsigned NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+);
+
+-- TABLE: VOTES
+CREATE TABLE IF NOT EXISTS `bx_cnl_votes` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_cnl_votes_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+-- TABLE: REPORTS
+CREATE TABLE IF NOT EXISTS `bx_cnl_reports` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_cnl_reports_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `type` varchar(32) NOT NULL default '',
+  `text` text NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  `checked_by` int(11) NOT NULL default '0',
+  `status` tinyint(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `report` (`object_id`, `author_nip`)
+);
+
+-- TABLE: metas
+CREATE TABLE `bx_cnl_meta_keywords` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+);
+
+CREATE TABLE `bx_cnl_meta_mentions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `profile_id` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `profile_id` (`profile_id`)
+);
+
+
+-- TABLE: favorites
+CREATE TABLE `bx_cnl_favorites_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`author_id`)
+);
+
+-- TABLE: scores
+CREATE TABLE IF NOT EXISTS `bx_cnl_scores` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count_up` int(11) NOT NULL default '0',
+  `count_down` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_cnl_scores_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `type` varchar(8) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+
+-- STORAGES & TRANSCODERS
+INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `cache_control`, `levels`, `table_files`, `ext_mode`, `ext_allow`, `ext_deny`, `quota_size`, `current_size`, `quota_number`, `current_number`, `max_file_size`, `ts`) VALUES
+('bx_channels_pics', @sStorageEngine, '', 360, 2592000, 3, 'bx_cnl_pics', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+('bx_channels_pics_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_cnl_pics_resized', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0);
+
+INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`) VALUES 
+('bx_channels_icon', 'bx_channels_pics_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_channels_pics";}', 'no', '1', '2592000', '0'),
+('bx_channels_thumb', 'bx_channels_pics_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_channels_pics";}', 'no', '1', '2592000', '0'),
+('bx_channels_avatar', 'bx_channels_pics_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_channels_pics";}', 'no', '1', '2592000', '0'),
+('bx_channels_avatar_big', 'bx_channels_pics_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_channels_pics";}', 'no', '1', '2592000', '0'),
+('bx_channels_picture', 'bx_channels_pics_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_channels_pics";}', 'no', '1', '2592000', '0'),
+('bx_channels_cover', 'bx_channels_pics_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_channels_pics";}', 'no', '1', '2592000', '0'),
+('bx_channels_cover_thumb', 'bx_channels_pics_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_channels_pics";}', 'no', '1', '2592000', '0'),
+('bx_channels_gallery', 'bx_channels_pics_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_channels_pics";}', 'no', '1', '2592000', '0');
+
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES 
+('bx_channels_icon', 'Resize', 'a:3:{s:1:"w";s:2:"30";s:1:"h";s:2:"30";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_channels_thumb', 'Resize', 'a:3:{s:1:"w";s:2:"50";s:1:"h";s:2:"50";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_channels_avatar', 'Resize', 'a:3:{s:1:"w";s:3:"100";s:1:"h";s:3:"100";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_channels_avatar_big', 'Resize', 'a:3:{s:1:"w";s:3:"200";s:1:"h";s:3:"200";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_channels_picture', 'Resize', 'a:3:{s:1:"w";s:4:"1024";s:1:"h";s:4:"1024";s:13:"square_resize";s:1:"0";}', '0'),
+('bx_channels_cover', 'Resize', 'a:1:{s:1:"w";s:4:"1200";}', '0'),
+('bx_channels_cover_thumb', 'Resize', 'a:3:{s:1:"w";s:2:"48";s:1:"h";s:2:"48";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_channels_gallery', 'Resize', 'a:1:{s:1:"w";s:3:"500";}', '0');
+
+-- FORMS
+INSERT INTO `sys_objects_form`(`object`, `module`, `title`, `action`, `form_attrs`, `table`, `key`, `uri`, `uri_title`, `submit_name`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_channel', 'bx_channels', '_bx_channels_form_profile', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_cnl_data', 'id', '', '', 'do_submit', '', 0, 1, 'BxCnlFormEntry', 'modules/boonex/channels/classes/BxCnlFormEntry.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_channel', 'bx_channel_add', 'bx_channels', 0, '_bx_channels_form_profile_display_add'),
+('bx_channel', 'bx_channel_delete', 'bx_channels', 0, '_bx_channels_form_profile_display_delete'),
+('bx_channel', 'bx_channel_edit', 'bx_channels', 0, '_bx_channels_form_profile_display_edit'),
+('bx_channel', 'bx_channel_edit_cover', 'bx_channels', 0, '_bx_channels_form_profile_display_edit_cover'),
+('bx_channel', 'bx_channel_view', 'bx_channels', 1, '_bx_channels_form_profile_display_view'),
+('bx_channel', 'bx_channel_view_full', 'bx_channels', 1, '_bx_channels_form_profile_display_view_full');
+
+INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES 
+('bx_channel', 'bx_channels', 'cf', '1', '#!sys_content_filter', 0, 'select', '_sys_form_entry_input_sys_cf', '_sys_form_entry_input_cf', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_channel', 'bx_channels', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_channels_form_profile_input_sys_delete_confirm', '_bx_channels_form_profile_input_delete_confirm', '_bx_channels_form_profile_input_delete_confirm_info', 1, 0, 0, '', '', '', 'avail', '', '_bx_channels_form_profile_input_delete_confirm_error', '', '', 1, 0),
+('bx_channel', 'bx_channels', 'do_submit', '_sys_form_account_input_submit', '', 0, 'submit', '_bx_channels_form_profile_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_channel', 'bx_channels', 'channel_name', '', '', 0, 'text', '_bx_channels_form_profile_input_sys_channel_name', '_bx_channels_form_profile_input_channel_name', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_channels_form_profile_input_channel_name_err', 'Xss', '', 1, 0),
+('bx_channel', 'bx_channels', 'cover', 'a:1:{i:0;s:22:"bx_channels_cover_crop";}', 'a:1:{s:22:"bx_channels_cover_crop";s:24:"_sys_uploader_crop_title";}', 0, 'files', '_bx_channels_form_profile_input_sys_cover', '_bx_channels_form_profile_input_cover', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_channel', 'bx_channels', 'picture', 'a:1:{i:0;s:24:"bx_channels_picture_crop";}', 'a:1:{s:24:"bx_channels_picture_crop";s:24:"_sys_uploader_crop_title";}', 0, 'files', '_bx_channels_form_profile_input_sys_picture', '_bx_channels_form_profile_input_picture', '', 0, 0, 0, '', '', '', '', '', '_bx_channels_form_profile_input_picture_err', '', '', 1, 0);
+
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_channel_add', 'channel_name', 2147483647, 1, 1),
+('bx_channel_add', 'cf', 2147483647, 1, 2),
+('bx_channel_add', 'do_submit', 2147483647, 1, 3),
+
+('bx_channel_delete', 'delete_confirm', 2147483647, 1, 0),
+('bx_channel_delete', 'do_submit', 2147483647, 1, 1),
+
+('bx_channel_edit', 'channel_name', 2147483647, 1, 1),
+('bx_channel_edit', 'cf', 2147483647, 1, 2),
+('bx_channel_edit', 'do_submit', 2147483647, 1, 3),
+
+('bx_channel_edit_cover', 'cover', 2147483647, 1, 1),
+('bx_channel_edit_cover', 'do_submit', 2147483647, 1, 2),
+
+('bx_channel_view', 'channel_name', 2147483647, 1, 1),
+
+('bx_channel_view_full', 'channel_name', 2147483647, 1, 1);
+
+-- COMMENTS
+INSERT INTO `sys_objects_cmts` (`Name`, `Module`, `Table`, `CharsPostMin`, `CharsPostMax`, `CharsDisplayMax`, `Html`, `PerView`, `PerViewReplies`, `BrowseType`, `IsBrowseSwitch`, `PostFormPosition`, `NumberOfLevels`, `IsDisplaySwitch`, `IsRatable`, `ViewingThreshold`, `IsOn`, `RootStylePrefix`, `BaseUrl`, `ObjectVote`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES
+('bx_channels', 'bx_channels', 'bx_cnl_cmts', 1, 5000, 1000, 3, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-channel-profile&id={object_id}', '', 'bx_cnl_data', 'id', 'author', 'channel_name', 'comments', '', ''),
+('bx_cnl_notes', 'bx_channels', 'bx_cnl_cmts_notes', 1, 5000, 1000, 0, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-post&id={object_id}', '', 'bx_cnl_data', 'id', 'author', 'title', '', 'BxTemplCmtsNotes', '');
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `module`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_channels', 'bx_channels', 'bx_cnl_views_track', '86400', '1', 'bx_cnl_data', 'id', 'author', 'views', '', '');
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `Module`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_channels', 'bx_channels', 'bx_cnl_votes', 'bx_cnl_votes_track', '604800', '1', '1', '0', '1', 'bx_cnl_data', 'id', 'author', 'rate', 'votes', '', '');
+
+-- SCORES
+INSERT INTO `sys_objects_score` (`name`, `module`, `table_main`, `table_track`, `post_timeout`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_score`, `trigger_field_cup`, `trigger_field_cdown`, `class_name`, `class_file`) VALUES 
+('bx_channels', 'bx_channels', 'bx_cnl_scores', 'bx_cnl_scores_track', '604800', '0', 'bx_cnl_data', 'id', 'author', 'score', 'sc_up', 'sc_down', '', '');
+
+-- REPORTS
+INSERT INTO `sys_objects_report` (`name`, `module`, `table_main`, `table_track`, `is_on`, `base_url`, `object_comment`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_channels', 'bx_channels', 'bx_cnl_reports', 'bx_cnl_reports_track', '1', 'page.php?i=view-channel-profile&id={object_id}', 'bx_cnl_notes', 'bx_cnl_data', 'id', 'author', 'reports', '', '');
+
+-- FAFORITES
+INSERT INTO `sys_objects_favorite` (`name`, `table_track`, `is_on`, `is_undo`, `is_public`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_channels', 'bx_cnl_favorites_track', '1', '1', '1', 'page.php?i=view-channel-profile&id={object_id}', 'bx_cnl_data', 'id', 'author', 'favorites', '', '');
+
+-- FEATURED
+INSERT INTO `sys_objects_feature` (`name`, `module`, `is_on`, `is_undo`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_flag`, `class_name`, `class_file`) VALUES 
+('bx_channels', 'bx_channels', '1', '1', 'page.php?i=view-channel-profile&id={object_id}', 'bx_cnl_data', 'id', 'author', 'featured', '', '');
+
+-- CONTENT INFO
+INSERT INTO `sys_objects_content_info` (`name`, `title`, `alert_unit`, `alert_action_add`, `alert_action_update`, `alert_action_delete`, `class_name`, `class_file`) VALUES
+('bx_channels', '_bx_channels', 'bx_channels', 'added', 'edited', 'deleted', '', ''),
+('bx_channels_cmts', '_bx_channels_cmts', 'bx_channels', 'commentPost', 'commentUpdated', 'commentRemoved', 'BxDolContentInfoCmts', '');
+
+INSERT INTO `sys_content_info_grids` (`object`, `grid_object`, `grid_field_id`, `condition`, `selection`) VALUES
+('bx_channels', 'bx_channels_administration', 'td`.`id', '', '');
+
+-- SEARCH EXTENDED
+INSERT INTO `sys_objects_search_extended` (`object`, `object_content_info`, `module`, `title`, `active`, `class_name`, `class_file`) VALUES
+('bx_channels', 'bx_channels', 'bx_channels', '_bx_channels_search_extended', 1, '', ''),
+('bx_channels_cmts', 'bx_channels_cmts', 'bx_channels', '_bx_channels_search_extended_cmts', 1, 'BxTemplSearchExtendedCmts', '');
+
+-- STUDIO PAGE & WIDGET
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_channels', '_bx_channels', '_bx_channels', 'bx_channels@modules/boonex/channels/|std-icon.svg');
+SET @iPageId = LAST_INSERT_ID();
+
+SET @iParentPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name` = 'home');
+SET @iParentPageOrder = (SELECT MAX(`order`) FROM `sys_std_pages_widgets` WHERE `page_id` = @iParentPageId);
+INSERT INTO `sys_std_widgets` (`page_id`, `module`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, 'bx_channels', 'extensions', '{url_studio}module.php?name=bx_channels', '', 'bx_channels@modules/boonex/channels/|std-icon.svg', '_bx_channels', 'a:4:{s:6:"module";s:11:"bx_channels";s:6:"method";s:18:"get_widget_notices";s:6:"params";a:0:{}s:5:"class";s:6:"Module";}', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_actions";s:6:"params";a:0:{}s:5:"class";s:18:"TemplStudioModules";}');
+INSERT INTO `sys_std_pages_widgets` (`page_id`, `widget_id`, `order`) VALUES
+(@iParentPageId, LAST_INSERT_ID(), IF(ISNULL(@iParentPageOrder), 1, @iParentPageOrder + 1));

+ 51 - 0
modules/boonex/classes/updates/14.0.0_14.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' => 'Classes',
+    'version_from' => '14.0.0',
+    'version_to' => '14.0.1',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/classes/updates/update_14.0.0_14.0.1/',
+    'home_uri' => 'classes_update_1400_1401',
+
+    'module_dir' => 'boonex/classes/',
+    'module_uri' => 'classes',
+
+    'db_prefix' => 'bx_classes_',
+    'class_prefix' => 'BxClss',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Classes',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/classes/updates/14.0.0_14.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 BxClssUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 152 - 0
modules/boonex/classes/updates/14.0.0_14.0.1/source/install/config.php

@@ -0,0 +1,152 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Classes Classes
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_classes',
+    'title' => 'Classes',
+    'note' => 'Classes module.',
+    'version' => '14.0.1',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/classes/',
+    'home_uri' => 'classes',
+
+    'db_prefix' => 'bx_classes_',
+    'class_prefix' => 'BxClss',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Classes',
+
+    /**
+     * List of page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_group_view_entry',
+    ),
+    
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+        '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_classes_covers',
+    	'bx_classes_photos',
+        'bx_classes_videos',
+        'bx_classes_sounds',
+        'bx_classes_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+        'bx_classes_preview',
+        'bx_classes_gallery',
+        'bx_classes_cover',
+
+        'bx_classes_preview_photos',
+        'bx_classes_gallery_photos', 
+
+        'bx_classes_videos_poster',
+        'bx_classes_videos_poster_preview',
+        'bx_classes_videos_mp4',
+        'bx_classes_videos_mp4_hd',
+
+        'bx_classes_sounds_mp3',
+
+        'bx_classes_preview_files',
+        'bx_classes_gallery_files'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_classes',
+    	'bx_classes_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'
+    ),
+
+);
+
+/** @} */

+ 47 - 0
modules/boonex/classes/updates/14.0.0_14.0.1/source/template/classes_in_context.html

@@ -0,0 +1,47 @@
+<bx_if:admin>
+<div class="bx-course-controls bx-def-margin-bottom bx-clearfix">
+    <div class="bx-course-controls-1 bx-clearfix">
+        <a class="bx-btn bx-def-margin-right" href="__new_class_url__"><bx_text:_bx_classes_txt_add_class /></a>
+        <a class="bx-btn" href="javascript:void(0);" onclick="bx_classes_show_module_add_form('__context_profile_id__')"><bx_text:_bx_classes_txt_add_module /></a>
+    </div>
+    <div class="bx-course-controls-2 bx-clearfix">
+        <a class="bx-btn" href="javascript:void(0);" onclick="bx_classes_reorder_modules('__context_profile_id__', true)"><bx_text:_bx_classes_txt_reorder_modules /></a>
+        <a class="bx-btn bx-def-margin-left" href="javascript:void(0);" onclick="bx_classes_reorder_classes('__context_profile_id__', true)"><bx_text:_bx_classes_txt_reorder_classes /></a>
+        <a class="bx-btn bx-def-margin-left bx-classes-btn-done" href="javascript:void(0);" onclick="bx_classes_reorder_classes('__context_profile_id__', false); bx_classes_reorder_modules('__context_profile_id__', false);">Done</a>
+    </div>
+</div>
+</bx_if:admin>
+<div class="bx-course-classes">
+    __form__
+</div>
+<bx_if:edit_modules>
+<script>    
+    $(document).ready(function () {
+        $('.bx-course-classes .bx-form-section').each(function () {
+            var iModuleId = parseInt($(this).attr('id').replace('module_', ''));
+            var sTmplBtn = $('#bx-classes-tmpl-btn').html();
+            $(this).find('.bx-form-section-title').append(sTmplBtn.replace('{icon}', 'pencil-alt').replace('{action}', 'edit').replace('{data}', iModuleId));
+            if (0 == $(this).find('.bx-classes-class').size())
+                $(this).find('.bx-form-section-title').append(sTmplBtn.replace('{icon}', 'times').replace('{action}', 'delete').replace('{data}', iModuleId));
+        });
+        $('.bx-course-classes .bx-form-section .bx-classes-module-action').each(function () {
+            $(this).click(function (eve) {
+                eve.stopPropagation();
+                eve.preventDefault();
+                var e = $(this);
+                switch (e.data('action')) {
+                    case 'edit':
+                        bx_classes_show_module_edit_form('__context_profile_id__', e.data('val'));
+                        break;
+                    case 'delete':
+                        bx_classes_delete_module('__context_profile_id__', e.data('val'));
+                        break;
+                }
+            });
+        });
+    });
+</script>
+</bx_if:edit_modules>
+<template id="bx-classes-tmpl-btn">
+    <a href="#" class="bx-btn bx-btn-small bx-classes-module-action bx-def-margin-sec-right" data-action="{action}" data-val="{data}"><i class="sys-icon {icon}"></i></a>
+</template>

+ 59 - 0
modules/boonex/classes/updates/14.0.0_14.0.1/source/template/css/main.css

@@ -0,0 +1,59 @@
+.bx-course-controls-1 {
+    float:left;
+}
+
+.bx-course-controls-2 {
+    float:right;
+}
+
+.bx-course-classes .bx-form-input-wrapper-custom {
+    min-height:1rem;
+}
+
+.bx-course-classes .bx-form-section-title .bx-form-section-toggler {
+    display: none;
+}
+
+.bx-course-classes .bx-form-section-title .bx-classes-module-action:last-child {
+    margin-right: 1.5rem;
+}
+
+.bx-course-classes .bx-classes-placeholder:not(:first-child),
+.bx-course-classes .bx-classes-class:not(:first-child) {
+    margin-top:1rem;
+}
+
+.bx-classes-btn-done {
+    display:none;
+}
+.bx-course-reordering-mode .bx-classes-btn-done {
+    display:block;
+}
+.bx-course-reordering-mode .bx-btn:not(.bx-classes-btn-done) {
+    display:none;
+}
+
+.bx-classes-class-status-completed b,
+.bx-classes-class-status-completed a {
+    text-decoration: line-through;
+}
+
+.bx-course-classes legend .bx-btn {
+    display:inline-block;
+    float:none;
+    vertical-align:top;
+}
+
+.bx-course-classes .handle {
+    cursor:move;
+}
+
+.bx-classes-field-view-module,
+.bx-classes-field-view-end-date,
+.bx-classes-field-view-start-date {
+    font-weight:bold;
+}
+
+.bx-classes-tip-icon {
+    cursor:pointer;
+}

+ 51 - 0
modules/boonex/convos/updates/14.0.1_14.0.2/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' => '14.0.1',
+    'version_to' => '14.0.2',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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_14.0.1_14.0.2/',
+    'home_uri' => 'convos_update_1401_1402',
+
+    '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/14.0.1_14.0.2/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);
+    }
+}

+ 134 - 0
modules/boonex/convos/updates/14.0.1_14.0.2/source/classes/BxCnvCmts.php

@@ -0,0 +1,134 @@
+<?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
+ *
+ * @{
+ */
+
+class BxCnvCmts extends BxTemplCmts
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    /**
+     * Silent Mode for Notification based modules.
+     */
+    protected $_iSilentMode;
+
+    function __construct($sSystem, $iId, $iInit = true, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_convos';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct($sSystem, $iId, $iInit, $oTemplate);
+
+        $this->_iSilentMode = 21; //--- Absolute for Timeline module only.
+
+        $this->_aT = array_merge($this->_aT, array(
+            'txt_min_form_placeholder' => '_bx_cnv_txt_min_form_placeholder'
+        ));
+    }
+
+    public function getObjectTitle ($iObjectId = 0)
+    {
+    	$sResult = parent::getObjectTitle($iObjectId);
+    	if(!empty($sResult))
+    		return strmaxtextlen($sResult, 20, '...');
+
+        return $sResult;
+    }
+
+    public function addCssJs($aBp = [], $aDp = [])
+    {
+        parent::addCssJs($aBp, $aDp);
+
+        $this->_oModule->_oTemplate->addCss(array('cmts.css'));
+    }
+
+    /**
+     * Comments are enabled for collaborators only
+     */
+    public function isEnabled ()
+    {
+        if (!parent::isEnabled ())
+            return false;
+
+        if (!$this->_oModule->_oDb->getContentInfoById((int)$this->getId()))
+            return false;
+
+        $aCollaborators = $this->_oModule->_oDb->getCollaborators((int)$this->getId());
+        if (!isset($aCollaborators[bx_get_logged_profile_id()]))
+            return false;
+
+        return true;
+    }
+
+    public function isRemoveAllowed ($aCmt, $isPerformAction = false)
+    {
+        if (isAdmin())
+            return true;
+
+        return false;
+    }
+
+    public function msgErrRemoveAllowed ()
+    {
+        return _t('_sys_txt_access_denied');
+    }
+
+    public function isEditAllowed ($aCmt, $isPerformAction = false)
+    {
+        return $this->isRemoveAllowed ($aCmt, $isPerformAction);
+    }
+
+    public function msgErrEditAllowed ()
+    {
+        return $this->msgErrRemoveAllowed ();
+    }
+
+    public function getCommentsBlock($aBp = array(), $aDp = array())
+    {
+        $mixedBlock = parent::getCommentsBlock($aBp, $aDp);
+        if (is_array($mixedBlock) && isset($mixedBlock['title']))
+            $mixedBlock['title'] = _t('_bx_cnv_page_block_title_entry_comments', $this->getCommentsCount());
+
+        return $mixedBlock;
+    }
+
+    public function getCommentBlock($iCmtId = 0, $aBp = array(), $aDp = array())
+    {
+        if(!$this->isEnabled())
+            return '';
+
+        return parent::getCommentBlock($iCmtId, $aBp, $aDp);
+    }
+
+    protected function _getFormObject($sAction = BX_CMT_ACTION_POST)
+    {
+        $oForm = parent::_getFormObject($sAction);
+        $oForm->aInputs['cmt_submit']['value'] = _t('_sys_send');
+        return $oForm;
+    }
+
+    protected function _prepareAlertParams($aCmt)
+    {
+        $aParams = parent::_prepareAlertParams($aCmt);
+        $aParams['silent_mode'] = $this->_iSilentMode;
+
+        return $aParams;
+    }
+
+    protected function _prepareAlertParamsReply($aCmt, $aCmtPrnt)
+    {
+        $aParams = parent::_prepareAlertParamsReply($aCmt, $aCmtPrnt);
+        $aParams['silent_mode'] = $this->_iSilentMode;
+
+        return $aParams;
+    }
+}
+
+/** @} */

+ 104 - 0
modules/boonex/convos/updates/14.0.1_14.0.2/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' => '14.0.2',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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/14.0.1_14.0.2/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' => '14.0.1',
+    'version_to' => '14.0.2',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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_14.0.1_14.0.2/',
+    'home_uri' => 'courses_update_1401_1402',
+
+    'module_dir' => 'boonex/courses/',
+    'module_uri' => 'courses',
+
+    'db_prefix' => 'bx_courses_',
+    'class_prefix' => 'BxCourses',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Courses',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/courses/updates/14.0.1_14.0.2/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);
+    }
+}

+ 284 - 0
modules/boonex/courses/updates/14.0.1_14.0.2/source/classes/BxCoursesConfig.php

@@ -0,0 +1,284 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Courses Courses
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxCoursesConfig extends BxBaseModGroupsConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_aMenuItems2MethodsActions = array_merge($this->_aMenuItems2MethodsActions, array(
+            'view-course-profile' => 'checkAllowedView',
+            'edit-course-profile' => 'checkAllowedEdit',
+            'edit-course-cover' => 'checkAllowedChangeCover',
+            'invite-to-course' => 'checkAllowedInvite',
+            'delete-course-profile' => 'checkAllowedDelete',
+            'approve-course-profile' => 'checkAllowedApprove',
+        ));
+
+        $this->CNF = array (
+
+            // module icon
+            'ICON' => 'book-reader col-blue3-dark',
+
+            // 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_NAME' => 'name',
+            'FIELD_TITLE' => 'name',
+            'FIELD_TEXT' => 'desc',
+            'FIELD_CATEGORY' => 'cat',
+            'FIELD_PICTURE' => 'picture',
+            'FIELD_COVER' => 'cover',
+            'FIELD_COVER_POSITION' => 'cover_data',
+            'FIELD_JOIN_CONFIRMATION' => 'join_confirmation',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_ALLOW_POST_TO' => 'allow_post_to',
+            'FIELD_CF' => 'cf',
+            'FIELD_VIEWS' => 'views',
+            'FIELD_VOTES' => 'votes',
+            'FIELD_STATUS' => 'status',
+            'FIELD_STATUS_ADMIN' => 'status_admin',
+            'FIELD_COMMENTS' => 'comments',
+            'FIELDS_QUICK_SEARCH' => array('name'),
+            'FIELD_LOCATION' => 'location',
+            'FIELD_LOCATION_PREFIX' => 'location',
+            'FIELD_LABELS' => 'labels',
+            '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_PRICE_ROLE_ID' => 'role_id',
+            'FIELD_PRICE_NAME' => 'name',
+
+            // page URIs
+            'URI_VIEW_ENTRY' => 'view-course-profile',
+            'URI_EDIT_ENTRY' => 'edit-course-profile',
+            'URI_JOIN_ENTRY' => 'join-course-profile',
+            'URI_JOINED_ENTRIES' => 'joined-courses',
+            'URI_MANAGE_COMMON' => 'courses-manage',
+            'URI_FAVORITES_LIST' => 'courses-favorites',
+
+            'URL_HOME' => 'page.php?i=courses-home',
+            'URL_ENTRY_FANS' => 'page.php?i=course-fans',
+            'URL_MANAGE_COMMON' => 'page.php?i=courses-manage',
+            'URL_MANAGE_ADMINISTRATION' => 'page.php?i=courses-administration',
+
+            'PARAM_AUTO_APPROVE' => 'bx_courses_enable_auto_approve',
+            'PARAM_NUM_RSS' => 'bx_courses_num_rss',
+            'PARAM_NUM_CONNECTIONS_QUICK' => 'bx_courses_num_connections_quick',
+
+            'PARAM_SEARCHABLE_FIELDS' => 'bx_courses_searchable_fields',
+            'PARAM_PER_PAGE_BROWSE_SHOWCASE' => 'bx_courses_per_page_browse_showcase',
+            'PARAM_PER_PAGE_BROWSE_RECOMMENDED' => 'bx_courses_per_page_browse_recommended',
+
+            'PARAM_MMODE' => 'bx_courses_members_mode',
+            'PARAM_PAID_JOIN_ENABLED' => true,
+            'PARAM_RECURRING_RESERVE' => 3, // 3 days for recurring payment to be registered
+            'PARAM_PER_PAGE_FOR_FAVORITES_LISTS' => 'bx_courses_per_page_for_favorites_lists',
+            'PARAM_USE_IN' => 'bx_courses_internal_notifications',
+
+            // objects
+            'OBJECT_STORAGE' => 'bx_courses_pics',
+            'OBJECT_STORAGE_COVER' => 'bx_courses_pics',
+            'OBJECT_IMAGES_TRANSCODER_THUMB' => 'bx_courses_thumb',
+            'OBJECT_IMAGES_TRANSCODER_ICON' => 'bx_courses_icon',
+            'OBJECT_IMAGES_TRANSCODER_AVATAR' => 'bx_courses_avatar',
+            'OBJECT_IMAGES_TRANSCODER_AVATAR_BIG' => 'bx_courses_avatar_big',
+            'OBJECT_IMAGES_TRANSCODER_PICTURE' => 'bx_courses_picture',
+            'OBJECT_IMAGES_TRANSCODER_COVER' => 'bx_courses_cover',
+            'OBJECT_IMAGES_TRANSCODER_COVER_THUMB' => 'bx_courses_cover_thumb',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => 'bx_courses_gallery',
+            'OBJECT_VIEWS' => 'bx_courses',
+            'OBJECT_VOTES' => 'bx_courses',
+            'OBJECT_SCORES' => 'bx_courses',
+            'OBJECT_FAVORITES' => 'bx_courses',
+            'OBJECT_FEATURED' => 'bx_courses',
+            'OBJECT_COMMENTS' => 'bx_courses',
+            'OBJECT_NOTES' => 'bx_courses_notes',
+            'OBJECT_REPORTS' => 'bx_courses',
+            'OBJECT_METATAGS' => 'bx_courses',
+            'OBJECT_CATEGORY' => 'bx_courses_cats',
+            'OBJECT_FORM_ENTRY' => 'bx_course',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => 'bx_course_view',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW_FULL' => 'bx_course_view_full', // for "info" tab on view course page
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_course_add',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => 'bx_course_edit',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT_COVER' => 'bx_course_edit_cover',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_course_delete',
+            'OBJECT_FORM_ENTRY_DISPLAY_INVITE' => 'bx_course_invite',
+            'OBJECT_FORM_PRICE' => 'bx_courses_price',
+            'OBJECT_FORM_PRICE_DISPLAY_ADD' => 'bx_courses_price_add',
+            'OBJECT_FORM_PRICE_DISPLAY_EDIT' => 'bx_courses_price_edit',
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_courses_view_actions', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_MORE' => 'bx_courses_view_actions_more', // actions menu on view entry page for "more" popup
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL' => 'bx_courses_view_actions_all', // all actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_courses_my', // actions menu on profile entries page
+            'OBJECT_MENU_SUBMENU' => 'bx_courses_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => 'bx_courses_view_submenu',  // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'courses-home', // first item in view entry submenu from main module submenu
+            'OBJECT_MENU_MANAGE_VIEW_ENTRY' => '',
+            'OBJECT_MENU_VIEW_ENTRY_META' => 'bx_courses_view_meta', // meta menu on view entry page
+            'OBJECT_MENU_SNIPPET_META' => 'bx_courses_snippet_meta', // menu for snippet meta info
+            'OBJECT_MENU_MANAGE_TOOLS' => 'bx_courses_menu_manage_tools', //manage menu in content administration tools
+            'OBJECT_PAGE_VIEW_ENTRY' => 'bx_courses_view_profile',
+            'OBJECT_PAGE_VIEW_ENTRY_CLOSED' => 'bx_courses_view_profile_closed',
+            'OBJECT_PAGE_JOINED_ENTRY' => 'bx_courses_join_profile',
+            'OBJECT_PRIVACY_VIEW' => 'bx_courses_allow_view_to',
+            'OBJECT_PRIVACY_LIST_VIEW' => 'bx_courses_allow_view_favorite_list',
+            'OBJECT_PRIVACY_VIEW_NOTIFICATION_EVENT' => 'bx_courses_allow_view_notification_to',
+            'OBJECT_PRIVACY_POST' => 'bx_courses_allow_post_to',
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_courses_administration',
+            'OBJECT_GRID_COMMON' => 'bx_courses_common',
+            'OBJECT_GRID_CONNECTIONS' => 'bx_courses_fans',
+            'OBJECT_GRID_INVITES' => 'bx_courses_invites',
+            'OBJECT_GRID_PRICES_MANAGE' => 'bx_courses_prices_manage',
+            'OBJECT_GRID_PRICES_VIEW' => 'bx_courses_prices_view',
+            'OBJECT_CONNECTIONS' => 'bx_courses_fans',
+            'OBJECT_UPLOADERS_COVER' => array('bx_courses_cover_crop'),
+            'OBJECT_UPLOADERS_PICTURE' => array('bx_courses_picture_crop'),
+            'OBJECT_PRE_LIST_ROLES' => 'bx_courses_roles',
+            'OBJECT_PRE_LIST_PERIOD_UNITS' => 'bx_courses_period_units',
+
+            'BADGES_AVALIABLE' => true,
+            
+            'INVITES_KEYS_LIFETIME' => 86400,
+
+            'EMAIL_INVITATION' => 'bx_courses_invitation',
+            'EMAIL_JOIN_REQUEST' => 'bx_courses_join_request',
+            'EMAIL_JOIN_CONFIRM' => 'bx_courses_join_confirm',
+            'EMAIL_FAN_BECOME_ADMIN' => 'bx_courses_fan_become_admin',
+            'EMAIL_ADMIN_BECOME_FAN' => 'bx_courses_admin_become_fan',
+            'EMAIL_FAN_REMOVE' => 'bx_courses_fan_remove',
+            'EMAIL_FAN_SET_ROLE' => 'bx_courses_set_role',
+            'EMAIL_JOIN_REJECT' => 'bx_courses_join_reject',
+
+            '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_courses_view_actions' => $this->_aMenuItems2MethodsActions,
+                'bx_courses_view_actions_more' => $this->_aMenuItems2MethodsActions,
+                'bx_courses_view_actions_all' => $this->_aMenuItems2MethodsActions,
+            ),
+
+            // informer messages
+            'INFORMERS' => array (
+                'status' => array (
+                    'name' => 'bx-courses-status-not-active',
+                    'map' => array (
+                        BX_PROFILE_STATUS_PENDING => '_bx_courses_txt_account_pending',
+                        BX_PROFILE_STATUS_SUSPENDED => '_bx_courses_txt_account_suspended',
+                    ),
+                ),
+                'approving' => array (
+                    'name' => 'bx-groups-approving',
+                    'map' => array (
+                        'pending' => array('msg' => '_bx_courses_txt_account_pending', 'type' => BX_INFORMER_ALERT),
+                        'hidden' => array('msg' => '_bx_courses_txt_status_hidden', 'type' => BX_INFORMER_ERROR),
+                    ),
+                ),
+            ),
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_courses_txt_sample_single',
+                'txt_sample_single_with_article' => '_bx_courses_txt_sample_single_with_article',
+                'txt_sample_comment_single' => '_bx_courses_txt_sample_comment_single',
+                'txt_sample_vote_single' => '_bx_courses_txt_sample_vote_single',
+                'txt_sample_score_up_single' => '_bx_courses_txt_sample_score_up_single',
+                'txt_sample_score_down_single' => '_bx_courses_txt_sample_score_down_single',
+                'txt_private_group' => '_bx_courses_txt_private_entry',
+                'txt_N_fans' => '_bx_courses_txt_N_fans',
+                'txt_ntfs_join_invitation' => '_bx_courses_txt_ntfs_join_invitation',
+                'txt_ntfs_join_request' => '_bx_courses_txt_ntfs_join_request',
+                'txt_ntfs_fan_added' => '_bx_courses_txt_ntfs_fan_added',
+                'txt_ntfs_timeline_post_common' => '_bx_courses_txt_ntfs_timeline_post_common',
+                'option_members_mode_multi_roles' => '_bx_courses_option_members_mode_multi_roles',
+                'form_field_author' => '_bx_courses_form_entry_input_author',
+                'menu_item_title_befriend_sent' => '_bx_courses_menu_item_title_befriend_sent',
+                'menu_item_title_unfriend_cancel_request' => '_bx_courses_menu_item_title_unfriend_cancel_request',
+                'menu_item_title_befriend_confirm' => '_bx_courses_menu_item_title_befriend_confirm',
+                'menu_item_title_unfriend_reject_request' => '_bx_courses_menu_item_title_unfriend_reject_request',
+                'menu_item_title_befriend' => '_bx_courses_menu_item_title_befriend',
+                'menu_item_title_unfriend' => '_bx_courses_menu_item_title_unfriend',
+                'grid_action_err_delete' => '_bx_courses_grid_action_err_delete',
+                'grid_txt_account_manager' => '_bx_courses_grid_txt_account_manager',
+                'filter_item_active' => '_bx_courses_grid_filter_item_title_adm_active',
+                'filter_item_hidden' => '_bx_courses_grid_filter_item_title_adm_hidden',
+                'filter_item_pending' => '_bx_courses_grid_filter_item_title_adm_pending',
+                'filter_item_suspended' => '_bx_courses_grid_filter_item_title_adm_suspended',
+                'filter_item_select_one_filter1' => '_bx_courses_grid_filter_item_title_adm_select_one_filter1',
+                'filter_item_select_one_filter2' => '_bx_courses_grid_filter_item_title_adm_select_one_filter2',
+                'menu_item_manage_my' => '_bx_courses_menu_item_title_manage_my',
+                'menu_item_manage_all' => '_bx_courses_menu_item_title_manage_all',
+                'menu_item_title_sm_join' => '_bx_courses_menu_item_title_sm_join',
+                'menu_item_title_sm_join_paid' => '_bx_courses_menu_item_title_sm_join_paid',
+                'menu_item_title_sm_join_requested' => '_bx_courses_menu_item_title_become_fan_sent',
+                'menu_item_title_sm_join_confirm' => '_bx_courses_menu_item_title_sm_join_confirm',
+                'menu_item_title_sm_leave' => '_bx_courses_menu_item_title_sm_leave',
+                'menu_item_title_sm_leave_cancel' => '_bx_courses_menu_item_title_sm_leave_cancel',
+                'menu_item_title_sm_leave_reject' => '_bx_courses_menu_item_title_sm_leave_reject',
+                'txt_all_entries_by_author' => '_bx_courses_page_title_browse_by_author',
+                'txt_invitation_popup_title' => '_bx_courses_txt_invite_popup_title',
+                'txt_invitation_popup_text' => '_bx_courses_txt_invite_popup_text',
+                'txt_invitation_popup_accept_button' => '_bx_courses_txt_invite_popup_button_accept',
+                'txt_invitation_popup_decline_button' => '_bx_courses_txt_invite_popup_button_decline',
+                'txt_invitation_popup_error_invitation_absent' => '_bx_courses_txt_invite_popup_error_invitation_absent',
+                'txt_invitation_popup_error_wrong_user' => '_bx_courses_txt_invite_popup_error_invitation_wrong_user',
+                'txt_n_unit' => '_bx_courses_txt_n_unit',
+                'txt_buy_title' => '_bx_courses_grid_action_title_buy_title',
+                'txt_cart_item_title' => '_bx_courses_txt_cart_item_title',
+                'txt_cart_item_title_lifetime' => '_bx_courses_txt_cart_item_title_lifetime',
+                'txt_subscribe_title' => '_bx_courses_grid_action_title_subscribe_title',
+                'msg_performed' => '_bx_courses_msg_performed',
+                'popup_title_price_add' => '_bx_courses_popup_title_price_add',
+                'popup_title_price_edit' => '_bx_courses_popup_title_price_edit',
+                'err_period_unit' => '_bx_courses_form_price_input_err_period_unit',
+                'err_price_duplicate' => '_bx_courses_err_price_duplicate',
+                'err_cannot_perform' => '_bx_courses_err_cannot_perform',
+            ),
+
+        );
+
+        $this->_aJsClasses = array(
+            'main' => 'BxCoursesMain',
+            'manage_tools' => 'BxCoursesManageTools',
+            'invite_popup' => 'BxCoursesInvitePopup',
+            'prices' => 'BxCoursesPrices'
+        );
+
+        $this->_aJsObjects = array(
+            'main' => 'oBxCoursesMain',
+            'manage_tools' => 'oBxCoursesManageTools',
+            'invite_popup' => 'oBxCoursesInvitePopup',
+            'prices' => 'oBxCoursesPrices'
+        );
+
+        $this->_aGridObjects = array(
+            'common' => $this->CNF['OBJECT_GRID_COMMON'],
+            'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION'],
+        );
+    }
+
+}
+
+/** @} */

+ 152 - 0
modules/boonex/courses/updates/14.0.1_14.0.2/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' => '14.0.2',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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',
+    ),
+);
+
+/** @} */

+ 51 - 0
modules/boonex/credits/updates/14.0.2_14.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' => 'Credits',
+    'version_from' => '14.0.2',
+    'version_to' => '14.0.3',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/credits/updates/update_14.0.2_14.0.3/',
+    'home_uri' => 'credits_update_1402_1403',
+
+    'module_dir' => 'boonex/credits/',
+    'module_uri' => 'credits',
+
+    'db_prefix' => 'bx_credits_',
+    'class_prefix' => 'BxCredits',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Credits',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/credits/updates/14.0.2_14.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 BxCreditsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 59 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/install/langs/en.xml

@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_credits_page_title_sys_withdrawals_common"><![CDATA[My Withdrawals]]></string_add>
+	<string_add name="_bx_credits_page_title_withdrawals_common"><![CDATA[Withdrawals]]></string_add>
+	<string_add name="_bx_credits_page_block_title_sys_withdrawals_common"><![CDATA[My Withdrawals]]></string_add>
+	<string_add name="_bx_credits_page_block_title_withdrawals_common"><![CDATA[Withdrawals]]></string_add>
+	<string_add name="_bx_credits_page_title_sys_withdrawals_administration"><![CDATA[All Withdrawals]]></string_add>
+	<string_add name="_bx_credits_page_title_withdrawals_administration"><![CDATA[Withdrawals]]></string_add>
+	<string_add name="_bx_credits_page_block_title_sys_withdrawals_administration"><![CDATA[All Withdrawals]]></string_add>
+	<string_add name="_bx_credits_page_block_title_withdrawals_administration"><![CDATA[Withdrawals]]></string_add>
+	<string_add name="_bx_credits_menu_item_title_system_withdrawals_administration"><![CDATA[All Withdrawals]]></string_add>
+	<string_add name="_bx_credits_menu_item_title_withdrawals_administration"><![CDATA[All Withdrawals]]></string_add>
+	<string_add name="_bx_credits_menu_item_title_system_withdrawals_common"><![CDATA[My Withdrawals]]></string_add>
+	<string_add name="_bx_credits_menu_item_title_withdrawals_common"><![CDATA[My Withdrawals]]></string_add>
+	<string_add name="_bx_credits_grid_column_title_wdw_profile_id"><![CDATA[Profile]]></string_add>
+	<string_add name="_bx_credits_grid_column_title_wdw_performer_id"><![CDATA[Performer]]></string_add>
+	<string_add name="_bx_credits_grid_column_title_wdw_amount"><![CDATA[Amount]]></string_add>
+	<string_add name="_bx_credits_grid_column_title_wdw_rate"><![CDATA[Rate]]></string_add>
+	<string_add name="_bx_credits_grid_column_title_wdw_message"><![CDATA[Message]]></string_add>
+	<string_add name="_bx_credits_grid_column_title_wdw_order"><![CDATA[Order]]></string_add>
+	<string_add name="_bx_credits_grid_column_title_wdw_added"><![CDATA[Added]]></string_add>
+	<string_add name="_bx_credits_grid_column_title_wdw_confirmed"><![CDATA[Confirmed]]></string_add>
+	<string_add name="_bx_credits_grid_column_title_wdw_status"><![CDATA[Status]]></string_add>
+	<string_add name="_bx_credits_grid_action_title_wdw_withdraw_confirm"><![CDATA[Confirm withdrawal]]></string_add>
+	<string_add name="_bx_credits_grid_action_title_wdw_withdraw_cancel"><![CDATA[Cancel withdrawal request]]></string_add>
+	<string_add name="_bx_credits_grid_action_title_wdw_withdraw_request"><![CDATA[Request withdrawal]]></string_add>
+	<string_add name="_bx_credits_grid_popup_title_wdw_withdraw_request"><![CDATA[Request withdrawal]]></string_add>
+	<string_add name="_bx_credits_et_txt_name_withdraw_canceled"><![CDATA[Withdrawal request canceled.]]></string_add>
+	<string_add name="_bx_credits_et_txt_subject_withdraw_canceled"><![CDATA[Withdrawal request canceled.]]></string_add>
+	<string_add name="_bx_credits_et_txt_body_withdraw_canceled"><![CDATA[{email_header}
+<p><a href="{profile_link}">{profile_name}</a> canceled his/her withdrawal request for <b>{amount}</b> credits.</p>
+<p>The canceled withdrawal request can be seen <a href="{manage_url}">here</a>.</p>
+{email_footer}]]></string_add>
+	<string_add name="_bx_credits_txt_withdrawal_status_requested"><![CDATA[Requested]]></string_add>
+	<string_add name="_bx_credits_txt_withdrawal_status_canceled"><![CDATA[Canceled]]></string_add>
+	<string_add name="_bx_credits_txt_withdrawal_status_confirmed"><![CDATA[Confirmed]]></string_add>
+	<string_add name="_bx_credits_msg_action_withdrawals_disabled"><![CDATA[Withdrawals are disabled.]]></string_add>
+	<string_add name="_bx_credits_err_withdrawal_not_found"><![CDATA[Withdrawal request wasn't found.]]></string_add>
+	<string_add name="_bx_credits_err_cannot_cancel_withdrawal"><![CDATA[Cannot cancel withdrawal request. Please report.]]></string_add>
+
+	<string_upd name="_bx_credits_et_txt_name_withdraw_requested"><![CDATA[Withdrawal request.]]></string_upd>
+	<string_upd name="_bx_credits_et_txt_subject_withdraw_requested"><![CDATA[Withdrawal request.]]></string_upd>
+	<string_upd name="_bx_credits_et_txt_body_withdraw_requested"><![CDATA[{email_header}
+<p><a href="{profile_link}">{profile_name}</a> requested to withdraw <b>{amount}</b> credits from his/her balance.</p>
+<p>Current withdrawal conversion rate is <b>{rate}</b></p>
+<p>Withdrawal can be confirmed <a href="{confirm_url}">here</a>.</p>
+<p>Notes from <b>{profile_name}</b>:<br />{message}</p>
+{email_footer}]]></string_upd>
+	<string_upd name="_bx_credits_et_txt_body_withdraw_sent"><![CDATA[{email_header}
+<p>Hello, {profile_name}.</p>
+<p>The requested amount of credits (<b>{amount}</b>) was withdrawn to you.</p>
+{email_footer}]]></string_upd>
+
+	<string_del name="_bx_credits_form_credit_display_withdraw_confirm"><![CDATA[Confirm Withdrawal]]></string_del>
+	<string_del name="_bx_credits_grid_action_title_htr_withdraw_confirm"><![CDATA[Confirm withdrawal]]></string_del>
+	<string_del name="_bx_credits_grid_action_title_htr_withdraw_request"><![CDATA[Request withdrawal]]></string_del>
+	<string_del name="_bx_credits_grid_popup_title_htr_withdraw_confirm"><![CDATA[Confirm withdrawal]]></string_del>
+	<string_del name="_bx_credits_grid_popup_title_htr_withdraw_request"><![CDATA[Request withdrawal]]></string_del>
+</resources>

+ 70 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/install/sql/enable.sql

@@ -0,0 +1,70 @@
+-- PAGES
+DELETE FROM `sys_objects_page` WHERE `object`='bx_credits_withdrawals_common';
+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_credits_withdrawals_common', '_bx_credits_page_title_sys_withdrawals_common', '_bx_credits_page_title_withdrawals_common', 'bx_credits', 5, 2147483647, 1, 'credits-withdrawals-common', 'page.php?i=credits-withdrawals-common', '', '', '', 0, 1, 0, 'BxCreditsPageWithdrawals', 'modules/boonex/credits/classes/BxCreditsPageWithdrawals.php');
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_credits_withdrawals_common';
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_credits_withdrawals_common', 1, 'bx_credits', '_bx_credits_page_block_title_sys_withdrawals_common', '_bx_credits_page_block_title_withdrawals_common', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_credits";s:6:"method";s:21:"get_block_withdrawals";}}', 0, 1, 0);
+
+DELETE FROM `sys_objects_page` WHERE `object`='bx_credits_withdrawals_administration';
+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_credits_withdrawals_administration', '_bx_credits_page_title_sys_withdrawals_administration', '_bx_credits_page_title_withdrawals_administration', 'bx_credits', 5, 192, 1, 'credits-withdrawals-administration', 'page.php?i=credits-withdrawals-administration', '', '', '', 0, 1, 0, 'BxCreditsPageWithdrawals', 'modules/boonex/credits/classes/BxCreditsPageWithdrawals.php');
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_credits_withdrawals_administration';
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_credits_withdrawals_administration', 1, 'bx_credits', '_bx_credits_page_block_title_sys_withdrawals_administration', '_bx_credits_page_block_title_withdrawals_administration', 11, 192, 'service', 'a:3:{s:6:"module";s:10:"bx_credits";s:6:"method";s:21:"get_block_withdrawals";s:6:"params";a:1:{i:0;s:14:"administration";}}', 0, 1, 0);
+
+
+-- MENUS
+UPDATE `sys_objects_menu` SET `override_class_name`='BxCreditsMenuManage', `override_class_file`='modules/boonex/credits/classes/BxCreditsMenuManage.php' WHERE `object`='bx_credits_manage_submenu';
+
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_credits_manage_submenu' AND `name` IN ('credits-withdrawals-common', 'credits-withdrawals-administration');
+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_credits_manage_submenu', 'bx_credits', 'credits-withdrawals-common', '_bx_credits_menu_item_title_system_withdrawals_common', '_bx_credits_menu_item_title_withdrawals_common', 'page.php?i=credits-withdrawals-common', '', '_self', '', '', '', 2147483646, 1, 0, 1, 5),
+('bx_credits_manage_submenu', 'bx_credits', 'credits-withdrawals-administration', '_bx_credits_menu_item_title_system_withdrawals_administration', '_bx_credits_menu_item_title_withdrawals_administration', 'page.php?i=credits-withdrawals-administration', '', '_self', '', '', '', 192, 1, 0, 1, 6);
+
+
+-- GRIDS
+DELETE FROM `sys_grid_actions` WHERE `object`='bx_credits_history_administration' AND `type`='independent' AND `name`='withdraw_confirm';
+DELETE FROM `sys_grid_actions` WHERE `object`='bx_credits_history_common' AND `type`='independent' AND `name`='withdraw_request';
+
+DELETE FROM `sys_objects_grid` WHERE `object` IN ('bx_credits_withdrawals_administration', 'bx_credits_withdrawals_common');
+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_credits_withdrawals_administration', 'Sql', 'SELECT * FROM `bx_credits_withdrawals` WHERE 1 ', 'bx_credits_withdrawals', 'id', 'added', '', '', 20, NULL, 'start', '', 'message,order', '', 'like', '', '', 192, 'BxCreditsGridWithdrawalsAdministration', 'modules/boonex/credits/classes/BxCreditsGridWithdrawalsAdministration.php'),
+('bx_credits_withdrawals_common', 'Sql', 'SELECT * FROM `bx_credits_withdrawals` WHERE 1 ', 'bx_credits_withdrawals', 'id', 'added', '', '', 20, NULL, 'start', '', 'message,order', '', 'like', '', '', 2147483647, 'BxCreditsGridWithdrawalsCommon', 'modules/boonex/credits/classes/BxCreditsGridWithdrawalsCommon.php');
+
+DELETE FROM `sys_grid_fields` WHERE `object` IN ('bx_credits_withdrawals_administration', 'bx_credits_withdrawals_common');
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_credits_withdrawals_administration', 'profile_id', '_bx_credits_grid_column_title_wdw_profile_id', '15%', 0, 0, '', 1),
+('bx_credits_withdrawals_administration', 'amount', '_bx_credits_grid_column_title_wdw_amount', '5%', 0, 0, '', 2),
+('bx_credits_withdrawals_administration', 'rate', '_bx_credits_grid_column_title_wdw_rate', '5%', 0, 0, '', 3),
+('bx_credits_withdrawals_administration', 'message', '_bx_credits_grid_column_title_wdw_message', '10%', 0, 16, '', 4),
+('bx_credits_withdrawals_administration', 'added', '_bx_credits_grid_column_title_wdw_added', '5%', 0, 0, '', 5),
+('bx_credits_withdrawals_administration', 'performer_id', '_bx_credits_grid_column_title_wdw_performer_id', '15%', 0, 0, '', 6),
+('bx_credits_withdrawals_administration', 'order', '_bx_credits_grid_column_title_wdw_order', '15%', 0, 16, '', 7),
+('bx_credits_withdrawals_administration', 'confirmed', '_bx_credits_grid_column_title_wdw_confirmed', '5%', 0, 0, '', 8),
+('bx_credits_withdrawals_administration', 'status', '_bx_credits_grid_column_title_wdw_status', '5%', 0, 0, '', 9),
+('bx_credits_withdrawals_administration', 'actions', '', '20%', 0, 0, '', 10),
+
+('bx_credits_withdrawals_common', 'amount', '_bx_credits_grid_column_title_wdw_amount', '10%', 0, 0, '', 1),
+('bx_credits_withdrawals_common', 'rate', '_bx_credits_grid_column_title_wdw_rate', '10%', 0, 0, '', 2),
+('bx_credits_withdrawals_common', 'message', '_bx_credits_grid_column_title_wdw_message', '15%', 0, 16, '', 3),
+('bx_credits_withdrawals_common', 'added', '_bx_credits_grid_column_title_wdw_added', '10%', 0, 0, '', 4),
+('bx_credits_withdrawals_common', 'order', '_bx_credits_grid_column_title_wdw_order', '15%', 0, 16, '', 5),
+('bx_credits_withdrawals_common', 'confirmed', '_bx_credits_grid_column_title_wdw_confirmed', '10%', 0, 0, '', 6),
+('bx_credits_withdrawals_common', 'status', '_bx_credits_grid_column_title_wdw_status', '10%', 0, 0, '', 7),
+('bx_credits_withdrawals_common', 'actions', '', '20%', 0, 0, '', 8);
+
+DELETE FROM `sys_grid_actions` WHERE `object` IN ('bx_credits_withdrawals_administration', 'bx_credits_withdrawals_common');
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_credits_withdrawals_administration', 'single', 'withdraw_confirm', '_bx_credits_grid_action_title_wdw_withdraw_confirm', 'check', 1, 1, 1),
+
+('bx_credits_withdrawals_common', 'independent', 'withdraw_request', '_bx_credits_grid_action_title_wdw_withdraw_request', '', 0, 0, 1),
+('bx_credits_withdrawals_common', 'single', 'withdraw_cancel', '_bx_credits_grid_action_title_wdw_withdraw_cancel', 'times', 1, 1, 1);
+
+
+-- EMAIL TEMPLATES
+DELETE FROM `sys_email_templates` WHERE `Name`='bx_credits_withdraw_canceled';
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES 
+('bx_credits', '_bx_credits_et_txt_name_withdraw_canceled', 'bx_credits_withdraw_canceled', '_bx_credits_et_txt_subject_withdraw_canceled', '_bx_credits_et_txt_body_withdraw_canceled');

+ 19 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/install/sql/install.sql

@@ -0,0 +1,19 @@
+-- TABLES
+CREATE TABLE IF NOT EXISTS `bx_credits_withdrawals` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `performer_id` int(11) unsigned NOT NULL default '0',
+  `profile_id` int(11) unsigned NOT NULL default '0',
+  `amount` float NOT NULL DEFAULT '0',
+  `rate` float NOT NULL DEFAULT '0',
+  `message` text NOT NULL default '',
+  `order` varchar(32) NOT NULL default '',
+  `added` int(11) unsigned NOT NULL default '0',
+  `confirmed` int(11) unsigned NOT NULL default '0',
+  `status` enum('requested', 'canceled', 'confirmed') NOT NULL DEFAULT 'requested',
+  PRIMARY KEY (`id`)
+);
+
+
+-- FORMS
+DELETE FROM `sys_form_displays` WHERE `display_name`='bx_credits_credit_withdraw_confirm';
+DELETE FROM `sys_form_display_inputs` WHERE `display_name`='bx_credits_credit_withdraw_confirm';

+ 339 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsConfig.php

@@ -0,0 +1,339 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Credits Credits
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxCreditsConfig extends BxBaseModGeneralConfig
+{
+    protected $_iAuthor;
+    protected $_aCurrency;
+
+    protected $_sCheckoutSessionKey;
+
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->CNF = array (
+
+            // module icon
+            'ICON' => 'copyright col-green3',
+
+            // database tables
+            'TABLE_BUNDLES' => $aModule['db_prefix'] . 'bundles',
+            'TABLE_ORDERS' => $aModule['db_prefix'] . 'orders',
+            'TABLE_ORDERS_DELETED' => $aModule['db_prefix'] . 'orders_deleted',
+            'TABLE_PROFILES' => $aModule['db_prefix'] . 'profiles',
+            'TABLE_HISTORY' => $aModule['db_prefix'] . 'history',
+            'TABLE_WITHDRAWALS' => $aModule['db_prefix'] . 'withdrawals',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => '',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => '',
+            'FIELD_NAME' => 'name',
+            'FIELD_TITLE' => 'title',
+            'FIELD_DESCRIPTION' => 'description',
+            'FIELD_AMOUNT' => 'amount',
+            'FIELD_BONUS' => 'bonus',
+            'FIELD_PRICE' => 'price',
+            'FIELD_STATUS' => 'active',
+
+            'FIELD_C_CLEARED' => 'cleared',
+            'FIELD_C_AMOUNT' => 'amount',
+            'FIELD_C_MESSAGE' => 'message',
+
+            'FIELD_H_ID' => 'id',
+            'FIELD_H_DIRECTION' => 'direction',
+            'FIELD_H_DATE' => 'date',
+            'FIELD_H_CLEARED' => 'cleared',
+
+            // page URIs
+            'URI_HOME' => 'credits-home',
+            'URL_HOME' => 'page.php?i=credits-home',
+            'URL_CHECKOUT' => 'page.php?i=credits-checkout',
+            'URL_ORDERS_COMMON' => 'page.php?i=credits-orders',
+            'URL_ORDERS_ADMINISTRATION' => 'page.php?i=credits-orders-administration',
+            'URL_HISTORY_COMMON' => 'page.php?i=credits-history-common',
+            'URL_HISTORY_ADMINISTRATION' => 'page.php?i=credits-history-administration',
+            'URL_WITHDRAWALS_COMMON' => 'page.php?i=credits-withdrawals-common',
+            'URL_WITHDRAWALS_ADMINISTRATION' => 'page.php?i=credits-withdrawals-administration',
+
+            // some params
+            'PARAM_WITHDRAW' => 'bx_credits_enable_withdraw',
+            'PARAM_WITHDRAW_EMAIL' => 'bx_credits_withdraw_email',
+            'PARAM_WITHDRAW_CLEARING' => 'bx_credits_withdraw_clearing',
+            'PARAM_WITHDRAW_MINIMUM' => 'bx_credits_withdraw_minimum',
+            'PARAM_WITHDRAW_REMAINING' => 'bx_credits_withdraw_remaining',
+            'PARAM_PRECISION' => 'bx_credits_precision',
+            'PARAM_CR_USE' => 'bx_credits_conversion_rate_use',
+            'PARAM_CR_WITHDRAW' => 'bx_credits_conversion_rate_withdraw',
+            'PARAM_PROVIDER_NAME' => 'credits',
+            'PARAM_PROVIDER_ENABLE' => 'bx_credits_enable_provider',
+            'PARAM_CODE' => 'bx_credits_code',
+            'PARAM_ICON' => 'bx_credits_icon',
+
+            // objects
+            'OBJECT_FORM_CREDIT' => 'bx_credits_credit',
+            'OBJECT_FORM_CREDIT_DISPLAY_GRANT' => 'bx_credits_credit_grant',
+            'OBJECT_FORM_CREDIT_DISPLAY_SEND' => 'bx_credits_credit_send',
+            'OBJECT_FORM_CREDIT_DISPLAY_WITHDRAW_REQUEST' => 'bx_credits_credit_withdraw_request',
+            'OBJECT_FORM_CREDIT_DISPLAY_WITHDRAW_CONFIRM' => 'bx_credits_credit_withdraw_confirm',
+            'OBJECT_FORM_BUNDLE' => 'bx_credits_bundle',
+            'OBJECT_FORM_BUNDLE_DISPLAY_ADD' => 'bx_credits_bundle_add',
+            'OBJECT_FORM_BUNDLE_DISPLAY_EDIT' => 'bx_credits_bundle_edit',
+            'OBJECT_FORM_PROFILE' => 'bx_credits_profile',
+            'OBJECT_FORM_PROFILE_DISPLAY_EDIT' => 'bx_credits_profile_edit',
+            'OBJECT_MENU_SUBMENU' => 'bx_credits_submenu', 
+            'OBJECT_MENU_MANAGE_SUBMENU' => 'bx_credits_manage_submenu',
+            'OBJECT_GRID_BUNDLES' => 'bx_credits_bundles',
+            'OBJECT_GRID_ORDERS_ADMINISTRATION' => 'bx_credits_orders_administration',
+            'OBJECT_GRID_ORDERS_COMMON' => 'bx_credits_orders_common',
+            'OBJECT_GRID_HISTORY_ADMINISTRATION' => 'bx_credits_history_administration',
+            'OBJECT_GRID_HISTORY_COMMON' => 'bx_credits_history_common',
+            'OBJECT_GRID_WITHDRAWALS_ADMINISTRATION' => 'bx_credits_withdrawals_administration',
+            'OBJECT_GRID_WITHDRAWALS_COMMON' => 'bx_credits_withdrawals_common',
+            'OBJECT_GRID_PROFILES_ADMINISTRATION' => 'bx_credits_profiles_administration',
+
+            // email templates
+            'ETEMPLATE_GRANTED' => 'bx_credits_granted',
+            'ETEMPLATE_RECEIVED' => 'bx_credits_received',
+            'ETEMPLATE_PURCHASED' => 'bx_credits_purchased',
+            'ETEMPLATE_IN' => 'bx_credits_in',
+            'ETEMPLATE_OUT' => 'bx_credits_out',
+            'ETEMPLATE_WITHDRAW_REQUESTED' => 'bx_credits_withdraw_requested',
+            'ETEMPLATE_WITHDRAW_CANCELED' => 'bx_credits_withdraw_canceled',
+            'ETEMPLATE_WITHDRAW_SENT' => 'bx_credits_withdraw_sent',
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_credits_txt_sample_single',
+                'grant_popup' => '_bx_credits_grid_popup_title_htr_grant',
+                'send_popup' => '_bx_credits_grid_popup_title_htr_send',
+                'withdraw_request_popup' => '_bx_credits_grid_popup_title_wdw_withdraw_request',
+            ),
+        );
+
+        $this->_aJsClasses = array_merge($this->_aJsClasses, array(
+            'studio' => 'BxCreditsStudio',
+            'checkout' => 'BxCreditsCheckout',
+            'subscribe' => 'BxCreditsSubscribe',
+            'withdraw' => 'BxCreditsWithdraw',
+        ));
+
+        $this->_aJsObjects = array_merge($this->_aJsObjects, array(
+            'studio' => 'oBxCreditsStudio',
+            'checkout' => 'oBxCreditsCheckout',
+            'subscribe' => 'oBxCreditsSubscribe',
+            'withdraw' => 'oBxCreditsWithdraw',
+        ));
+
+        $sPrefix = str_replace('_', '-', $this->_sName);
+        $this->_aHtmlIds = array(
+            'add_bundle_popup' =>  $sPrefix . '-add-bundle-popup',
+            'edit_bundle_popup' =>  $sPrefix . '-edit-bundle-popup',
+
+            'send_popup' =>  $sPrefix . '-send-popup',
+            'grant_popup' =>  $sPrefix . '-grant-popup',
+            'withdraw_request_popup' =>  $sPrefix . '-withdraw-request-popup',
+            'withdraw_confirm_popup' =>  $sPrefix . '-withdraw-confirm-popup',
+            'withdraw_field_rate' => $sPrefix . '-wff-rate',
+            'withdraw_field_amount' => $sPrefix . '-wff-amount',
+            'withdraw_field_result' => $sPrefix . '-wff-result',
+
+            'edit_profile_popup' =>  $sPrefix . '-edit-profile-popup',
+
+            'subscribe_popup' =>  $sPrefix . '-subscribe-popup',
+        );
+
+        $this->_aPrefixes = array(
+            'style' => 'bx-credits',
+        );
+
+        $oPayments = BxDolPayments::getInstance();
+        $this->_iAuthor = (int)$oPayments->getOption('site_admin');
+        $this->_aCurrency = array(
+            'code' => $oPayments->getOption('default_currency_code'),
+            'sign' => $oPayments->getOption('default_currency_sign')
+        );
+        
+        $this->_sCheckoutSessionKey = $this->_sName . '_checkout';
+    }
+
+    public function getHtmlIds($sKey = '')
+    {
+        if(empty($sKey))
+            return $this->_aHtmlIds;
+
+        return isset($this->_aHtmlIds[$sKey]) ? $this->_aHtmlIds[$sKey] : '';
+    }
+
+    public function getAuthor()
+    {
+    	return $this->_iAuthor;
+    }
+
+    public function getCurrency()
+    {
+    	return $this->_aCurrency;
+    }
+
+    public function isWithdraw()
+    {
+        return getParam($this->CNF['PARAM_WITHDRAW']) == 'on';
+    }
+
+    public function getWithdrawEmail()
+    {
+        $sEmail = getParam($this->CNF['PARAM_WITHDRAW_EMAIL']);
+        if(empty($sEmail))
+            $sEmail = getParam('site_email');
+
+        return $sEmail;
+    }
+
+    public function getWithdrawClearing()
+    {
+        return (int)getParam($this->CNF['PARAM_WITHDRAW_CLEARING']);
+    }
+
+    public function getWithdrawMinimum()
+    {
+        return (int)getParam($this->CNF['PARAM_WITHDRAW_MINIMUM']);
+    }
+
+    public function getWithdrawRemaining()
+    {
+        return (int)getParam($this->CNF['PARAM_WITHDRAW_REMAINING']);
+    }
+
+    public function getTransferTypesForClearing()
+    {
+        return [
+            BX_CREDITS_TRANSFER_TYPE_PURCHASE,
+            BX_CREDITS_TRANSFER_TYPE_CHECKOUT,
+            BX_CREDITS_TRANSFER_TYPE_GRANT,
+            BX_CREDITS_TRANSFER_TYPE_SEND,
+            BX_CREDITS_TRANSFER_TYPE_SERVICE
+        ];
+    }
+
+    public function getTransferTypesForSpending()
+    {
+        return [
+            BX_CREDITS_TRANSFER_TYPE_CHECKOUT,
+            BX_CREDITS_TRANSFER_TYPE_SEND,
+            BX_CREDITS_TRANSFER_TYPE_WITHDRAW,
+            BX_CREDITS_TRANSFER_TYPE_SERVICE
+        ];
+    }
+
+    public function getPrecision()
+    {
+        return (int)getParam($this->CNF['PARAM_PRECISION']);
+    }
+
+    public function getConversionRateUse()
+    {
+        return $this->_getConversionRate('use');
+    }
+
+    public function getConversionRateWithdraw()
+    {
+        return $this->_getConversionRate('withdraw');
+    }
+
+    public function getCheckoutUrl()
+    {
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink($this->CNF['URL_CHECKOUT']));
+    }
+
+    public function getBundleUrl($aBundle)
+    {
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink($this->CNF['URL_HOME']));
+    }
+
+    public function getBundleName($sName)
+    {
+        return uriGenerate($sName, $this->CNF['TABLE_BUNDLES'], $this->CNF['FIELD_NAME'], ['empty' => 'cat', 'divider' => '_', 'lowercase' => false]);
+    }
+
+    public function getBundleDescription($aBundle)
+    {
+        if(empty($aBundle[$this->CNF['FIELD_BONUS']]))
+            return $aBundle[$this->CNF['FIELD_AMOUNT']];
+
+        return _t('_bx_credits_txt_n_plus_m_for_free', $aBundle[$this->CNF['FIELD_AMOUNT']], $aBundle[$this->CNF['FIELD_BONUS']]);
+    }
+
+    public function getCheckoutData()
+    {
+        return BxDolSession::getInstance()->getUnsetValue($this->_sCheckoutSessionKey);
+    }
+
+    public function setCheckoutData($aData)
+    {
+        return BxDolSession::getInstance()->setValue($this->_sCheckoutSessionKey, $aData);
+    }
+
+    public function getOrder($iLength = 16)
+    {
+        return strtoupper(genRndPwd($iLength, false));
+    }
+
+    public function constructCheckoutCustomData()
+    {
+        $aParams = func_get_args();
+        return urlencode(base64_encode(implode('|', $aParams)));
+    }
+
+    public function deconstructCheckoutCustomData($sData)
+    {
+        return explode('|', base64_decode(urldecode($sData)));
+    }
+
+    /**
+     * Convert Credits to Money
+     */
+    public function convertC2M($fCredits, $fRate = false, $iPrecision = false)
+    {
+        if($fRate === false)
+            $fRate = $this->getConversionRateUse();
+        if($iPrecision === false)
+            $iPrecision = $this->getPrecision();
+
+        return round((float)$fCredits * $fRate, $iPrecision);
+    }
+
+    /**
+     * Convert Money to Credits
+     */
+    public function convertM2C($fMoney, $fRate = false, $iPrecision = false)
+    {
+        if($fRate === false)
+            $fRate = $this->getConversionRateUse();
+        if($iPrecision === false)
+            $iPrecision = $this->getPrecision();
+
+        return round((float)$fMoney / $fRate, $iPrecision);
+    }
+
+    /*
+     * Internal methods
+     */
+    protected function _getConversionRate($sType)
+    {
+        $fRate = (float)getParam($this->CNF['PARAM_CR_' . strtoupper($sType)]);
+
+        return $fRate > 0 && $fRate <= 1 ? $fRate : 1;
+    }
+}
+
+/** @} */

+ 448 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsDb.php

@@ -0,0 +1,448 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Credits Credits
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/*
+ * Module database queries
+ */
+class BxCreditsDb extends BxBaseModGeneralDb
+{
+    function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+    }
+
+    /**
+     * Bundle related methods.
+     */
+    public function getBundle($aParams = array())
+    {
+    	$CNF = &$this->_oConfig->CNF;
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+    	$sSelectClause = "`tb`.*";
+    	$sJoinClause = $sWhereClause = $sLimitClause = "";
+        $sOrderClause = "`tb`.`order` ASC";
+        switch($aParams['type']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = array(
+                    'id' => $aParams['id']
+                );
+
+                $sWhereClause = " AND `tb`.`id`=:id";
+                break;
+
+            case 'order_max':
+            	$aMethod['name'] = 'getOne';
+
+                $sSelectClause = "IFNULL(MAX(`tb`.`order`), 0)";
+                break;
+
+            case 'all':
+                break;
+        }
+
+        if(isset($aParams['active']))
+            $sWhereClause .= $this->prepareAsString(" AND `tb`.`active`=?", (bool)$aParams['active'] ? 1 : 0);
+
+        $sOrderClause = !empty($sOrderClause) ? "ORDER BY " . $sOrderClause : "";
+        $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : "";
+
+        $aMethod['params'][0] = "SELECT
+                " . $sSelectClause . "
+            FROM `" . $CNF['TABLE_BUNDLES'] . "` AS `tb`" . $sJoinClause . "
+            WHERE 1" . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function isBundle($iId)
+    {
+        $aSport = $this->getBundle(array('type' => 'id', 'id' => $iId));
+        return !empty($aSport) && is_array($aSport);
+    }
+
+    public function insertBundle($aSet)
+    {
+        $sQuery = "INSERT INTO `" . $this->_oConfig->CNF['TABLE_BUNDLES'] . "` SET " . $this->arrayToSQL($aSet);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function updateBundle($aSet, $aWhere)
+    {
+        $sQuery = "UPDATE `" . $this->_oConfig->CNF['TABLE_BUNDLES'] . "` SET " . $this->arrayToSQL($aSet) . " WHERE " . (!empty($aWhere) ? $this->arrayToSQL($aWhere, ' AND ') : "1");
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function deleteBundle($aWhere)
+    {
+    	if(empty($aWhere))
+            return false;
+
+        $sQuery = "DELETE FROM `" . $this->_oConfig->CNF['TABLE_BUNDLES'] . "` WHERE " . $this->arrayToSQL($aWhere, ' AND ');
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    /**
+     * Order related methods.
+     */
+    public function getOrder($aParams = array())
+    {
+    	$CNF = &$this->_oConfig->CNF;
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+    	$sSelectClause = "`to`.*";
+    	$sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+        switch($aParams['type']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = array(
+                    'id' => $aParams['id']
+                );
+
+                $sWhereClause = " AND `to`.`id`=:id";
+                break;
+
+            case 'row_by':
+                $aMethod['name'] = 'getRow';
+                $sWhereClause = " AND " . $this->arrayToSQL($aParams['by'], ' AND ');
+                break;
+
+            case 'all':
+                break;
+        }
+
+        $sOrderClause = !empty($sOrderClause) ? "ORDER BY " . $sOrderClause : "";
+        $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : "";
+
+        $aMethod['params'][0] = "SELECT
+                " . $sSelectClause . "
+            FROM `" . $CNF['TABLE_ORDERS'] . "` AS `to`" . $sJoinClause . "
+            WHERE 1" . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function isOrder($iId)
+    {
+        $aOrder = $this->getOrder(array('type' => 'id', 'id' => $iId));
+        return !empty($aOrder) && is_array($aOrder);
+    }
+
+    public function isOrderByPbo($iProfileId, $iBundleId, $sOrder)
+    {
+        $aOrder = $this->getOrder(array('type' => 'row_by', 'by' => array('profile_id' => $iProfileId, 'bundle_id' => $iBundleId, 'order' => $sOrder)));
+        return !empty($aOrder) && is_array($aOrder);
+    }
+
+    public function insertOrder($aSet, $sSetAddon = '')
+    {
+        $sQuery = "INSERT INTO `" . $this->_oConfig->CNF['TABLE_ORDERS'] . "` SET " . $this->arrayToSQL($aSet) . $sSetAddon;
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function insertOrderDeleted($aSet, $sSetAddon = '')
+    {
+        $sQuery = "INSERT INTO `" . $this->_oConfig->CNF['TABLE_ORDERS_DELETED'] . "` SET " . $this->arrayToSQL($aSet) . $sSetAddon;
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function registerOrder($iProfileId, $iBundleId, $iCount, $sOrder, $sLicense, $sType, $sDuration = '', $iTrial = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sSetAddon = ', `added`=UNIX_TIMESTAMP()';
+
+        return $this->insertOrder(array(
+            'profile_id' => $iProfileId,
+            'bundle_id' => $iBundleId,
+            'count' => $iCount,
+            'order' => $sOrder,
+            'license' => $sLicense,
+            'type' => $sType
+        ), $sSetAddon);
+    }
+
+    public function updateOrder($aSet, $aWhere)
+    {
+        $sQuery = "UPDATE `" . $this->_oConfig->CNF['TABLE_ORDERS'] . "` SET " . $this->arrayToSQL($aSet) . " WHERE " . (!empty($aWhere) ? $this->arrayToSQL($aWhere, ' AND ') : "1");
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    /**
+     * Note. Prolong isn't allowed for now.
+     */
+    public function prolongOrder($iProfileId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType, $sDuration, $iTrial)
+    {
+        return false;
+    }
+
+    public function deleteOrder($aWhere)
+    {
+    	if(empty($aWhere))
+            return false;
+
+        $sQuery = "DELETE FROM `" . $this->_oConfig->CNF['TABLE_ORDERS'] . "` WHERE " . $this->arrayToSQL($aWhere, ' AND ');
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function unregisterOrder($iProfileId, $iItemId, $sOrder, $sLicense, $sType)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aOrder = $this->getOrder(array('type' => 'row_by', 'by' => array(
+            'profile_id' => $iProfileId,
+            'bundle_id' => $iItemId,
+            'order' => $sOrder,
+            'license' => $sLicense
+    	)));
+
+        if(empty($aOrder) || !is_array($aOrder))
+            return true;
+
+        //--- Move to deleted orders table with 'refund' as reason.
+        $this->insertOrderDeleted($aOrder, ", `reason`='refund', `deleted`=UNIX_TIMESTAMP()");
+
+        return $this->deleteOrder(array('id' => $aOrder[$CNF['FIELD_ID']]));
+    }
+
+    /**
+     * Profile related methods.
+     */
+    public function getProfile($aParams = array())
+    {
+    	$CNF = &$this->_oConfig->CNF;
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+    	$sSelectClause = "`tp`.*";
+    	$sJoinClause = $sWhereClause = $sLimitClause = "";
+        switch($aParams['type']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = array(
+                    'id' => $aParams['id']
+                );
+
+                $sWhereClause = " AND `tp`.`id`=:id";
+                break;
+            
+            case 'balance':
+            	$aMethod['name'] = 'getOne';
+            	$aMethod['params'][1] = array(
+                    'id' => $aParams['id']
+                );
+
+                $sSelectClause = "`tp`.`balance`";
+                $sWhereClause = " AND `tp`.`id`=:id";
+                break;
+        }
+
+        $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT
+                " . $sSelectClause . "
+            FROM `" . $CNF['TABLE_PROFILES'] . "` AS `tp`" . $sJoinClause . "
+            WHERE 1" . $sWhereClause . " " . $sLimitClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function isProfile($iId)
+    {
+        $aProfile = $this->getProfile(array('type' => 'id', 'id' => $iId));
+        return !empty($aProfile) && is_array($aProfile);
+    }
+
+    public function insertProfile($aSet)
+    {
+        $sQuery = "INSERT INTO `" . $this->_oConfig->CNF['TABLE_PROFILES'] . "` SET " . $this->arrayToSQL($aSet);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function updateProfile($aSet, $aWhere)
+    {
+        $sQuery = "UPDATE `" . $this->_oConfig->CNF['TABLE_PROFILES'] . "` SET " . $this->arrayToSQL($aSet) . " WHERE " . (!empty($aWhere) ? $this->arrayToSQL($aWhere, ' AND ') : "1");
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function updateProfileBalance($iId, $fAmount, $bCleared = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sBalance = $bCleared ? 'cleared' : 'balance';
+
+        if(!$this->isProfile($iId))
+            return $this->insertProfile(['id' => $iId, $sBalance => $fAmount]);
+
+        $sQuery = "UPDATE `" . $CNF['TABLE_PROFILES'] . "` SET `" . $sBalance . "`=`" . $sBalance . "`+:amount WHERE `id`=:id";
+        return (int)$this->query($sQuery, [
+            'id' => $iId,
+            'amount' => $fAmount
+        ]) > 0;
+    }
+
+    public function deleteProfile($aWhere)
+    {
+    	if(empty($aWhere))
+            return false;
+
+        $sQuery = "DELETE FROM `" . $this->_oConfig->CNF['TABLE_PROFILES'] . "` WHERE " . $this->arrayToSQL($aWhere, ' AND ');
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    /**
+     * History related methods.
+     */
+    public function getHistory($aParams = array())
+    {
+    	$CNF = &$this->_oConfig->CNF;
+    	$aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+
+    	$sSelectClause = "`th`.*";
+    	$sJoinClause = $sWhereClause = $sLimitClause = "";
+        switch($aParams['type']) {
+            case 'cleared':
+                $aMethod['name'] = 'getOne';
+                $aMethod['params'][1] = [
+                    'profile' => $aParams['profile']
+                ];
+
+                $sSelectClause = "SUM(`th`.`amount`)";
+                $sWhereClause = " AND `th`.`first_pid`=:profile AND `th`.`direction`='in' AND `th`.`type` IN (" . $this->implode_escape($this->_oConfig->getTransferTypesForClearing()) . ") AND `th`.`cleared`<>'0'";
+                break;
+
+            case 'spent':
+                $aMethod['name'] = 'getOne';
+                $aMethod['params'][1] = [
+                    'profile' => $aParams['profile'],
+                    'type_cancel' => BX_CREDITS_TRANSFER_TYPE_CANCELLATION
+                ];
+
+                $sSelectClause = "SUM(`th`.`amount`)";
+                $sJoinClause = " LEFT JOIN `" . $CNF['TABLE_HISTORY'] . "` AS `thc` ON `th`.`order`=`thc`.`order` AND `thc`.`type`=:type_cancel";
+                $sWhereClause = " AND `th`.`first_pid`=:profile AND `th`.`direction`='out' AND `th`.`type` IN (" . $this->implode_escape($this->_oConfig->getTransferTypesForSpending()) . ") AND ISNULL(`thc`.`id`)";
+                break;
+
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause = " AND `th`.`id`=:id";
+                break;
+
+            case 'row_by':
+                $aMethod['name'] = 'getRow';
+                $sWhereClause = " AND " . $this->arrayToSQL($aParams['by'], ' AND ');
+                break;
+
+            case 'clearing':
+                $aMethod['params'][1] = [
+                    'clearing' => $aParams['clearing']
+                ];
+
+                $sJoinClause = " LEFT JOIN `" . $CNF['TABLE_PROFILES'] . "` AS `tp` ON `th`.`first_pid`=`tp`.`id`";
+                $sWhereClause = " AND `th`.`direction`='in' AND `th`.`type` IN (" . $this->implode_escape($this->_oConfig->getTransferTypesForClearing()) . ") AND `th`.`date` < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL IF(`tp`.`wdw_clearing` <> 0, `tp`.`wdw_clearing`, :clearing) DAY)) AND `th`.`cleared`='0'";
+                break;
+        }
+
+        $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT
+                " . $sSelectClause . "
+            FROM `" . $CNF['TABLE_HISTORY'] . "` AS `th`" . $sJoinClause . "
+            WHERE 1" . $sWhereClause . " " . $sLimitClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function isHistory($iId)
+    {
+        $aHistory = $this->getHistory(array('type' => 'id', 'id' => $iId));
+        return !empty($aHistory) && is_array($aHistory);
+    }
+
+    public function insertHistory($aSet)
+    {
+        $sQuery = "INSERT INTO `" . $this->_oConfig->CNF['TABLE_HISTORY'] . "` SET " . $this->arrayToSQL($aSet);
+        return (int)$this->query($sQuery) > 0 ? $this->lastId() : false;
+    }
+
+    public function updateHistory($aSet, $aWhere)
+    {
+        $sQuery = "UPDATE `" . $this->_oConfig->CNF['TABLE_HISTORY'] . "` SET " . $this->arrayToSQL($aSet) . " WHERE " . (!empty($aWhere) ? $this->arrayToSQL($aWhere, ' AND ') : "1");
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function deleteHistory($aWhere)
+    {
+    	if(empty($aWhere))
+            return false;
+
+        $sQuery = "DELETE FROM `" . $this->_oConfig->CNF['TABLE_HISTORY'] . "` WHERE " . $this->arrayToSQL($aWhere, ' AND ');
+        return (int)$this->query($sQuery) > 0;
+    }
+    
+    /**
+     * Withdrawals related methods.
+     */
+    public function getWithdrawal($aParams = [])
+    {
+    	$CNF = &$this->_oConfig->CNF;
+    	$aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+
+    	$sSelectClause = "`tw`.*";
+    	$sJoinClause = $sWhereClause = $sLimitClause = "";
+        switch($aParams['type']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause = " AND `tw`.`id`=:id";
+                break;
+        }
+
+        $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT
+                " . $sSelectClause . "
+            FROM `" . $CNF['TABLE_WITHDRAWALS'] . "` AS `tw`" . $sJoinClause . "
+            WHERE 1" . $sWhereClause . " " . $sLimitClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+
+    public function insertWithdrawal($aSet)
+    {
+        $sQuery = "INSERT INTO `" . $this->_oConfig->CNF['TABLE_WITHDRAWALS'] . "` SET " . $this->arrayToSQL($aSet);
+        return (int)$this->query($sQuery) > 0 ? $this->lastId() : false;
+    }
+
+    public function updateWithdrawal($aSet, $aWhere)
+    {
+        $sQuery = "UPDATE `" . $this->_oConfig->CNF['TABLE_WITHDRAWALS'] . "` SET " . $this->arrayToSQL($aSet) . " WHERE " . (!empty($aWhere) ? $this->arrayToSQL($aWhere, ' AND ') : "1");
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function deleteWithdrawal($aWhere)
+    {
+    	if(empty($aWhere))
+            return false;
+
+        $sQuery = "DELETE FROM `" . $this->_oConfig->CNF['TABLE_WITHDRAWALS'] . "` WHERE " . $this->arrayToSQL($aWhere, ' AND ');
+        return (int)$this->query($sQuery) > 0;
+    }
+}
+
+/** @} */

+ 114 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsGrid.php

@@ -0,0 +1,114 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Credits Credits
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+class BxCreditsGrid extends BxTemplGrid
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_iUserId;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_credits';
+    	$this->_oModule = BxDolModule::getInstance($this->_sModule);
+    	if(!$oTemplate)
+            $oTemplate = $this->_oModule->_oTemplate;
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        $iUserId = bx_get_logged_profile_id();
+        if($iUserId !== false) {
+            $this->_iUserId = (int)$iUserId;
+            $this->_aQueryAppend['user_id'] = $this->_iUserId;
+        }
+    }
+
+    protected function _getProfile($mixedValue) 
+    {
+        if(is_numeric($mixedValue) && (int)$mixedValue == 0)
+            $mixedValue = $this->_oModule->_oConfig->getAuthor();
+
+        $oProfile = BxDolProfile::getInstanceMagic($mixedValue);
+        if(!$oProfile)
+            return $mixedValue;
+
+        return $oProfile->getUnit(0, ['template' => ['name' => 'unit', 'size' => 'icon']]);
+    }
+
+    protected function _performActionWithProfileAmount($sAction)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $oForm = $this->_getFormObject($sAction);
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+            $iProfile = (int)$oForm->getCleanValue('profile');
+            $fAmount = (float)$oForm->getCleanValue('amount');
+            $sMessage = $oForm->getCleanValue('message');
+
+            $aResult = $this->_oModule->{'process' . bx_gen_method_name($sAction)}($this->_iUserId, $iProfile, $fAmount, $sMessage);
+            echoJson($this->_onPerformAction($aResult));
+        }
+        else {
+            $sContent = BxTemplFunctions::getInstance()->popupBox($this->_oModule->_oConfig->getHtmlIds($sAction . '_popup'), _t($CNF['T'][$sAction . '_popup']), $this->_oModule->_oTemplate->parseHtmlByName('credit_form.html', [
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            ]));
+
+            echoJson(['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => false]]]);
+        }
+    }
+    
+    protected function _onPerformAction($aResult)
+    {
+        $aRes = [];
+
+        if((int)$aResult['code'] == 0) {
+            if(!empty($aResult['id']))
+                $aRes = ['grid' => $this->getCode(false), 'blink' => $aResult['id']];
+            else
+                $aRes = ['msg' => _t(!empty($aResult['msg']) ? $aResult['msg'] : '_bx_credits_msg_action_performed')];
+        }
+        else
+            $aRes = ['msg' => _t(!empty($aResult['msg']) ? $aResult['msg'] : '_bx_credits_err_cannot_perform_action')];
+
+        return $aRes;
+    }
+
+    protected function _getFormObject($sAction)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_CREDIT'], $CNF['OBJECT_FORM_CREDIT_DISPLAY_' . strtoupper($sAction)]);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+        $oForm->setUserId($this->_iUserId);
+
+        return $oForm;
+    }
+    
+    protected function _getId()
+    {
+        $aIds = bx_get('ids');
+        if(!empty($aIds) && is_array($aIds))
+            return array_shift($aIds);
+
+        if(($iId = bx_get('id')) !== false)
+            return (int)$iId;
+
+        return false;
+    }
+}
+
+/** @} */

+ 114 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsGridHistoryAdministration.php

@@ -0,0 +1,114 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Credits Credits
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+require_once('BxCreditsGrid.php');
+
+class BxCreditsGridHistoryAdministration extends BxCreditsGrid
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sDefaultSortingOrder = 'DESC';
+    }
+
+    public function getCode($isDisplayHeader = true)
+    {
+        $sResult = parent::getCode($isDisplayHeader);
+        if(!empty($sResult) && $isDisplayHeader)
+            $sResult = $this->_oModule->_oTemplate->getJsCode('withdraw') . $sResult;
+
+        return $sResult;
+    }
+
+    public function performActionGrant()
+    {
+        $sAction = 'grant';
+
+        $this->_performActionWithProfileAmount($sAction);
+    }
+
+    protected function _getCellDirection($mixedValue, $sKey, $aField, $aRow)
+    {
+        if(in_array($mixedValue, [BX_CREDITS_DIRECTION_IN, BX_CREDITS_DIRECTION_OUT]))
+            $mixedValue = _t('_bx_credits_txt_direction_' . $mixedValue);
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellFirstPid($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_getProfile($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellSecondPid($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_getProfile($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellAmount($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_oModule->convertC2S($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellOrder($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellDate($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(bx_time_js($mixedValue, BX_FORMAT_DATE, true), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellCleared($mixedValue, $sKey, $aField, $aRow)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if($aRow[$CNF['FIELD_H_DIRECTION']] == BX_CREDITS_DIRECTION_IN) {
+            if(empty($mixedValue)) {
+                $iPeriod = (int)$aRow['wdw_clearing'];
+                if($iPeriod == 0) {
+                    $iPeriod = $this->_oModule->_oConfig->getWithdrawClearing();
+                    if($iPeriod == 0)
+                        $iPeriod = 1;
+                }
+
+                $oDate = date_create('@' . $aRow[$CNF['FIELD_H_DATE']]);
+                date_add($oDate, new DateInterval('P' . $iPeriod . 'D'));
+                $mixedValue = date_format($oDate, 'U');
+            }
+
+            $mixedValue = bx_time_js($mixedValue, BX_FORMAT_DATE, true);
+        }
+        else 
+            $mixedValue = '';
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+        $this->_oModule->_oTemplate->addJs([
+            'jquery.form.min.js'
+        ]);
+
+        $this->_oModule->_oTemplate->addCss([
+            'main.css'
+        ]);
+
+        $oForm = new BxTemplFormView([]);
+        $oForm->addCssJs();
+    }
+}
+
+/** @} */

+ 39 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsGridHistoryCommon.php

@@ -0,0 +1,39 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Credits Credits
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+require_once('BxCreditsGridHistoryAdministration.php');
+
+class BxCreditsGridHistoryCommon extends BxCreditsGridHistoryAdministration
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+    }
+
+    public function performActionSend()
+    {
+        $sAction = 'send';
+
+        $this->_performActionWithProfileAmount($sAction);
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        if(empty($this->_iUserId) || $this->_iUserId != bx_get_logged_profile_id())
+            return [];
+
+        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `first_pid`=?", $this->_iUserId);
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+}
+
+/** @} */

+ 67 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsGridOrdersAdministration.php

@@ -0,0 +1,67 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Credits Credits
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+require_once('BxCreditsGrid.php');
+
+class BxCreditsGridOrdersAdministration extends BxCreditsGrid
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sDefaultSortingOrder = 'DESC';
+        $this->_aQueryReset = array($this->_aOptions['order_get_field'], $this->_aOptions['order_get_dir'], $this->_aOptions['paginate_get_start'], $this->_aOptions['paginate_get_per_page']);
+    }
+
+    protected function _getCellProfileId($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_getProfile($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellBundle($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = $this->_oTemplate->parseHtmlByName('bundle_link.html', [
+            'href' => $this->_oModule->_oConfig->getBundleUrl(['id' => $aRow['bundle_id']]),
+            'title' => bx_html_attribute($mixedValue),
+            'content' => $mixedValue
+        ]);
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellType($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(_t('_bx_credits_grid_column_value_ord_type_' . $mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellAdded($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(bx_time_js($mixedValue, BX_FORMAT_DATE, true), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellExpired($mixedValue, $sKey, $aField, $aRow)
+    {
+    	$mixedValue = (int)$mixedValue != 0 ? bx_time_js($mixedValue, BX_FORMAT_DATE, true): _t('_bx_credits_txt_never');
+    		
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getProfile($mixedValue) 
+    {
+        $oProfile = BxDolProfile::getInstanceMagic($mixedValue);
+        if(!$oProfile)
+            return $mixedValue;
+
+        return $oProfile->getUnit(0, ['template' => ['name' => 'unit', 'size' => 'icon']]);
+    }
+}
+
+/** @} */

+ 104 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsGridWithdrawalsAdministration.php

@@ -0,0 +1,104 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Credits Credits
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+require_once('BxCreditsGrid.php');
+
+class BxCreditsGridWithdrawalsAdministration extends BxCreditsGrid
+{
+    protected $_bWithdraw;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sDefaultSortingOrder = 'DESC';
+
+        $this->_bWithdraw = $this->_oModule->_oConfig->isWithdraw();
+    }
+
+
+    public function performActionWithdrawConfirm()
+    {
+        if(!$this->_bWithdraw)
+            return echoJson([]);
+
+        $sAction = 'withdraw_confirm';
+
+        $iId = $this->_getId();
+        if(!$iId)
+            return echoJson([]);
+
+        $aResult = $this->_oModule->processWithdrawConfirm($this->_iUserId, $iId);
+        return echoJson($this->_onPerformAction($aResult));
+    }
+
+    protected function _getActionWithdrawConfirm($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(!$this->_bWithdraw || $aRow['status'] != BX_CREDITS_WITHDRAWAL_STATUS_REQUESTED)
+            return $this->_bIsApi ? [] : '';
+
+        return  parent::_getActionDefault($sType, $sKey, $a, false, $isDisabled, $aRow);
+    }
+
+    protected function _getCellProfileId($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_getProfile($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellPerformerId($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(!empty($mixedValue) ? $this->_getProfile($mixedValue) : '', $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellAmount($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_oModule->convertC2S($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellOrder($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellAdded($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(bx_time_js($mixedValue, BX_FORMAT_DATE, true), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellConfirmed($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(!empty($mixedValue) ? bx_time_js($mixedValue, BX_FORMAT_DATE, true) : '', $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellStatus($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(_t('_bx_credits_txt_withdrawal_status_' . $mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+        $this->_oModule->_oTemplate->addJs([
+            'jquery.form.min.js', 
+            'withdraw.js'
+        ]);
+
+        $this->_oModule->_oTemplate->addCss([
+            'main.css',
+            'withdraw.css'
+        ]);
+
+        $oForm = new BxTemplFormView([]);
+        $oForm->addCssJs();
+    }
+}
+
+/** @} */

+ 73 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsGridWithdrawalsCommon.php

@@ -0,0 +1,73 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Credits Credits
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+require_once('BxCreditsGridWithdrawalsAdministration.php');
+
+class BxCreditsGridWithdrawalsCommon extends BxCreditsGridWithdrawalsAdministration
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+    }
+
+    public function performActionWithdrawRequest()
+    {
+        if(!$this->_bWithdraw)
+            return echoJson([]);
+
+        $sAction = 'withdraw_request';
+
+        $this->_performActionWithProfileAmount($sAction);
+    }
+
+    public function performActionWithdrawCancel()
+    {
+        if(!$this->_bWithdraw)
+            return echoJson([]);
+
+        $sAction = 'withdraw_cancel';
+
+        $iId = $this->_getId();
+        if(!$iId)
+            return echoJson([]);
+
+        $aResult = $this->_oModule->processWithdrawCancel($iId);
+        return echoJson($this->_onPerformAction($aResult));
+    }
+
+    protected function _getActionWithdrawRequest($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(!$this->_bWithdraw)
+            return $this->_bIsApi ? [] : '';
+
+        return parent::_getActionDefault($sType, $sKey, $a, false, $isDisabled, $aRow);
+    }
+
+    protected function _getActionWithdrawCancel($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(!$this->_bWithdraw || $aRow['status'] != BX_CREDITS_WITHDRAWAL_STATUS_REQUESTED)
+            return $this->_bIsApi ? [] : '';
+
+        return parent::_getActionDefault($sType, $sKey, $a, false, $isDisabled, $aRow);
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        if(empty($this->_iUserId) || $this->_iUserId != bx_get_logged_profile_id())
+            return [];
+
+        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `profile_id`=?", $this->_iUserId);
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+}
+
+/** @} */

+ 42 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsMenuManage.php

@@ -0,0 +1,42 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Credits Credits
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+class BxCreditsMenuManage extends BxTemplMenu
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+
+        $this->_sModule = 'bx_credits';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+    }
+
+    protected function _isVisible ($a)
+    {
+        if(!parent::_isVisible($a))
+            return false;
+
+        $bResult = true;
+        switch ($a['name']) {
+            case 'credits-withdrawals-common':
+            case 'credits-withdrawals-administration':
+                $bResult = $this->_oModule->_oConfig->isWithdraw();
+                break;
+        }
+
+        return $bResult;
+    }
+}
+
+/** @} */

+ 1471 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsModule.php

@@ -0,0 +1,1471 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Credits Credits
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define('BX_CREDITS_TRANSFER_TYPE_PURCHASE', 'purchase');
+define('BX_CREDITS_TRANSFER_TYPE_CHECKOUT', 'checkout');
+define('BX_CREDITS_TRANSFER_TYPE_CANCELLATION', 'cancellation');
+define('BX_CREDITS_TRANSFER_TYPE_GRANT', 'grant');
+define('BX_CREDITS_TRANSFER_TYPE_SEND', 'send');
+define('BX_CREDITS_TRANSFER_TYPE_WITHDRAW', 'withdraw');
+define('BX_CREDITS_TRANSFER_TYPE_SERVICE', 'service');
+
+define('BX_CREDITS_DIRECTION_IN', 'in');
+define('BX_CREDITS_DIRECTION_OUT', 'out');
+
+define('BX_CREDITS_ORDER_TYPE_SINGLE', 'single'); //--- one-time payment
+define('BX_CREDITS_ORDER_TYPE_RECURRING', 'recurring'); //--- recurring payment (subscription)
+
+define('BX_CREDITS_WITHDRAWAL_STATUS_REQUESTED', 'requested');
+define('BX_CREDITS_WITHDRAWAL_STATUS_CANCELED', 'canceled');
+define('BX_CREDITS_WITHDRAWAL_STATUS_CONFIRMED', 'confirmed');
+
+class BxCreditsModule extends BxBaseModGeneralModule
+{
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+
+    public function actionGetProfiles()
+    {
+        $sTerm = bx_get('term');
+
+        $a = BxDolService::call('system', 'profiles_search', array($sTerm), 'TemplServiceProfiles');
+
+        echoJson($a);
+    }
+
+    public function actionCheckBundleName()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$sName = bx_process_input(bx_get('name'));
+    	if(empty($sName))
+            return echoJson(array());
+
+        $sResult = '';
+
+        $iId = (int)bx_get('id');
+        if(!empty($iId)) {
+            $aBundle = $this->_oDb->getBundle(array('type' => 'id', 'id' => $iId)); 
+            if(strcmp($sName, $aBundle[$CNF['FIELD_NAME']]) == 0) 
+                $sResult = $sName;
+        }
+
+    	echoJson(array(
+            'name' => !empty($sResult) ? $sResult : $this->_oConfig->getBundleName($sName)
+    	));
+    }
+
+    public function actionCheckout()
+    {
+        $iBuyerId = bx_get_logged_profile_id();
+        if(!$iBuyerId)
+            return echoJson(['code' => 1, 'msg' => _t('_bx_credits_err_unknown_buyer')]);
+
+        $sErrIncorrectData = _t('_bx_credits_err_incorrect_data');
+
+        $aData = $this->_oConfig->getCheckoutData();
+        if(empty($aData) || !is_array($aData))
+            return echoJson(['code' => 2, 'msg' => $sErrIncorrectData]);
+
+        $fConversion = $this->_oConfig->getConversionRateUse();
+        $iPrecision = $this->_oConfig->getPrecision();
+
+        $iSellerId = (int)$aData['seller'];
+        $fAmount = (float)$aData['amount'];
+        $aCustomData = $this->_oConfig->deconstructCheckoutCustomData($aData['custom']);
+
+        $oPayments = BxDolPayments::getInstance();
+        $aPpOrders = $oPayments->getPendingOrdersInfo(['id' => (int)$aCustomData[1]]);
+        if(!empty($aPpOrders) && is_array($aPpOrders)) {
+            $aPpOrder = reset($aPpOrders);
+            if(empty($aPpOrder) || !is_array($aPpOrder) || (int)$aPpOrder['seller_id'] != $iSellerId)
+                return echoJson(['code' => 3, 'msg' => $sErrIncorrectData]);
+
+            $fAmountM = (float)$aPpOrder['amount'];
+            $sCurrencyDefault = $oPayments->getCurrencyCode();
+            if(strcmp($aPpOrder['currency'], $sCurrencyDefault) != 0)
+                $fAmountM = $oPayments->convert ($fAmountM, $aPpOrder['currency'], $sCurrencyDefault);
+
+            if($this->_oConfig->convertM2C($fAmountM, $fConversion, $iPrecision) != $fAmount)
+                return echoJson(['code' => 3, 'msg' => $sErrIncorrectData]);
+        }
+
+        $fBalance = (float)$this->_oDb->getProfile(['type' => 'balance', 'id' => $iBuyerId]);
+        if($fAmount > $fBalance)
+            return echoJson(['code' => 4, 'msg' => _t('_bx_credits_err_low_balance')]);
+
+        $sOrder = $this->_oConfig->getOrder();
+        $sInfo = '_bx_credits_txt_history_info_checkout';
+        $sData = serialize([
+            'conversion' => $fConversion,
+            'precision' => $iPrecision
+        ]);
+
+        $this->updateProfileBalance($iBuyerId, $iSellerId, -$fAmount, BX_CREDITS_TRANSFER_TYPE_CHECKOUT, $sOrder, $sInfo, $sData);
+        $this->updateProfileBalance($iSellerId, $iBuyerId, $fAmount, BX_CREDITS_TRANSFER_TYPE_CHECKOUT, $sOrder, $sInfo, $sData);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_credits-checkout 'bx_credits', 'checkout' - hook after checkout with creadits was performed
+         * - $unit_name - equals `bx_credits`
+         * - $action - equals `checkout`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `seller` - [int] seller profile id
+         *      - `buyer` - [int] buyer profile id
+         *      - `amount` - [float] amount was paid
+         *      - `order` - [string] order number for processed checkout action
+         * @hook @ref hook-bx_credits-checkout
+         */
+        bx_alert($this->getName(), 'checkout', 0, false, [
+            'seller' => $iSellerId,
+            'buyer' => $iBuyerId,
+            'amount' => $fAmount, 
+            'order' => $sOrder
+        ]);
+
+        return echoJson([
+            'code' => 0,
+            'redirect' => bx_append_url_params($aData['return_data_url'], ['o' => $sOrder, 'c' => $aData['custom']])
+        ]);
+    }
+
+    public function actionSubscribe()
+    {
+        $iBuyerId = bx_get_logged_profile_id();
+        if(!$iBuyerId)
+            return echoJson(array('code' => 1, 'msg' => _t('_bx_credits_err_unknown_buyer')));
+
+        $aData = $this->_oConfig->getCheckoutData();
+        if(empty($aData) || !is_array($aData))
+            return echoJson(array('code' => 2, 'msg' => _t('_bx_credits_err_incorrect_data')));
+
+        $iSellerId = (int)$aData['seller'];
+        $fAmount = (float)$aData['amount'];
+
+        $fBalance = (float)$this->_oDb->getProfile(array('type' => 'balance', 'id' => $iBuyerId));
+        if($fAmount > $fBalance)
+            return echoJson(array('code' => 3, 'msg' => _t('_bx_credits_err_low_balance')));
+
+        $sUnique = $this->_oConfig->getOrder(9);
+        $sCustomer = 'bx_cus_' . $sUnique;
+        $sSubscription = 'bx_sub_' . $sUnique;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_credits-subscribe 'bx_credits', 'subscribe' - hook after subscription was registered
+         * - $unit_name - equals `bx_credits`
+         * - $action - equals `subscribe`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `seller` - [int] seller profile id
+         *      - `buyer` - [int] buyer profile id
+         *      - `amount` - [float] amount was paid
+         *      - `trial` - [boolean] if trial period is available or not
+         *      - `customer` - [string] unique customer id for newly registered subscription
+         *      - `subscription` - [string] unique subscription id
+         * @hook @ref hook-bx_credits-subscribe
+         */
+        bx_alert($this->getName(), 'subscribe', 0, false, [
+            'seller' => $iSellerId,
+            'buyer' => $iBuyerId,
+            'amount' => $fAmount, 
+            'trial' => $aData['trial'],
+            'customer' => $sCustomer,
+            'subscription' => $sSubscription
+        ]);
+
+        return echoJson([
+            'code' => 0,
+            'redirect' => bx_append_url_params($aData['return_data_url'], [
+                'cs' => $sCustomer, 
+                'sb' => $sSubscription,
+                'tr' => $aData['trial'],
+                'c' => $aData['custom']
+            ])
+        ]);
+    }
+
+    public function serviceGetSafeServices()
+    {
+        return array (
+            'GetBlockBundles' => '',
+            'GetBlockOrders' => '',
+            'GetBlockHistory' => '',
+        );
+    }
+
+    public function serviceGetCheckoutUrl()
+    {
+        return $this->_oConfig->getCheckoutUrl();
+    }
+
+    public function serviceConvertMoneyToCredits($fMoney, $fRate = false, $iPrecision = false)
+    {
+        return $this->_oConfig->convertM2C($fMoney, $fRate, $iPrecision);
+    }
+
+    public function serviceConvertCreditsToMoney($fCredits, $fRate = false, $iPrecision = false)
+    {
+        return $this->_oConfig->convertC2M($fCredits, $fRate, $iPrecision);
+    }
+
+    public function serviceValidateCheckout($iSeller, $iBuyer, $fAmount, $sOrder)
+    {
+        $fAmount = (float)$fAmount;
+
+        $aOut = $this->_oDb->getHistory(array('type' => 'row_by', 'by' => array('first_pid' => $iBuyer, 'direction' => BX_CREDITS_DIRECTION_OUT, 'order' => $sOrder)));
+        if(empty($aOut) || !is_array($aOut) || (int)$aOut['second_pid'] != (int)$iSeller)
+            return false;
+        
+        $aDataOut = unserialize($aOut['data']);
+        if($this->_oConfig->convertM2C($fAmount, $aDataOut['conversion'], $aDataOut['precision']) != (float)$aOut['amount'])
+            return false;
+
+        $aIn = $this->_oDb->getHistory(array('type' => 'row_by', 'by' => array('first_pid' => $iSeller, 'direction' => BX_CREDITS_DIRECTION_IN, 'order' => $sOrder)));
+        if(empty($aIn) || !is_array($aIn) || (int)$aIn['second_pid'] != (int)$iBuyer)
+            return false;
+
+        $aDataIn = unserialize($aIn['data']);
+        if($this->_oConfig->convertM2C($fAmount, $aDataIn['conversion'], $aDataIn['precision']) != (float)$aIn['amount'])
+            return false;
+
+        return true;
+    }
+
+    public function serviceGetBlockCheckout()
+    {
+        $oBuyer = BxDolProfile::getInstance();
+        if(!$oBuyer)
+            return MsgBox(_t('_bx_credits_err_unknown_buyer'));
+        
+        $iSeller = (int)bx_get('seller');
+        $oSeller = BxDolProfile::getInstance($iSeller);
+        if(!$oSeller)
+            return MsgBox(_t('_bx_credits_err_unknown_seller'));
+
+        $fAmountM = $fAmountMInDef = (float)bx_get('amount');
+
+        $oPayments = BxDolPayments::getInstance();
+        $sCurrency = bx_process_input(bx_get('currency_code'));
+        $sCurrencyDefault = $oPayments->getCurrencyCode();
+        if(strcmp($sCurrency, $sCurrencyDefault) != 0)
+            $fAmountMInDef = $oPayments->convert($fAmountM, $sCurrency, $sCurrencyDefault);
+
+        $fAmountC = $this->_oConfig->convertM2C($fAmountMInDef);
+
+        $aData = [
+            'seller' => $iSeller,
+            'currency' => [
+                'code' => $sCurrency,
+                'sign' => bx_process_input(bx_get('currency_sign')),
+            ],
+            'amountm' => $fAmountM,
+            'amountc' => $fAmountC
+        ];
+
+        $iItemsCount = (int)bx_get('items_count');
+        for($i = 0; $i < $iItemsCount; $i++) {
+            $aData['items'][] = [
+                'title' => bx_process_input(bx_get('item_title_' . $i)),
+                'quantity' => (int)bx_get('item_quantity_' . $i)
+            ];
+        }
+
+        $this->_oConfig->setCheckoutData([
+            'seller' => $iSeller,
+            'amount' => $fAmountC,
+            'custom' => bx_process_input(bx_get('custom')),
+            'return_data_url' => bx_process_input(bx_get('return_data_url')),
+        ]);
+        return $this->_oTemplate->getBlockCheckout($oBuyer, $oSeller, $aData);
+    }
+
+    public function serviceGetPopupSubscribe($aData)
+    {
+        $oBuyer = BxDolProfile::getInstance();
+        if(!$oBuyer)
+            return ['msg' => _t('_bx_credits_err_unknown_buyer')];
+
+        $iSeller = (int)$aData['seller'];
+        $oSeller = BxDolProfile::getInstance($iSeller);
+        if(!$oSeller)
+            return ['msg' => _t('_bx_credits_err_unknown_seller')];
+
+        $fAmountM = $fAmountMInDef = (float)$aData['amount'];
+
+        $oPayments = BxDolPayments::getInstance();
+        $sCurrency = $aData['currency_code'];
+        $sCurrencyDefault = $oPayments->getCurrencyCode();
+        if(strcmp($sCurrency, $sCurrencyDefault) != 0)
+            $fAmountMInDef = $oPayments->convert($fAmountM, $sCurrency, $sCurrencyDefault);
+
+        $fAmountC = $this->_oConfig->convertM2C($fAmountMInDef);
+
+        $aData = array_merge($aData, [
+            'currency' => [
+                'code' => $sCurrency,
+                'sign' => $aData['currency_sign'],
+            ],
+            'amountm' => $fAmountM,
+            'amountc' => $fAmountC
+        ]);
+
+        $this->_oConfig->setCheckoutData([
+            'seller' => $iSeller,
+            'amount' => $fAmountC,
+            'trial' => (int)$aData['trial'] > 0,
+            'custom' => bx_process_input($aData['custom']),
+            'return_data_url' => bx_process_input($aData['return_data_url']),
+        ]);
+        return $this->_oTemplate->getPopupSubscribe($oBuyer, $oSeller, $aData);
+    }
+
+    public function serviceGetMenuItemAddonAmount()
+    {
+        $iProfileId = bx_get_logged_profile_id();
+        if(!$iProfileId)
+            return '';
+
+        return array(
+            'unit' => $this->_oTemplate->getUnit(), 
+            'value' => $this->convertC2S($this->_oDb->getProfile(array('type' => 'balance', 'id' => $iProfileId)), false)
+        );
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-page_blocks Page Blocks
+     * @subsubsection bx_credits-get_block_bundles get_block_bundles
+     * 
+     * @code bx_srv('bx_credits', 'get_block_bundles'); @endcode
+     * 
+     * Get page block with bundles
+     * 
+     * @see BxCreditsModule::serviceGetBlockBundles
+     */
+    /** 
+     * @ref bx_credits-get_block_bundles "get_block_bundles"
+     */
+    public function serviceGetBlockBundles()
+    {
+        return $this->_oTemplate->getBlockBundles();
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-page_blocks Page Blocks
+     * @subsubsection bx_credits-get_block_orders_note get_block_orders_note
+     * 
+     * @code bx_srv('bx_credits', 'get_block_orders_note', [...]); @endcode
+     * 
+     * Get page block with a notice for orders usage.
+     *
+     * @return HTML string with block content to display on the site.
+     * 
+     * @see BxCreditsModule::serviceBlockLicensesNote
+     */
+    /** 
+     * @ref bx_credits-get_block_orders_note "get_block_orders_note"
+     */
+    public function serviceGetBlockOrdersNote()
+    {
+        return MsgBox(_t('_bx_credits_page_block_content_orders_common_note'));
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-page_blocks Page Blocks
+     * @subsubsection bx_credits-get_block_orders get_block_orders
+     * 
+     * @code bx_srv('bx_credits', 'get_block_orders', [...]); @endcode
+     * 
+     * Get page block with a list of orders 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 BxCreditsModule::serviceGetBlockOrders
+     */
+    /** 
+     * @ref bx_credits-get_block_orders "get_block_orders"
+     */
+    public function serviceGetBlockOrders($sType = 'common') 
+    {
+        return $this->_getBlockOrders($sType);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-page_blocks Page Blocks
+     * @subsubsection bx_credits-get_block_history get_block_history
+     * 
+     * @code bx_srv('bx_credits', 'get_block_history', [...]); @endcode
+     * 
+     * Get page block with a list of all changes with credits.
+     *
+     * @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 BxCreditsModule::serviceGetBlockHistory
+     */
+    /** 
+     * @ref bx_credits-get_block_history "get_block_history"
+     */
+    public function serviceGetBlockHistory($sType = 'common') 
+    {
+        return $this->_getBlockHistory($sType);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-page_blocks Page Blocks
+     * @subsubsection bx_credits-get_block_withdrawals get_block_withdrawals
+     * 
+     * @code bx_srv('bx_credits', 'get_block_withdrawals', [...]); @endcode
+     * 
+     * Get page block with a list of all credits withdrawals.
+     *
+     * @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 BxCreditsModule::serviceGetBlockHistory
+     */
+    /** 
+     * @ref bx_credits-get_block_withdrawals "get_block_withdrawals"
+     */
+    public function serviceGetBlockWithdrawals($sType = 'common') 
+    {
+        if(!$this->_oConfig->isWithdraw())
+            return MsgBox (_t('_bx_credits_msg_action_withdrawals_disabled'));
+
+        return $this->_getBlockWithdrawals($sType);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-page_blocks Page Blocks
+     * @subsubsection bx_credits-get_block_profiles get_block_profiles
+     * 
+     * @code bx_srv('bx_credits', 'get_block_profiles', [...]); @endcode
+     * 
+     * Get page block with a list of profiles for managing their parameters.
+     *
+     * @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 BxCreditsModule::serviceGetBlockProfiles
+     */
+    /** 
+     * @ref bx_credits-get_block_profiles "get_block_profiles"
+     */
+    public function serviceGetBlockProfiles($sType = 'common') 
+    {
+        return $this->_getBlockProfiles($sType);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-payments Payments
+     * @subsubsection bx_credits-get_payment_data get_payment_data
+     * 
+     * @code bx_srv('bx_credits', '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 BxCreditsModule::serviceGetPaymentData
+     */
+    /** 
+     * @ref bx_credits-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_absolute_url($oPermalink->permalink($CNF['URL_ORDERS_COMMON'], array('filter' => '{order}')));
+        $aResult['url_browse_order_administration'] = bx_absolute_url($oPermalink->permalink($CNF['URL_ORDERS_ADMINISTRATION'], array('filter' => '{order}')));
+
+        return $aResult;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-payments Payments
+     * @subsubsection bx_credits-get_cart_item get_cart_item
+     * 
+     * @code bx_srv('bx_credits', 'get_cart_item', [...]); @endcode
+     * 
+     * Get an array with prodict's description. Is used in Shopping Cart in payments processing module.
+     * 
+     * @param $iItemId product's ID.
+     * @return an array with prodict's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxCreditsModule::serviceGetCartItem
+     */
+    /** 
+     * @ref bx_credits-get_cart_item "get_cart_item"
+     */
+    public function serviceGetCartItem($iItemId)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        if(!$iItemId)
+            return array();
+
+        $aItem = $this->_oDb->getBundle(array('type' => 'id', 'id' => $iItemId));
+        if(empty($aItem) || !is_array($aItem))
+            return array();
+
+        return array (
+            'id' => $aItem[$CNF['FIELD_ID']],
+            'author_id' => $this->_oConfig->getAuthor(),
+            'name' => $aItem[$CNF['FIELD_NAME']],
+            'title' => _t($aItem[$CNF['FIELD_TITLE']]),
+            'description' => $this->_oConfig->getBundleDescription($aItem),
+            'url' => $this->_oConfig->getBundleUrl($aItem),
+            'price_single' => $aItem[$CNF['FIELD_PRICE']],
+            'price_recurring' => '',
+            'period_recurring' => 1,
+            'period_unit_recurring' => '',
+            'trial_recurring' => ''
+        );
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-payments Payments
+     * @subsubsection bx_credits-get_cart_items get_cart_items
+     * 
+     * @code bx_srv('bx_credits', '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 BxCreditsModule::serviceGetCartItems
+     */
+    /** 
+     * @ref bx_credits-get_cart_items "get_cart_items"
+     */
+    public function serviceGetCartItems($iSellerId)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        $iAuthorId = $this->_oConfig->getAuthor();
+        if($iSellerId != $iAuthorId && !BxDolAcl::getInstance()->isMemberLevelInSet([MEMBERSHIP_ID_ADMINISTRATOR], $iSellerId))
+            return array();
+
+        $aItems = $this->_oDb->getBundle(array('type' => 'all', 'active' => 1));
+
+        $aResult = array();
+        foreach($aItems as $aItem)
+            $aResult[] = array(
+                'id' => $aItem[$CNF['FIELD_ID']],
+                'author_id' => $iAuthorId,
+                'name' => $aItem[$CNF['FIELD_NAME']],
+                'title' => _t($aItem[$CNF['FIELD_TITLE']]),
+                'description' => $this->_oConfig->getBundleDescription($aItem),
+                'url' => $this->_oConfig->getBundleUrl($aItem),
+                'price_single' => $aItem[$CNF['FIELD_PRICE']],
+                'price_recurring' => '',
+                'period_recurring' => 1,
+                'period_unit_recurring' => '',
+                'trial_recurring' => ''
+            );
+
+        return $aResult;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-payments Payments
+     * @subsubsection bx_credits-register_cart_item register_cart_item
+     * 
+     * @code bx_srv('bx_credits', 'register_cart_item', [...]); @endcode
+     * 
+     * Register a processed single time payment inside the Credits 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 BxCreditsModule::serviceRegisterCartItem
+     */
+    /** 
+     * @ref bx_credits-register_cart_item "register_cart_item"
+     */
+    public function serviceRegisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        return $this->_serviceRegisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, BX_CREDITS_ORDER_TYPE_SINGLE);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-payments Payments
+     * @subsubsection bx_credits-register_subscription_item register_subscription_item
+     * 
+     * @code bx_srv('bx_credits', 'register_subscription_item', [...]); @endcode
+     * 
+     * Register a processed subscription (recurring payment) inside the Credits 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 BxCreditsModule::serviceRegisterSubscriptionItem
+     */
+    /** 
+     * @ref bx_credits-register_subscription_item "register_subscription_item"
+     */
+    public function serviceRegisterSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        return $this->_serviceRegisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, BX_CREDITS_ORDER_TYPE_RECURRING);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-payments Payments
+     * @subsubsection bx_credits-reregister_cart_item reregister_cart_item
+     * 
+     * @code bx_srv('bx_credits', 'reregister_cart_item', [...]); @endcode
+     * 
+     * Reregister a single time payment inside the Credits 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 BxCreditsModule::serviceReregisterCartItem
+     */
+    /** 
+     * @ref bx_credits-reregister_cart_item "reregister_cart_item"
+     */
+    public function serviceReregisterCartItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
+    {
+        return array();
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-payments Payments
+     * @subsubsection bx_credits-reregister_subscription_item reregister_subscription_item
+     * 
+     * @code bx_srv('bx_credits', 'reregister_subscription_item', [...]); @endcode
+     * 
+     * Reregister a subscription (recurring payment) inside the Credits 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 BxCreditsModule::serviceReregisterSubscriptionItem
+     */
+    /** 
+     * @ref bx_credits-reregister_subscription_item "reregister_subscription_item"
+     */
+    public function serviceReregisterSubscriptionItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
+    {
+        return array();
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-payments Payments
+     * @subsubsection bx_credits-unregister_cart_item unregister_cart_item
+     * 
+     * @code bx_srv('bx_credits', 'unregister_cart_item', [...]); @endcode
+     * 
+     * Unregister an earlier processed single time payment inside the Credits 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 BxCreditsModule::serviceUnregisterCartItem
+     */
+    /** 
+     * @ref bx_credits-unregister_cart_item "unregister_cart_item"
+     */
+    public function serviceUnregisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        return $this->_serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, BX_CREDITS_ORDER_TYPE_SINGLE);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-payments Payments
+     * @subsubsection bx_credits-unregister_subscription_item unregister_subscription_item
+     * 
+     * @code bx_srv('bx_credits', 'unregister_subscription_item', [...]); @endcode
+     * 
+     * Unregister an earlier processed subscription (recurring payment) inside the Credits 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 BxCreditsModule::serviceUnregisterSubscriptionItem
+     */
+    /** 
+     * @ref bx_credits-unregister_subscription_item "unregister_subscription_item"
+     */
+    public function serviceUnregisterSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+    	return $this->_serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, BX_CREDITS_ORDER_TYPE_RECURRING); 
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_credits Credits
+     * @subsection bx_credits-payments Payments
+     * @subsubsection bx_credits-cancel_subscription_item cancel_subscription_item
+     * 
+     * @code bx_srv('bx_credits', 'cancel_subscription_item', [...]); @endcode
+     * 
+     * Cancel an earlier processed subscription (recurring payment) inside the Credits 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 BxCreditsModule::serviceCancelSubscriptionItem
+     */
+    /** 
+     * @ref bx_credits-cancel_subscription_item "cancel_subscription_item"
+     */
+    public function serviceCancelSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder)
+    {
+    	return true;
+    }
+
+    public function serviceGetProfileBalance($iProfileId = 0)
+    {
+        return $this->getProfileBalance($iProfileId);
+    }
+
+    public function serviceUpdateProfileBalance($iFirstPid, $fAmount, $iSecondPid = 0, $sOrder = '', $sInfo = '')
+    {
+        if(empty($sInfo))
+            $sInfo = '_bx_credits_txt_history_info_service';
+
+        return $this->updateProfileBalance($iFirstPid, $iSecondPid, $fAmount, BX_CREDITS_TRANSFER_TYPE_SERVICE, $sOrder, $sInfo);
+    }
+    
+    public function serviceMakePayment($iBuyerPid, $fAmount, $iSellerPid, $sOrder = '')
+    {
+        $sInfo = '_bx_credits_txt_history_info_checkout';
+
+        if(!$this->updateProfileBalance($iBuyerPid, $iSellerPid, -$fAmount, BX_CREDITS_TRANSFER_TYPE_CHECKOUT, $sOrder, $sInfo))
+            return false;
+
+        if(!$this->updateProfileBalance($iSellerPid, $iBuyerPid, $fAmount, $sOrder, BX_CREDITS_TRANSFER_TYPE_CHECKOUT, $sInfo)) {
+            $this->updateProfileBalance($iBuyerPid, 0, $fAmount, BX_CREDITS_TRANSFER_TYPE_CANCELLATION, $sOrder, '_bx_credits_txt_history_info_cancellation');
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Delete all content by profile 
+     * @param $iProfileId profile id 
+     * @return number of deleted items
+     */
+    public function serviceDeleteEntitiesByAuthor ($iProfileId)
+    {
+        $this->_oDb->deleteProfile(array('id' => $iProfileId));
+        $this->_oDb->deleteHistory(array('first_pid' => $iProfileId));
+    }
+
+
+    /*
+     * Common methods
+     */
+    public function convertC2S($fCredits, $bWithUnit = true)
+    {
+        $sResult = '';
+        if($bWithUnit)
+            $sResult .= $this->_oTemplate->getUnit();
+
+        $iPrecision = $this->_oConfig->getPrecision();
+        $sResult .= sprintf("%01." . $iPrecision . "f", round((float)$fCredits, $iPrecision));
+
+        return $sResult;
+    }
+
+    public function getProfileLimits($iProfileId = 0)
+    {
+        if(empty($iProfileId))
+            $iProfileId = bx_get_logged_profile_id();
+
+        $aResults = [
+            'wdw_clearing' => $this->_oConfig->getWithdrawClearing(),
+            'wdw_minimum' => $this->_oConfig->getWithdrawMinimum(),
+            'wdw_remaining' => $this->_oConfig->getWithdrawRemaining(),
+        ];
+
+        if(empty($iProfileId))
+            return $aResults;
+
+        $aProfile = $this->_oDb->getProfile(['type' => 'id', 'id' => $iProfileId]);
+
+        foreach($aResults as $sKey => $mixedValue)
+            if(!empty($aProfile[$sKey]))
+                $aResults[$sKey] = $aProfile[$sKey];
+
+        return $aResults;
+    }
+
+    public function getProfileBalance($iProfileId = 0)
+    {
+        if(empty($iProfileId))
+            $iProfileId = bx_get_logged_profile_id();
+
+        if(empty($iProfileId))
+            return 0;
+
+        return (float)$this->_oDb->getProfile(array('type' => 'balance', 'id' => $iProfileId));
+    }
+
+    public function getProfileBalanceCleared($iProfileId = 0)
+    {
+        if(empty($iProfileId))
+            $iProfileId = bx_get_logged_profile_id();
+
+        if(empty($iProfileId))
+            return 0;
+
+        $fCleared = (float)$this->_oDb->getHistory(['type' => 'cleared', 'profile' => $iProfileId]);
+        $fSpent = (float)$this->_oDb->getHistory(['type' => 'spent', 'profile' => $iProfileId]);
+
+        return $fCleared > $fSpent ? $fCleared - $fSpent : 0;
+    }
+
+    public function updateProfileBalance($iFirstPid, $iSecondPid, $fAmount, $sType, $sOrder = '', $sInfo = '', $sData = '')
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($sOrder))
+            $sOrder = $this->_oConfig->getOrder();
+
+        if(empty($sData))
+            $sData = serialize(array(
+                'conversion' => $this->_oConfig->getConversionRateUse(),
+                'precision' => $this->_oConfig->getPrecision()
+            ));
+
+        if(!$this->_oDb->updateProfileBalance($iFirstPid, $fAmount))
+            return false;
+
+        $fAmountAbs = abs($fAmount);
+        $sDirection = $fAmount > 0 ? BX_CREDITS_DIRECTION_IN : BX_CREDITS_DIRECTION_OUT;
+
+        $iHistoryId = $this->_oDb->insertHistory([
+            'first_pid' => $iFirstPid,
+            'second_pid' => $iSecondPid,
+            'amount' => $fAmountAbs,
+            'type' => $sType,
+            'direction' => $sDirection,
+            'order' => $sOrder,
+            'data' => $sData,
+            'info' => $sInfo,
+            'date' => time()
+        ]);
+
+        if(!$iHistoryId)
+            return false;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_credits-update_balance 'bx_credits', 'update_balance' - hook after profile's credits balance was updated (credits were transferred from one profile to another)
+         * - $unit_name - equals `bx_credits`
+         * - $action - equals `update_balance`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `first_pid` - [int] first profile id
+         *      - `second_pid` - [int] second profile id
+         *      - `amount` - [float] amount was transferred
+         *      - `type` - [string] transfer type: purchase, checkout, cancellation, grant, send, withdraw, service
+         *      - `direction` - [string] transfer direction: in or out
+         *      - `order` - [string] unique order number associated with the transfer
+         * @hook @ref hook-bx_credits-update_balance
+         */
+        bx_alert($this->getName(), 'update_balance', 0, false, [
+            'first_pid' => $iFirstPid,
+            'second_pid' => $iSecondPid,
+            'amount' => $fAmountAbs,
+            'type' => $sType,
+            'direction' => $sDirection,
+            'order' => $sOrder,
+        ]);
+
+        $oSecondProfile = BxDolProfile::getInstanceMagic($iSecondPid);
+        sendMailTemplate($CNF['ETEMPLATE_' . strtoupper($sDirection)], 0, $iFirstPid, array(
+            'second_profile_name' => $oSecondProfile->getDisplayName(),
+            'amount' => $fAmountAbs,
+        ));
+
+        return $iHistoryId;
+    }
+
+    public function processGrant($iUserId, $iProfileId, $fAmount, $sMessage = '')
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        $oProfile = BxDolProfile::getInstance($iProfileId);
+        if(!$oProfile)
+            return ['code' => 2, 'msg' => '_bx_credits_err_profile_not_found'];
+
+        $sInfo = '_bx_credits_txt_history_info_grant';
+        $iHistoryId = $this->updateProfileBalance($iProfileId, 0, $fAmount, BX_CREDITS_TRANSFER_TYPE_GRANT, '', $sInfo);
+        if(!$iHistoryId)
+            return ['code' => 3, 'msg' => '_bx_credits_err_cannot_update_balance'];
+
+        sendMailTemplate($CNF['ETEMPLATE_GRANTED'], 0, $iProfileId, [
+            'amount' => $fAmount,
+            'message' => $sMessage
+        ]);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_credits-granted 'bx_credits', 'granted' - hook after some amount of credits was granted to a profile
+         * - $unit_name - equals `bx_credits`
+         * - $action - equals `granted`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `profile` - [int] recipient profile id
+         *      - `amount` - [float] amount was granted
+         * @hook @ref hook-bx_credits-granted
+         */
+        bx_alert($this->getName(), 'granted', 0, false, [
+            'profile' => $iProfileId,
+            'amount' => $fAmount,
+        ]);
+
+        return ['code' => 0, 'id' => $iHistoryId];
+    }
+
+    public function processSend($iUserId, $iProfileId, $fAmount, $sMessage = '')
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $fAmountAvail = $this->getProfileBalance($iUserId);
+        if($fAmount > $fAmountAvail)
+            return ['code' => 1, 'msg' => '_bx_credits_err_low_balance'];
+
+        $oProfile = null;
+        if(!$iProfileId || !($oProfile = BxDolProfile::getInstance($iProfileId)))
+            return ['code' => 2, 'msg' => '_bx_credits_err_profile_not_found'];
+
+        $sOrder = $this->_oConfig->getOrder();
+        $sInfo = !empty($sMessage) ? $sMessage : '_bx_credits_txt_history_info_send';
+
+        $iHistoryId = $this->updateProfileBalance($iUserId, $iProfileId, -$fAmount, BX_CREDITS_TRANSFER_TYPE_SEND, $sOrder, $sInfo);
+        if(!$iHistoryId)
+            return ['code' => 3, 'msg' => '_bx_credits_err_cannot_update_balance'];
+
+        if(!$this->updateProfileBalance($iProfileId, $iUserId, $fAmount, BX_CREDITS_TRANSFER_TYPE_SEND, $sOrder, $sInfo)) {
+            $sInfo = '_bx_credits_txt_history_info_cancellation';
+            $iHistoryId = $this->updateProfileBalance($iUserId, 0, $fAmount, BX_CREDITS_TRANSFER_TYPE_CANCELLATION, $sOrder, $sInfo);
+
+            return ['code' => 3, 'id' => $iHistoryId, 'msg' => '_bx_credits_err_cannot_update_balance'];
+        }
+
+        $oUser = BxDolProfile::getInstance($iUserId);
+        sendMailTemplate($CNF['ETEMPLATE_RECEIVED'], 0, $iProfileId, [
+            'performer_id' => $iUserId,
+            'performer_name' => $oUser->getDisplayName(),
+            'performer_link' => $oUser->getUrl(),
+            'amount' => $fAmount,
+            'order' => $sOrder,
+            'message' => $sMessage
+        ]);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_credits-sent 'bx_credits', 'sent' - hook after some amount of credits was sent from one profile to another
+         * - $unit_name - equals `bx_credits`
+         * - $action - equals `sent`
+         * - $object_id - not used
+         * - $sender_id - sender profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `performer` - [int] sender profile id
+         *      - `profile` - [int] recipient profile id
+         *      - `amount` - [float] amount was sent
+         *      - `order` - [string] unique order number associated with 'sent' action
+         * @hook @ref hook-bx_credits-sent
+         */
+        bx_alert($this->getName(), 'sent', 0, $iUserId, [
+            'performer' => $iUserId,
+            'profile' => $iProfileId,
+            'amount' => $fAmount,
+            'order' => $sOrder,
+        ]);
+
+        return ['code' => 0, 'id' => $iHistoryId];
+    }
+
+    public function processWithdrawRequest($iUserId, $iProfileId, $fAmount, $sMessage = '')
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($iProfileId))
+            $iProfileId = bx_get_logged_profile_id ();
+
+        if(empty($iProfileId))
+            return ['code' => 1, 'msg' => '_bx_credits_err_login_required'];
+
+        $oProfile = BxDolProfile::getInstance($iProfileId);
+        if(!$oProfile)
+            return ['code' => 1, 'msg' => '_bx_credits_err_login_required'];
+
+        $fBalanceCleared = $this->getProfileBalanceCleared($iProfileId);
+        if($fAmount > $fBalanceCleared)
+            return ['code' => 2, 'msg' => '_bx_credits_err_low_balance'];
+
+        $aProfileInfo = $this->_oDb->getProfile(['type' => 'id', 'id' => $iProfileId]);
+
+        $iWithdrawMinimum = !empty($aProfileInfo['wdw_minimum']) ? (int)$aProfileInfo['wdw_minimum'] : (int)getParam($CNF['PARAM_WITHDRAW_MINIMUM']);
+        if($fAmount < $iWithdrawMinimum)
+            return ['code' => 3, 'msg' => _t('_bx_credits_err_withdraw_minimum', $iWithdrawMinimum)];
+
+        $fBalance = $this->getProfileBalance($iProfileId);
+        $iWithdrawRemaining = !empty($aProfileInfo['wdw_remaining']) ? (int)$aProfileInfo['wdw_remaining'] : (int)getParam($CNF['PARAM_WITHDRAW_REMAINING']);
+        if(($fBalance - $fAmount) < $iWithdrawRemaining)
+            return ['code' => 4, 'msg' => _t('_bx_credits_err_withdraw_remaining', $iWithdrawRemaining)];
+
+        $aResult = ['code' => 5, 'msg' => '_bx_credits_err_cannot_send'];
+
+        $fRate = $this->_oConfig->getConversionRateWithdraw();
+
+        $iId = $this->_oDb->insertWithdrawal([
+            'profile_id' => $iProfileId, 
+            'amount' => $fAmount,
+            'rate' => $fRate,
+            'message' => $sMessage,
+            'added' => time()
+        ]);
+
+        if(!$iId)
+            return $aResult;
+
+        $aTemplateVars = [
+            'profile_link' => $oProfile->getUrl(),
+            'profile_name' => $oProfile->getDisplayName(),
+            'amount' => $fAmount,
+            'rate' => $fRate,
+            'message' => $sMessage,
+            'confirm_url' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_HISTORY_ADMINISTRATION']))
+        ];
+        $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($CNF['ETEMPLATE_WITHDRAW_REQUESTED'], $aTemplateVars);
+        if(!$aTemplate)
+            return $aResult;
+
+        $sEmail = $this->_oConfig->getWithdrawEmail();
+        if(!sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, [], BX_EMAIL_SYSTEM))
+            return $aResult;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_credits-withdraw_requested 'bx_credits', 'withdraw_requested' - hook after a profile requested to withdraw some amount of credits from his balance
+         * - $unit_name - equals `bx_credits`
+         * - $action - equals `withdraw_requested`
+         * - $object_id - not used
+         * - $sender_id - performer profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `profile` - [int] performer profile id
+         *      - `amount` - [float] amount to withdraw
+         *      - `rate` - [float] withdraw conversion rate
+         * @hook @ref hook-bx_credits-withdraw_requested
+         */
+        bx_alert($this->getName(), 'withdraw_requested', 0, $iProfileId, [
+            'profile' => $iProfileId,
+            'amount' => $fAmount,
+            'rate' => $fRate
+        ]);
+
+        return ['code' => 0, 'id' => $iId];
+    }
+
+    public function processWithdrawCancel($iId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aWithdrawal = $this->_oDb->getWithdrawal(['type' => 'id', 'id' => $iId]);
+        if(empty($aWithdrawal) || !is_array($aWithdrawal))
+            return ['code' => 1, 'msg' => '_bx_credits_err_withdrawal_not_found'];
+
+        $iProfileId = (int)$aWithdrawal['profile_id'];
+        $oProfile = BxDolProfile::getInstance($iProfileId);
+        if(!$oProfile)
+            return ['code' => 2, 'msg' => '_bx_credits_err_profile_not_found'];
+
+        $aResult = ['code' => 3, 'msg' => '_bx_credits_err_cannot_cancel_withdrawal'];       
+
+        $aTemplateVars = [
+            'profile_link' => $oProfile->getUrl(),
+            'profile_name' => $oProfile->getDisplayName(),
+            'amount' => $aWithdrawal['amount'],
+            'manage_url' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_WITHDRAWALS_ADMINISTRATION']))
+        ];
+        $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($CNF['ETEMPLATE_WITHDRAW_CANCELED'], $aTemplateVars);
+        if(!$aTemplate)
+            return $aResult;
+
+        $sEmail = $this->_oConfig->getWithdrawEmail();
+        if(!sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, [], BX_EMAIL_SYSTEM))
+            return $aResult;
+
+        if(!$this->_oDb->updateWithdrawal(['status' => BX_CREDITS_WITHDRAWAL_STATUS_CANCELED], ['id' => $iId]))
+            return $aResult;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_credits-withdraw_canceled 'bx_credits', 'withdraw_canceled' - hook after a profile canceled his withdrawal request
+         * - $unit_name - equals `bx_credits`
+         * - $action - equals `withdraw_canceled`
+         * - $object_id - not used
+         * - $sender_id - performer profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `profile` - [int] performer profile id
+         *      - `amount` - [float] amount to withdraw
+         *      - `rate` - [float] withdraw conversion rate
+         * @hook @ref hook-bx_credits-withdraw_canceled
+         */
+        bx_alert($this->getName(), 'withdraw_canceled', $iId, $iProfileId, [
+            'profile' => $iProfileId,
+            'amount' => $aWithdrawal['amount'],
+        ]);
+
+        return ['code' => 0, 'id' => $iId];
+    }
+
+    public function processWithdrawConfirm($iUserId, $iWithdrawalId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aWithdrawal = $this->_oDb->getWithdrawal(['type' => 'id', 'id' => $iWithdrawalId]);
+        if(empty($aWithdrawal) || !is_array($aWithdrawal))
+            return ['code' => 1, 'msg' => '_bx_credits_err_withdrawal_not_found'];
+
+        $iProfileId = (int)$aWithdrawal['profile_id'];
+        $oProfile = BxDolProfile::getInstance($iProfileId);
+        if(!$oProfile)
+            return ['code' => 2, 'msg' => '_bx_credits_err_profile_not_found'];
+
+        $fAmount = (float)$aWithdrawal['amount'];
+        $fBalance = $this->getProfileBalance($iProfileId);
+        if($fAmount > $fBalance)
+            return ['code' => 3, 'msg' => '_bx_credits_err_low_balance'];
+
+        $sInfo = '_bx_credits_txt_history_info_withdraw';
+        $iHistoryId = $this->updateProfileBalance($iProfileId, 0, -$fAmount, BX_CREDITS_TRANSFER_TYPE_WITHDRAW, '', $sInfo);
+        if(!$iHistoryId)
+            return ['code' => 4, 'msg' => '_bx_credits_err_cannot_update_balance'];
+
+        $aHistory = $this->_oDb->getHistory(['type' => 'id', 'id' => $iHistoryId]);
+        
+        if(!$this->_oDb->updateWithdrawal(['performer_id' => $iUserId, 'order' => $aHistory['order'], 'confirmed' => time(), 'status' => BX_CREDITS_WITHDRAWAL_STATUS_CONFIRMED], ['id' => $iWithdrawalId]))
+            return $aResult;
+
+        sendMailTemplate($CNF['ETEMPLATE_WITHDRAW_SENT'], 0, $iProfileId, [
+            'amount' => $fAmount
+        ], BX_EMAIL_SYSTEM);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_credits-withdraw_sent 'bx_credits', 'withdraw_sent' - hook after the amount of credits requested to withdraw was sent
+         * - $unit_name - equals `bx_credits`
+         * - $action - equals `withdraw_sent`
+         * - $object_id - not used
+         * - $sender_id - performer profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `profile` - [int] performer profile id
+         *      - `amount` - [float] amount to withdraw
+         *      - `rate` - [float] withdraw conversion rate
+         * @hook @ref hook-bx_credits-withdraw_sent
+         */
+        bx_alert($this->getName(), 'withdraw_sent', $iWithdrawalId, $iUserId, [
+            'performer' => $iUserId,
+            'profile' => $iProfileId,
+            'amount' => $fAmount,
+        ]);
+
+        return ['code' => 0, 'id' => $iWithdrawalId];
+    }
+
+    public function processClearing()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aItems = $this->_oDb->getHistory(['type' => 'clearing', 'clearing' => $this->_oConfig->getWithdrawClearing()]);
+        if(empty($aItems) || !is_array($aItems))
+            return;
+
+        $iNow = time();
+        foreach($aItems as $aItem) {
+            $this->_oDb->updateHistory([$CNF['FIELD_H_CLEARED'] => $iNow], [$CNF['FIELD_H_ID'] => $aItem['id']]);
+
+            //TODO: Some action(s) related to clearing can be performed here.
+        }
+    }
+
+    /*
+     * Internal methods
+     */
+    protected function _serviceRegisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$aItem = $this->serviceGetCartItem($iItemId);
+        if(empty($aItem) || !is_array($aItem))
+            return array();
+
+        $aBundle = $this->_oDb->getBundle(array('type' => 'id', 'id' => $iItemId));
+        if(empty($aBundle) || !is_array($aBundle))
+            return array();
+
+        $iTrial = 0;
+        $sDuration = '';
+        $sAction = 'register';
+        if($sType == BX_CREDITS_ORDER_TYPE_RECURRING && isset($CNF['FIELD_DURATION_RECURRING'], $CNF['FIELD_TRIAL_RECURRING'])) {
+            $iTrial = $aBundle[$CNF['FIELD_TRIAL_RECURRING']];
+            $sDuration = $aBundle[$CNF['FIELD_DURATION_RECURRING']];
+
+            if($this->_oDb->isOrderByPbo($iClientId, $iItemId, $sOrder))
+                $sAction = 'prolong';
+        }
+
+        if(!$this->_oDb->{$sAction . 'Order'}($iClientId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType, $sDuration, $iTrial))
+            return array();
+
+        $sInfo = '_bx_credits_txt_history_info_purchase';
+        $fAmount = ((float)$aBundle[$CNF['FIELD_AMOUNT']] + (float)$aBundle[$CNF['FIELD_BONUS']]) * $iItemCount;
+        if(!$this->updateProfileBalance($iClientId, 0, $fAmount, BX_CREDITS_TRANSFER_TYPE_PURCHASE, '', $sInfo))
+            return array();
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_credits-order_register 'bx_credits', 'order_register' - hook after the payment for a bundle of credits was processed with payment processing module
+         * - $unit_name - equals `bx_credits`
+         * - $action - equals `order_register`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `profile_id` - [int] client (buyer) profile id
+         *      - `bundle_id` - [int] bundle id
+         *      - `product_id` - [int] bundle id
+         *      - `count` - [int] number of items in order
+         *      - `order` - [string] order number provided with payment processing module
+         *      - `license` - [string] license number provided with payment processing module
+         *      - `type` - [string] payment type ('single' or 'recurring'), current version supports 'single' type payments for bundles only
+         *      - `duration` - [string] isn't supported
+         *      - `trial` - [string] isn't supported
+         * @hook @ref hook-bx_credits-order_register
+         */
+        /**
+         * @hooks
+         * @hookdef hook-bx_credits-order_prolong 'bx_credits', 'order_prolong' - hook isn't currently used because 'single' type payments for bundles are only supported
+         * It's equivalent to @ref hook-bx_credits-order_register
+         * @hook @ref hook-bx_credits-order_prolong
+         */
+        bx_alert($this->getName(), 'order_' . $sAction, 0, false, [
+            'profile_id' => $iClientId,
+            'bundle_id' => $iItemId,
+            'product_id' => $iItemId,   //--- Alias for 'bundle_id'
+            'count' => $iItemCount,
+            'order' => $sOrder,
+            'license' => $sLicense,
+            'type' => $sType,
+            'duration' => $sDuration,
+            'trial' => $iTrial
+        ]);
+
+        $oClient = BxDolProfile::getInstanceMagic($iClientId);
+        $oSeller = BxDolProfile::getInstanceMagic($iSellerId);
+        $sSellerUrl = $oSeller->getUrl();
+        $sSellerName = $oSeller->getDisplayName();
+
+        sendMailTemplate($CNF['ETEMPLATE_PURCHASED'], 0, $iClientId, array(
+            'client_name' => $oClient->getDisplayName(),
+            'bundle_name' => $aBundle[$CNF['FIELD_NAME']],
+            'bundle_title' => _t($aBundle[$CNF['FIELD_TITLE']]),
+            'bundle_url' => $this->_oConfig->getBundleUrl($aBundle),
+            'vendor_url' => $sSellerUrl,
+            'vendor_name' => $sSellerName,
+            'order' => $sOrder,
+            'license' => $sLicense,
+            'notes' => _t('_bx_credits_txt_purchased_note', $sSellerUrl, $sSellerName),
+        ));
+
+        return $aItem;
+    }
+
+    protected function _serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aBundle = $this->_oDb->getBundle(array('type' => 'id', 'id' => $iItemId));
+        if(empty($aBundle) || !is_array($aBundle))
+            return false;
+
+        if(!$this->_oDb->unregisterOrder($iClientId, $iItemId, $sOrder, $sLicense, $sType))
+            return false;
+
+        $fAmount = (float)$aBundle[$CNF['FIELD_AMOUNT']] + (float)$aBundle[$CNF['FIELD_BONUS']];
+        $aProfile = $this->_oDb->getProfile(array('type' => 'id', 'id' => $iClientId));
+        if(!empty($aProfile) && is_array($aProfile))
+            $this->_oDb->updateProfile(array('balance' => (float)$aProfile['balance'] - $fAmount), array('id' => $aProfile['id']));
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_credits-order_unregister 'bx_credits', 'order_unregister' - hook after the payment for a bundle of credits was refunded with payment processing module
+         * - $unit_name - equals `bx_credits`
+         * - $action - equals `order_unregister`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `profile_id` - [int] client (buyer) profile id
+         *      - `bundle_id` - [int] bundle id
+         *      - `product_id` - [int] bundle id
+         *      - `count` - [int] number of items in order
+         *      - `order` - [string] order number provided with payment processing module
+         *      - `license` - [string] license number provided with payment processing module
+         *      - `type` - [string] payment type ('single' or 'recurring'), current version supports 'single' type payments for bundles only
+         * @hook @ref hook-bx_credits-order_unregister
+         */
+        bx_alert($this->getName(), 'order_unregister', 0, false, [
+            'profile_id' => $iClientId,
+            'bundle_id' => $iItemId,
+            'product_id' => $iItemId,   //--- Alias for 'bundle_id'
+            'count' => $iItemCount,
+            'order' => $sOrder,
+            'license' => $sLicense,
+            'type' => $sType,
+        ]);
+
+        return true;
+    }
+
+    protected function _getBlockOrders($sType) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sGrid = $CNF['OBJECT_GRID_ORDERS_' . strtoupper($sType)];
+        $oGrid = BxDolGrid::getObjectInstance($sGrid);
+        if(!$oGrid)
+            return '';
+
+        return [
+            'content' => $oGrid->getCode(),
+            'menu' => $CNF['OBJECT_MENU_MANAGE_SUBMENU']
+        ];
+    }
+
+    protected function _getBlockHistory($sType) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sGrid = $CNF['OBJECT_GRID_HISTORY_' . strtoupper($sType)];
+        $oGrid = BxDolGrid::getObjectInstance($sGrid);
+        if(!$oGrid)
+            return '';
+
+        return [
+            'content' => $oGrid->getCode(),
+            'menu' => $CNF['OBJECT_MENU_MANAGE_SUBMENU']
+        ];
+    }
+
+    protected function _getBlockWithdrawals($sType) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sGrid = $CNF['OBJECT_GRID_WITHDRAWALS_' . strtoupper($sType)];
+        $oGrid = BxDolGrid::getObjectInstance($sGrid);
+        if(!$oGrid)
+            return '';
+
+        return [
+            'content' => $oGrid->getCode(),
+            'menu' => $CNF['OBJECT_MENU_MANAGE_SUBMENU']
+        ];
+    }
+
+    protected function _getBlockProfiles($sType) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sKey = 'OBJECT_GRID_PROFILES_' . strtoupper($sType);
+        if(empty($CNF[$sKey]))
+            return '';
+
+        $sGrid = $CNF[$sKey];
+        $oGrid = BxDolGrid::getObjectInstance($sGrid);
+        if(!$oGrid)
+            return '';
+
+        return [
+            'content' => $oGrid->getCode(),
+            'menu' => $CNF['OBJECT_MENU_MANAGE_SUBMENU']
+        ];
+    }
+}
+
+/** @} */

+ 34 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/classes/BxCreditsPageWithdrawals.php

@@ -0,0 +1,34 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Credits Credits
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Profile's withdrawals page.
+ */
+class BxCreditsPageWithdrawals extends BxTemplPage
+{
+    protected $_sModule;
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_credits';
+
+        parent::__construct($aObject, $oTemplate);
+
+        if(($oMenuSubmenu = BxDolMenu::getObjectInstance('sys_site_submenu')) !== false) {
+            $sMenuSubmenu = 'sys_account_dashboard';
+            $oMenuSubmenu->setObjectSubmenu($sMenuSubmenu, array('title' => _t('_sys_menu_item_title_account_dashboard'), 'link' => '', 'icon' => ''));
+
+            BxDolMenu::getObjectInstance($sMenuSubmenu)->setSelected($this->_sModule, 'credits-manage');
+        }
+    }
+}
+
+/** @} */

+ 77 - 0
modules/boonex/credits/updates/14.0.2_14.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    Credits Credits
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_credits',
+    'title' => 'Credits',
+    'note' => 'Credits module.',
+    'version' => '14.0.3',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/credits/',
+    'home_uri' => 'credits',
+
+    'db_prefix' => 'bx_credits_',
+    'class_prefix' => 'BxCredits',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Credits',
+
+    /**
+     * 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(),
+
+    /**
+     * Relations Section
+     */
+    'relations' => array(),
+
+);
+
+/** @} */

+ 344 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/install/langs/en.xml

@@ -0,0 +1,344 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string name="_bx_credits"><![CDATA[Credits]]></string>
+
+
+    <!-- Options -->
+    <string name="_bx_credits_option_enable_withdraw"><![CDATA[Allow members to withdraw credits converting them to money]]></string>
+    <string name="_bx_credits_option_withdraw_email"><![CDATA[Email for withdraw requests]]></string>
+    <string name="_bx_credits_option_withdraw_clearing"><![CDATA[Clearing period (in days) before received credits can be withdrawn]]></string>
+    <string name="_bx_credits_option_withdraw_minimum"><![CDATA[Minimum amount of cleared credits which can be withdrawn]]></string>
+    <string name="_bx_credits_option_withdraw_remaining"><![CDATA[Minimum credits balance after withdrawal]]></string>
+    <string name="_bx_credits_option_precision"><![CDATA[Precision (number of digits after the decimal point)]]></string>
+    <string name="_bx_credits_option_conversion_rate_use"><![CDATA[Conversion rate to pay with credits (for site currency)]]></string>
+    <string name="_bx_credits_option_conversion_rate_withdraw"><![CDATA[Conversion rate to withdraw credits (for site currency)]]></string>
+    <string name="_bx_credits_option_code"><![CDATA[Code to prefix amount]]></string>
+    <string name="_bx_credits_option_icon"><![CDATA[Icon to prefix amount]]></string>
+    <string name="_bx_credits_enable_provider"><![CDATA[Auto activate 'Credits' provider for all newly created profiles]]></string>
+
+
+    <!-- Forms -->
+    <string name="_bx_credits_form_bundle"><![CDATA[Bundle]]></string>
+    <string name="_bx_credits_form_bundle_display_add"><![CDATA[Add Bundle]]></string>
+    <string name="_bx_credits_form_bundle_display_edit"><![CDATA[Edit Bundle]]></string>
+    <string name="_bx_credits_form_bundle_input_sys_title"><![CDATA[Title]]></string>
+    <string name="_bx_credits_form_bundle_input_title"><![CDATA[Title]]></string>
+    <string name="_bx_credits_form_bundle_input_title_err"><![CDATA[This field is essential. Please fill it in for all languages.]]></string>
+    <string name="_bx_credits_form_bundle_input_sys_description"><![CDATA[Description]]></string>
+    <string name="_bx_credits_form_bundle_input_description"><![CDATA[Description]]></string>
+    <string name="_bx_credits_form_bundle_input_sys_name"><![CDATA[Name]]></string>
+    <string name="_bx_credits_form_bundle_input_name"><![CDATA[Name]]></string>
+    <string name="_bx_credits_form_bundle_input_name_err"><![CDATA[This field is essential for API calls. Please fill it in.]]></string>
+    <string name="_bx_credits_form_bundle_input_sys_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_credits_form_bundle_input_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_credits_form_bundle_input_amount_err"><![CDATA[This field is essential. Please fill it in.]]></string>
+    <string name="_bx_credits_form_bundle_input_sys_bonus"><![CDATA[Bonus]]></string>
+    <string name="_bx_credits_form_bundle_input_bonus"><![CDATA[Bonus]]></string>
+    <string name="_bx_credits_form_bundle_input_sys_price"><![CDATA[Price]]></string>
+    <string name="_bx_credits_form_bundle_input_price"><![CDATA[Price]]></string>
+    <string name="_bx_credits_form_bundle_input_price_err"><![CDATA[This field is essential. Please fill it in.]]></string>
+    <string name="_bx_credits_form_bundle_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_credits_form_bundle_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_credits_form_bundle_input_sys_do_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_credits_form_bundle_input_do_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_credits_form_credit"><![CDATA[Credit]]></string>
+    <string name="_bx_credits_form_credit_display_grant"><![CDATA[Grant]]></string>
+    <string name="_bx_credits_form_credit_display_send"><![CDATA[Send]]></string>
+    <string name="_bx_credits_form_credit_display_withdraw_request"><![CDATA[Request Withdrawal]]></string>
+    <string name="_bx_credits_form_credit_input_sys_balance"><![CDATA[Balance]]></string>
+    <string name="_bx_credits_form_credit_input_balance"><![CDATA[Balance]]></string>
+    <string name="_bx_credits_form_credit_input_sys_cleared"><![CDATA[Cleared Balance]]></string>
+    <string name="_bx_credits_form_credit_input_cleared"><![CDATA[Cleared Balance]]></string>
+    <string name="_bx_credits_form_credit_input_cleared_inf"><![CDATA[Clearing period is {wdw_clearing} days before received credits can be withdrawn.]]></string>
+    <string name="_bx_credits_form_credit_input_sys_rate"><![CDATA[Conversion rate]]></string>
+    <string name="_bx_credits_form_credit_input_rate"><![CDATA[Conversion rate]]></string>
+    <string name="_bx_credits_form_credit_input_sys_result"><![CDATA[Result]]></string>
+    <string name="_bx_credits_form_credit_input_result"><![CDATA[Result]]></string>
+    <string name="_bx_credits_form_credit_input_sys_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_credits_form_credit_input_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_credits_form_credit_input_amount_inf"><![CDATA[Minimum amount is {wdw_minimum} credits and remaining balance after withdrawal should be {wdw_remaining} credits.]]></string>
+    <string name="_bx_credits_form_credit_input_amount_err"><![CDATA[This field is essential. Please fill it in.]]></string>
+    <string name="_bx_credits_form_credit_input_sys_message"><![CDATA[Message]]></string>
+    <string name="_bx_credits_form_credit_input_message"><![CDATA[Message]]></string>
+    <string name="_bx_credits_form_credit_input_message_inf_g"><![CDATA[]]></string>
+    <string name="_bx_credits_form_credit_input_message_inf_s"><![CDATA[Indicate the purpose of sending to reflect it in history for future references]]></string>
+    <string name="_bx_credits_form_credit_input_message_inf_wr"><![CDATA[Payment instructions and other notes]]></string>
+    <string name="_bx_credits_form_credit_input_message_inf_wc"><![CDATA[Payment confirmation and other notes]]></string>
+    <string name="_bx_credits_form_credit_input_profile"><![CDATA[Profile]]></string>
+    <string name="_bx_credits_form_credit_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_credits_form_credit_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_credits_form_credit_input_sys_do_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_credits_form_credit_input_do_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_credits_form_profile"><![CDATA[Profile]]></string>
+    <string name="_bx_credits_form_profile_display_edit"><![CDATA[Edit Profile]]></string>
+    <string name="_bx_credits_form_profile_input_sys_wdw_clearing"><![CDATA[Clearing period]]></string>
+    <string name="_bx_credits_form_profile_input_wdw_clearing"><![CDATA[Clearing period (in days)]]></string>
+    <string name="_bx_credits_form_profile_input_wdw_clearing_inf"><![CDATA[Leave empty (0) to use global value]]></string>
+    <string name="_bx_credits_form_profile_input_sys_wdw_minimum"><![CDATA[Minimum withdrawal amount]]></string>
+    <string name="_bx_credits_form_profile_input_wdw_minimum"><![CDATA[Minimum withdrawal amount]]></string>
+    <string name="_bx_credits_form_profile_input_wdw_minimum_inf"><![CDATA[Leave empty (0) to use global value]]></string>
+    <string name="_bx_credits_form_profile_input_sys_wdw_remaining"><![CDATA[Minimum remaining amount]]></string>
+    <string name="_bx_credits_form_profile_input_wdw_remaining"><![CDATA[Minimum remaining amount]]></string>
+    <string name="_bx_credits_form_profile_input_wdw_remaining_inf"><![CDATA[Leave empty (0) to use global value]]></string>
+    <string name="_bx_credits_form_profile_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_credits_form_profile_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_credits_form_profile_input_sys_do_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_credits_form_profile_input_do_cancel"><![CDATA[Cancel]]></string>
+
+
+    <!-- Pages -->
+    <string name="_bx_credits_page_title_sys_home"><![CDATA[Credits]]></string>
+    <string name="_bx_credits_page_title_home"><![CDATA[Credits]]></string>
+    <string name="_bx_credits_page_block_title_sys_bundles"><![CDATA[Credits]]></string>
+    <string name="_bx_credits_page_block_title_bundles"><![CDATA[Credits]]></string>
+    <string name="_bx_credits_page_title_sys_checkout"><![CDATA[Checkout]]></string>
+    <string name="_bx_credits_page_title_checkout"><![CDATA[Checkout]]></string>
+    <string name="_bx_credits_page_block_title_sys_checkout"><![CDATA[Checkout]]></string>
+    <string name="_bx_credits_page_block_title_checkout"><![CDATA[Checkout]]></string>
+    <string name="_bx_credits_page_title_sys_history_common"><![CDATA[My History]]></string>
+    <string name="_bx_credits_page_title_history_common"><![CDATA[History]]></string>
+    <string name="_bx_credits_page_block_title_sys_history_common"><![CDATA[My History]]></string>
+    <string name="_bx_credits_page_block_title_history_common"><![CDATA[History]]></string>    
+    <string name="_bx_credits_page_title_sys_history_administration"><![CDATA[All History]]></string>
+    <string name="_bx_credits_page_title_history_administration"><![CDATA[History]]></string>
+    <string name="_bx_credits_page_block_title_sys_history_administration"><![CDATA[All History]]></string>
+    <string name="_bx_credits_page_block_title_history_administration"><![CDATA[History]]></string>
+    <string name="_bx_credits_page_title_sys_orders_common"><![CDATA[My Orders]]></string>
+    <string name="_bx_credits_page_title_orders_common"><![CDATA[Orders]]></string>
+    <string name="_bx_credits_page_block_title_sys_orders_common_note"><![CDATA[Note]]></string>
+    <string name="_bx_credits_page_block_title_orders_common_note"><![CDATA[Note]]></string>
+    <string name="_bx_credits_page_block_content_orders_common_note"><![CDATA[The orders are for reference only.]]></string>
+    <string name="_bx_credits_page_block_title_sys_orders_common"><![CDATA[My Orders]]></string>
+    <string name="_bx_credits_page_block_title_orders_common"><![CDATA[Orders]]></string>
+    <string name="_bx_credits_page_title_sys_orders_administration"><![CDATA[All Orders]]></string>
+    <string name="_bx_credits_page_title_orders_administration"><![CDATA[Orders]]></string>
+    <string name="_bx_credits_page_block_title_sys_orders_administration"><![CDATA[All Orders]]></string>
+    <string name="_bx_credits_page_block_title_orders_administration"><![CDATA[Orders]]></string>
+    <string name="_bx_credits_page_title_sys_withdrawals_common"><![CDATA[My Withdrawals]]></string>
+    <string name="_bx_credits_page_title_withdrawals_common"><![CDATA[Withdrawals]]></string>
+    <string name="_bx_credits_page_block_title_sys_withdrawals_common"><![CDATA[My Withdrawals]]></string>
+    <string name="_bx_credits_page_block_title_withdrawals_common"><![CDATA[Withdrawals]]></string>    
+    <string name="_bx_credits_page_title_sys_withdrawals_administration"><![CDATA[All Withdrawals]]></string>
+    <string name="_bx_credits_page_title_withdrawals_administration"><![CDATA[Withdrawals]]></string>
+    <string name="_bx_credits_page_block_title_sys_withdrawals_administration"><![CDATA[All Withdrawals]]></string>
+    <string name="_bx_credits_page_block_title_withdrawals_administration"><![CDATA[Withdrawals]]></string>
+    <string name="_bx_credits_page_title_sys_profiles_administration"><![CDATA[All Profiles]]></string>
+    <string name="_bx_credits_page_title_profiles_administration"><![CDATA[Profiles]]></string>
+    <string name="_bx_credits_page_block_title_sys_profiles_administration"><![CDATA[All Profiles]]></string>
+    <string name="_bx_credits_page_block_title_profiles_administration"><![CDATA[Profiles]]></string>
+
+
+    <!-- Menus -->
+    <string name="_bx_credits_menu_item_title_system_credits"><![CDATA[Credits]]></string>
+    <string name="_bx_credits_menu_item_title_credits"><![CDATA[Credits]]></string>
+    <string name="_bx_credits_menu_item_title_system_history"><![CDATA[Balance]]></string>
+    <string name="_bx_credits_menu_item_title_history"><![CDATA[{unit}{value}]]></string>
+    <string name="_bx_credits_menu_item_title_system_notifications"><![CDATA[Balance]]></string>
+    <string name="_bx_credits_menu_item_title_notifications"><![CDATA[{value}]]></string>
+    <string name="_bx_credits_menu_title_submenu"><![CDATA[Credits Submenu]]></string>
+    <string name="_bx_credits_menu_set_title_submenu"><![CDATA[Credits Submenu]]></string>
+    <string name="_bx_credits_menu_item_title_system_home"><![CDATA[Home]]></string>
+    <string name="_bx_credits_menu_item_title_home"><![CDATA[Home]]></string>
+    <string name="_bx_credits_menu_item_title_system_admt_credits"><![CDATA[Credits]]></string>
+    <string name="_bx_credits_menu_item_title_admt_credits"><![CDATA[Credits]]></string>
+    <string name="_bx_credits_menu_item_title_bundles"><![CDATA[Bundles]]></string>
+    <string name="_bx_credits_menu_item_title_system_manage"><![CDATA[Credits]]></string>
+    <string name="_bx_credits_menu_item_title_manage"><![CDATA[Credits]]></string>
+    <string name="_bx_credits_menu_title_manage_submenu"><![CDATA[Orders Submenu]]></string>
+    <string name="_bx_credits_menu_set_title_manage_submenu"><![CDATA[Orders Submenu]]></string>
+    <string name="_bx_credits_menu_item_title_system_orders_administration"><![CDATA[All Orders]]></string>
+    <string name="_bx_credits_menu_item_title_orders_administration"><![CDATA[All Orders]]></string>
+    <string name="_bx_credits_menu_item_title_system_orders_common"><![CDATA[My Orders]]></string>
+    <string name="_bx_credits_menu_item_title_orders_common"><![CDATA[My Orders]]></string>
+    <string name="_bx_credits_menu_item_title_system_history_administration"><![CDATA[All History]]></string>
+    <string name="_bx_credits_menu_item_title_history_administration"><![CDATA[All History]]></string>
+    <string name="_bx_credits_menu_item_title_system_history_common"><![CDATA[My History]]></string>
+    <string name="_bx_credits_menu_item_title_history_common"><![CDATA[My History]]></string>
+    <string name="_bx_credits_menu_item_title_system_withdrawals_administration"><![CDATA[All Withdrawals]]></string>
+    <string name="_bx_credits_menu_item_title_withdrawals_administration"><![CDATA[All Withdrawals]]></string>
+    <string name="_bx_credits_menu_item_title_system_withdrawals_common"><![CDATA[My Withdrawals]]></string>
+    <string name="_bx_credits_menu_item_title_withdrawals_common"><![CDATA[My Withdrawals]]></string>
+    <string name="_bx_credits_menu_item_title_system_profiles_administration"><![CDATA[All Profiles]]></string>
+    <string name="_bx_credits_menu_item_title_profiles_administration"><![CDATA[All Profiles]]></string>
+
+
+    <!-- Grids -->
+    <string name="_bx_credits_grid_column_title_name"><![CDATA[Name]]></string>
+    <string name="_bx_credits_grid_column_title_title"><![CDATA[Title]]></string>
+    <string name="_bx_credits_grid_column_title_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_credits_grid_column_title_bonus"><![CDATA[Bonus]]></string>
+    <string name="_bx_credits_grid_column_title_price"><![CDATA[Price]]></string>
+    <string name="_bx_credits_grid_action_title_add"><![CDATA[Add]]></string>
+    <string name="_bx_credits_grid_action_title_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_credits_grid_action_title_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_credits_grid_popup_title_add_bundle"><![CDATA[Add Bundle]]></string>
+    <string name="_bx_credits_grid_popup_title_edit_bundle"><![CDATA[Edit '{0}' Bundle]]></string>
+
+    <string name="_bx_credits_grid_column_title_htr_pid"><![CDATA[Profile]]></string>
+    <string name="_bx_credits_grid_column_title_htr_first_pid"><![CDATA[Profile 1]]></string>
+    <string name="_bx_credits_grid_column_title_htr_second_pid"><![CDATA[Profile 2]]></string>
+    <string name="_bx_credits_grid_column_title_htr_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_credits_grid_column_title_htr_order"><![CDATA[Order]]></string>
+    <string name="_bx_credits_grid_column_title_htr_direction"><![CDATA[Direction]]></string>
+    <string name="_bx_credits_grid_column_title_htr_info"><![CDATA[Notice]]></string>
+    <string name="_bx_credits_grid_column_title_htr_date"><![CDATA[Date]]></string>
+    <string name="_bx_credits_grid_column_title_htr_cleared"><![CDATA[Clearing]]></string>
+    <string name="_bx_credits_grid_action_title_htr_grant"><![CDATA[Grant]]></string>
+    <string name="_bx_credits_grid_action_title_htr_send"><![CDATA[Send]]></string>
+    <string name="_bx_credits_grid_popup_title_htr_grant"><![CDATA[Grant]]></string>
+    <string name="_bx_credits_grid_popup_title_htr_send"><![CDATA[Send]]></string>
+
+    <string name="_bx_credits_grid_column_title_ord_profile_id"><![CDATA[Profile]]></string>
+    <string name="_bx_credits_grid_column_title_ord_bundle"><![CDATA[Bundle]]></string>
+    <string name="_bx_credits_grid_column_title_ord_transaction"><![CDATA[Transaction]]></string>
+    <string name="_bx_credits_grid_column_title_ord_type"><![CDATA[Type]]></string>
+    <string name="_bx_credits_grid_column_value_ord_type_single"><![CDATA[Single]]></string>
+    <string name="_bx_credits_grid_column_value_ord_type_recurring"><![CDATA[Recurring]]></string>
+    <string name="_bx_credits_grid_column_title_ord_added"><![CDATA[Added]]></string>
+    <string name="_bx_credits_grid_column_title_ord_expired"><![CDATA[Expires]]></string>
+
+    <string name="_bx_credits_grid_column_title_wdw_profile_id"><![CDATA[Profile]]></string>
+    <string name="_bx_credits_grid_column_title_wdw_performer_id"><![CDATA[Performer]]></string>
+    <string name="_bx_credits_grid_column_title_wdw_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_credits_grid_column_title_wdw_rate"><![CDATA[Rate]]></string>
+    <string name="_bx_credits_grid_column_title_wdw_message"><![CDATA[Message]]></string>
+    <string name="_bx_credits_grid_column_title_wdw_order"><![CDATA[Order]]></string>
+    <string name="_bx_credits_grid_column_title_wdw_added"><![CDATA[Added]]></string>
+    <string name="_bx_credits_grid_column_title_wdw_confirmed"><![CDATA[Confirmed]]></string>
+    <string name="_bx_credits_grid_column_title_wdw_status"><![CDATA[Status]]></string>
+    <string name="_bx_credits_grid_action_title_wdw_withdraw_confirm"><![CDATA[Confirm withdrawal]]></string>
+    <string name="_bx_credits_grid_action_title_wdw_withdraw_cancel"><![CDATA[Cancel withdrawal request]]></string>
+    <string name="_bx_credits_grid_action_title_wdw_withdraw_request"><![CDATA[Request withdrawal]]></string>
+    <string name="_bx_credits_grid_popup_title_wdw_withdraw_request"><![CDATA[Request withdrawal]]></string>
+
+    <string name="_bx_credits_grid_column_title_pfl_id"><![CDATA[Profile]]></string>
+    <string name="_bx_credits_grid_column_title_pfl_wdw_clearing"><![CDATA[Clearing period (in days)]]></string>
+    <string name="_bx_credits_grid_column_title_pfl_wdw_minimum"><![CDATA[Min withdrawal amount]]></string>
+    <string name="_bx_credits_grid_column_title_pfl_wdw_remaining"><![CDATA[Min remaining amount]]></string>
+    <string name="_bx_credits_grid_column_title_pfl_balance"><![CDATA[Balance]]></string>
+    <string name="_bx_credits_grid_column_title_pfl_balance_cleared"><![CDATA[Cleared balance]]></string>
+    <string name="_bx_credits_grid_action_title_pfl_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_credits_grid_popup_title_pfl_edit"><![CDATA[Edit '{0}' Profile's Limitations]]></string>
+
+    <!-- Email templates -->
+    <string name="_bx_credits_et_txt_name_granted"><![CDATA[Credits granted.]]></string>
+    <string name="_bx_credits_et_txt_subject_granted"><![CDATA[You're granted {amount} credits.]]></string>
+    <string name="_bx_credits_et_txt_body_granted"><![CDATA[{email_header}
+<p>Hello, {profile_name}.</p>
+<p>You're granted <b>{amount}</b> credits.</p>
+<p>{message}</p>
+{email_footer}]]></string>
+    <string name="_bx_credits_et_txt_name_received"><![CDATA[Credits received.]]></string>
+    <string name="_bx_credits_et_txt_subject_received"><![CDATA[You've received {amount} credits.]]></string>
+    <string name="_bx_credits_et_txt_body_received"><![CDATA[{email_header}
+<p>Hello, {profile_name}.</p>
+<p>You've received <b>{amount}</b> credits from <a href="{performer_link}">{performer_name}</a>.<br />The order is <b>{order}</b>.</p>
+<p>{message}</p>
+{email_footer}]]></string>
+    <string name="_bx_credits_et_txt_name_purchased"><![CDATA[Credits purchased.]]></string>
+    <string name="_bx_credits_et_txt_subject_purchased"><![CDATA[You've purchased {bundle_title} credits bundle.]]></string>
+    <string name="_bx_credits_et_txt_body_purchased"><![CDATA[{email_header}
+<p>Hello, {client_name}.</p>
+<p>You've purchased <a href="{bundle_url}">{bundle_title}</a> credits bundle.<br />Your order is <b>{order}</b>.</p>
+<p>{notes}</p>
+{email_footer}]]></string>
+    <string name="_bx_credits_et_txt_name_in"><![CDATA[Credits in.]]></string>
+    <string name="_bx_credits_et_txt_subject_in"><![CDATA[Credits in.]]></string>
+    <string name="_bx_credits_et_txt_body_in"><![CDATA[{email_header}
+<p>Hello, {profile_name}.</p>
+<p>You've received <b>{amount}</b> credits from {second_profile_name}.</p>
+{email_footer}]]></string>
+    <string name="_bx_credits_et_txt_name_out"><![CDATA[Credits out.]]></string>
+    <string name="_bx_credits_et_txt_subject_out"><![CDATA[Credits out.]]></string>
+    <string name="_bx_credits_et_txt_body_out"><![CDATA[{email_header}
+<p>Hello, {profile_name}.</p>
+<p>You've sent <b>{amount}</b> credits to {second_profile_name}.</p>
+{email_footer}]]></string>
+    <string name="_bx_credits_et_txt_name_withdraw_requested"><![CDATA[Withdrawal request.]]></string>
+    <string name="_bx_credits_et_txt_subject_withdraw_requested"><![CDATA[Withdrawal request.]]></string>
+    <string name="_bx_credits_et_txt_body_withdraw_requested"><![CDATA[{email_header}
+<p><a href="{profile_link}">{profile_name}</a> requested to withdraw <b>{amount}</b> credits from his/her balance.</p>
+<p>Current withdrawal conversion rate is <b>{rate}</b></p>
+<p>Withdrawal can be confirmed <a href="{confirm_url}">here</a>.</p>
+<p>Notes from <b>{profile_name}</b>:<br />{message}</p>
+{email_footer}]]></string>
+    <string name="_bx_credits_et_txt_name_withdraw_canceled"><![CDATA[Withdrawal request canceled.]]></string>
+    <string name="_bx_credits_et_txt_subject_withdraw_canceled"><![CDATA[Withdrawal request canceled.]]></string>
+    <string name="_bx_credits_et_txt_body_withdraw_canceled"><![CDATA[{email_header}
+<p><a href="{profile_link}">{profile_name}</a> canceled his/her withdrawal request for <b>{amount}</b> credits.</p>
+<p>The canceled withdrawal request can be seen <a href="{manage_url}">here</a>.</p>
+{email_footer}]]></string>
+    <string name="_bx_credits_et_txt_name_withdraw_sent"><![CDATA[Withdraw was sent.]]></string>
+    <string name="_bx_credits_et_txt_subject_withdraw_sent"><![CDATA[Withdraw was sent.]]></string>
+    <string name="_bx_credits_et_txt_body_withdraw_sent"><![CDATA[{email_header}
+<p>Hello, {profile_name}.</p>
+<p>The requested amount of credits (<b>{amount}</b>) was withdrawn to you.</p>
+{email_footer}]]></string>
+
+
+    <!-- Other -->
+    <string name="_bx_credits_txt_sample_single"><![CDATA[credit]]></string>
+    <string name="_bx_credits_txt_sample_single_with_article"><![CDATA[a credit]]></string>
+    <string name="_bx_credits_txt_for_free"><![CDATA[for Free]]></string>
+    <string name="_bx_credits_txt_n_plus_m_for_free"><![CDATA[{0} (+{1} for free)]]></string>
+    <string name="_bx_credits_txt_purchase"><![CDATA[Purchase]]></string>
+    <string name="_bx_credits_txt_never"><![CDATA[never]]></string>
+    <string name="_bx_credits_txt_direction_out"><![CDATA[sent to]]></string>
+    <string name="_bx_credits_txt_direction_in"><![CDATA[got from]]></string>
+    <string name="_bx_credits_txt_purchased_note"><![CDATA[Contact <a href="{0}">{1}</a> if you have any questions or need support.]]></string>
+    <string name="_bx_credits_txt_history_info_grant"><![CDATA[Grant]]></string>
+    <string name="_bx_credits_txt_history_info_send"><![CDATA[Transfer]]></string>
+    <string name="_bx_credits_txt_history_info_purchase"><![CDATA[Bundle purchase]]></string>
+    <string name="_bx_credits_txt_history_info_checkout"><![CDATA[Profile to profile checkout]]></string>
+    <string name="_bx_credits_txt_history_info_withdraw"><![CDATA[Withdrawal by request]]></string>
+    <string name="_bx_credits_txt_history_info_service"><![CDATA[Artificially initiated transfer]]></string>
+    <string name="_bx_credits_txt_history_info_refund"><![CDATA[Refund]]></string>
+    <string name="_bx_credits_txt_history_info_cancellation"><![CDATA[Cancellation]]></string>
+    <string name="_bx_credits_txt_withdrawal_status_requested"><![CDATA[Requested]]></string>
+    <string name="_bx_credits_txt_withdrawal_status_canceled"><![CDATA[Canceled]]></string>
+    <string name="_bx_credits_txt_withdrawal_status_confirmed"><![CDATA[Confirmed]]></string>
+
+
+    <string name="_bx_credits_msg_empty_author"><![CDATA['Main seller' is empty. You need to mark some profile as 'Main seller' in Settings of currently active Payment app.]]></string>
+    <string name="_bx_credits_msg_action_performed"><![CDATA[The action was performed successfully.]]></string>
+    <string name="_bx_credits_msg_action_withdrawals_disabled"><![CDATA[Withdrawals are disabled.]]></string>
+    <string name="_bx_credits_err_profile_not_found"><![CDATA[Profile wasn't found.]]></string>
+    <string name="_bx_credits_err_login_required"><![CDATA[Login required.]]></string>
+    <string name="_bx_credits_err_low_balance"><![CDATA[Low balance.]]></string>
+    <string name="_bx_credits_err_withdrawal_not_found"><![CDATA[Withdrawal request wasn't found.]]></string>
+    <string name="_bx_credits_err_withdraw_minimum"><![CDATA[Withdrawal less then {0} credits isn't available.]]></string>
+    <string name="_bx_credits_err_withdraw_remaining"><![CDATA[Minimum remaining balance after withdrawal should be more then {0} credits.]]></string>
+    <string name="_bx_credits_err_cannot_update_balance"><![CDATA[Cannot update balance.]]></string>
+    <string name="_bx_credits_err_cannot_send"><![CDATA[Cannot send message. Please report.]]></string>
+    <string name="_bx_credits_err_cannot_cancel_withdrawal"><![CDATA[Cannot cancel withdrawal request. Please report.]]></string>
+    <string name="_bx_credits_err_cannot_perform_action"><![CDATA[Cannot perform the action. Please report.]]></string>
+
+
+    <!-- Checkout process -->
+    <string name="_bx_credits_txt_checkout"><![CDATA[Checkout]]></string>
+    <string name="_bx_credits_txt_checkout_to"><![CDATA[Pay to {0} for:]]></string>
+    <string name="_bx_credits_txt_checkout_price_money"><![CDATA[Price:]]></string>
+    <string name="_bx_credits_txt_checkout_price_credits"><![CDATA[In Credits:]]></string>
+    <string name="_bx_credits_txt_checkout_rate"><![CDATA[Rate:]]></string>
+    <string name="_bx_credits_txt_checkout_qt"><![CDATA[qt.]]></string>
+
+    <!-- Subscribe process -->
+    <string name="_bx_credits_txt_subscribe"><![CDATA[Subscribe]]></string>
+    <string name="_bx_credits_txt_subscribe_for"><![CDATA[Subscribe for:]]></string>
+    <string name="_bx_credits_txt_subscribe_lifetime"><![CDATA[lifetime]]></string>    
+    <string name="_bx_credits_txt_subscribe_period_mask"><![CDATA[{0} {1}]]></string>
+    <string name="_bx_credits_txt_subscribe_period_unit_year"><![CDATA[yr.]]></string>
+    <string name="_bx_credits_txt_subscribe_period_unit_month"><![CDATA[mo.]]></string>
+    <string name="_bx_credits_txt_subscribe_period_unit_week"><![CDATA[wk.]]></string>
+    <string name="_bx_credits_txt_subscribe_period_unit_day"><![CDATA[d.]]></string>
+    <string name="_bx_credits_txt_subscribe_period_unit_hour"><![CDATA[hr.]]></string>
+    <string name="_bx_credits_txt_subscribe_period_unit_minute"><![CDATA[min.]]></string>
+    <string name="_bx_credits_txt_subscribe_trial"><![CDATA[Trial:]]></string>
+    <string name="_bx_credits_txt_subscribe_trial_mask"><![CDATA[{0} {1}]]></string>
+
+    <string name="_bx_credits_err_unknown_buyer"><![CDATA[Login required.]]></string>
+    <string name="_bx_credits_err_unknown_seller"><![CDATA[Unknown seller.]]></string>
+    <string name="_bx_credits_err_incorrect_data"><![CDATA[Incorrect input data. Please report.]]></string>
+</resources>

+ 32 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/install/sql/disable.sql

@@ -0,0 +1,32 @@
+
+-- SETTINGS
+SET @iTypeId = (SELECT `ID` FROM `sys_options_types` WHERE `name` = 'bx_credits' LIMIT 1);
+SET @iCategId = (SELECT `ID` FROM `sys_options_categories` WHERE `type_id` = @iTypeId LIMIT 1);
+DELETE FROM `sys_options` WHERE `category_id` = @iCategId;
+DELETE FROM `sys_options_categories` WHERE `type_id` = @iTypeId;
+DELETE FROM `sys_options_types` WHERE `id` = @iTypeId;
+
+-- PAGES
+DELETE FROM `sys_objects_page` WHERE `module` = 'bx_credits';
+DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_credits' OR `object` IN ('bx_credits_home', 'bx_credits_checkout', 'bx_credits_orders_common', 'bx_credits_orders_administration', 'bx_credits_history_common', 'bx_credits_history_administration', 'bx_credits_withdrawals_common', 'bx_credits_withdrawals_administration');
+
+-- MENU
+DELETE FROM `sys_objects_menu` WHERE `module` = 'bx_credits';
+DELETE FROM `sys_menu_sets` WHERE `module` = 'bx_credits';
+DELETE FROM `sys_menu_items` WHERE `module` = 'bx_credits' OR `set_name` IN ('bx_credits_submenu', 'bx_credits_orders_submenu');
+
+-- GRIDS
+DELETE FROM `sys_objects_grid` WHERE `object` LIKE 'bx_credits_%';
+DELETE FROM `sys_grid_fields` WHERE `object` LIKE 'bx_credits_%';
+DELETE FROM `sys_grid_actions` WHERE `object` LIKE 'bx_credits_%';
+
+-- ALERTS
+SET @iHandler := (SELECT `id` FROM `sys_alerts_handlers` WHERE `name` = 'bx_credits' LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `handler_id` = @iHandler;
+DELETE FROM `sys_alerts_handlers` WHERE `id` = @iHandler;
+
+-- EMAIL TEMPLATES
+DELETE FROM `sys_email_templates` WHERE `Module` = 'bx_credits';
+
+-- CRON
+DELETE FROM `sys_cron_jobs` WHERE `name` LIKE 'bx_credits_%';

+ 293 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/install/sql/enable.sql

@@ -0,0 +1,293 @@
+
+-- 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_credits', '_bx_credits', 'bx_credits@modules/boonex/credits/|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_credits', '_bx_credits', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_credits_enable_withdraw', '', @iCategId, '_bx_credits_option_enable_withdraw', 'checkbox', '', '', '', 1),
+('bx_credits_withdraw_email', '', @iCategId, '_bx_credits_option_withdraw_email', 'digit', '', '', '', 2),
+('bx_credits_withdraw_clearing', '30', @iCategId, '_bx_credits_option_withdraw_clearing', 'digit', '', '', '', 3),
+('bx_credits_withdraw_minimum', '500', @iCategId, '_bx_credits_option_withdraw_minimum', 'digit', '', '', '', 4),
+('bx_credits_withdraw_remaining', '100', @iCategId, '_bx_credits_option_withdraw_remaining', 'digit', '', '', '', 5),
+
+('bx_credits_precision', '2', @iCategId, '_bx_credits_option_precision', 'digit', '', '', '', 10),
+('bx_credits_conversion_rate_use', '1.0', @iCategId, '_bx_credits_option_conversion_rate_use', 'digit', '', '', '', 11),
+('bx_credits_conversion_rate_withdraw', '1.0', @iCategId, '_bx_credits_option_conversion_rate_withdraw', 'digit', '', '', '', 12),
+
+('bx_credits_code', '', @iCategId, '_bx_credits_option_code', 'digit', '', '', '', 20),
+('bx_credits_icon', 'copyright', @iCategId, '_bx_credits_option_icon', 'digit', '', '', '', 21),
+
+('bx_credits_enable_provider', '', @iCategId, '_bx_credits_enable_provider', 'checkbox', '', '', '', 30);
+
+
+-- PAGE: module home
+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_credits_home', 'credits-home', '_bx_credits_page_title_sys_home', '_bx_credits_page_title_home', 'bx_credits', 5, 2147483647, 1, 'page.php?i=credits-home', '', '', '', 0, 1, 0, 'BxCreditsPageBrowse', 'modules/boonex/credits/classes/BxCreditsPageBrowse.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_credits_home', 1, 'bx_credits', '_bx_credits_page_block_title_sys_bundles', '_bx_credits_page_block_title_bundles', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_credits";s:6:"method";s:17:"get_block_bundles";}', 0, 1, 1, 0);
+
+-- PAGE: checkout
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `type_id`, `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_credits_checkout', 'credits-checkout', '_bx_credits_page_title_sys_checkout', '_bx_credits_page_title_checkout', 'bx_credits', 2, 5, 2147483647, 1, 'page.php?i=credits-checkout', '', '', '', 0, 1, 0, 'BxCreditsPageBrowse', 'modules/boonex/credits/classes/BxCreditsPageBrowse.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_credits_checkout', 1, 'bx_credits', '_bx_credits_page_block_title_sys_checkout', '_bx_credits_page_block_title_checkout', 0, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_credits";s:6:"method";s:18:"get_block_checkout";}', 0, 0, 1, 0);
+
+-- PAGE: profile's orders
+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_credits_orders_common', '_bx_credits_page_title_sys_orders_common', '_bx_credits_page_title_orders_common', 'bx_credits', 5, 2147483647, 1, 'credits-orders-common', '', '', '', '', 0, 1, 0, 'BxCreditsPageOrders', 'modules/boonex/credits/classes/BxCreditsPageOrders.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_credits_orders_common', 1, 'bx_credits', '_bx_credits_page_block_title_sys_orders_common_note', '_bx_credits_page_block_title_orders_common_note', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_credits";s:6:"method";s:21:"get_block_orders_note";}', 0, 0, 1, 0),
+('bx_credits_orders_common', 1, 'bx_credits', '_bx_credits_page_block_title_sys_orders_common', '_bx_credits_page_block_title_orders_common', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_credits";s:6:"method";s:16:"get_block_orders";}', 0, 0, 1, 1);
+
+-- PAGE: orders administration
+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_credits_orders_administration', '_bx_credits_page_title_sys_orders_administration', '_bx_credits_page_title_orders_administration', 'bx_credits', 5, 192, 1, 'credits-orders-administration', '', '', '', '', 0, 1, 0, 'BxCreditsPageOrders', 'modules/boonex/credits/classes/BxCreditsPageOrders.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_credits_orders_administration', 1, 'bx_credits', '_bx_credits_page_block_title_sys_orders_administration', '_bx_credits_page_block_title_orders_administration', 11, 192, 'service', 'a:3:{s:6:"module";s:10:"bx_credits";s:6:"method";s:16:"get_block_orders";s:6:"params";a:1:{i:0;s:14:"administration";}}', 0, 0, 1, 0);
+
+-- PAGE: profile's history
+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_credits_history_common', '_bx_credits_page_title_sys_history_common', '_bx_credits_page_title_history_common', 'bx_credits', 5, 2147483647, 1, 'credits-history-common', 'page.php?i=credits-history-common', '', '', '', 0, 1, 0, 'BxCreditsPageHistory', 'modules/boonex/credits/classes/BxCreditsPageHistory.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_credits_history_common', 1, 'bx_credits', '_bx_credits_page_block_title_sys_history_common', '_bx_credits_page_block_title_history_common', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_credits";s:6:"method";s:17:"get_block_history";}}', 0, 1, 0);
+
+-- PAGE: history administration
+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_credits_history_administration', '_bx_credits_page_title_sys_history_administration', '_bx_credits_page_title_history_administration', 'bx_credits', 5, 192, 1, 'credits-history-administration', 'page.php?i=credits-history-administration', '', '', '', 0, 1, 0, 'BxCreditsPageHistory', 'modules/boonex/credits/classes/BxCreditsPageHistory.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_credits_history_administration', 1, 'bx_credits', '_bx_credits_page_block_title_sys_history_administration', '_bx_credits_page_block_title_history_administration', 11, 192, 'service', 'a:3:{s:6:"module";s:10:"bx_credits";s:6:"method";s:17:"get_block_history";s:6:"params";a:1:{i:0;s:14:"administration";}}', 0, 1, 0);
+
+-- PAGE: profile's withdrawals
+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_credits_withdrawals_common', '_bx_credits_page_title_sys_withdrawals_common', '_bx_credits_page_title_withdrawals_common', 'bx_credits', 5, 2147483647, 1, 'credits-withdrawals-common', 'page.php?i=credits-withdrawals-common', '', '', '', 0, 1, 0, 'BxCreditsPageWithdrawals', 'modules/boonex/credits/classes/BxCreditsPageWithdrawals.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_credits_withdrawals_common', 1, 'bx_credits', '_bx_credits_page_block_title_sys_withdrawals_common', '_bx_credits_page_block_title_withdrawals_common', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_credits";s:6:"method";s:21:"get_block_withdrawals";}}', 0, 1, 0);
+
+-- PAGE: withdrawals administration
+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_credits_withdrawals_administration', '_bx_credits_page_title_sys_withdrawals_administration', '_bx_credits_page_title_withdrawals_administration', 'bx_credits', 5, 192, 1, 'credits-withdrawals-administration', 'page.php?i=credits-withdrawals-administration', '', '', '', 0, 1, 0, 'BxCreditsPageWithdrawals', 'modules/boonex/credits/classes/BxCreditsPageWithdrawals.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_credits_withdrawals_administration', 1, 'bx_credits', '_bx_credits_page_block_title_sys_withdrawals_administration', '_bx_credits_page_block_title_withdrawals_administration', 11, 192, 'service', 'a:3:{s:6:"module";s:10:"bx_credits";s:6:"method";s:21:"get_block_withdrawals";s:6:"params";a:1:{i:0;s:14:"administration";}}', 0, 1, 0);
+
+-- PAGE: profiles administration
+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_credits_profiles_administration', '_bx_credits_page_title_sys_profiles_administration', '_bx_credits_page_title_profiles_administration', 'bx_credits', 5, 192, 1, 'credits-profiles-administration', 'page.php?i=credits-profiles-administration', '', '', '', 0, 1, 0, 'BxCreditsPageProfiles', 'modules/boonex/credits/classes/BxCreditsPageProfiles.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_credits_profiles_administration', 1, 'bx_credits', '_bx_credits_page_block_title_sys_profiles_administration', '_bx_credits_page_block_title_profiles_administration', 11, 192, 'service', 'a:3:{s:6:"module";s:10:"bx_credits";s:6:"method";s:18:"get_block_profiles";s:6:"params";a:1:{i:0;s:14:"administration";}}', 0, 1, 0);
+
+
+-- 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_credits', 'credits-home', '_bx_credits_menu_item_title_system_credits', '_bx_credits_menu_item_title_credits', 'page.php?i=credits-home', '', '', 'copyright col-green3', 'bx_credits_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_credits', 'credits-home', '_bx_credits_menu_item_title_system_credits', '_bx_credits_menu_item_title_credits', 'page.php?i=credits-home', '', '', 'copyright col-green3', 'bx_credits_submenu', 2147483647, 1, 1, IFNULL(@iHomepageMenuOrder, 0) + 1);
+
+-- MENU: member toolbar
+SET @iMenuToolbarMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_toolbar_member' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `markers`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_toolbar_member', 'bx_credits', 'credits-history', '_bx_credits_menu_item_title_system_history', '_bx_credits_menu_item_title_history', 'page.php?i=credits-history-common', '', '', '', '', 'a:2:{s:6:"module";s:10:"bx_credits";s:6:"method";s:26:"get_menu_item_addon_amount";}', '', 0, 2147483646, 0, 1, 0);
+
+-- MENU: Notifications
+SET @iAccountNotificationsMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name` = 'sys_account_notifications' AND `order` < 9999);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `markers`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES
+('sys_account_notifications', 'bx_credits', 'notifications-credits', '_bx_credits_menu_item_title_system_notifications', '_bx_credits_menu_item_title_notifications', 'page.php?i=credits-history-common', '', '', 'copyright col-green3', '', 'a:2:{s:6:"module";s:10:"bx_credits";s:6:"method";s:26:"get_menu_item_addon_amount";}', '', '0', 2147483646, 1, 1, @iAccountNotificationsMenuOrder + 1);
+
+-- MENU: account dashboard
+SET @iAccountDashboardMenuOrder = (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', 'bx_credits', 'credits-manage', '_bx_credits_menu_item_title_system_manage', '_bx_credits_menu_item_title_manage', 'page.php?i=credits-history-common', '', '', 'copyright col-green3', '', '', 2147483646, 1, 0, 1, @iAccountDashboardMenuOrder + 1);
+
+-- 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_credits_submenu', '_bx_credits_menu_title_submenu', 'bx_credits_submenu', 'bx_credits', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_credits_submenu', 'bx_credits', '_bx_credits_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_credits_submenu', 'bx_credits', 'credits-home', '_bx_credits_menu_item_title_system_home', '_bx_credits_menu_item_title_home', 'page.php?i=credits-home', '', '', '', '', 2147483647, 0, 1, 1);
+
+-- MENU: manage submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_credits_manage_submenu', '_bx_credits_menu_title_manage_submenu', 'bx_credits_manage_submenu', 'bx_credits', 6, 0, 1, 'BxCreditsMenuManage', 'modules/boonex/credits/classes/BxCreditsMenuManage.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_credits_manage_submenu', 'bx_credits', '_bx_credits_menu_set_title_manage_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_credits_manage_submenu', 'bx_credits', 'credits-history-common', '_bx_credits_menu_item_title_system_history_common', '_bx_credits_menu_item_title_history_common', 'page.php?i=credits-history-common', '', '_self', '', '', '', 2147483646, 1, 0, 1, 1),
+('bx_credits_manage_submenu', 'bx_credits', 'credits-history-administration', '_bx_credits_menu_item_title_system_history_administration', '_bx_credits_menu_item_title_history_administration', 'page.php?i=credits-history-administration', '', '_self', '', '', '', 192, 1, 0, 1, 2),
+('bx_credits_manage_submenu', 'bx_credits', 'credits-orders-common', '_bx_credits_menu_item_title_system_orders_common', '_bx_credits_menu_item_title_orders_common', 'page.php?i=credits-orders-common', '', '_self', '', '', '', 2147483646, 1, 0, 1, 3),
+('bx_credits_manage_submenu', 'bx_credits', 'credits-orders-administration', '_bx_credits_menu_item_title_system_orders_administration', '_bx_credits_menu_item_title_orders_administration', 'page.php?i=credits-orders-administration', '', '_self', '', '', '', 192, 1, 0, 1, 4),
+('bx_credits_manage_submenu', 'bx_credits', 'credits-withdrawals-common', '_bx_credits_menu_item_title_system_withdrawals_common', '_bx_credits_menu_item_title_withdrawals_common', 'page.php?i=credits-withdrawals-common', '', '_self', '', '', '', 2147483646, 1, 0, 1, 5),
+('bx_credits_manage_submenu', 'bx_credits', 'credits-withdrawals-administration', '_bx_credits_menu_item_title_system_withdrawals_administration', '_bx_credits_menu_item_title_withdrawals_administration', 'page.php?i=credits-withdrawals-administration', '', '_self', '', '', '', 192, 1, 0, 1, 6),
+('bx_credits_manage_submenu', 'bx_credits', 'credits-profiles-administration', '_bx_credits_menu_item_title_system_profiles_administration', '_bx_credits_menu_item_title_profiles_administration', 'page.php?i=credits-profiles-administration', '', '_self', '', '', '', 192, 1, 0, 1, 7);
+
+-- 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_credits', 'credits-history-administration', '_bx_credits_menu_item_title_system_admt_credits', '_bx_credits_menu_item_title_admt_credits', 'page.php?i=credits-history-administration', '', '_self', 'copyright', 'a:2:{s:6:"module";s:10:"bx_credits";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
+
+
+-- GRIDS: bundles
+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_credits_bundles', 'Sql', 'SELECT * FROM `bx_credits_bundles` WHERE 1 ', 'bx_credits_bundles', 'id', 'order', 'active', '', 100, NULL, 'start', '', 'period,period_unit,price', '', 'like', '', '', 192, 'BxCreditsGridBundles', 'modules/boonex/credits/classes/BxCreditsGridBundles.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_credits_bundles', 'checkbox', '_sys_select', '1%', 0, '', '', 1),
+('bx_credits_bundles', 'order', '', '1%', 0, '', '', 2),
+('bx_credits_bundles', 'name', '_bx_credits_grid_column_title_name', '23%', 0, 32, '', 3),
+('bx_credits_bundles', 'title', '_bx_credits_grid_column_title_title', '30%', 1, 16, '', 4),
+('bx_credits_bundles', 'amount', '_bx_credits_grid_column_title_amount', '10%', 0, 16, '', 5),
+('bx_credits_bundles', 'bonus', '_bx_credits_grid_column_title_bonus', '5%', 0, 16, '', 6),
+('bx_credits_bundles', 'price', '_bx_credits_grid_column_title_price', '10%', 0, 16, '', 7),
+('bx_credits_bundles', 'actions', '', '20%', 0, '', '', 8);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_credits_bundles', 'independent', 'add', '_bx_credits_grid_action_title_add', '', 0, 0, 1),
+('bx_credits_bundles', 'single', 'edit', '_bx_credits_grid_action_title_edit', 'pencil-alt', 1, 0, 1),
+('bx_credits_bundles', 'single', 'delete', '_bx_credits_grid_action_title_delete', 'remove', 1, 1, 2),
+('bx_credits_bundles', 'bulk', 'delete', '_bx_credits_grid_action_title_delete', '', 0, 1, 1);
+
+-- GRIDS: orders
+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_credits_orders_administration', 'Sql', 'SELECT `to`.`id` AS `id`, `to`.`profile_id` AS `profile_id`, `to`.`bundle_id` AS `bundle_id`, `tb`.`title` AS `bundle`, `to`.`order` AS `transaction`, `to`.`license` AS `license`, `to`.`type` AS `type`, `to`.`added` AS `added`, `to`.`expired` AS `expired` FROM `bx_credits_orders` AS `to` LEFT JOIN `bx_credits_bundles` AS `tb` ON `to`.`bundle_id`=`tb`.`id` WHERE 1 ', 'bx_credits_orders', 'id', 'added', '', '', 20, NULL, 'start', '', 'tb`.`title,to`.`order,to`.`license,to`.`type', '', 'like', '', '', 192, 'BxCreditsGridOrdersAdministration', 'modules/boonex/credits/classes/BxCreditsGridOrdersAdministration.php'),
+('bx_credits_orders_common', 'Sql', 'SELECT `to`.`id` AS `id`, `to`.`profile_id` AS `profile_id`, `to`.`bundle_id` AS `bundle_id`, `tb`.`title` AS `bundle`, `to`.`order` AS `transaction`, `to`.`license` AS `license`, `to`.`type` AS `type`, `to`.`added` AS `added`, `to`.`expired` AS `expired` FROM `bx_credits_orders` AS `to` LEFT JOIN `bx_credits_bundles` AS `tb` ON `to`.`bundle_id`=`tb`.`id` WHERE 1 ', 'bx_credits_orders', 'id', 'added', '', '', 20, NULL, 'start', '', 'tb`.`title,to`.`order,to`.`license,to`.`type', '', 'like', '', '', 2147483647, 'BxCreditsGridOrdersCommon', 'modules/boonex/credits/classes/BxCreditsGridOrdersCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_credits_orders_administration', 'profile_id', '_bx_credits_grid_column_title_ord_profile_id', '10%', 0, '28', '', 1),
+('bx_credits_orders_administration', 'bundle', '_bx_credits_grid_column_title_ord_bundle', '20%', 1, '28', '', 2),
+('bx_credits_orders_administration', 'transaction', '_bx_credits_grid_column_title_ord_transaction', '10%', 0, '32', '', 3),
+('bx_credits_orders_administration', 'type', '_bx_credits_grid_column_title_ord_type', '5%', 1, '12', '', 4),
+('bx_credits_orders_administration', 'added', '_bx_credits_grid_column_title_ord_added', '10%', 1, '25', '', 5),
+('bx_credits_orders_administration', 'expired', '_bx_credits_grid_column_title_ord_expired', '10%', 1, '25', '', 6),
+
+('bx_credits_orders_common', 'bundle', '_bx_credits_grid_column_title_ord_bundle', '20%', 1, '28', '', 1),
+('bx_credits_orders_common', 'transaction', '_bx_credits_grid_column_title_ord_transaction', '10%', 0, '32', '', 2),
+('bx_credits_orders_common', 'type', '_bx_credits_grid_column_title_ord_type', '10%', 1, '12', '', 3),
+('bx_credits_orders_common', 'added', '_bx_credits_grid_column_title_ord_added', '10%', 1, '25', '', 4),
+('bx_credits_orders_common', 'expired', '_bx_credits_grid_column_title_ord_expired', '10%', 1, '25', '', 5);
+
+-- GRIDS: history
+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_credits_history_administration', 'Sql', 'SELECT `th`.*, `tp`.`wdw_clearing` FROM `bx_credits_history` AS `th` LEFT JOIN `bx_credits_profiles` AS `tp` ON `th`.`first_pid`=`tp`.`id` WHERE 1 ', 'bx_credits_history', 'id', 'date', '', '', 20, NULL, 'start', '', 'th`.`direction,th`.`order,th`.`info', '', 'like', '', '', 192, 'BxCreditsGridHistoryAdministration', 'modules/boonex/credits/classes/BxCreditsGridHistoryAdministration.php'),
+('bx_credits_history_common', 'Sql', 'SELECT `th`.*, `tp`.`wdw_clearing` FROM `bx_credits_history` AS `th` LEFT JOIN `bx_credits_profiles` AS `tp` ON `th`.`first_pid`=`tp`.`id` WHERE 1 ', 'bx_credits_history', 'id', 'date', '', '', 20, NULL, 'start', '', 'th`.`direction,th`.`order,th`.`info', '', 'like', '', '', 2147483647, 'BxCreditsGridHistoryCommon', 'modules/boonex/credits/classes/BxCreditsGridHistoryCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_credits_history_administration', 'first_pid', '_bx_credits_grid_column_title_htr_first_pid', '15%', 0, '', '', 1),
+('bx_credits_history_administration', 'direction', '_bx_credits_grid_column_title_htr_direction', '10%', 0, '', '', 2),
+('bx_credits_history_administration', 'second_pid', '_bx_credits_grid_column_title_htr_second_pid', '15%', 0, '', '', 3),
+('bx_credits_history_administration', 'amount', '_bx_credits_grid_column_title_htr_amount', '10%', 1, '', '', 4),
+('bx_credits_history_administration', 'order', '_bx_credits_grid_column_title_htr_order', '15%', 0, '16', '', 5),
+('bx_credits_history_administration', 'info', '_bx_credits_grid_column_title_htr_info', '15%', 1, '24', '', 6),
+('bx_credits_history_administration', 'date', '_bx_credits_grid_column_title_htr_date', '10%', 0, '', '', 7),
+('bx_credits_history_administration', 'cleared', '_bx_credits_grid_column_title_htr_cleared', '10%', 0, '', '', 8),
+
+('bx_credits_history_common', 'direction', '_bx_credits_grid_column_title_htr_direction', '10%', 0, '', '', 1),
+('bx_credits_history_common', 'second_pid', '_bx_credits_grid_column_title_htr_pid', '25%', 0, '', '', 2),
+('bx_credits_history_common', 'amount', '_bx_credits_grid_column_title_htr_amount', '15%', 1, '', '', 3),
+('bx_credits_history_common', 'order', '_bx_credits_grid_column_title_htr_order', '15%', 0, '16', '', 4),
+('bx_credits_history_common', 'info', '_bx_credits_grid_column_title_htr_info', '15%', 1, '32', '', 5),
+('bx_credits_history_common', 'date', '_bx_credits_grid_column_title_htr_date', '10%', 0, '', '', 6),
+('bx_credits_history_common', 'cleared', '_bx_credits_grid_column_title_htr_cleared', '10%', 0, '', '', 7);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_credits_history_administration', 'independent', 'grant', '_bx_credits_grid_action_title_htr_grant', '', 0, 0, 1),
+
+('bx_credits_history_common', 'independent', 'send', '_bx_credits_grid_action_title_htr_send', '', 0, 0, 1);
+
+-- GRIDS: withdrawals
+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_credits_withdrawals_administration', 'Sql', 'SELECT * FROM `bx_credits_withdrawals` WHERE 1 ', 'bx_credits_withdrawals', 'id', 'added', '', '', 20, NULL, 'start', '', 'message,order', '', 'like', '', '', 192, 'BxCreditsGridWithdrawalsAdministration', 'modules/boonex/credits/classes/BxCreditsGridWithdrawalsAdministration.php'),
+('bx_credits_withdrawals_common', 'Sql', 'SELECT * FROM `bx_credits_withdrawals` WHERE 1 ', 'bx_credits_withdrawals', 'id', 'added', '', '', 20, NULL, 'start', '', 'message,order', '', 'like', '', '', 2147483647, 'BxCreditsGridWithdrawalsCommon', 'modules/boonex/credits/classes/BxCreditsGridWithdrawalsCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_credits_withdrawals_administration', 'profile_id', '_bx_credits_grid_column_title_wdw_profile_id', '15%', 0, 0, '', 1),
+('bx_credits_withdrawals_administration', 'amount', '_bx_credits_grid_column_title_wdw_amount', '5%', 0, 0, '', 2),
+('bx_credits_withdrawals_administration', 'rate', '_bx_credits_grid_column_title_wdw_rate', '5%', 0, 0, '', 3),
+('bx_credits_withdrawals_administration', 'message', '_bx_credits_grid_column_title_wdw_message', '10%', 0, 16, '', 4),
+('bx_credits_withdrawals_administration', 'added', '_bx_credits_grid_column_title_wdw_added', '5%', 0, 0, '', 5),
+('bx_credits_withdrawals_administration', 'performer_id', '_bx_credits_grid_column_title_wdw_performer_id', '15%', 0, 0, '', 6),
+('bx_credits_withdrawals_administration', 'order', '_bx_credits_grid_column_title_wdw_order', '15%', 0, 16, '', 7),
+('bx_credits_withdrawals_administration', 'confirmed', '_bx_credits_grid_column_title_wdw_confirmed', '5%', 0, 0, '', 8),
+('bx_credits_withdrawals_administration', 'status', '_bx_credits_grid_column_title_wdw_status', '5%', 0, 0, '', 9),
+('bx_credits_withdrawals_administration', 'actions', '', '20%', 0, 0, '', 10),
+
+('bx_credits_withdrawals_common', 'amount', '_bx_credits_grid_column_title_wdw_amount', '10%', 0, 0, '', 1),
+('bx_credits_withdrawals_common', 'rate', '_bx_credits_grid_column_title_wdw_rate', '10%', 0, 0, '', 2),
+('bx_credits_withdrawals_common', 'message', '_bx_credits_grid_column_title_wdw_message', '15%', 0, 16, '', 3),
+('bx_credits_withdrawals_common', 'added', '_bx_credits_grid_column_title_wdw_added', '10%', 0, 0, '', 4),
+('bx_credits_withdrawals_common', 'order', '_bx_credits_grid_column_title_wdw_order', '15%', 0, 16, '', 5),
+('bx_credits_withdrawals_common', 'confirmed', '_bx_credits_grid_column_title_wdw_confirmed', '10%', 0, 0, '', 6),
+('bx_credits_withdrawals_common', 'status', '_bx_credits_grid_column_title_wdw_status', '10%', 0, 0, '', 7),
+('bx_credits_withdrawals_common', 'actions', '', '20%', 0, 0, '', 8);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_credits_withdrawals_administration', 'single', 'withdraw_confirm', '_bx_credits_grid_action_title_wdw_withdraw_confirm', 'check', 1, 1, 1),
+
+('bx_credits_withdrawals_common', 'independent', 'withdraw_request', '_bx_credits_grid_action_title_wdw_withdraw_request', '', 0, 0, 1),
+('bx_credits_withdrawals_common', 'single', 'withdraw_cancel', '_bx_credits_grid_action_title_wdw_withdraw_cancel', 'times', 1, 1, 1);
+
+
+-- GRIDS: profiles
+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_credits_profiles_administration', 'Sql', 'SELECT * FROM `bx_credits_profiles` WHERE 1 ', 'bx_credits_profiles', 'id', '', '', '', 20, NULL, 'start', '', '', '', 'like', '', '', 192, 'BxCreditsGridProfilesAdministration', 'modules/boonex/credits/classes/BxCreditsGridProfilesAdministration.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_credits_profiles_administration', 'id', '_bx_credits_grid_column_title_pfl_id', '40%', 0, '', '', 1),
+('bx_credits_profiles_administration', 'wdw_clearing', '_bx_credits_grid_column_title_pfl_wdw_clearing', '10%', 0, '', '', 2),
+('bx_credits_profiles_administration', 'wdw_minimum', '_bx_credits_grid_column_title_pfl_wdw_minimum', '10%', 0, '', '', 3),
+('bx_credits_profiles_administration', 'wdw_remaining', '_bx_credits_grid_column_title_pfl_wdw_remaining', '10%', 0, '', '', 4),
+('bx_credits_profiles_administration', 'balance', '_bx_credits_grid_column_title_pfl_balance', '15%', 0, '', '', 5),
+('bx_credits_profiles_administration', 'balance_cleared', '_bx_credits_grid_column_title_pfl_balance_cleared', '15%', 0, '', '', 6),
+('bx_credits_profiles_administration', 'actions', '', '20%', 0, '', '', 7);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_credits_profiles_administration', 'single', 'edit', '_bx_credits_grid_action_title_pfl_edit', 'pencil-alt', 1, 0, 1);
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_credits', 'BxCreditsAlertsResponse', 'modules/boonex/credits/classes/BxCreditsAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('profile', 'add', @iHandler),
+('profile', 'delete', @iHandler);
+
+
+-- EMAIL TEMPLATES
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES 
+('bx_credits', '_bx_credits_et_txt_name_granted', 'bx_credits_granted', '_bx_credits_et_txt_subject_granted', '_bx_credits_et_txt_body_granted'),
+('bx_credits', '_bx_credits_et_txt_name_received', 'bx_credits_received', '_bx_credits_et_txt_subject_received', '_bx_credits_et_txt_body_received'),
+('bx_credits', '_bx_credits_et_txt_name_purchased', 'bx_credits_purchased', '_bx_credits_et_txt_subject_purchased', '_bx_credits_et_txt_body_purchased'),
+('bx_credits', '_bx_credits_et_txt_name_in', 'bx_credits_in', '_bx_credits_et_txt_subject_in', '_bx_credits_et_txt_body_in'),
+('bx_credits', '_bx_credits_et_txt_name_out', 'bx_credits_out', '_bx_credits_et_txt_subject_out', '_bx_credits_et_txt_body_out'),
+('bx_credits', '_bx_credits_et_txt_name_withdraw_requested', 'bx_credits_withdraw_requested', '_bx_credits_et_txt_subject_withdraw_requested', '_bx_credits_et_txt_body_withdraw_requested'),
+('bx_credits', '_bx_credits_et_txt_name_withdraw_canceled', 'bx_credits_withdraw_canceled', '_bx_credits_et_txt_subject_withdraw_canceled', '_bx_credits_et_txt_body_withdraw_canceled'),
+('bx_credits', '_bx_credits_et_txt_name_withdraw_sent', 'bx_credits_withdraw_sent', '_bx_credits_et_txt_subject_withdraw_sent', '_bx_credits_et_txt_body_withdraw_sent');
+
+
+-- CRON
+INSERT INTO `sys_cron_jobs` (`name`, `time`, `class`, `file`, `service_call`) VALUES
+('bx_credits_clearing', '0 0 * * *', 'BxCreditsCronClearing', 'modules/boonex/credits/classes/BxCreditsCronClearing.php', '');

+ 213 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/install/sql/install.sql

@@ -0,0 +1,213 @@
+-- TABLE: bundles
+CREATE TABLE IF NOT EXISTS `bx_credits_bundles` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `added` int(11) NOT NULL,
+  `name` varchar(255) NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `description` varchar(255) NOT NULL,
+  `amount` int(11) NOT NULL DEFAULT '0',
+  `bonus` int(11) NOT NULL DEFAULT '0',
+  `price` float NOT NULL DEFAULT '0',
+  `active` tinyint(4) NOT NULL DEFAULT '0',
+  `order` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`)
+);
+
+-- TABLE: orders
+CREATE TABLE IF NOT EXISTS `bx_credits_orders` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `profile_id` int(11) unsigned NOT NULL default '0',
+  `bundle_id` int(11) unsigned NOT NULL default '0',
+  `count` int(11) unsigned NOT NULL default '0',
+  `order` varchar(32) NOT NULL default '',
+  `license` varchar(32) NOT NULL default '',
+  `type` varchar(16) NOT NULL default '',
+  `added` int(11) unsigned NOT NULL default '0',
+  `expired` int(11) unsigned NOT NULL default '0',
+  `new` tinyint(1) NOT NULL default '1',
+  PRIMARY KEY (`id`),
+  KEY `order_id` (`bundle_id`, `profile_id`),
+  KEY `license` (`license`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_credits_orders_deleted` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `profile_id` int(11) unsigned NOT NULL default '0',
+  `bundle_id` int(11) unsigned NOT NULL default '0',
+  `count` int(11) unsigned NOT NULL default '0',
+  `order` varchar(32) NOT NULL default '',
+  `license` varchar(32) NOT NULL default '',
+  `type` varchar(16) NOT NULL default '',
+  `added` int(11) unsigned NOT NULL default '0',
+  `expired` int(11) unsigned NOT NULL default '0',
+  `new` tinyint(1) NOT NULL default '1',
+  `reason` varchar(16) NOT NULL default '',
+  `deleted` int(11) unsigned NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `order_id` (`bundle_id`, `profile_id`),
+  KEY `license` (`license`)
+);
+
+-- TABLE: profiles
+CREATE TABLE IF NOT EXISTS `bx_credits_profiles` (
+  `id` int(11) NOT NULL DEFAULT '0',
+  `wdw_clearing` int(11) unsigned NOT NULL default '0',
+  `wdw_minimum` int(11) unsigned NOT NULL default '0',
+  `wdw_remaining` int(11) unsigned NOT NULL default '0',
+  `balance` float NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`)
+);
+
+-- TABLE: history
+CREATE TABLE IF NOT EXISTS `bx_credits_history` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `first_pid` int(11) NOT NULL DEFAULT '0',
+  `second_pid` int(11) NOT NULL DEFAULT '0',
+  `amount` float NOT NULL DEFAULT '0',
+  `type` varchar(16) NOT NULL default '',
+  `direction` enum('in', 'out') NOT NULL DEFAULT 'in',
+  `order` varchar(32) NOT NULL default '',
+  `data` text NOT NULL default '',
+  `info` varchar(255) NOT NULL DEFAULT '',
+  `date` int(11) NOT NULL DEFAULT '0',
+  `cleared` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`)
+);
+
+-- TABLE: withdrawals
+CREATE TABLE IF NOT EXISTS `bx_credits_withdrawals` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `performer_id` int(11) unsigned NOT NULL default '0',
+  `profile_id` int(11) unsigned NOT NULL default '0',
+  `amount` float NOT NULL DEFAULT '0',
+  `rate` float NOT NULL DEFAULT '0',
+  `message` text NOT NULL default '',
+  `order` varchar(32) NOT NULL default '',
+  `added` int(11) unsigned NOT NULL default '0',
+  `confirmed` int(11) unsigned NOT NULL default '0',
+  `status` enum('requested', 'canceled', 'confirmed') NOT NULL DEFAULT 'requested',
+  PRIMARY KEY (`id`)
+);
+
+
+-- FORMS: credit
+INSERT INTO `sys_objects_form`(`object`, `module`, `title`, `action`, `form_attrs`, `table`, `key`, `uri`, `uri_title`, `submit_name`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_credits_credit', 'bx_credits', '_bx_credits_form_credit', '', 'a:1:{s:7:"enctype";s:19:"multipart/form-data";}', '', '', '', '', 'a:1:{i:0;s:9:"do_submit";}', '', 0, 1, 'BxCreditsFormCredit', 'modules/boonex/credits/classes/BxCreditsFormCredit.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_credits_credit', 'bx_credits_credit_send', 'bx_credits', 0, '_bx_credits_form_credit_display_send'),
+('bx_credits_credit', 'bx_credits_credit_grant', 'bx_credits', 0, '_bx_credits_form_credit_display_grant'),
+('bx_credits_credit', 'bx_credits_credit_withdraw_request', 'bx_credits', 0, '_bx_credits_form_credit_display_withdraw_request');
+
+INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES 
+('bx_credits_credit', 'bx_credits', 'balance', '', '', 0, 'text', '_bx_credits_form_credit_input_sys_balance', '_bx_credits_form_credit_input_balance', '', 0, 0, 0, 'a:1:{s:8:"disabled";s:8:"disabled";}', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_credits_credit', 'bx_credits', 'cleared', '', '', 0, 'text', '_bx_credits_form_credit_input_sys_cleared', '_bx_credits_form_credit_input_cleared', '_bx_credits_form_credit_input_cleared_inf', 0, 0, 0, 'a:1:{s:8:"disabled";s:8:"disabled";}', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_credits_credit', 'bx_credits', 'rate', '', '', 0, 'text', '_bx_credits_form_credit_input_sys_rate', '_bx_credits_form_credit_input_rate', '', 0, 0, 0, 'a:1:{s:8:"disabled";s:8:"disabled";}', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_credits_credit', 'bx_credits', 'result', '', '', 0, 'text', '_bx_credits_form_credit_input_sys_result', '_bx_credits_form_credit_input_result', '', 0, 0, 0, 'a:1:{s:8:"disabled";s:8:"disabled";}', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_credits_credit', 'bx_credits', 'amount', '', '', 0, 'text', '_bx_credits_form_credit_input_sys_amount', '_bx_credits_form_credit_input_amount', '_bx_credits_form_credit_input_amount_inf', 1, 0, 0, '', '', '', 'Avail', '', '_bx_credits_form_credit_input_amount_err', 'Xss', '', 1, 0),
+('bx_credits_credit', 'bx_credits', 'message', '', '', 0, 'textarea', '_bx_credits_form_credit_input_sys_message', '_bx_credits_form_credit_input_message', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_credits_credit', 'bx_credits', 'profile', '', '', 0, 'custom', '_bx_credits_form_credit_input_sys_profile', '_bx_credits_form_credit_input_profile', '', 1, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_credits_credit', 'bx_credits', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_credits_credit', 'bx_credits', 'do_submit', '_bx_credits_form_credit_input_do_submit', '', 0, 'submit', '_bx_credits_form_credit_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_credits_credit', 'bx_credits', 'do_cancel', '_bx_credits_form_credit_input_do_cancel', '', 0, 'button', '_bx_credits_form_credit_input_sys_do_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 1, 0);
+
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_credits_credit_send', 'profile', 2147483647, 1, 1),
+('bx_credits_credit_send', 'amount', 2147483647, 1, 2),
+('bx_credits_credit_send', 'message', 2147483647, 1, 3),
+('bx_credits_credit_send', 'controls', 2147483647, 1, 4),
+('bx_credits_credit_send', 'do_submit', 2147483647, 1, 5),
+('bx_credits_credit_send', 'do_cancel', 2147483647, 1, 6),
+
+('bx_credits_credit_grant', 'profile', 2147483647, 1, 1),
+('bx_credits_credit_grant', 'amount', 2147483647, 1, 2),
+('bx_credits_credit_grant', 'message', 2147483647, 1, 3),
+('bx_credits_credit_grant', 'controls', 2147483647, 1, 4),
+('bx_credits_credit_grant', 'do_submit', 2147483647, 1, 5),
+('bx_credits_credit_grant', 'do_cancel', 2147483647, 1, 6),
+
+('bx_credits_credit_withdraw_request', 'balance', 2147483647, 1, 1),
+('bx_credits_credit_withdraw_request', 'cleared', 2147483647, 1, 2),
+('bx_credits_credit_withdraw_request', 'rate', 2147483647, 1, 3),
+('bx_credits_credit_withdraw_request', 'amount', 2147483647, 1, 4),
+('bx_credits_credit_withdraw_request', 'result', 2147483647, 1, 5),
+('bx_credits_credit_withdraw_request', 'message', 2147483647, 1, 6),
+('bx_credits_credit_withdraw_request', 'controls', 2147483647, 1, 7),
+('bx_credits_credit_withdraw_request', 'do_submit', 2147483647, 1, 8),
+('bx_credits_credit_withdraw_request', 'do_cancel', 2147483647, 1, 9);
+
+-- FORMS: bundle
+INSERT INTO `sys_objects_form`(`object`, `module`, `title`, `action`, `form_attrs`, `table`, `key`, `uri`, `uri_title`, `submit_name`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_credits_bundle', 'bx_credits', '_bx_credits_form_bundle', '', 'a:1:{s:7:"enctype";s:19:"multipart/form-data";}', 'bx_credits_bundles', 'id', '', '', 'a:1:{i:0;s:9:"do_submit";}', '', 0, 1, 'BxCreditsFormBundle', 'modules/boonex/credits/classes/BxCreditsFormBundle.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_credits_bundle', 'bx_credits_bundle_add', 'bx_credits', 0, '_bx_credits_form_bundle_display_add'),
+('bx_credits_bundle', 'bx_credits_bundle_edit', 'bx_credits', 0, '_bx_credits_form_bundle_display_edit');
+
+INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES 
+('bx_credits_bundle', 'bx_credits', 'title', '', '', 0, 'text_translatable', '_bx_credits_form_bundle_input_sys_title', '_bx_credits_form_bundle_input_title', '', 1, 0, 0, '', '', '', 'AvailTranslatable', 'a:1:{i:0;s:5:"title";}', '_bx_credits_form_bundle_input_title_err', 'Xss', '', 1, 0),
+('bx_credits_bundle', 'bx_credits', 'description', '', '', 0, 'textarea_translatable', '_bx_credits_form_bundle_input_sys_description', '_bx_credits_form_bundle_input_description', '', 0, 0, 3, '', '', '', '', '', '', 'XssHtml', '', 1, 0),
+('bx_credits_bundle', 'bx_credits', 'name', '', '', 0, 'text', '_bx_credits_form_bundle_input_sys_name', '_bx_credits_form_bundle_input_name', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_credits_form_bundle_input_name_err', 'Xss', '', 1, 0),
+('bx_credits_bundle', 'bx_credits', 'amount', '', '', 0, 'text', '_bx_credits_form_bundle_input_sys_amount', '_bx_credits_form_bundle_input_amount', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_credits_form_bundle_input_amount_err', 'Xss', '', 1, 0),
+('bx_credits_bundle', 'bx_credits', 'bonus', '', '', 0, 'text', '_bx_credits_form_bundle_input_sys_bonus', '_bx_credits_form_bundle_input_bonus', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_credits_bundle', 'bx_credits', 'price', '', '', 0, 'price', '_bx_credits_form_bundle_input_sys_price', '_bx_credits_form_bundle_input_price', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_credits_form_bundle_input_price_err', 'Xss', '', 1, 0),
+('bx_credits_bundle', 'bx_credits', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_credits_bundle', 'bx_credits', 'do_submit', '_bx_credits_form_bundle_input_do_submit', '', 0, 'submit', '_bx_credits_form_bundle_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_credits_bundle', 'bx_credits', 'do_cancel', '_bx_credits_form_bundle_input_do_cancel', '', 0, 'button', '_bx_credits_form_bundle_input_sys_do_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 1, 0);
+
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_credits_bundle_add', 'name', 2147483647, 1, 1),
+('bx_credits_bundle_add', 'title', 2147483647, 1, 2),
+('bx_credits_bundle_add', 'description', 2147483647, 1, 3),
+('bx_credits_bundle_add', 'amount', 2147483647, 1, 4),
+('bx_credits_bundle_add', 'bonus', 2147483647, 1, 5),
+('bx_credits_bundle_add', 'price', 2147483647, 1, 6),
+('bx_credits_bundle_add', 'controls', 2147483647, 1, 7),
+('bx_credits_bundle_add', 'do_submit', 2147483647, 1, 8),
+('bx_credits_bundle_add', 'do_cancel', 2147483647, 1, 9),
+
+('bx_credits_bundle_edit', 'name', 2147483647, 1, 1),
+('bx_credits_bundle_edit', 'title', 2147483647, 1, 2),
+('bx_credits_bundle_edit', 'description', 2147483647, 1, 3),
+('bx_credits_bundle_edit', 'amount', 2147483647, 1, 4),
+('bx_credits_bundle_edit', 'bonus', 2147483647, 1, 5),
+('bx_credits_bundle_edit', 'price', 2147483647, 1, 6),
+('bx_credits_bundle_edit', 'controls', 2147483647, 1, 7),
+('bx_credits_bundle_edit', 'do_submit', 2147483647, 1, 8),
+('bx_credits_bundle_edit', 'do_cancel', 2147483647, 1, 9);
+
+-- FORMS: profile
+INSERT INTO `sys_objects_form`(`object`, `module`, `title`, `action`, `form_attrs`, `table`, `key`, `uri`, `uri_title`, `submit_name`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_credits_profile', 'bx_credits', '_bx_credits_form_profile', '', 'a:1:{s:7:"enctype";s:19:"multipart/form-data";}', 'bx_credits_profiles', 'id', '', '', 'a:1:{i:0;s:9:"do_submit";}', '', 0, 1, 'BxCreditsFormProfile', 'modules/boonex/credits/classes/BxCreditsFormProfile.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_credits_profile', 'bx_credits_profile_edit', 'bx_credits', 0, '_bx_credits_form_profile_display_edit');
+
+INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES 
+('bx_credits_profile', 'bx_credits', 'wdw_clearing', '', '', 0, 'text', '_bx_credits_form_profile_input_sys_wdw_clearing', '_bx_credits_form_profile_input_wdw_clearing', '_bx_credits_form_profile_input_wdw_clearing_inf', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_credits_profile', 'bx_credits', 'wdw_minimum', '', '', 0, 'text', '_bx_credits_form_profile_input_sys_wdw_minimum', '_bx_credits_form_profile_input_wdw_minimum', '_bx_credits_form_profile_input_wdw_minimum_inf', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_credits_profile', 'bx_credits', 'wdw_remaining', '', '', 0, 'text', '_bx_credits_form_profile_input_sys_wdw_remaining', '_bx_credits_form_profile_input_wdw_remaining', '_bx_credits_form_profile_input_wdw_remaining_inf', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_credits_profile', 'bx_credits', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_credits_profile', 'bx_credits', 'do_submit', '_bx_credits_form_profile_input_do_submit', '', 0, 'submit', '_bx_credits_form_profile_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_credits_profile', 'bx_credits', 'do_cancel', '_bx_credits_form_profile_input_do_cancel', '', 0, 'button', '_bx_credits_form_bundle_input_sys_do_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 1, 0);
+
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_credits_profile_edit', 'wdw_clearing', 2147483647, 1, 1),
+('bx_credits_profile_edit', 'wdw_minimum', 2147483647, 1, 2),
+('bx_credits_profile_edit', 'wdw_remaining', 2147483647, 1, 3),
+('bx_credits_profile_edit', 'controls', 2147483647, 1, 4),
+('bx_credits_profile_edit', 'do_submit', 2147483647, 1, 5),
+('bx_credits_profile_edit', 'do_cancel', 2147483647, 1, 6);
+
+
+-- STUDIO: page & widget
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_credits', '_bx_credits', '_bx_credits', 'bx_credits@modules/boonex/credits/|std-icon.svg');
+SET @iPageId = LAST_INSERT_ID();
+
+SET @iParentPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name` = 'home');
+SET @iParentPageOrder = (SELECT MAX(`order`) FROM `sys_std_pages_widgets` WHERE `page_id` = @iParentPageId);
+INSERT INTO `sys_std_widgets` (`page_id`, `module`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, 'bx_credits', 'extensions', '{url_studio}module.php?name=bx_credits', '', 'bx_credits@modules/boonex/credits/|std-icon.svg', '_bx_credits', '', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_actions";s:6:"params";a:0:{}s:5:"class";s:18:"TemplStudioModules";}');
+INSERT INTO `sys_std_pages_widgets` (`page_id`, `widget_id`, `order`) VALUES
+(@iParentPageId, LAST_INSERT_ID(), IF(ISNULL(@iParentPageOrder), 1, @iParentPageOrder + 1));

+ 16 - 0
modules/boonex/credits/updates/14.0.2_14.0.3/source/install/sql/uninstall.sql

@@ -0,0 +1,16 @@
+
+-- TABLES
+DROP TABLE IF EXISTS `bx_credits_bundles`, `bx_credits_orders`, `bx_credits_orders_deleted`, `bx_credits_profiles`, `bx_credits_history`, `bx_credits_withdrawals`;
+
+
+-- FORMS
+DELETE FROM `sys_objects_form` WHERE `module` = 'bx_credits';
+DELETE FROM `sys_form_displays` WHERE `module` = 'bx_credits';
+DELETE FROM `sys_form_inputs` WHERE `module` = 'bx_credits';
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` LIKE 'bx_credits_%';
+
+
+-- STUDIO: page & widget
+DELETE FROM `tp`, `tw`, `twb`, `tpw` 
+USING `sys_std_pages` AS `tp` LEFT JOIN `sys_std_widgets` AS `tw` ON `tp`.`id` = `tw`.`page_id` LEFT JOIN `sys_std_widgets_bookmarks` AS `twb` ON `tw`.`id` = `twb`.`widget_id` LEFT JOIN `sys_std_pages_widgets` AS `tpw` ON `tw`.`id` = `tpw`.`widget_id`
+WHERE  `tp`.`name` = 'bx_credits';

+ 51 - 0
modules/boonex/developer/updates/14.0.2_14.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' => '14.0.2',
+    'version_to' => '14.0.3',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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_14.0.2_14.0.3/',
+    'home_uri' => 'developer_update_1402_1403',
+
+    'module_dir' => 'boonex/developer/',
+    'module_uri' => 'developer',
+
+    'db_prefix' => 'bx_dev_',
+    'class_prefix' => 'BxDev',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'BoonEx Developer',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/developer/updates/14.0.2_14.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);
+    }
+}

+ 5 - 0
modules/boonex/developer/updates/14.0.2_14.0.3/install/sql/install.sql

@@ -0,0 +1,5 @@
+SET @sName = 'bx_developer';
+
+
+-- GRIDS
+UPDATE `sys_objects_grid` SET `paginate_get_start`='start' WHERE `object`='bx_developer_pgt_manage';

+ 69 - 0
modules/boonex/developer/updates/14.0.2_14.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' => '14.0.3',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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(),
+
+);
+
+/** @} */

+ 730 - 0
modules/boonex/developer/updates/14.0.2_14.0.3/source/install/sql/install.sql

@@ -0,0 +1,730 @@
+SET @sName = 'bx_developer';
+
+
+--
+-- Studio page and widget.
+--
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, @sName, '_bx_dev_adm_page_cpt', '_bx_dev_adm_page_cpt', 'bx_developer@modules/boonex/developer/|std-icon.svg');
+SET @iPageId = LAST_INSERT_ID();
+
+SET @iParentPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name`='home');
+SET @iParentPageOrder = (SELECT MAX(`order`) FROM `sys_std_pages_widgets` WHERE `page_id`=@iParentPageId);
+INSERT INTO `sys_std_widgets`(`page_id`, `module`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, @sName, 'extensions', CONCAT('{url_studio}module.php?name=', @sName), '', 'bx_developer@modules/boonex/developer/|std-icon.svg', '_bx_dev_adm_wgt_cpt', '', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_actions";s:6:"params";a:0:{}s:5:"class";s:18:"TemplStudioModules";}');
+INSERT INTO `sys_std_pages_widgets`(`page_id`, `widget_id`, `order`) VALUES
+(@iParentPageId, LAST_INSERT_ID(), IF(NOT ISNULL(@iParentPageOrder), @iParentPageOrder + 1, 1));
+
+
+--
+-- Forms Builder -> Grid descriptors
+--
+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_developer_forms', 'Sql', 'SELECT * FROM `sys_objects_form` WHERE 1 ', 'sys_objects_form', 'id', 'module,title', 'active', '', 100, NULL, 'start', '', 'module', 'title', 'like', 'module', 'title', 2147483647, 'BxDevFormsForms', 'modules/boonex/developer/classes/BxDevFormsForms.php'),
+('bx_developer_forms_displays', 'Sql', 'SELECT `td`.`id` AS `id`, `td`.`object` AS `object`, `td`.`display_name` AS `display_name`, `td`.`title` AS `display_title`, `td`.`module` AS `module`, `tf`.`title` AS `form_title` FROM `sys_form_displays` AS `td` LEFT JOIN `sys_objects_form` AS `tf` ON `td`.`object`=`tf`.`object` WHERE 1 ', 'sys_form_displays', 'id', 'module,object,display_title', '', '', 100, NULL, 'start', '', 'td`.`module', 'td`.`title', 'like', 'module', 'display_title,form_title', 2147483647, 'BxDevFormsDisplays', 'modules/boonex/developer/classes/BxDevFormsDisplays.php'),
+('bx_developer_forms_fields', 'Sql', 'SELECT `tdi`.`id` AS `id`, `ti`.`caption_system` AS `caption_system`, `ti`.`caption` AS `caption`, `ti`.`type` AS `type`, `ti`.`module` AS `module`, `tdi`.`visible_for_levels` AS `visible_for_levels`, `tdi`.`active` AS `active`, `ti`.`editable` AS `editable`, `ti`.`deletable` AS `deletable`, `tdi`.`order` AS `order` FROM `sys_form_display_inputs` AS `tdi` LEFT JOIN `sys_form_inputs` AS `ti` ON `tdi`.`input_name`=`ti`.`name` AND `ti`.`object`=? WHERE 1 AND `tdi`.`display_name`=?', 'sys_form_display_inputs', 'id', 'order', 'active', '', 100, NULL, 'start', '', 'ti`.`type', 'ti`.`caption_system', 'like', '', '', 2147483647, 'BxDevFormsFields', 'modules/boonex/developer/classes/BxDevFormsFields.php'),
+
+('bx_developer_forms_pre_lists', 'Sql', 'SELECT * FROM `sys_form_pre_lists` WHERE 1 ', 'sys_form_pre_lists', 'id', '', '', '', 100, NULL, 'start', '', 'module,key', 'title', 'auto', 'module', 'title', 2147483647, 'BxDevFormsPreLists', 'modules/boonex/developer/classes/BxDevFormsPreLists.php'),
+('bx_developer_forms_pre_values', 'Sql', 'SELECT * FROM `sys_form_pre_values` WHERE 1 ', 'sys_form_pre_values', 'id', 'Order', '', '', 1000, NULL, 'start', '', 'Key,Value', 'LKey,LKey2', 'auto', '', '', 2147483647, 'BxDevFormsPreValues', 'modules/boonex/developer/classes/BxDevFormsPreValues.php'),
+
+('bx_developer_search_forms', 'Sql', 'SELECT * FROM `sys_objects_search_extended` WHERE 1 ', 'sys_objects_search_extended', 'id', 'module,title', 'active', '', 100, NULL, 'start', '', 'module', 'title', 'like', 'module', 'title', 2147483647, 'BxDevFormsSearchForms', 'modules/boonex/developer/classes/BxDevFormsSearchForms.php'),
+('bx_developer_search_forms_fields', 'Sql', 'SELECT * FROM `sys_search_extended_fields` WHERE 1 AND `object`=?', 'sys_search_extended_fields', 'id', 'order', 'active', '', 100, NULL, 'start', '', 'type', 'caption', 'like', '', '', 2147483647, 'BxDevFormsSearchFields', 'modules/boonex/developer/classes/BxDevFormsSearchFields.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_developer_forms', 'switcher', '', '10%', 0, '', '', 1),
+('bx_developer_forms', 'title', '_bx_dev_frm_txt_forms_gl_title', '40%', 1, '38', '', 2),
+('bx_developer_forms', 'module', '_bx_dev_frm_txt_forms_gl_module', '15%', 0, '13', '', 3),
+('bx_developer_forms', 'displays', '_bx_dev_frm_txt_forms_gl_displays', '15%', 0, '13', '', 4),
+('bx_developer_forms', 'actions', '', '20%', 0, '', '', 5),
+
+('bx_developer_forms_displays', 'display_title', '_bx_dev_frm_txt_displays_gl_title', '30%', 1, '48', '', 1),
+('bx_developer_forms_displays', 'module', '_bx_dev_frm_txt_displays_gl_module', '13%', 0, '11', '', 2),
+('bx_developer_forms_displays', 'form_title', '_bx_dev_frm_txt_displays_gl_form', '24%', 1, '22', '', 3),
+('bx_developer_forms_displays', 'fields', '_bx_dev_frm_txt_displays_gl_fields', '13%', 0, '11', '', 4),
+('bx_developer_forms_displays', 'actions', '', '20%', 0, '', '', 5),
+
+('bx_developer_forms_fields', 'order', '', '1%', 0, '', '', 1),
+('bx_developer_forms_fields', 'switcher', '', '9%', 0, '', '', 2),
+('bx_developer_forms_fields', 'type', '_bx_dev_frm_txt_fields_gl_type', '5%', 0, '', '', 3),
+('bx_developer_forms_fields', 'caption_system', '_bx_dev_frm_txt_fields_gl_caption_system', '40%', 1, '38', '', 4),
+('bx_developer_forms_fields', 'module', '_bx_dev_frm_txt_fields_gl_module', '15%', 0, '13', '', 5),
+('bx_developer_forms_fields', 'visible_for_levels', '_bx_dev_frm_txt_fields_gl_visible', '10%', 0, '10', '', 6),
+('bx_developer_forms_fields', 'actions', '', '20%', 0, '', '', 7),
+
+('bx_developer_forms_pre_lists', 'title', '_bx_dev_frm_txt_pre_lists_gl_title', '45%', 1, '50', '', 1),
+('bx_developer_forms_pre_lists', 'values', '_bx_dev_frm_txt_pre_lists_gl_values', '12%', 0, '10', '', 2),
+('bx_developer_forms_pre_lists', 'module', '_bx_dev_frm_txt_pre_lists_gl_module', '13%', 0, '11', '', 3),
+('bx_developer_forms_pre_lists', 'use_for_sets', '_bx_dev_frm_txt_pre_lists_gl_use_for_sets', '10%', 0, '8', '', 4),
+('bx_developer_forms_pre_lists', 'actions', '', '20%', 0, '', '', 5),
+
+('bx_developer_forms_pre_values', 'order', '', '1%', 0, '', '', 1),
+('bx_developer_forms_pre_values', 'LKey', '_bx_dev_frm_txt_pre_values_gl_lkey', '79%', 1, '75', '', 2),
+('bx_developer_forms_pre_values', 'actions', '', '20%', 0, '', '', 3),
+
+('bx_developer_search_forms', 'switcher', '', '10%', 0, '', '', 1),
+('bx_developer_search_forms', 'title', '_bx_dev_frm_txt_search_forms_gl_title', '40%', 1, '38', '', 2),
+('bx_developer_search_forms', 'module', '_bx_dev_frm_txt_search_forms_gl_module', '15%', 0, '13', '', 3),
+('bx_developer_search_forms', 'fields', '_bx_dev_frm_txt_search_forms_gl_fields', '15%', 0, '13', '', 4),
+('bx_developer_search_forms', 'actions', '', '20%', 0, '', '', 5),
+
+('bx_developer_search_forms_fields', 'order', '', '1%', 0, '', '', 1),
+('bx_developer_search_forms_fields', 'switcher', '', '9%', 0, '', '', 2),
+('bx_developer_search_forms_fields', 'type', '_bx_dev_frm_txt_search_forms_fields_gl_type', '10%', 0, '', '', 3),
+('bx_developer_search_forms_fields', 'caption', '_bx_dev_frm_txt_search_forms_fields_gl_caption', '40%', 1, '38', '', 4),
+('bx_developer_search_forms_fields', 'search_type', '_bx_dev_frm_txt_search_forms_fields_gl_search_type', '10%', 0, '', '', 5),
+('bx_developer_search_forms_fields', 'search_operator', '_bx_dev_frm_txt_search_forms_fields_gl_search_operator', '10%', 0, '', '', 6),
+('bx_developer_search_forms_fields', 'actions', '', '20%', 0, '', '', 7);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_developer_forms', 'independent', 'add', '_bx_dev_frm_btn_forms_gl_create', '', 0, 1),
+('bx_developer_forms', 'independent', 'import_full', '_bx_dev_btn_import_full', '', 0, 2),
+('bx_developer_forms', 'independent', 'export_full', '_bx_dev_btn_export_full', '', 0, 3),
+('bx_developer_forms', 'single', 'export', '', 'download', 0, 1),
+('bx_developer_forms', 'single', 'edit', '', 'pencil-alt', 0, 2),
+
+('bx_developer_forms_displays', 'independent', 'add', '_bx_dev_frm_btn_displays_gl_create', '', 0, 1),
+('bx_developer_forms_displays', 'single', 'edit', '', 'pencil-alt', 0, 1),
+
+('bx_developer_forms_fields', 'single', 'edit', '', 'pencil-alt', 0, 1),
+('bx_developer_forms_fields', 'single', 'delete', '', 'remove', 1, 2),
+('bx_developer_forms_fields', 'single', 'show_to', '_bx_dev_frm_btn_fields_visible', '', 0, 3),
+('bx_developer_forms_fields', 'independent', 'add', '_bx_dev_frm_btn_fields_create', '', 0, 1),
+
+('bx_developer_forms_pre_lists', 'independent', 'add', '_bx_dev_frm_btn_pre_lists_create', '', 0, 1),
+('bx_developer_forms_pre_lists', 'single', 'export', '', 'download', 0, 1),
+('bx_developer_forms_pre_lists', 'single', 'edit', '', 'pencil-alt', 0, 2),
+('bx_developer_forms_pre_lists', 'single', 'delete', '', 'remove', 1, 3),
+
+('bx_developer_forms_pre_values', 'independent', 'add', '_bx_dev_frm_btn_pre_values_create', '', 0, 1),
+('bx_developer_forms_pre_values', 'single', 'edit', '', 'pencil-alt', 0, 1),
+('bx_developer_forms_pre_values', 'single', 'delete', '', 'remove', 1, 2),
+
+('bx_developer_search_forms', 'independent', 'add', '_bx_dev_frm_btn_search_forms_create', '', 0, 1),
+('bx_developer_search_forms', 'single', 'edit', '', 'pencil-alt', 0, 1),
+
+('bx_developer_search_forms_fields', 'single', 'edit', '', 'pencil-alt', 0, 1),
+('bx_developer_search_forms_fields', 'independent', 'reset', '_bx_dev_frm_btn_search_forms_fields_reset', '', 0, 1);
+
+
+--
+-- Forms Builder -> Forms.
+--
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_developer_forms_form', @sName, '_bx_dev_frm_txt_forms_form', '', '', 'do_submit', 'sys_objects_form', 'id', '', '', '', 0, 1, 'BxDevFormView', 'modules/boonex/developer/classes/BxDevFormView.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_developer_forms_form_add', @sName, 'bx_developer_forms_form', '_bx_dev_frm_txt_forms_display_add', 0),
+('bx_developer_forms_form_edit', @sName, 'bx_developer_forms_form', '_bx_dev_frm_txt_forms_display_edit', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_developer_forms_form', @sName, 'id', '0', '', 0, 'hidden', '_bx_dev_frm_txt_sys_forms_id', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_forms_form', @sName, 'object', '', '', 0, 'text', '_bx_dev_frm_txt_sys_forms_object', '_bx_dev_frm_txt_forms_object', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_frm_err_forms_object', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'module', '', '', 0, 'select', '_bx_dev_frm_txt_sys_forms_module', '_bx_dev_frm_txt_forms_module', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_frm_err_forms_module', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'title', '', '', 0, 'text', '_bx_dev_frm_txt_sys_forms_title', '_bx_dev_frm_txt_forms_title', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_frm_err_forms_title', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'action', '', '', 0, 'text', '_bx_dev_frm_txt_sys_forms_action', '_bx_dev_frm_txt_forms_action', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'form_attrs', '', '', 0, 'textarea', '_bx_dev_frm_txt_sys_forms_form_attrs', '_bx_dev_frm_txt_forms_form_attrs', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'submit_name', '', '', 0, 'text', '_bx_dev_frm_txt_sys_forms_submit_name', '_bx_dev_frm_txt_forms_submit_name', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'table', '', '', 0, 'text', '_bx_dev_frm_txt_sys_forms_table', '_bx_dev_frm_txt_forms_table', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'key', '', '', 0, 'text', '_bx_dev_frm_txt_sys_forms_key', '_bx_dev_frm_txt_forms_key', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'uri', '', '', 0, 'text', '_bx_dev_frm_txt_sys_forms_uri', '_bx_dev_frm_txt_forms_uri', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'uri_title', '', '', 0, 'text', '_bx_dev_frm_txt_sys_forms_uri_title', '_bx_dev_frm_txt_forms_uri_title', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'params', '', '', 0, 'textarea', '_bx_dev_frm_txt_sys_forms_params', '_bx_dev_frm_txt_forms_params', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'deletable', '1', '', 0, 'switcher', '_bx_dev_frm_txt_sys_forms_deletable', '_bx_dev_frm_txt_forms_deletable', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_forms_form', @sName, 'override_class_name', '', '', 0, 'text', '_bx_dev_frm_txt_sys_forms_override_class_name', '_bx_dev_frm_txt_forms_override_class_name', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'override_class_file', '', '', 0, 'text', '_bx_dev_frm_txt_sys_forms_override_class_file', '_bx_dev_frm_txt_forms_override_class_file', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_form', @sName, 'controls', '', 'do_submit,cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_forms_form', @sName, 'do_submit', '_bx_dev_frm_btn_forms_add', '', 0, 'submit', '_bx_dev_frm_btn_sys_forms_add', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_forms_form', @sName, 'cancel', '_bx_dev_frm_btn_forms_cancel', '', 0, 'button', '_bx_dev_frm_btn_sys_forms_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_developer_forms_form_add', 'object', 2147483647, 1, 1),
+('bx_developer_forms_form_add', 'module', 2147483647, 1, 2),
+('bx_developer_forms_form_add', 'title', 2147483647, 1, 3),
+('bx_developer_forms_form_add', 'action', 2147483647, 1, 4),
+('bx_developer_forms_form_add', 'form_attrs', 2147483647, 1, 5),
+('bx_developer_forms_form_add', 'submit_name', 2147483647, 1, 6),
+('bx_developer_forms_form_add', 'table', 2147483647, 1, 7),
+('bx_developer_forms_form_add', 'key', 2147483647, 1, 8),
+('bx_developer_forms_form_add', 'uri', 2147483647, 1, 9),
+('bx_developer_forms_form_add', 'uri_title', 2147483647, 1, 10),
+('bx_developer_forms_form_add', 'params', 2147483647, 1, 11),
+('bx_developer_forms_form_add', 'deletable', 2147483647, 1, 12),
+('bx_developer_forms_form_add', 'override_class_name', 2147483647, 1, 13),
+('bx_developer_forms_form_add', 'override_class_file', 2147483647, 1, 14),
+('bx_developer_forms_form_add', 'controls', 2147483647, 1, 15),
+('bx_developer_forms_form_add', 'do_submit', 2147483647, 1, 16),
+('bx_developer_forms_form_add', 'cancel', 2147483647, 1, 17),
+('bx_developer_forms_form_edit', 'id', 2147483647, 1, 1),
+('bx_developer_forms_form_edit', 'object', 2147483647, 1, 2),
+('bx_developer_forms_form_edit', 'module', 2147483647, 1, 3),
+('bx_developer_forms_form_edit', 'title', 2147483647, 1, 4),
+('bx_developer_forms_form_edit', 'action', 2147483647, 1, 5),
+('bx_developer_forms_form_edit', 'form_attrs', 2147483647, 1, 6),
+('bx_developer_forms_form_edit', 'submit_name', 2147483647, 1, 7),
+('bx_developer_forms_form_edit', 'table', 2147483647, 1, 8),
+('bx_developer_forms_form_edit', 'key', 2147483647, 1, 9),
+('bx_developer_forms_form_edit', 'uri', 2147483647, 1, 10),
+('bx_developer_forms_form_edit', 'uri_title', 2147483647, 1, 11),
+('bx_developer_forms_form_edit', 'params', 2147483647, 1, 12),
+('bx_developer_forms_form_edit', 'deletable', 2147483647, 1, 13),
+('bx_developer_forms_form_edit', 'override_class_name', 2147483647, 1, 14),
+('bx_developer_forms_form_edit', 'override_class_file', 2147483647, 1, 15),
+('bx_developer_forms_form_edit', 'controls', 2147483647, 1, 16),
+('bx_developer_forms_form_edit', 'do_submit', 2147483647, 1, 17),
+('bx_developer_forms_form_edit', 'cancel', 2147483647, 1, 18);
+
+--
+-- Forms Builder -> Displays.
+--
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_developer_forms_display', @sName, '_bx_dev_frm_txt_displays_diplay', '', '', 'do_submit', 'sys_form_displays', 'id', '', '', '', 0, 1, 'BxDevFormView', 'modules/boonex/developer/classes/BxDevFormView.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_developer_forms_display_add', @sName, 'bx_developer_forms_display', '_bx_dev_frm_txt_displays_display_add', 0),
+('bx_developer_forms_display_edit', @sName, 'bx_developer_forms_display', '_bx_dev_frm_txt_displays_display_edit', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_developer_forms_display', @sName, 'id', '0', '', 0, 'hidden', '_bx_dev_frm_txt_sys_displays_id', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_forms_display', @sName, 'display_name', '', '', 0, 'text', '_bx_dev_frm_txt_sys_displays_display_name', '_bx_dev_frm_txt_displays_display_name', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_frm_err_displays_display_name', 'Xss', '', 0, 0),
+('bx_developer_forms_display', @sName, 'module', '', '', 0, 'select', '_bx_dev_frm_txt_sys_displays_module', '_bx_dev_frm_txt_displays_module', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_frm_err_displays_module', 'Xss', '', 0, 0),
+('bx_developer_forms_display', @sName, 'object', '', '', 0, 'select', '_bx_dev_frm_txt_sys_displays_object', '_bx_dev_frm_txt_displays_object', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_frm_err_displays_object', 'Xss', '', 0, 0),
+('bx_developer_forms_display', @sName, 'title', '', '', 0, 'text', '_bx_dev_frm_txt_sys_displays_title', '_bx_dev_frm_txt_displays_title', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_frm_err_displays_title', 'Xss', '', 0, 0),
+('bx_developer_forms_display', @sName, 'view_mode', '1', '', 0, 'switcher', '_bx_dev_frm_txt_sys_displays_view_mode', '_bx_dev_frm_txt_displays_view_mode', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_forms_display', @sName, 'controls', '', 'do_submit,cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_forms_display', @sName, 'do_submit', '_bx_dev_frm_btn_displays_add', '', 0, 'submit', '_bx_dev_frm_btn_sys_displays_add', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_forms_display', @sName, 'cancel', '_bx_dev_frm_btn_displays_cancel', '', 0, 'button', '_bx_dev_frm_btn_sys_displays_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_developer_forms_display_add', 'display_name', 2147483647, 1, 1),
+('bx_developer_forms_display_add', 'module', 2147483647, 1, 2),
+('bx_developer_forms_display_add', 'object', 2147483647, 1, 3),
+('bx_developer_forms_display_add', 'title', 2147483647, 1, 4),
+('bx_developer_forms_display_add', 'view_mode', 2147483647, 1, 5),
+('bx_developer_forms_display_add', 'controls', 2147483647, 1, 6),
+('bx_developer_forms_display_add', 'do_submit', 2147483647, 1, 7),
+('bx_developer_forms_display_add', 'cancel', 2147483647, 1, 8),
+('bx_developer_forms_display_edit', 'id', 2147483647, 1, 1),
+('bx_developer_forms_display_edit', 'display_name', 2147483647, 1, 1),
+('bx_developer_forms_display_edit', 'module', 2147483647, 1, 2),
+('bx_developer_forms_display_edit', 'object', 2147483647, 1, 3),
+('bx_developer_forms_display_edit', 'title', 2147483647, 1, 4),
+('bx_developer_forms_display_edit', 'view_mode', 2147483647, 1, 5),
+('bx_developer_forms_display_edit', 'controls', 2147483647, 1, 6),
+('bx_developer_forms_display_edit', 'do_submit', 2147483647, 1, 7),
+('bx_developer_forms_display_edit', 'cancel', 2147483647, 1, 8);
+
+--
+-- Forms Builder -> Pre Lists.
+--
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_developer_forms_prelist', @sName, '_bx_dev_frm_txt_prelists_prelist', '', '', 'do_submit', 'sys_form_pre_lists', 'id', '', '', '', 0, 1, 'BxDevFormView', 'modules/boonex/developer/classes/BxDevFormView.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_developer_forms_prelist_add', @sName, 'bx_developer_forms_prelist', '_bx_dev_frm_txt_prelists_display_add', 0),
+('bx_developer_forms_prelist_edit', @sName, 'bx_developer_forms_prelist', '_bx_dev_frm_txt_prelists_display_edit', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_developer_forms_prelist', @sName, 'id', '0', '', 0, 'hidden', '_bx_dev_frm_txt_sys_prelists_id', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_forms_prelist', @sName, 'key', '', '', 0, 'text', '_bx_dev_frm_txt_sys_prelists_key', '_bx_dev_frm_txt_prelists_key', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_frm_err_prelists_key', 'Xss', '', 0, 0),
+('bx_developer_forms_prelist', @sName, 'module', '', '', 0, 'select', '_bx_dev_frm_txt_sys_prelists_module', '_bx_dev_frm_txt_prelists_module', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_frm_err_prelists_module', 'Xss', '', 0, 0),
+('bx_developer_forms_prelist', @sName, 'title', '', '', 0, 'text', '_bx_dev_frm_txt_sys_prelists_title', '_bx_dev_frm_txt_prelists_title', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_frm_err_prelists_title', 'Xss', '', 0, 0),
+('bx_developer_forms_prelist', @sName, 'use_for_sets', '1', '', 1, 'switcher', '_bx_dev_frm_txt_sys_prelists_use_for_sets', '_bx_dev_frm_txt_prelists_use_for_sets', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_forms_prelist', @sName, 'controls', '', 'do_submit,cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_forms_prelist', @sName, 'do_submit', '_bx_dev_frm_btn_prelists_add', '', 0, 'submit', '_bx_dev_frm_btn_sys_prelists_add', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_forms_prelist', @sName, 'cancel', '_bx_dev_frm_btn_prelists_cancel', '', 0, 'button', '_bx_dev_frm_btn_sys_prelists_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_developer_forms_prelist_add', 'key', 2147483647, 1, 1),
+('bx_developer_forms_prelist_add', 'module', 2147483647, 1, 2),
+('bx_developer_forms_prelist_add', 'title', 2147483647, 1, 3),
+('bx_developer_forms_prelist_add', 'use_for_sets', 2147483647, 1, 4),
+('bx_developer_forms_prelist_add', 'controls', 2147483647, 1, 5),
+('bx_developer_forms_prelist_add', 'do_submit', 2147483647, 1, 6),
+('bx_developer_forms_prelist_add', 'cancel', 2147483647, 1, 7),
+('bx_developer_forms_prelist_edit', 'id', 2147483647, 1, 1),
+('bx_developer_forms_prelist_edit', 'module', 2147483647, 1, 2),
+('bx_developer_forms_prelist_edit', 'title', 2147483647, 1, 3),
+('bx_developer_forms_prelist_edit', 'use_for_sets', 2147483647, 1, 4),
+('bx_developer_forms_prelist_edit', 'controls', 2147483647, 1, 5),
+('bx_developer_forms_prelist_edit', 'do_submit', 2147483647, 1, 6),
+('bx_developer_forms_prelist_edit', 'cancel', 2147483647, 1, 7);
+
+--
+-- Forms Builder -> Pre Values.
+--
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_developer_forms_prevalue', @sName, '_bx_dev_frm_txt_prevalues_prevalue', '', '', 'do_submit', 'sys_form_pre_values', 'id', '', '', '', 0, 1, 'BxDevFormView', 'modules/boonex/developer/classes/BxDevFormView.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_developer_forms_prevalue_add', @sName, 'bx_developer_forms_prevalue', '_bx_dev_frm_txt_prevalues_display_add', 0),
+('bx_developer_forms_prevalue_edit', @sName, 'bx_developer_forms_prevalue', '_bx_dev_frm_txt_prevalues_display_edit', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_developer_forms_prevalue', @sName, 'id', '0', '', 0, 'hidden', '_bx_dev_frm_txt_sys_prevalues_id', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_forms_prevalue', @sName, 'Key', '', '', 0, 'select', '_bx_dev_frm_txt_sys_prevalues_key', '_bx_dev_frm_txt_prevalues_key', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_frm_err_prevalues_key', 'Xss', '', 0, 0),
+('bx_developer_forms_prevalue', @sName, 'Value', '', '', 0, 'text', '_bx_dev_frm_txt_sys_prevalues_value', '_bx_dev_frm_txt_prevalues_value', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:1;s:3:"max";i:255;}', '_bx_dev_frm_err_prevalues_value', 'Xss', '', 0, 0),
+('bx_developer_forms_prevalue', @sName, 'LKey', '', '', 0, 'text', '_bx_dev_frm_txt_sys_prevalues_lkey', '_bx_dev_frm_txt_prevalues_lkey', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:1;s:3:"max";i:100;}', '_bx_dev_frm_err_prevalues_lkey', 'Xss', '', 0, 0),
+('bx_developer_forms_prevalue', @sName, 'LKey2', '', '', 0, 'text', '_bx_dev_frm_txt_sys_prevalues_lkey2', '_bx_dev_frm_txt_prevalues_lkey2', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_prevalue', @sName, 'Data', '', '', 0, 'textarea', '_bx_dev_frm_txt_sys_prevalues_data', '_bx_dev_frm_txt_prevalues_data', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_prevalue', @sName, 'controls', '', 'do_submit,cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_forms_prevalue', @sName, 'do_submit', '_bx_dev_frm_btn_prevalues_add', '', 0, 'submit', '_bx_dev_frm_btn_sys_prevalues_add', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_forms_prevalue', @sName, 'cancel', '_bx_dev_frm_btn_prevalues_cancel', '', 0, 'button', '_bx_dev_frm_btn_sys_prevalues_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_developer_forms_prevalue_add', 'Key', 2147483647, 1, 1),
+('bx_developer_forms_prevalue_add', 'Value', 2147483647, 1, 2),
+('bx_developer_forms_prevalue_add', 'LKey', 2147483647, 1, 3),
+('bx_developer_forms_prevalue_add', 'LKey2', 2147483647, 1, 4),
+('bx_developer_forms_prevalue_add', 'Data', 2147483647, 1, 5),
+('bx_developer_forms_prevalue_add', 'controls', 2147483647, 1, 6),
+('bx_developer_forms_prevalue_add', 'do_submit', 2147483647, 1, 7),
+('bx_developer_forms_prevalue_add', 'cancel', 2147483647, 1, 8),
+
+('bx_developer_forms_prevalue_edit', 'id', 2147483647, 1, 1),
+('bx_developer_forms_prevalue_edit', 'Key', 2147483647, 1, 2),
+('bx_developer_forms_prevalue_edit', 'Value', 2147483647, 1, 3),
+('bx_developer_forms_prevalue_edit', 'LKey', 2147483647, 1, 4),
+('bx_developer_forms_prevalue_edit', 'LKey2', 2147483647, 1, 5),
+('bx_developer_forms_prevalue_edit', 'Data', 2147483647, 1, 6),
+('bx_developer_forms_prevalue_edit', 'controls', 2147483647, 1, 7),
+('bx_developer_forms_prevalue_edit', 'do_submit', 2147483647, 1, 8),
+('bx_developer_forms_prevalue_edit', 'cancel', 2147483647, 1, 9);
+
+--
+-- Forms Builder -> Search Forms.
+--
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_developer_forms_search_form', @sName, '_bx_dev_frm_txt_search_forms_form', '', '', 'do_submit', 'sys_objects_search_extended', 'id', '', '', '', 0, 1, 'BxDevFormView', 'modules/boonex/developer/classes/BxDevFormView.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_developer_forms_search_form_add', @sName, 'bx_developer_forms_search_form', '_bx_dev_frm_txt_search_forms_display_add', 0),
+('bx_developer_forms_search_form_edit', @sName, 'bx_developer_forms_search_form', '_bx_dev_frm_txt_search_forms_display_edit', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_developer_forms_search_form', @sName, 'id', '0', '', 0, 'hidden', '_bx_dev_frm_txt_sys_search_forms_id', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_forms_search_form', @sName, 'object', '', '', 0, 'text', '_bx_dev_frm_txt_sys_search_forms_object', '_bx_dev_frm_txt_search_forms_object', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_frm_err_forms_object', 'Xss', '', 0, 0),
+('bx_developer_forms_search_form', @sName, 'object_content_info', '', '', 0, 'select', '_bx_dev_frm_txt_sys_search_forms_object_content_info', '_bx_dev_frm_txt_search_forms_object_content_info', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_frm_err_forms_object_content_info', 'Xss', '', 0, 0),
+('bx_developer_forms_search_form', @sName, 'module', '', '', 0, 'select', '_bx_dev_frm_txt_sys_search_forms_module', '_bx_dev_frm_txt_search_forms_module', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_frm_err_forms_module', 'Xss', '', 0, 0),
+('bx_developer_forms_search_form', @sName, 'title', '', '', 0, 'text', '_bx_dev_frm_txt_sys_search_forms_title', '_bx_dev_frm_txt_search_forms_title', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_frm_err_forms_title', 'Xss', '', 0, 0),
+('bx_developer_forms_search_form', @sName, 'class_name', '', '', 0, 'text', '_bx_dev_frm_txt_sys_search_forms_class_name', '_bx_dev_frm_txt_search_forms_class_name', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_search_form', @sName, 'class_file', '', '', 0, 'text', '_bx_dev_frm_txt_sys_search_forms_class_file', '_bx_dev_frm_txt_search_forms_class_file', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_search_form', @sName, 'controls', '', 'do_submit,cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_forms_search_form', @sName, 'do_submit', '_bx_dev_frm_btn_search_forms_add', '', 0, 'submit', '_bx_dev_frm_btn_sys_search_forms_add', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_forms_search_form', @sName, 'cancel', '_bx_dev_frm_btn_search_forms_cancel', '', 0, 'button', '_bx_dev_frm_btn_sys_search_forms_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_developer_forms_search_form_add', 'object', 2147483647, 1, 1),
+('bx_developer_forms_search_form_add', 'object_content_info', 2147483647, 1, 2),
+('bx_developer_forms_search_form_add', 'module', 2147483647, 1, 3),
+('bx_developer_forms_search_form_add', 'title', 2147483647, 1, 4),
+('bx_developer_forms_search_form_add', 'class_name', 2147483647, 1, 5),
+('bx_developer_forms_search_form_add', 'class_file', 2147483647, 1, 6),
+('bx_developer_forms_search_form_add', 'controls', 2147483647, 1, 7),
+('bx_developer_forms_search_form_add', 'do_submit', 2147483647, 1, 8),
+('bx_developer_forms_search_form_add', 'cancel', 2147483647, 1, 9),
+
+('bx_developer_forms_search_form_edit', 'id', 2147483647, 1, 1),
+('bx_developer_forms_search_form_edit', 'object', 2147483647, 1, 2),
+('bx_developer_forms_search_form_edit', 'object_content_info', 2147483647, 1, 3),
+('bx_developer_forms_search_form_edit', 'module', 2147483647, 1, 4),
+('bx_developer_forms_search_form_edit', 'title', 2147483647, 1, 5),
+('bx_developer_forms_search_form_edit', 'class_name', 2147483647, 1, 6),
+('bx_developer_forms_search_form_edit', 'class_file', 2147483647, 1, 7),
+('bx_developer_forms_search_form_edit', 'controls', 2147483647, 1, 8),
+('bx_developer_forms_search_form_edit', 'do_submit', 2147483647, 1, 9),
+('bx_developer_forms_search_form_edit', 'cancel', 2147483647, 1, 10);
+
+--
+-- Forms Builder -> Search Fields.
+--
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_developer_forms_search_fields', @sName, '_bx_dev_frm_txt_search_fields_form', '', '', 'do_submit', 'sys_search_extended_fields', 'id', '', '', '', 0, 1, 'BxDevFormView', 'modules/boonex/developer/classes/BxDevFormView.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_developer_forms_search_fields_edit', @sName, 'bx_developer_forms_search_fields', '_bx_dev_frm_txt_search_fields_display_edit', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_developer_forms_search_fields', @sName, 'id', '0', '', 0, 'hidden', '_bx_dev_frm_txt_sys_search_fields_id', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_forms_search_fields', @sName, 'object', '', '', 0, 'select', '_bx_dev_frm_txt_sys_search_fields_object', '_bx_dev_frm_txt_search_fields_object', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_frm_err_forms_object', 'Xss', '', 0, 0),
+('bx_developer_forms_search_fields', @sName, 'name', '', '', 0, 'text', '_bx_dev_frm_txt_sys_search_fields_name', '_bx_dev_frm_txt_search_fields_name', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_frm_err_search_fields_name', 'Xss', '', 0, 0),
+('bx_developer_forms_search_fields', @sName, 'type', '', '', 0, 'select', '_bx_dev_frm_txt_sys_search_fields_type', '_bx_dev_frm_txt_search_fields_type', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_frm_err_search_fields_type', 'Xss', '', 0, 0),
+('bx_developer_forms_search_fields', @sName, 'caption', '', '', 0, 'text', '_bx_dev_frm_txt_sys_search_fields_caption', '_bx_dev_frm_txt_search_fields_caption', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_frm_err_search_fields_caption', 'Xss', '', 0, 0),
+('bx_developer_forms_search_fields', @sName, 'values', '', '', 0, 'text', '_bx_dev_frm_txt_sys_search_fields_values', '_bx_dev_frm_txt_search_fields_values', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_search_fields', @sName, 'search_type', '', '', 0, 'select', '_bx_dev_frm_txt_sys_search_fields_search_type', '_bx_dev_frm_txt_search_fields_search_type', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_frm_err_search_fields_search_type', 'Xss', '', 0, 0),
+('bx_developer_forms_search_fields', @sName, 'search_value', '', '', 0, 'text', '_bx_dev_frm_txt_sys_search_fields_search_value', '_bx_dev_frm_txt_search_fields_search_value', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_forms_search_fields', @sName, 'search_operator', '', '', 0, 'select', '_bx_dev_frm_txt_sys_search_fields_search_operator', '_bx_dev_frm_txt_search_fields_search_operator', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_frm_err_search_fields_search_operator', 'Xss', '', 0, 0),
+('bx_developer_forms_search_fields', @sName, 'controls', '', 'do_submit,cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_forms_search_fields', @sName, 'do_submit', '_bx_dev_frm_btn_search_fields_save', '', 0, 'submit', '_bx_dev_frm_btn_sys_search_fields_save', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_forms_search_fields', @sName, 'cancel', '_bx_dev_frm_btn_search_fields_cancel', '', 0, 'button', '_bx_dev_frm_btn_sys_search_fields_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_developer_forms_search_fields_edit', 'id', 2147483647, 1, 1),
+('bx_developer_forms_search_fields_edit', 'object', 2147483647, 1, 2),
+('bx_developer_forms_search_fields_edit', 'name', 2147483647, 1, 3),
+('bx_developer_forms_search_fields_edit', 'type', 2147483647, 1, 4),
+('bx_developer_forms_search_fields_edit', 'caption', 2147483647, 1, 5),
+('bx_developer_forms_search_fields_edit', 'values', 2147483647, 1, 6),
+('bx_developer_forms_search_fields_edit', 'search_type', 2147483647, 1, 7),
+('bx_developer_forms_search_fields_edit', 'search_value', 2147483647, 1, 8),
+('bx_developer_forms_search_fields_edit', 'search_operator', 2147483647, 1, 9),
+('bx_developer_forms_search_fields_edit', 'controls', 2147483647, 1, 10),
+('bx_developer_forms_search_fields_edit', 'do_submit', 2147483647, 1, 11),
+('bx_developer_forms_search_fields_edit', 'cancel', 2147483647, 1, 12);
+
+--
+-- Navigation Builder -> Grid descriptors
+--
+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_developer_nav_menus', 'Sql', 'SELECT `tm`.*, `tms`.`title` AS `set_title`, `tmt`.`title` AS `template_title` FROM `sys_objects_menu` AS `tm` LEFT JOIN `sys_menu_sets` AS `tms` ON `tm`.`set_name`=`tms`.`set_name` LEFT JOIN `sys_menu_templates` AS `tmt` ON `tm`.`template_id`=`tmt`.`id` WHERE 1 ', 'sys_objects_menu', 'id', '', 'active', '', 100, NULL, 'start', '', '', 'tm`.`title,tms`.`title,tmt`.`title', 'auto', '', '', 2147483647, 'BxDevNavigationMenus', 'modules/boonex/developer/classes/BxDevNavigationMenus.php'),
+('bx_developer_nav_sets', 'Sql', 'SELECT * FROM `sys_menu_sets` WHERE 1 ', 'sys_menu_sets', 'set_name', '', '', '', 100, NULL, 'start', '', '', 'title', 'auto', '', '', 2147483647, 'BxDevNavigationSets', 'modules/boonex/developer/classes/BxDevNavigationSets.php'),
+('bx_developer_nav_items', 'Sql', 'SELECT * FROM `sys_menu_items` WHERE 1 ', 'sys_menu_items', 'id', 'order', 'active', '', 100, NULL, 'start_it', '', 'link', 'title_system', 'like', '', '', 2147483647, 'BxDevNavigationItems', 'modules/boonex/developer/classes/BxDevNavigationItems.php');
+
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_developer_nav_menus', 'switcher', '', '10%', 0, '', '', 1),
+('bx_developer_nav_menus', 'title', '_bx_dev_nav_txt_menus_gl_title', '17%', 0, '15', '', 2),
+('bx_developer_nav_menus', 'set_title', '_bx_dev_nav_txt_menus_gl_set_title', '17%', 1, '15', '', 3),
+('bx_developer_nav_menus', 'items', '_bx_dev_nav_txt_menus_gl_items', '10%', 0, '8', '', 4),
+('bx_developer_nav_menus', 'template_title', '_bx_dev_nav_txt_menus_gl_template_title', '17%', 1, '15', '', 5),
+('bx_developer_nav_menus', 'module', '_bx_dev_nav_txt_menus_gl_module', '12%', 0, '10', '', 6),
+('bx_developer_nav_menus', 'actions', '', '17%', 0, '', '', 7),
+('bx_developer_nav_sets', 'title', '_bx_dev_nav_txt_sets_gl_title', '50%', 1, '48', '', 1),
+('bx_developer_nav_sets', 'module', '_bx_dev_nav_txt_sets_gl_module', '15%', 0, '13', '', 2),
+('bx_developer_nav_sets', 'items', '_bx_dev_nav_txt_sets_gl_items', '15%', 0, '13', '', 3),
+('bx_developer_nav_sets', 'actions', '', '20%', 0, '', '', 4),
+('bx_developer_nav_items', 'order', '', '1%', 0, '', '', 1),
+('bx_developer_nav_items', 'switcher', '', '9%', 0, '', '', 2),
+('bx_developer_nav_items', 'icon', '_bx_dev_nav_txt_items_gl_icon', '5%', 0, '', '', 3),
+('bx_developer_nav_items', 'title_system', '_bx_dev_nav_txt_items_gl_title_system', '23%', 1, '23', '', 4),
+('bx_developer_nav_items', 'link', '_bx_dev_nav_txt_items_gl_link', '23%', 0, '23', '', 5),
+('bx_developer_nav_items', 'module', '_bx_dev_nav_txt_items_gl_module', '12%', 0, '12', '', 6),
+('bx_developer_nav_items', 'visible_for_levels', '_bx_dev_nav_txt_items_gl_visible', '10%', 0, '10', '', 7),
+('bx_developer_nav_items', 'actions', '', '17%', 0, '', '', 8);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_developer_nav_menus', 'independent', 'add', '_bx_dev_nav_btn_menus_gl_create', '', 0, 1),
+('bx_developer_nav_menus', 'independent', 'import_full', '_bx_dev_btn_import_full', '', 0, 2),
+('bx_developer_nav_menus', 'independent', 'export_full', '_bx_dev_btn_export_full', '', 0, 3),
+('bx_developer_nav_menus', 'single', 'export', '', 'download', 0, 1),
+('bx_developer_nav_menus', 'single', 'edit', '', 'pencil-alt', 0, 2),
+('bx_developer_nav_menus', 'single', 'delete', '', 'remove', 1, 3),
+
+('bx_developer_nav_sets', 'independent', 'add', '_bx_dev_nav_btn_sets_gl_create', '', 0, 1),
+('bx_developer_nav_sets', 'single', 'edit', '', 'pencil-alt', 0, 1),
+('bx_developer_nav_sets', 'single', 'delete', '', 'remove', 1, 2),
+
+('bx_developer_nav_items', 'independent', 'import', '_bx_dev_nav_btn_items_gl_import', '', 0, 1),
+('bx_developer_nav_items', 'independent', 'add', '_bx_dev_nav_btn_items_gl_create', '', 0, 2),
+('bx_developer_nav_items', 'single', 'edit', '', 'pencil-alt', 0, 1),
+('bx_developer_nav_items', 'single', 'delete', '', 'remove', 1, 2),
+('bx_developer_nav_items', 'single', 'show_to', '_bx_dev_nav_btn_items_gl_visible', '', 0, 3);
+
+--
+-- Navigation Builder -> Menus.
+--
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_developer_nav_menu', @sName, '_bx_dev_nav_txt_menus_menu', '', '', 'do_submit', 'sys_objects_menu', 'id', '', '', '', 0, 1, 'BxDevFormView', 'modules/boonex/developer/classes/BxDevFormView.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_developer_nav_menu_add', @sName, 'bx_developer_nav_menu', '_bx_dev_nav_txt_menus_display_add', 0),
+('bx_developer_nav_menu_edit', @sName, 'bx_developer_nav_menu', '_bx_dev_nav_txt_menus_display_edit', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_developer_nav_menu', @sName, 'id', '0', '', 0, 'hidden', '_bx_dev_nav_txt_sys_menus_id', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_nav_menu', @sName, 'object', '', '', 0, 'text', '_bx_dev_nav_txt_sys_menus_object', '_bx_dev_nav_txt_menus_object', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_nav_err_menus_object', 'Xss', '', 0, 0),
+('bx_developer_nav_menu', @sName, 'module', '', '', 0, 'select', '_bx_dev_nav_txt_sys_menus_module', '_bx_dev_nav_txt_menus_module', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_nav_err_menus_module', 'Xss', '', 0, 0),
+('bx_developer_nav_menu', @sName, 'title', '', '', 0, 'text', '_bx_dev_nav_txt_sys_menus_title', '_bx_dev_nav_txt_menus_title', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_nav_err_menus_title', 'Xss', '', 0, 0),
+('bx_developer_nav_menu', @sName, 'set_name', '', '', 0, 'select', '_bx_dev_nav_txt_sys_menus_set_name', '_bx_dev_nav_txt_menus_set_name', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_nav_menu', @sName, 'template_id', '', '', 0, 'select', '_bx_dev_nav_txt_sys_menus_template_id', '_bx_dev_nav_txt_menus_template_id', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_nav_err_menus_template_id', 'Int', '', 0, 0),
+('bx_developer_nav_menu', @sName, 'deletable', '1', '', 0, 'switcher', '_bx_dev_nav_txt_sys_menus_deletable', '_bx_dev_nav_txt_menus_deletable', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_nav_menu', @sName, 'override_class_name', '', '', 0, 'text', '_bx_dev_nav_txt_sys_menus_override_class_name', '_bx_dev_nav_txt_menus_override_class_name', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_nav_menu', @sName, 'override_class_file', '', '', 0, 'text', '_bx_dev_nav_txt_sys_menus_override_class_file', '_bx_dev_nav_txt_menus_override_class_file', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_nav_menu', @sName, 'controls', '', 'do_submit,cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_nav_menu', @sName, 'do_submit', '_bx_dev_nav_btn_menus_add', '', 0, 'submit', '_bx_dev_nav_btn_sys_menus_add', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_nav_menu', @sName, 'cancel', '_bx_dev_nav_btn_menus_cancel', '', 0, 'button', '_bx_dev_nav_btn_sys_menus_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_developer_nav_menu_add', 'object', 2147483647, 1, 1),
+('bx_developer_nav_menu_add', 'module', 2147483647, 1, 2),
+('bx_developer_nav_menu_add', 'title', 2147483647, 1, 3),
+('bx_developer_nav_menu_add', 'set_name', 2147483647, 1, 4),
+('bx_developer_nav_menu_add', 'template_id', 2147483647, 1, 5),
+('bx_developer_nav_menu_add', 'deletable', 2147483647, 1, 6),
+('bx_developer_nav_menu_add', 'override_class_name', 2147483647, 1, 7),
+('bx_developer_nav_menu_add', 'override_class_file', 2147483647, 1, 8),
+('bx_developer_nav_menu_add', 'controls', 2147483647, 1, 9),
+('bx_developer_nav_menu_add', 'do_submit', 2147483647, 1, 10),
+('bx_developer_nav_menu_add', 'cancel', 2147483647, 1, 11),
+('bx_developer_nav_menu_edit', 'id', 2147483647, 1, 1),
+('bx_developer_nav_menu_edit', 'object', 2147483647, 1, 2),
+('bx_developer_nav_menu_edit', 'module', 2147483647, 1, 3),
+('bx_developer_nav_menu_edit', 'title', 2147483647, 1, 4),
+('bx_developer_nav_menu_edit', 'set_name', 2147483647, 1, 5),
+('bx_developer_nav_menu_edit', 'template_id', 2147483647, 1, 6),
+('bx_developer_nav_menu_edit', 'deletable', 2147483647, 1, 7),
+('bx_developer_nav_menu_edit', 'override_class_name', 2147483647, 1, 8),
+('bx_developer_nav_menu_edit', 'override_class_file', 2147483647, 1, 9),
+('bx_developer_nav_menu_edit', 'controls', 2147483647, 1, 10),
+('bx_developer_nav_menu_edit', 'do_submit', 2147483647, 1, 11),
+('bx_developer_nav_menu_edit', 'cancel', 2147483647, 1, 12);
+
+--
+-- Navigation Builder -> Sets.
+--
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_developer_nav_set', @sName, '_bx_dev_nav_txt_sets_set', '', '', 'do_submit', 'sys_menu_sets', 'set_name', '', '', '', 0, 1, 'BxDevFormView', 'modules/boonex/developer/classes/BxDevFormView.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_developer_nav_set_add', @sName, 'bx_developer_nav_set', '_bx_dev_nav_txt_sets_display_add', 0),
+('bx_developer_nav_set_edit', @sName, 'bx_developer_nav_set', '_bx_dev_nav_txt_sets_display_edit', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_developer_nav_set', @sName, 'module', '', '', 0, 'select', '_bx_dev_nav_txt_sys_sets_module', '_bx_dev_nav_txt_sets_module', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_nav_err_sets_module', 'Xss', '', 0, 0),
+('bx_developer_nav_set', @sName, 'set_name', '', '', 0, 'text', '_bx_dev_nav_txt_sys_sets_set_name', '_bx_dev_nav_txt_sets_set_name', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_nav_err_sets_set_name', 'Xss', '', 0, 0),
+('bx_developer_nav_set', @sName, 'title', '', '', 0, 'text', '_bx_dev_nav_txt_sys_sets_title', '_bx_dev_nav_txt_sets_title', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_nav_err_sets_title', 'Xss', '', 0, 0),
+('bx_developer_nav_set', @sName, 'deletable', '1', '', 0, 'switcher', '_bx_dev_nav_txt_sys_sets_deletable', '_bx_dev_nav_txt_sets_deletable', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_nav_set', @sName, 'controls', '', 'do_submit,cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_nav_set', @sName, 'do_submit', '_bx_dev_nav_btn_sets_add', '', 0, 'submit', '_bx_dev_nav_btn_sys_sets_add', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_nav_set', @sName, 'cancel', '_bx_dev_nav_btn_sets_cancel', '', 0, 'button', '_bx_dev_nav_btn_sys_sets_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_developer_nav_set_add', 'module', 2147483647, 1, 1),
+('bx_developer_nav_set_add', 'set_name', 2147483647, 1, 2),
+('bx_developer_nav_set_add', 'title', 2147483647, 1, 3),
+('bx_developer_nav_set_add', 'deletable', 2147483647, 1, 4),
+('bx_developer_nav_set_add', 'controls', 2147483647, 1, 5),
+('bx_developer_nav_set_add', 'do_submit', 2147483647, 1, 6),
+('bx_developer_nav_set_add', 'cancel', 2147483647, 1, 7),
+('bx_developer_nav_set_edit', 'module', 2147483647, 1, 1),
+('bx_developer_nav_set_edit', 'set_name', 2147483647, 0, 2),
+('bx_developer_nav_set_edit', 'title', 2147483647, 1, 3),
+('bx_developer_nav_set_edit', 'deletable', 2147483647, 1, 4),
+('bx_developer_nav_set_edit', 'controls', 2147483647, 1, 5),
+('bx_developer_nav_set_edit', 'do_submit', 2147483647, 1, 6),
+('bx_developer_nav_set_edit', 'cancel', 2147483647, 1, 7);
+
+--
+-- Navigation Builder -> Items.
+--
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_developer_nav_item', @sName, '_bx_dev_nav_txt_items_item', '', '', 'do_submit', 'sys_menu_items', 'id', '', '', '', 0, 1, 'BxDevFormView', 'modules/boonex/developer/classes/BxDevFormView.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_developer_nav_item_add', @sName, 'bx_developer_nav_item', '_bx_dev_nav_txt_items_display_add', 0),
+('bx_developer_nav_item_edit', @sName, 'bx_developer_nav_item', '_bx_dev_nav_txt_items_display_edit', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_developer_nav_item', @sName, 'id', '0', '', 0, 'hidden', '_bx_dev_nav_txt_sys_items_id', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_nav_item', @sName, 'module', '', '', 0, 'select', '_bx_dev_nav_txt_sys_items_module', '_bx_dev_nav_txt_items_module', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_nav_err_items_module', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'set_name', '', '', 0, 'text', '_bx_dev_nav_txt_sys_items_set_name', '_bx_dev_nav_txt_items_set_name', '', 0, 0, 0, 'a:1:{s:8:"readonly";s:8:"readonly";}', '', '', 'Avail', '', '_bx_dev_nav_err_items_set_name', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'name', '', '', 0, 'text', '_bx_dev_nav_txt_sys_items_name', '_bx_dev_nav_txt_items_name', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_nav_err_items_name', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'title_system', '', '', 0, 'text', '_bx_dev_nav_txt_sys_items_title_system', '_bx_dev_nav_txt_items_title_system', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'title', '', '', 0, 'text', '_bx_dev_nav_txt_sys_items_title', '_bx_dev_nav_txt_items_title', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_nav_err_items_title', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'link', '', '', 0, 'text', '_bx_dev_nav_txt_sys_items_link', '_bx_dev_nav_txt_items_link', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'onclick', '', '', 0, 'text', '_bx_dev_nav_txt_sys_items_onclick', '_bx_dev_nav_txt_items_onclick', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'target', '', '', 0, 'text', '_bx_dev_nav_txt_sys_items_target', '_bx_dev_nav_txt_items_target', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'icon', '', '', 0, 'text', '_bx_dev_nav_txt_sys_items_icon', '_bx_dev_nav_txt_items_icon', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'addon', '', '', 0, 'textarea', '_bx_dev_nav_txt_sys_items_addon', '_bx_dev_nav_txt_items_addon', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'submenu_object', '', '', 0, 'text', '_bx_dev_nav_txt_sys_items_submenu_object', '_bx_dev_nav_txt_items_submenu_object', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'submenu_popup', '1', '', 0, 'switcher', '_bx_dev_nav_txt_sys_items_submenu_popup', '_bx_dev_nav_txt_items_submenu_popup', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_nav_item', @sName, 'visibility_custom', '', '', 0, 'textarea', '_bx_dev_nav_txt_sys_items_visibility_custom', '_bx_dev_nav_txt_items_visibility_custom', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'hidden_on', '', '', 0, 'select_multiple', '_bx_dev_nav_txt_sys_items_hidden_on', '_bx_dev_nav_txt_items_hidden_on', '', 0, 0, 0, '', '', '', '', '', '', 'Set', '', 0, 0),
+('bx_developer_nav_item', @sName, 'hidden_on_pt', '', '', 0, 'select_multiple', '_bx_dev_nav_txt_sys_items_hidden_on_pt', '_bx_dev_nav_txt_items_hidden_on_pt', '', 0, 0, 0, '', '', '', '', '', '', 'Set', '', 0, 0),
+('bx_developer_nav_item', @sName, 'hidden_on_col', '', '', 0, 'select_multiple', '_bx_dev_nav_txt_sys_items_hidden_on_col', '_bx_dev_nav_txt_items_hidden_on_col', '', 0, 0, 0, '', '', '', '', '', '', 'Set', '', 0, 0),
+('bx_developer_nav_item', @sName, 'hidden_on_cxt', '', '', 0, 'text', '_bx_dev_nav_txt_sys_items_hidden_on_cxt', '_bx_dev_nav_txt_items_hidden_on_cxt', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_nav_item', @sName, 'primary', '1', '', 0, 'switcher', '_bx_dev_nav_txt_sys_items_primary', '_bx_dev_nav_txt_items_primary', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_nav_item', @sName, 'collapsed', '1', '', 0, 'switcher', '_bx_dev_nav_txt_sys_items_collapsed', '_bx_dev_nav_txt_items_collapsed', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_nav_item', @sName, 'copyable', '1', '', 0, 'switcher', '_bx_dev_nav_txt_sys_items_copyable', '_bx_dev_nav_txt_items_copyable', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_nav_item', @sName, 'active_api', '1', '', 0, 'switcher', '_bx_dev_nav_txt_sys_items_active_api', '_bx_dev_nav_txt_items_active_api', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_nav_item', @sName, 'controls', '', 'do_submit,cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_nav_item', @sName, 'do_submit', '_bx_dev_nav_btn_items_add', '', 0, 'submit', '_bx_dev_nav_btn_sys_items_add', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_nav_item', @sName, 'cancel', '_bx_dev_nav_btn_items_cancel', '', 0, 'button', '_bx_dev_nav_btn_sys_items_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_developer_nav_item_add', 'module', 2147483647, 1, 1),
+('bx_developer_nav_item_add', 'set_name', 2147483647, 1, 2),
+('bx_developer_nav_item_add', 'name', 2147483647, 1, 3),
+('bx_developer_nav_item_add', 'title_system', 2147483647, 1, 4),
+('bx_developer_nav_item_add', 'title', 2147483647, 1, 5),
+('bx_developer_nav_item_add', 'link', 2147483647, 1, 6),
+('bx_developer_nav_item_add', 'onclick', 2147483647, 1, 7),
+('bx_developer_nav_item_add', 'target', 2147483647, 1, 8),
+('bx_developer_nav_item_add', 'icon', 2147483647, 1, 9),
+('bx_developer_nav_item_add', 'addon', 2147483647, 1, 10),
+('bx_developer_nav_item_add', 'submenu_object', 2147483647, 1, 11),
+('bx_developer_nav_item_add', 'submenu_popup', 2147483647, 1, 12),
+('bx_developer_nav_item_add', 'visibility_custom', 2147483647, 1, 13),
+('bx_developer_nav_item_add', 'hidden_on', 2147483647, 1, 14),
+('bx_developer_nav_item_add', 'hidden_on_pt', 2147483647, 1, 15),
+('bx_developer_nav_item_add', 'hidden_on_col', 2147483647, 1, 16),
+('bx_developer_nav_item_add', 'hidden_on_cxt', 2147483647, 1, 17),
+('bx_developer_nav_item_add', 'primary', 2147483647, 1, 18),
+('bx_developer_nav_item_add', 'collapsed', 2147483647, 1, 19),
+('bx_developer_nav_item_add', 'copyable', 2147483647, 1, 20),
+('bx_developer_nav_item_add', 'active_api', 2147483647, 1, 21),
+('bx_developer_nav_item_add', 'controls', 2147483647, 1, 22),
+('bx_developer_nav_item_add', 'do_submit', 2147483647, 1, 23),
+('bx_developer_nav_item_add', 'cancel', 2147483647, 1, 24),
+
+('bx_developer_nav_item_edit', 'id', 2147483647, 1, 1),
+('bx_developer_nav_item_edit', 'module', 2147483647, 1, 2),
+('bx_developer_nav_item_edit', 'set_name', 2147483647, 1, 3),
+('bx_developer_nav_item_edit', 'name', 2147483647, 1, 4),
+('bx_developer_nav_item_edit', 'title_system', 2147483647, 1, 5),
+('bx_developer_nav_item_edit', 'title', 2147483647, 1, 6),
+('bx_developer_nav_item_edit', 'link', 2147483647, 1, 7),
+('bx_developer_nav_item_edit', 'onclick', 2147483647, 1, 8),
+('bx_developer_nav_item_edit', 'target', 2147483647, 1, 9),
+('bx_developer_nav_item_edit', 'icon', 2147483647, 1, 10),
+('bx_developer_nav_item_edit', 'addon', 2147483647, 1, 11),
+('bx_developer_nav_item_edit', 'submenu_object', 2147483647, 1, 12),
+('bx_developer_nav_item_edit', 'submenu_popup', 2147483647, 1, 13),
+('bx_developer_nav_item_edit', 'visibility_custom', 2147483647, 1, 14),
+('bx_developer_nav_item_edit', 'hidden_on', 2147483647, 1, 15),
+('bx_developer_nav_item_edit', 'hidden_on_pt', 2147483647, 1, 16),
+('bx_developer_nav_item_edit', 'hidden_on_col', 2147483647, 1, 17),
+('bx_developer_nav_item_edit', 'hidden_on_cxt', 2147483647, 1, 18),
+('bx_developer_nav_item_edit', 'primary', 2147483647, 1, 19),
+('bx_developer_nav_item_edit', 'collapsed', 2147483647, 1, 20),
+('bx_developer_nav_item_edit', 'copyable', 2147483647, 1, 21),
+('bx_developer_nav_item_edit', 'active_api', 2147483647, 1, 22),
+('bx_developer_nav_item_edit', 'controls', 2147483647, 1, 23),
+('bx_developer_nav_item_edit', 'do_submit', 2147483647, 1, 24),
+('bx_developer_nav_item_edit', 'cancel', 2147483647, 1, 25);
+
+--
+-- Page Builder -> Page.
+--
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_developer_bp_page', @sName, '_bx_dev_bp_txt_page_form', '', '', 'do_submit', 'sys_objects_page', 'id', '', '', '', 0, 1, 'BxDevFormView', 'modules/boonex/developer/classes/BxDevFormView.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_developer_bp_page_add', @sName, 'bx_developer_bp_page', '_bx_dev_bp_txt_page_display_add', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_developer_bp_page', @sName, 'object', '', '', 0, 'text', '_bx_dev_bp_txt_sys_page_object', '_bx_dev_bp_txt_page_object', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_bp_err_page_object', 'Xss', '', 0, 0),
+('bx_developer_bp_page', @sName, 'module', '', '', 0, 'select', '_bx_dev_bp_txt_sys_page_module', '_bx_dev_bp_txt_page_module', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_bp_err_page_module', 'Xss', '', 0, 0),
+('bx_developer_bp_page', @sName, 'title_system', '', '', 0, 'text', '_bx_dev_bp_txt_sys_page_title_system', '_bx_dev_bp_txt_page_title_system', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_bp_page', @sName, 'title', '', '', 0, 'text', '_bx_dev_bp_txt_sys_page_title', '_bx_dev_bp_txt_page_title', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_bp_err_page_title', 'Xss', '', 0, 0),
+('bx_developer_bp_page', @sName, 'uri', '', '', 0, 'text', '_bx_dev_bp_txt_sys_page_uri', '_bx_dev_bp_txt_page_uri', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_bp_page', @sName, 'url', '', '', 0, 'text', '_bx_dev_bp_txt_sys_page_url', '_bx_dev_bp_txt_page_url', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_bp_page', @sName, 'layout_id', '', '', 0, 'select', '_bx_dev_bp_txt_sys_page_layout_id', '_bx_dev_bp_txt_page_layout_id', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_bp_err_page_layout_id', 'Int', '', 0, 0),
+('bx_developer_bp_page', @sName, 'deletable', '1', '', 0, 'switcher', '_bx_dev_bp_txt_sys_page_deletable', '_bx_dev_bp_txt_page_deletable', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_bp_page', @sName, 'override_class_name', '', '', 0, 'text', '_bx_dev_bp_txt_sys_page_override_class_name', '_bx_dev_bp_txt_page_override_class_name', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_bp_page', @sName, 'override_class_file', '', '', 0, 'text', '_bx_dev_bp_txt_sys_page_override_class_file', '_bx_dev_bp_txt_page_override_class_file', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_bp_page', @sName, 'controls', '', 'do_submit,cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_bp_page', @sName, 'do_submit', '_bx_dev_bp_btn_page_add', '', 0, 'submit', '_bx_dev_bp_btn_sys_page_add', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_bp_page', @sName, 'cancel', '_bx_dev_bp_btn_page_cancel', '', 0, 'button', '_bx_dev_bp_btn_sys_page_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_developer_bp_page_add', 'object', 2147483647, 1, 1),
+('bx_developer_bp_page_add', 'module', 2147483647, 1, 2),
+('bx_developer_bp_page_add', 'title_system', 2147483647, 1, 3),
+('bx_developer_bp_page_add', 'title', 2147483647, 1, 4),
+('bx_developer_bp_page_add', 'uri', 2147483647, 1, 5),
+('bx_developer_bp_page_add', 'url', 2147483647, 1, 6),
+('bx_developer_bp_page_add', 'layout_id', 2147483647, 1, 7),
+('bx_developer_bp_page_add', 'deletable', 2147483647, 1, 8),
+('bx_developer_bp_page_add', 'override_class_name', 2147483647, 1, 9),
+('bx_developer_bp_page_add', 'override_class_file', 2147483647, 1, 10),
+('bx_developer_bp_page_add', 'controls', 2147483647, 1, 11),
+('bx_developer_bp_page_add', 'do_submit', 2147483647, 1, 12),
+('bx_developer_bp_page_add', 'cancel', 2147483647, 1, 13);
+
+--
+-- Page Builder -> Block.
+--
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_developer_bp_block', @sName, '_bx_dev_bp_txt_block_form', '', '', 'do_submit', 'sys_pages_blocks', 'id', '', '', '', 0, 1, 'BxDevFormView', 'modules/boonex/developer/classes/BxDevFormView.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_developer_bp_block_edit', @sName, 'bx_developer_bp_block', '_bx_dev_bp_txt_block_display_edit', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_developer_bp_block', @sName, 'id', '0', '', 0, 'hidden', '_bx_dev_bp_txt_sys_block_id', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_bp_block', @sName, 'object', '', '', 0, 'text', '_bx_dev_bp_txt_sys_block_object', '_bx_dev_bp_txt_block_object', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:1;s:3:"max";i:64;}', '_bx_dev_bp_err_block_object', 'Xss', '', 0, 0),
+('bx_developer_bp_block', @sName, 'module', '', '', 0, 'select', '_bx_dev_bp_txt_sys_block_module', '_bx_dev_bp_txt_block_module', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_bp_err_block_module', 'Xss', '', 0, 0),
+('bx_developer_bp_block', @sName, 'title_system', '', '', 0, 'text', '_bx_dev_bp_txt_sys_block_title_system', '_bx_dev_bp_txt_block_title_system', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_bp_block', @sName, 'title', '', '', 0, 'text', '_bx_dev_bp_txt_sys_block_title', '_bx_dev_bp_txt_block_title', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:100;}', '_bx_dev_bp_err_block_title', 'Xss', '', 0, 0),
+('bx_developer_bp_block', @sName, 'designbox_id', '', '', 0, 'select', '_bx_dev_bp_txt_sys_block_designbox_id', '_bx_dev_bp_txt_block_designbox_id', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_bp_err_block_designbox_id', 'Xss', '', 0, 0),
+('bx_developer_bp_block', @sName, 'class', '', '', 0, 'text', '_bx_dev_bp_txt_sys_block_class', '_bx_dev_bp_txt_block_class', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+
+('bx_developer_bp_block', @sName, 'async', '', '', 0, 'select', '_bx_dev_bp_txt_sys_block_async', '_bx_dev_bp_txt_block_async', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_bp_block', @sName, 'submenu', '', '', 0, 'select', '_bx_dev_bp_txt_sys_block_submenu', '_bx_dev_bp_txt_block_submenu', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_bp_block', @sName, 'tabs', '1', '', 0, 'switcher', '_bx_dev_bp_txt_sys_block_tabs', '_bx_dev_bp_txt_block_tabs', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_bp_block', @sName, 'hidden_on', '', '', 0, 'select_multiple', '_bx_dev_bp_txt_sys_block_hidden_on', '_bx_dev_bp_txt_block_hidden_on', '', 0, 0, 0, '', '', '', '', '', '', 'Set', '', 0, 0),
+
+('bx_developer_bp_block', @sName, 'visible_for', '', '', 0, 'select', '_bx_dev_bp_txt_sys_block_visible_for', '_bx_dev_bp_txt_block_visible_for', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_developer_bp_block', @sName, 'visible_for_levels', '', '', 0, 'checkbox_set', '_bx_dev_bp_txt_sys_block_visible_for_levels', '_bx_dev_bp_txt_block_visible_for_levels', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_bp_block', @sName, 'deletable', '1', '', 0, 'switcher', '_bx_dev_bp_txt_sys_block_deletable', '_bx_dev_bp_txt_block_deletable', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_bp_block', @sName, 'copyable', '1', '', 0, 'switcher', '_bx_dev_bp_txt_sys_block_copyable', '_bx_dev_bp_txt_block_copyable', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_bp_block', @sName, 'active', '1', '', 0, 'switcher', '_bx_dev_bp_txt_sys_block_active', '_bx_dev_bp_txt_block_active', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_bp_block', @sName, 'active_api', '1', '', 0, 'switcher', '_bx_dev_bp_txt_sys_block_active_api', '_bx_dev_bp_txt_block_active_api', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_bp_block', @sName, 'controls', '', 'do_submit,cancel,delete', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_bp_block', @sName, 'do_submit', '_bx_dev_bp_btn_block_add', '', 0, 'submit', '_bx_dev_bp_btn_sys_block_add', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_bp_block', @sName, 'cancel', '_bx_dev_bp_btn_block_cancel', '', 0, 'button', '_bx_dev_bp_btn_sys_block_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_bp_block', @sName, 'delete', '_bx_dev_bp_btn_block_delete', '', 0, 'button', '_bx_dev_bp_btn_sys_block_delete', '', '', 0, 0, 0, 'a:1:{s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_developer_bp_block_edit', 'id', 2147483647, 1, 1),
+('bx_developer_bp_block_edit', 'object', 2147483647, 1, 2),
+('bx_developer_bp_block_edit', 'module', 2147483647, 1, 3),
+('bx_developer_bp_block_edit', 'title_system', 2147483647, 1, 4),
+('bx_developer_bp_block_edit', 'title', 2147483647, 1, 5),
+('bx_developer_bp_block_edit', 'designbox_id', 2147483647, 1, 6),
+('bx_developer_bp_block_edit', 'async', 2147483647, 1, 7),
+('bx_developer_bp_block_edit', 'submenu', 2147483647, 1, 8),
+('bx_developer_bp_block_edit', 'tabs', 2147483647, 1, 9),
+('bx_developer_bp_block_edit', 'hidden_on', 2147483647, 1, 10),
+('bx_developer_bp_block_edit', 'visible_for', 2147483647, 1, 11),
+('bx_developer_bp_block_edit', 'visible_for_levels', 2147483647, 1, 12),
+('bx_developer_bp_block_edit', 'class', 2147483647, 1, 13),
+('bx_developer_bp_block_edit', 'deletable', 2147483647, 1, 14),
+('bx_developer_bp_block_edit', 'copyable', 2147483647, 1, 15),
+('bx_developer_bp_block_edit', 'active', 2147483647, 1, 16),
+('bx_developer_bp_block_edit', 'active_api', 2147483647, 1, 17),
+('bx_developer_bp_block_edit', 'controls', 2147483647, 1, 18),
+('bx_developer_bp_block_edit', 'do_submit', 2147483647, 1, 19),
+('bx_developer_bp_block_edit', 'cancel', 2147483647, 1, 20),
+('bx_developer_bp_block_edit', 'delete', 2147483647, 1, 21);
+
+--
+-- Polyglot -> Grid descriptors
+--
+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_developer_pgt_manage', 'Sql', 'SELECT * FROM `sys_modules` WHERE 1 ', 'sys_modules', 'id', 'name', '', '', 100, NULL, 'start', '', '', '', '', '', '', 2147483647, 'BxDevPolyglotManage', 'modules/boonex/developer/classes/BxDevPolyglotManage.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_developer_pgt_manage', 'title', '_bx_dev_pgt_txt_manage_gl_title', '100%', 0, '', '', 1);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_developer_pgt_manage', 'independent', 'add_keys', '_bx_dev_pgt_btn_manage_gl_add_keys', '', 0, 0),
+('bx_developer_pgt_manage', 'independent', 'recompile', '_bx_dev_pgt_btn_manage_gl_recompile', '', 0, 1),
+('bx_developer_pgt_manage', 'independent', 'restore', '_bx_dev_pgt_btn_manage_gl_restore', '', 0, 2);
+
+--
+-- Polyglot -> Manage.
+--
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_developer_pgt_keys', @sName, '_bx_dev_pgt_txt_keys_form', '', '', 'do_submit', 'sys_localization_keys', 'ID', '', '', '', 0, 1, 'BxDevFormView', 'modules/boonex/developer/classes/BxDevFormView.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_developer_pgt_keys_add', @sName, 'bx_developer_pgt_keys', '_bx_dev_pgt_txt_keys_display_add', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_developer_pgt_keys', @sName, 'language', '', '', 0, 'select', '_bx_dev_pgt_txt_sys_keys_language', '_bx_dev_pgt_txt_keys_language', '_bx_dev_pgt_inf_keys_language', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_pgt_keys', @sName, 'category', '', '', 0, 'select', '_bx_dev_pgt_txt_sys_keys_category', '_bx_dev_pgt_txt_keys_category', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_pgt_err_keys_category', 'Int', '', 0, 0),
+('bx_developer_pgt_keys', @sName, 'content', '', '', 0, 'textarea', '_bx_dev_pgt_txt_sys_keys_content', '_bx_dev_pgt_txt_keys_content', '_bx_dev_pgt_inf_keys_content', 1, 0, 0, '', '', '', 'Avail', '', '_bx_dev_pgt_err_keys_content', 'Xss', '', 0, 0),
+('bx_developer_pgt_keys', @sName, 'replace', '1', '', 0, 'switcher', '_bx_dev_pgt_txt_sys_keys_replace', '_bx_dev_pgt_txt_keys_replace', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_developer_pgt_keys', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_pgt_keys', @sName, 'do_submit', '_bx_dev_pgt_btn_keys_submit', '', 0, 'submit', '_bx_dev_pgt_btn_sys_keys_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_developer_pgt_keys', @sName, 'do_cancel', '_bx_dev_pgt_btn_keys_cancel', '', 0, 'button', '_bx_dev_pgt_btn_sys_keys_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_developer_pgt_keys_add', 'language', 2147483647, 1, 1),
+('bx_developer_pgt_keys_add', 'category', 2147483647, 1, 2),
+('bx_developer_pgt_keys_add', 'content', 2147483647, 1, 3),
+('bx_developer_pgt_keys_add', 'replace', 2147483647, 1, 4),
+('bx_developer_pgt_keys_add', 'controls', 2147483647, 1, 5),
+('bx_developer_pgt_keys_add', 'do_submit', 2147483647, 1, 6),
+('bx_developer_pgt_keys_add', 'do_cancel', 2147483647, 1, 7);

+ 27 - 0
modules/boonex/developer/updates/14.0.2_14.0.3/source/template/images/icons/std-icon.svg

@@ -0,0 +1,27 @@
+<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="80" height="80" fill="url(#paint0_linear_1007_4132)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M27.1684 28.2781C28.4046 29.8183 28.2441 32.1431 26.8098 33.4707L21.2028 38.6606C20.29 39.5054 19.6869 40.0692 19.2725 40.5C19.6869 40.9308 20.2898 41.4945 21.2027 42.3393L26.8098 47.5293C28.2441 48.8569 28.4046 51.1817 27.1684 52.7219C25.9321 54.2621 23.7672 54.4345 22.3329 53.107L16.7261 47.9172C16.6788 47.8735 16.6314 47.8297 16.5842 47.786C15.53 46.8108 14.4916 45.8501 13.7452 44.9446C12.9202 43.9437 12 42.4859 12 40.5C12 38.5141 12.9202 37.0563 13.7452 36.0554C14.4916 35.1499 15.53 34.1893 16.5842 33.214C16.6314 33.1703 16.6787 33.1266 16.7259 33.0829L22.3329 27.8931C23.7672 26.5655 25.9321 26.7379 27.1684 28.2781Z" fill="black" fill-opacity="0.2"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M52.8317 28.278C54.0679 26.7378 56.2328 26.5655 57.6671 27.8931L63.2736 33.0827C63.3206 33.1261 63.3679 33.1699 63.4148 33.2133C64.4694 34.1888 65.5082 35.1496 66.2548 36.0554C67.0799 37.0563 68 38.5141 68 40.5C68 42.4859 67.0799 43.9437 66.2548 44.9446C65.5082 45.8504 64.4694 46.8112 63.4148 47.7867C63.3679 47.8301 63.3209 47.8736 63.2739 47.917L57.6671 53.1069C56.2328 54.4345 54.0679 54.2622 52.8317 52.722C51.5954 51.1818 51.7559 48.857 53.1901 47.5294L58.797 42.3395C59.7098 41.4948 60.3131 40.9307 60.7275 40.5C60.3131 40.0693 59.7102 39.5056 58.7973 38.6608L53.1901 33.4706C51.7559 32.143 51.5954 29.8182 52.8317 28.278Z" fill="black" fill-opacity="0.2"/>
+<path d="M40.3452 23.8799C40.9017 21.7371 43.0826 20.4782 45.2165 21.0682C47.3504 21.6581 48.6291 23.8734 48.0726 26.0162L39.7351 58.1201C39.1786 60.2629 36.9976 61.5218 34.8637 60.9319C32.7299 60.3419 31.4512 58.1266 32.0077 55.9838L40.3452 23.8799Z" fill="black" fill-opacity="0.2"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M27.1684 27.2781C28.4046 28.8183 28.2441 31.1431 26.8098 32.4707L21.2028 37.6605C20.29 38.5054 19.6869 39.0692 19.2725 39.5C19.6869 39.9308 20.2898 40.4945 21.2027 41.3393L26.8098 46.5293C28.2441 47.8569 28.4046 50.1817 27.1684 51.7219C25.9321 53.2621 23.7672 53.4345 22.3329 52.107L16.7261 46.9172C16.6788 46.8735 16.6314 46.8297 16.5842 46.786C15.53 45.8107 14.4916 44.8501 13.7452 43.9446C12.9202 42.9437 12 41.4859 12 39.5C12 37.5141 12.9202 36.0563 13.7452 35.0554C14.4916 34.1499 15.53 33.1893 16.5842 32.214C16.6314 32.1703 16.6787 32.1266 16.7259 32.0829L22.3329 26.893C23.7672 25.5655 25.9321 25.7379 27.1684 27.2781Z" fill="url(#paint1_linear_1007_4132)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M52.8317 27.278C54.0679 25.7378 56.2328 25.5655 57.6671 26.8931L63.2736 32.0826C63.3206 32.1261 63.3679 32.1698 63.4148 32.2133C64.4694 33.1888 65.5082 34.1496 66.2548 35.0554C67.0799 36.0563 68 37.5141 68 39.5C68 41.4859 67.0799 42.9437 66.2548 43.9446C65.5082 44.8504 64.4694 45.8112 63.4148 46.7867C63.3679 46.8301 63.3209 46.8736 63.2739 46.917L57.6671 52.1069C56.2328 53.4345 54.0679 53.2622 52.8317 51.722C51.5954 50.1818 51.7559 47.857 53.1901 46.5294L58.797 41.3395C59.7098 40.4948 60.3131 39.9307 60.7275 39.5C60.3131 39.0693 59.7101 38.5056 58.7973 37.6608L53.1901 32.4706C51.7559 31.143 51.5954 28.8182 52.8317 27.278Z" fill="url(#paint2_linear_1007_4132)"/>
+<rect width="8.01727" height="41.1861" rx="4.00863" transform="matrix(0.963846 0.266461 -0.251365 0.967892 41.3528 19)" fill="url(#paint3_linear_1007_4132)"/>
+<defs>
+<linearGradient id="paint0_linear_1007_4132" x1="40" y1="0" x2="40" y2="80" gradientUnits="userSpaceOnUse">
+<stop stop-color="#6B7280"/>
+<stop offset="1" stop-color="#1F2937"/>
+</linearGradient>
+<linearGradient id="paint1_linear_1007_4132" x1="20" y1="26" x2="20" y2="53" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F9FAFB"/>
+<stop offset="1" stop-color="#9CA3AF"/>
+</linearGradient>
+<linearGradient id="paint2_linear_1007_4132" x1="60" y1="26" x2="60" y2="53" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F9FAFB"/>
+<stop offset="1" stop-color="#9CA3AF"/>
+</linearGradient>
+<linearGradient id="paint3_linear_1007_4132" x1="4.00863" y1="0" x2="4.00863" y2="41.1861" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FDE68A"/>
+<stop offset="1" stop-color="#D97706"/>
+</linearGradient>
+</defs>
+</svg>

+ 51 - 0
modules/boonex/events/updates/14.0.4_14.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' => '14.0.4',
+    'version_to' => '14.0.5',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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_14.0.4_14.0.5/',
+    'home_uri' => 'events_update_1404_1405',
+
+    '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' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Events',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/events/updates/14.0.4_14.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);
+    }
+}

+ 5 - 0
modules/boonex/events/updates/14.0.4_14.0.5/install/sql/enable.sql

@@ -0,0 +1,5 @@
+SET @sName = 'bx_events';
+
+
+-- PAGES
+UPDATE `sys_objects_page` SET `url`='page.php?i=event-manage' WHERE `object`='bx_events_manage_item';

+ 338 - 0
modules/boonex/events/updates/14.0.4_14.0.5/source/classes/BxEventsConfig.php

@@ -0,0 +1,338 @@
+<?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',
+            'event-manage' => 'checkAllowedEdit',
+            'event-questionnaire' => 'checkAllowedEdit',
+            'event-sessions' => 'checkAllowedEdit',
+            'event-cover' => 'checkAllowedChangeCover',
+            'invite-to-event' => 'checkAllowedInvite',
+            'delete-event-profile' => 'checkAllowedDelete',
+            'approve-event-profile' => 'checkAllowedApprove',
+            'profile-check-in' =>  'checkAllowedCheckIn',
+            '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_CHECK_IN' => $aModule['db_prefix'] . 'check_in',
+            'TABLE_INVITES' => $aModule['db_prefix'] . 'invites',
+            'TABLE_PRICES' => $aModule['db_prefix'] . 'prices',
+            'TABLE_QUESTIONS' => $aModule['db_prefix'] . 'qnr_questions',
+            'TABLE_ANSWERS' => $aModule['db_prefix'] . 'qnr_answers',
+            'TABLE_SESSIONS' => $aModule['db_prefix'] . 'sessions',
+
+            // 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_COVER_POSITION' => 'cover_data',
+            '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_VIEW_MEMBERS' => 'event-fans',
+            'URI_EDIT_ENTRY' => 'edit-event-profile',
+            'URI_ENTRIES_BY_CONTEXT' => 'events-context',
+            'URI_JOIN_ENTRY' => 'join-event-profile',
+            'URI_JOINED_ENTRIES' => 'joined-events',
+            'URI_FOLLOWED_ENTRIES' => 'followed-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_ENTRY_MANAGE' => 'page.php?i=event-manage',
+            '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_FORMAT_TIME' => 'bx_events_time_format',
+            'PARAM_FORMAT_DATE' => 'bx_events_short_date_format',
+            'PARAM_FORMAT_DATETIME' => 'bx_events_datetime_format',
+            '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_QUESTION' => 'bx_events_question',
+            'OBJECT_FORM_QUESTION_DISPLAY_ADD' => 'bx_events_question_add',
+            'OBJECT_FORM_QUESTION_DISPLAY_EDIT' => 'bx_events_question_edit',
+            'OBJECT_FORM_SESSION' => 'bx_events_session',
+            'OBJECT_FORM_SESSION_DISPLAY_ADD' => 'bx_events_session_add',
+            'OBJECT_FORM_SESSION_DISPLAY_EDIT' => 'bx_events_session_edit',
+            '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_MANAGE_VIEW_ENTRY' => '',
+            '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_PAGE_JOINED_ENTRY' => 'bx_events_join_profile',
+            '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_QUESTIONS_MANAGE' => 'bx_events_questions_manage',
+            'OBJECT_GRID_SESSIONS_MANAGE' => 'bx_events_sessions_manage',
+            '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_sm_join' => '_bx_events_menu_item_title_become_fan',
+                'menu_item_title_sm_join_requested' => '_bx_events_menu_item_title_become_fan_sent',
+                'menu_item_title_sm_leave' => '_bx_events_menu_item_title_leave_group',
+                'menu_item_title_sm_leave_cancel' => '_bx_events_menu_item_title_leave_group_cancel_request',
+                'menu_item_title_sm_members' => '_bx_events_menu_item_title_sm_members',
+                'menu_item_title_sm_subscribers' => '_bx_events_menu_item_title_sm_subscribers',
+            	'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',
+                'form_qnr_field_qn_err' => '_bx_events_form_questionnaire_input_question_err',
+                'popup_title_questionnaire' => '_bx_events_popup_title_questionnaire',
+                'popup_title_question_add' => '_bx_events_popup_title_qn_add',
+                'popup_title_question_edit' => '_bx_events_popup_title_qn_edit',
+                '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']
+        );
+
+        $sHtmlPrefix = str_replace('_', '-', $this->_sName);
+        $this->_aHtmlIds = array_merge($this->_aHtmlIds, [
+            'popup_bfilters_recent' => $sHtmlPrefix . '-popup-bfilters-recent',
+            'popup_question' => $sHtmlPrefix . '-popup-question',
+            'popup_questionnaire' => $sHtmlPrefix . '-popup-questionnaire',
+            'popup_session' => $sHtmlPrefix . '-popup-session'
+        ]);
+    }
+
+}
+
+/** @} */

+ 350 - 0
modules/boonex/events/updates/14.0.4_14.0.5/source/classes/BxEventsFormEntry.php

@@ -0,0 +1,350 @@
+<?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']) && 'DateTimeUtc' == $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->aInputs['date_end']['value'] = $this->aInputs['date_start']['value']; //--- is needed for correct work of 'fixTimezone' in insert/update
+                    $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)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        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($CNF['PARAM_FORMAT_TIME']), $aStartEnd['start']->getTimestamp()), date(getParam($CNF['PARAM_FORMAT_TIME']), $aStartEnd['end']->getTimestamp()));
+            else
+                $aInput['value'] = '';
+        }
+        return $this->genViewRowWrapped($aInput);
+    }
+ 
+    function genViewRowValue(&$aInput)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        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') ? $CNF['PARAM_FORMAT_DATE'] : $CNF['PARAM_FORMAT_DATETIME']);
+            $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-1970-2030.min.js', 'modules/base/groups/js/|entry.js', 'entry.js', 'intervals.js'));
+            $this->oTemplate->addCss('informer.css');
+            self::$_isCssJsEventsAdded = true;
+        }  
+
+        parent::addCssJs ();
+    }
+}
+
+/** @} */

+ 934 - 0
modules/boonex/events/updates/14.0.4_14.0.5/source/classes/BxEventsModule.php

@@ -0,0 +1,934 @@
+<?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
+ *
+ * @{
+ */
+
+use Spatie\CalendarLinks\Link;
+
+/**
+ * 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, [
+            $CNF['FIELD_TIMEZONE'],
+            $CNF['FIELD_JOIN_CONFIRMATION'],
+            $CNF['FIELD_REMINDER']
+        ]);
+
+        $this->_aBrowsingFiltersKeys = array_merge($this->_aBrowsingFiltersKeys, [
+            'by_location_country', 'by_location_state', 'by_location_city',
+            'by_date', 'date_start', 'date_end', 'timezone'
+        ]);
+    }
+
+    public function actionCheckIn()
+    {
+    	$iId = (int)bx_get('id');
+    	if(empty($iId) || empty($this->_iProfileId))
+            return echoJson(['code' => 1]);
+
+        if(!$this->serviceCheckIn($iId, $this->_iProfileId))
+            return echoJson(['code' => 2]);
+
+        return echoJson(['code' => 0, 'reload' => 1]);
+    }
+
+    public function actionCalendarSync($iContentId = 0)
+    {
+        $aContentInfo = (int)$iContentId ? $this->_oDb->getContentInfoById((int)$iContentId) : null;
+        if (!$aContentInfo) {
+            $this->_oTemplate->displayPageNotFound();
+            exit;
+        }
+
+        if (CHECK_ACTION_RESULT_ALLOWED !== $this->checkAllowedView($aContentInfo)) {
+            $this->_oTemplate->displayAccessDenied();
+            exit;
+        }
+
+        $CNF = $this->_oConfig->CNF;
+
+        if (!isset($aContentInfo['date_start']) || !$aContentInfo['date_start'] || !isset($aContentInfo['date_end']) || !$aContentInfo['date_end'] || !$aContentInfo[$CNF['FIELD_TIMEZONE']] || empty($CNF['OBJECT_METATAGS'])) {
+            $this->_oTemplate->displayPageNotFound();
+            exit;
+        }
+
+        $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS']);
+        $sLocation = $oMetatags && $oMetatags->locationsIsEnabled() ? $oMetatags->locationsString($aContentInfo[$CNF['FIELD_ID']], false) : '';
+
+        $oDateStart = new DateTime('@' . $aContentInfo['date_start']);
+        $oDateEnd = new DateTime('@' . ($aContentInfo['date_end'] > $aContentInfo['repeat_stop'] ? $aContentInfo['date_end'] : $aContentInfo['repeat_stop']));
+
+        $oTz = new DateTimeZone($aContentInfo[$CNF['FIELD_TIMEZONE']]);
+        $oDateStart->setTimezone($oTz);
+        $oDateEnd->setTimezone($oTz);
+
+        $oICalLink = $oDateStart && $oDateEnd ? Link::create(
+            $aContentInfo[$CNF['FIELD_TITLE']],
+            $oDateStart,
+            $oDateEnd
+        ) : null;
+
+        if ($sLocation)
+            $oICalLink->address($sLocation);
+
+        $s = $oICalLink->ics();
+
+        if (!preg_match('/^data:([a-zA-Z0-9\/]+);charset=[a-zA-Z0-9]+;base64,(.*)$/', $s, $m)) {
+            $this->_oTemplate->displayErrorOccured();
+            exit;
+        }
+
+        header('Content-type: ' . $m[1] . '; charset=utf-8');
+        header('Content-Disposition: inline; filename="event.ics"');
+        echo base64_decode($m[2]);
+    }
+
+    public function actionCalendarData()
+    {
+        $aParams = [
+            'type' => ($sType = bx_get('type')) !== false ? $sType : 'browse',
+            'start' => bx_get('start'),
+            'end' => bx_get('end')
+        ];
+        if(($iEventId = bx_get('event')) !== false)
+            $aParams['event_id'] = (int)$iEventId;
+        if(($iProfileId = bx_get('profile_id')) !== false)
+            $aParams['profile_id'] = (int)$iProfileId;
+        if(($iContextId = bx_get('context_id')) !== false)
+            $aParams['context_id'] = (int)$iContextId;
+    
+        $aResult = $this->serviceCalendarData($aParams);
+        if(isset($aResult['data']))
+            $aResult = $aResult['data'];
+
+        header('Content-Type: application/json; charset=utf-8');
+        echo json_encode($aResult);
+    }
+
+    public function serviceCheckIn($iId, $iProfileId = 0)
+    {
+        if(!$iProfileId)
+            $iProfileId = $this->_iProfileId;
+        if(!$iProfileId)
+            return false;
+        
+        $aDataEntry = $this->_oDb->getContentInfoById($iId);
+        if(empty($aDataEntry) || !is_array($aDataEntry))
+            return false;
+
+        if($this->checkAllowedCheckIn($aDataEntry) !== CHECK_ACTION_RESULT_ALLOWED)
+            return false;
+
+        if(!$this->_oDb->checkIn($iProfileId, $iId))
+            return false;
+
+         /**
+         * @hooks
+         * @hookdef hook-bx_events-check_in 'bx_events', 'check_in' - hook in on somebody check-in some event 
+         * - $unit_name - equals `bx_events`
+         * - $action - equals `check_in` 
+         * - $object_id - event_id
+         * - $sender_id - current user's profile_id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `event_profile_id` - [int] profile_id from checked event
+         * @hook @ref hook-bx_events-check_in
+         */
+        bx_alert($this->getName(), 'check_in', $iId, $iProfileId, [
+            'event_profile_id' => $aDataEntry['profile_id'],
+        ]);
+
+        return true;
+    }
+
+    public function serviceCalendarData($aParams = [])
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if($this->_bIsApi && is_string($aParams)) {
+            $aParams = json_decode($aParams, true);
+            if(!empty($aParams['params']))
+                $aParams = $aParams['params'];
+            
+             if (isset($aParams['profile_id']) && $aParams['profile_id'] == '{profile_id}')
+                $aParams['profile_id'] =  bx_get_logged_profile_id();
+        }
+
+        $sModule = $this->getName();
+        $oPrivacy = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_VIEW']);
+
+        $iNow = time();
+
+        if(empty($aParams['start']))
+            $sStart = date('d.m.Y', $iNow);
+        else if(is_numeric($aParams['start']))
+            $sStart = date('d.m.Y', $aParams['start']);
+        else
+            $sStart = $aParams['start'];
+
+        if(empty($aParams['end']))
+            $sEnd = date('d.m.Y', $iNow + 3600 * 24 * 30);
+        else if(is_numeric($aParams['end']))
+            $sEnd = date('d.m.Y', $aParams['end']);
+        else
+            $sEnd = $aParams['end']; 
+
+        $iContentId = 0;
+        $iContextId = 0;
+        $aSQLPart = [];
+        switch($aParams['type']) {
+            case 'event':
+                $iContentId = !empty($aParams['event_id']) ? (int)$aParams['event_id'] : 0;
+                $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+                if(CHECK_ACTION_RESULT_ALLOWED !== $this->checkAllowedView($aContentInfo))
+                    $this->_oTemplate->displayAccessDenied();
+                break;
+
+            case 'author':
+                $iProfileId = !empty($aParams['profile_id']) ? (int)$aParams['profile_id'] : 0;
+
+                $aSQLPart = [
+                    'where' => $this->_oDb->prepareAsString("AND `{$CNF['TABLE_ENTRIES']}`.`{$CNF['FIELD_AUTHOR']}`=?", $iProfileId)
+                ];
+                break;
+
+            case 'joined':
+                $iProfileId = !empty($aParams['profile_id']) ? (int)$aParams['profile_id'] : 0;
+
+                $oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS']);
+                if(!$oConnection)
+                    return [];
+
+                $aEventsJoined = $oConnection->getConnectedContent($iProfileId, true);
+                if(empty($aEventsJoined) || !is_array($aEventsJoined))
+                    return [];
+
+                $aSQLPart = [
+                    'join' => "INNER JOIN `sys_profiles` ON `{$CNF['TABLE_ENTRIES']}`.`{$CNF['FIELD_ID']}`=`sys_profiles`.`content_id` AND `sys_profiles`.`type`='{$sModule}'",
+                    'where' => "AND `sys_profiles`.`id` IN (" . $this->_oDb->implode_escape($aEventsJoined) . ")"
+                ];
+                break;
+                
+            case 'followed':
+                $iProfileId = !empty($aParams['profile_id']) ? (int)$aParams['profile_id'] : 0;
+
+                $oConnection = BxDolConnection::getObjectInstance('sys_profiles_subscriptions');
+                if(!$oConnection)
+                    return [];
+
+                $aEventsFollowed = $oConnection->getConnectedContent($iProfileId, false);
+                if(empty($aEventsFollowed) || !is_array($aEventsFollowed))
+                    return [];
+
+                $aSQLPart = [
+                    'join' => "INNER JOIN `sys_profiles` ON `{$CNF['TABLE_ENTRIES']}`.`{$CNF['FIELD_ID']}`=`sys_profiles`.`content_id` AND `sys_profiles`.`type`='{$sModule}'",
+                    'where' => "AND `sys_profiles`.`id` IN (" . $this->_oDb->implode_escape($aEventsFollowed) . ")"
+                ];
+                break;
+
+            case 'context':
+                $iContextId = !empty($aParams['context_id']) ? (int)$aParams['context_id'] : 0;
+                if(!$this->serviceIsEnableForContext($iContextId))
+                    return [];
+
+                $aSQLPart = $oPrivacy->getContentByGroupAsSQLPart(-$iContextId);
+                break;
+            
+            default:
+                $aSQLPart = $oPrivacy->getContentPublicAsSQLPart(0, $oPrivacy->getPartiallyVisiblePrivacyGroups());
+        }
+
+        // get entries
+        $aEntries = $this->_oDb->getEntriesByDate($sStart, $sEnd, $iContentId, $aSQLPart);
+        
+        foreach($aEntries as &$aEntry){
+            $aEntry['cover'] = $this->serviceGetCover($aEntry['id']);
+        }
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_events-calendar_data 'bx_events', 'calendar_data' - hook in get data for calendar
+         * - $unit_name - equals `bx_events`
+         * - $action - equals `calendar_data` 
+         * - $object_id - not used 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `params` - [array] array of paramaretes in calendar 
+         *      - `event` - [int] event id
+         *      - `context_id` - [int] profile_id for context of current event
+         *      - `start` - [string] start date in format date('d.m.Y')
+         *      - `end` - [string] end date in format date('d.m.Y')
+         *      - `sql_part` - [array] by ref, sql for data selection, can be overridden in hook processing
+         *      - `data` - [array] by ref, data for calendar, can be overridden in hook processing
+         * @hook @ref hook-bx_events-calendar_data
+         */
+        bx_alert($this->getName(), 'calendar_data', 0, false, array(
+            'params' => $aParams,
+            'event' => $iContentId,
+            'context_id' => $iContextId,
+            'start' => $sStart,
+            'end' =>  $sEnd,
+            'sql_part' => &$aSQLPart,
+            'data' => &$aEntries,
+        ));
+
+        return [
+            'params' => ['start' => strtotime($sStart), 'end' => strtotime($sEnd)],
+            'data' => $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 decodeDataAPI($aData, $aParams = [])
+    {
+        $CNF = $this->_oConfig->CNF;
+        $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS']);
+
+        $aResult = parent::decodeDataAPI($aData, $aParams);
+        $aResult = array_merge($aResult, [
+            'date_start' => $aData[$CNF['FIELD_DATE_START']],
+            'date_end' => $aData[$CNF['FIELD_DATE_END']],
+            'description' => $aData[$CNF['FIELD_TEXT']],
+            'location_data' => $oMetatags->locationGet($aData[$CNF['FIELD_ID']]),
+            'threshold' => $aData['threshold'],
+            'location' => $oMetatags->locationsString($aData[$CNF['FIELD_ID']], false)
+        ]);
+        return $aResult;
+    }
+
+    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()
+    {
+        return array_merge(parent::serviceGetSafeServices(), [
+            'CheckIn' => '',
+            'BrowsePastProfiles' => '',
+            'Calendar' => '',
+            'CalendarData' => ''
+        ]);
+    }
+
+    public function serviceEntitySessions($iProfileId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if(!$iProfileId)
+            return '';
+
+        $aProfileInfo = BxDolProfileQuery::getInstance()->getInfoById($iProfileId);
+        if(empty($aProfileInfo) || !is_array($aProfileInfo))
+            return '';
+        
+        $aContentInfo = $this->_oDb->getContentInfoById($aProfileInfo['content_id']);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return '';
+
+        if($this->checkAllowedEdit($aContentInfo) !== CHECK_ACTION_RESULT_ALLOWED)
+            return MsgBox(_t('_Access denied'));
+
+        $oGrid = BxDolGrid::getObjectInstance($CNF['OBJECT_GRID_SESSIONS_MANAGE']);
+        if(!$oGrid)
+            return '';
+
+        if($this->_bIsApi){
+            return [
+                bx_api_get_block('grid', $oGrid->getCodeAPI())
+            ];
+            
+        }
+
+        
+        return $oGrid->getCode();
+    }
+
+    /**
+     * @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);
+    }
+
+    public function serviceBrowseRecentProfiles ($bDisplayEmptyMsg = false, $bAjaxPaginate = true, $sUnitView = false)
+    {
+        $sMode = 'recent';
+
+        $sFilterSelector = '#' . $this->_oConfig->getHtmlIds('popup_bfilters_recent');
+        $aFilterParams = ['mode' => $sMode];
+
+        $aParams = [
+            'filters' => [
+                'values' => [],
+                'onclick' => $this->_oConfig->getJsObject('main') . ".changeBrowsingFilters(this, '" . $sFilterSelector . "', " . json_encode($aFilterParams) . ")"
+            ]
+        ];
+        if ($sUnitView) {
+            $aParams['unit_view'] = $sUnitView;
+        }
+        return $this->_serviceBrowse ($sMode, $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 = [], $sTemplate = 'calendar.html')
+    {
+        if(isset($aData['event']) && !isset($aData['type']))
+            $aData['type'] = 'event';
+
+        if(isset($aData['profile_id']) && !isset($aData['type']))
+            $aData['type'] = 'joined';
+
+        if(isset($aData['context_id'])) {
+            if(!$this->serviceIsEnableForContext($aData['context_id']))
+                return '';
+
+            $aData['type'] = 'context';
+        }
+
+        if(!isset($aData['type']))
+            $aData['type'] = 'browse';
+
+        $oCalendar = new BxTemplCalendar([
+            'eventSources' => [
+                bx_append_url_params(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'calendar_data', $aData),
+            ],
+        ], $this->_oTemplate);
+
+        if (bx_is_api())
+            return [bx_api_get_block('calendar', ['request_url' => $this->getName() . '/calendar_data&params[]=' . json_encode(['params' => $aData])])];
+        
+        $this->_oTemplate->addCss(['main.css']);
+        return $oCalendar->display($sTemplate);
+    }
+
+    public function serviceSessions($iContentId = 0)
+    {
+        if(!$iContentId)
+            $iContentId = (int)bx_get('id');
+        if(!$iContentId)
+            return '';
+        
+        return $this->_oTemplate->getBlockSessions($iContentId);
+    }
+
+    /**
+     * @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);
+
+                /**
+                 * @hooks
+                 * @hookdef hook-bx_events-reminder 'bx_events', 'reminder' - hook on enent's reminder
+                 * - $unit_name - equals `bx_events`
+                 * - $action - equals `reminder` 
+                 * - $object_id - event_id
+                 * - $sender_id - event profile_id
+                 * - $extra_params - array of additional params with the following array keys:
+                 *      - `object_author_id` - [int] event profile_id 
+                 *      - `reminder` - [int] reminder id
+                 * @hook @ref hook-bx_events-reminder
+                 */
+                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' => bx_absolute_url(str_replace(BX_DOL_URL_ROOT, '', $oEventProfile->getUrl()), '{bx_url_root}'),
+            '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'));
+            $a['content']['date_start'] = $aContentInfo['date_start'];
+        }
+        
+        $oDateEnd = date_create('@' . $aContentInfo['date_end']);
+        if ($oDateEnd){
+            $oDateEnd->setTimezone(new DateTimeZone($aContentInfo['timezone'] ? $aContentInfo['timezone'] : 'UTC'));
+            $a['content']['date_end'] = $aContentInfo['date_end'];
+        }
+
+        $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, true) : '',
+                    'date_c' => $oDateStart->format('c'),
+            ]],
+            'bx_if:location' => array(
+                'condition' => !!$sLocationString,
+                'content' => array('location' => $sLocationString),
+            ),
+        ]);
+
+        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 checkAllowedCheckIn($aDataEntry, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sError = _t('_sys_txt_access_denied');
+        if(!$this->_iProfileId || !$this->isFan($aDataEntry[$CNF['FIELD_ID']], $this->_iProfileId))
+            return $sError;
+
+        if(!$this->isOngoing($aDataEntry))
+            return $sError;
+
+        if($this->_oDb->isCheckedIn($this->_iProfileId, $aDataEntry[$CNF['FIELD_ID']]))
+            return $sError;
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    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($CNF['PARAM_FORMAT_DATE']), $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_absolute_url(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;
+    }
+    
+    public function isOngoing($aDataEntry)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($aDataEntry[$CNF['FIELD_DATE_START']]) || empty($aDataEntry[$CNF['FIELD_DATE_END']]))
+            return false;
+
+        $iTime = time();
+        return $iTime >= $aDataEntry[$CNF['FIELD_DATE_START']] && $iTime <= $aDataEntry[$CNF['FIELD_DATE_END']];
+    }
+}
+
+/** @} */

+ 152 - 0
modules/boonex/events/updates/14.0.4_14.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' => '14.0.5',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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',
+    ),
+);
+
+/** @} */

+ 796 - 0
modules/boonex/events/updates/14.0.4_14.0.5/source/install/sql/enable.sql

@@ -0,0 +1,796 @@
+
+-- 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_enable_subscribe_for_past_events', 'on', @iCategId, '_bx_events_option_enable_subscribe_for_past_events', 'checkbox', '', '', '', 57),
+('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_profile_sessions', 11, '', 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:8:"sessions";s:6:"params";a:1:{i:0;s:12:"{content_id}";}}', 0, 0, 1, 1),
+('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, 2),
+('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: questionnaire (join)
+
+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_questionnaire', 'event-questionnaire', '_bx_events_page_title_sys_questionnaire', '_bx_events_page_title_questionnaire', 'bx_events', 5, 2147483647, 1, 'page.php?i=event-questionnaire', '', '', '', 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_questionnaire', 1, 'bx_events', '_bx_events_page_block_title_edit_questionnaire', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_events";s:6:"method";s:25:"entity_edit_questionnaire";}', 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 sessions
+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_sessions', 'event-sessions', '_bx_events_page_title_sys_profile_sessions', '_bx_events_page_title_profile_sessions', 'bx_events', 5, 2147483647, 1, 'page.php?i=event-sessions', '', '', '', 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_sessions', 1, 'bx_events', '', '_bx_events_page_block_title_profile_sessions', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:15:"entity_sessions";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 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', 'event-pricing', '_bx_events_page_title_sys_profile_pricing', '_bx_events_page_title_profile_pricing', 'bx_events', 5, 2147483647, 1, 'page.php?i=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_profile_pricing', 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:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:14:"browse_members";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:2:{s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}}', 0, 0, 1, 1);
+
+
+-- PAGE: event manage
+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_manage_item', 'event-manage', '_bx_events_page_title_sys_manage_profile', '_bx_events_page_title_manage_profile', 'bx_events', 5, 2147483647, 1, 'page.php?i=event-manage', '', '', '', 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_manage_item', 1, 'bx_events', '_bx_events_page_block_title_system_fans_manage', '_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_manage_item', 1, 'bx_events', '_bx_events_page_block_title_system_subscribers_manage', '_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_manage_item', 1, 'bx_events', '_bx_events_page_block_title_system_invites_manage', '_bx_events_page_block_title_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: followed 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_followed_events', '_bx_events_page_title_sys_followed', '_bx_events_page_title_followed', 'bx_events', 5, 2147483647, 1, 'events-followed', 'page.php?i=events-followed', '', '', '', 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_followed_events', 1, 'bx_events', '_bx_events_page_block_title_followed_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:23:"browse_followed_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),
+('bx_events_joined', 1, 'bx_events', '_bx_events_page_block_title_sys_joined_calendar', '_bx_events_page_block_title_joined_calendar', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_events";s:6:"method";s:8:"calendar";s:6:"params";a:1:{i:0;a:1:{s:10:"profile_id";s:12:"{profile_id}";}}}', 0, 0, 1, 5);
+
+
+-- 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)', '{onclick_add_fan}', '', '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-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', '', 0, 2147483647, '', 1, 0, 1, 6),
+('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-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', '', 0, 2147483647, '', 1, 0, 1, 21),
+('bx_events_view_actions', 'bx_events', 'profile-check-in', '_bx_events_menu_item_title_system_check_in', '_bx_events_menu_item_title_check_in', 'javascript:void(0)', 'javascript:{js_object_entry}.checkIn(this, {content_id});', '', 'check', '', 0, 2147483647, '', 1, 0, 1, 25),
+('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', 'modules/?r=events/calendar_sync/{content_id}', '', '', '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', 'event-manage', '_bx_events_menu_item_title_system_view_manage', '_bx_events_menu_item_title_view_manage', 'page.php?i=event-manage&profile_id={profile_id}', '', '', 'users', '', 2147483647, '', 1, 0, 10),
+('bx_events_view_actions_more', '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', '', 192, '', 1, 0, 20),
+('bx_events_view_actions_more', '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', '', 192, '', 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', 'event-questionnaire', '_bx_events_menu_item_title_system_edit_questionnaire', '_bx_events_menu_item_title_edit_questionnaire', 'page.php?i=event-questionnaire&profile_id={profile_id}', '', '', 'check-double', '', 2147483647, '', 1, 0, 41),
+('bx_events_view_actions_more', 'bx_events', 'event-sessions', '_bx_events_menu_item_title_system_edit_sessions', '_bx_events_menu_item_title_edit_sessions', 'page.php?i=event-sessions&profile_id={profile_id}', '', '', 'calendar-day', '', 2147483647, '', 1, 0, 42),
+('bx_events_view_actions_more', 'bx_events', 'event-pricing', '_bx_events_menu_item_title_system_edit_pricing', '_bx_events_menu_item_title_edit_pricing', 'page.php?i=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, 43),
+('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, 44),
+('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`, `persistent`, `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, 1, 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-check-in', '_bx_events_menu_item_title_system_check_in', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 45),
+('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', 'modules/?r=events/calendar_sync/{content_id}', '', '', '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', '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', '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', '_bx_events_menu_item_title_sm_members', '', '', '', '', '', 0, 2147483647, '', 1, 0, 10),
+('bx_events_view_meta', 'bx_events', 'subscribers', '_sys_menu_item_title_system_sm_subscribers', '_bx_events_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-followed', '_bx_events_menu_item_title_system_entries_followed', '_bx_events_menu_item_title_entries_followed', 'page.php?i=events-followed', '', '', '', '', 2147483647, 1, 1, 8),
+('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, 9);
+
+-- 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_events_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', 'BxEventsConnectionFans', 'modules/boonex/events/classes/BxEventsConnectionFans.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_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', '40%', '', 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', '', '30%', '', 20);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_events_fans', 'single', 'questionnaire', '_bx_events_txt_view_answers', 'check-double', 1, 0, 5),
+('bx_events_fans', 'single', 'accept', '_sys_accept', '', 0, 0, 10),
+('bx_events_fans', 'single', 'set_role', '_bx_events_txt_set_role', '', 0, 0, 20),
+('bx_events_fans', 'single', 'set_role_submit', '', '', 0, 0, 21),
+('bx_events_fans', 'single', 'delete', '', 'remove', 0, 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_profile` 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_profile` 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: questionnaire
+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_questions_manage', 'Sql', 'SELECT * FROM `bx_events_qnr_questions` WHERE 1 ', 'bx_events_qnr_questions', 'id', 'order', '', '', 100, NULL, 'start', '', 'question', '', 'like', '', '', 2147483647, 'BxEventsGridQuestionsManage', 'modules/boonex/events/classes/BxEventsGridQuestionsManage.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_events_questions_manage', 'checkbox', '_sys_select', '1%', 0, '', '', 1),
+('bx_events_questions_manage', 'order', '', '1%', 0, '', '', 2),
+('bx_events_questions_manage', 'question', '_bx_events_grid_column_title_qn_question', '78%', 0, 64, '', 3),
+('bx_events_questions_manage', 'actions', '', '20%', 0, '', '', 4);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_events_questions_manage', 'independent', 'add', '_bx_events_grid_action_title_qn_add', '', 0, 0, 1),
+('bx_events_questions_manage', 'single', 'edit', '_bx_events_grid_action_title_qn_edit', 'pencil-alt', 1, 0, 1),
+('bx_events_questions_manage', 'single', 'delete', '_bx_events_grid_action_title_qn_delete', 'remove', 1, 1, 2),
+('bx_events_questions_manage', 'bulk', 'delete', '_bx_events_grid_action_title_qn_delete', '', 0, 1, 1);
+
+-- GRIDS: Sessions
+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_sessions_manage', 'Sql', 'SELECT * FROM `bx_events_sessions` WHERE 1 ', 'bx_events_sessions', 'id', 'order', '', '', 100, NULL, 'start', '', 'title,description', '', 'like', '', '', 2147483647, 'BxEventsGridSessionsManage', 'modules/boonex/events/classes/BxEventsGridSessionsManage.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_events_sessions_manage', 'checkbox', '_sys_select', '1%', 0, '', '', 1),
+('bx_events_sessions_manage', 'order', '', '1%', 0, '', '', 2),
+('bx_events_sessions_manage', 'title', '_bx_events_grid_column_title_sn_title', '28%', 0, 16, '', 3),
+('bx_events_sessions_manage', 'description', '_bx_events_grid_column_title_sn_description', '30%', 0, 32, '', 4),
+('bx_events_sessions_manage', 'date_start', '_bx_events_grid_column_title_sn_date_start', '10%', 0, 0, '', 5),
+('bx_events_sessions_manage', 'date_end', '_bx_events_grid_column_title_sn_date_end', '10%', 0, 0, '', 6),
+('bx_events_sessions_manage', 'actions', '', '20%', 0, '', '', 7);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_events_sessions_manage', 'independent', 'add', '_bx_events_grid_action_title_sn_add', '', 0, 0, 1),
+('bx_events_sessions_manage', 'single', 'edit', '_bx_events_grid_action_title_sn_edit', 'pencil-alt', 1, 0, 1),
+('bx_events_sessions_manage', 'single', 'delete', '_bx_events_grid_action_title_sn_delete', 'remove', 1, 1, 2),
+('bx_events_sessions_manage', 'bulk', 'delete', '_bx_events_grid_action_title_sn_delete', '', 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),
+('system', 'check_allowed_fan_add', @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', '');

+ 12 - 0
modules/boonex/events/updates/14.0.4_14.0.5/source/template/timeline_post.html

@@ -0,0 +1,12 @@
+<div class="bx-tl-item-raw-cnt bx-event">
+    <bx_if:date>
+        <div class="bx-tl-info bx-def-margin-sec-bottom bx-def-font-h3">
+            <i class="sys-icon calendar-alt bx-def-margin-thd-right"></i> <span class="dtstart" title="__date_c__">__date__</span>
+        </div>
+    </bx_if:date>
+    <bx_if:location>
+        <div class="bx-tl-info bx-def-margin-sec-bottom bx-def-font-h3">
+            <i class="sys-icon map-marker-alt bx-def-margin-thd-right"></i> <span class="location">__location__</span>
+        </div>
+    </bx_if:location>
+</div>

+ 51 - 0
modules/boonex/forum/updates/14.0.2_14.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' => 'Discussions',
+    'version_from' => '14.0.2',
+    'version_to' => '14.0.3',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '14.0.0-RC1'
+    ),
+
+    /**
+     * '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_14.0.2_14.0.3/',
+    'home_uri' => 'forum_update_1402_1403',
+
+    'module_dir' => 'boonex/forum/',
+    'module_uri' => 'forum',
+
+    'db_prefix' => 'bx_forum_',
+    'class_prefix' => 'BxForum',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Discussions',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است