Ver Fonte

Modules updates.

AntonLV há 3 anos atrás
pai
commit
7d8d1778f5
100 ficheiros alterados com 15824 adições e 0 exclusões
  1. 51 0
      modules/boonex/accounts/updates/13.0.2_13.0.3/install/config.php
  2. 13 0
      modules/boonex/accounts/updates/13.0.2_13.0.3/install/installer.php
  3. 4 0
      modules/boonex/accounts/updates/13.0.2_13.0.3/install/langs/en.xml
  4. 16 0
      modules/boonex/accounts/updates/13.0.2_13.0.3/install/sql/enable.sql
  5. 779 0
      modules/boonex/accounts/updates/13.0.2_13.0.3/source/classes/BxAccntGridAdministration.php
  6. 71 0
      modules/boonex/accounts/updates/13.0.2_13.0.3/source/install/config.php
  7. 121 0
      modules/boonex/accounts/updates/13.0.2_13.0.3/source/install/langs/en.xml
  8. 114 0
      modules/boonex/accounts/updates/13.0.2_13.0.3/source/install/sql/enable.sql
  9. 34 0
      modules/boonex/accounts/updates/13.0.2_13.0.3/source/template/images/icons/std-icon.svg
  10. 51 0
      modules/boonex/acl/updates/13.0.1_13.0.2/install/config.php
  11. 23 0
      modules/boonex/acl/updates/13.0.1_13.0.2/install/installer.php
  12. 12 0
      modules/boonex/acl/updates/13.0.1_13.0.2/install/langs/en.xml
  13. 7 0
      modules/boonex/acl/updates/13.0.1_13.0.2/install/sql/enable.sql
  14. 27 0
      modules/boonex/acl/updates/13.0.1_13.0.2/install/sql/install.sql
  15. 151 0
      modules/boonex/acl/updates/13.0.1_13.0.2/source/classes/BxAclConfig.php
  16. 259 0
      modules/boonex/acl/updates/13.0.1_13.0.2/source/classes/BxAclDb.php
  17. 140 0
      modules/boonex/acl/updates/13.0.1_13.0.2/source/classes/BxAclGridView.php
  18. 651 0
      modules/boonex/acl/updates/13.0.1_13.0.2/source/classes/BxAclModule.php
  19. 70 0
      modules/boonex/acl/updates/13.0.1_13.0.2/source/install/config.php
  20. 114 0
      modules/boonex/acl/updates/13.0.1_13.0.2/source/install/langs/en.xml
  21. 30 0
      modules/boonex/acl/updates/13.0.1_13.0.2/source/install/sql/disable.sql
  22. 45 0
      modules/boonex/acl/updates/13.0.1_13.0.2/source/install/sql/enable.sql
  23. 136 0
      modules/boonex/acl/updates/13.0.1_13.0.2/source/install/sql/install.sql
  24. 29 0
      modules/boonex/acl/updates/13.0.1_13.0.2/source/install/sql/uninstall.sql
  25. 35 0
      modules/boonex/acl/updates/13.0.1_13.0.2/source/template/images/icons/std-icon.svg
  26. 79 0
      modules/boonex/ads/updates/13.0.5_13.0.6/install/config.php
  27. 23 0
      modules/boonex/ads/updates/13.0.5_13.0.6/install/installer.php
  28. 10 0
      modules/boonex/ads/updates/13.0.5_13.0.6/install/langs/en.xml
  29. 34 0
      modules/boonex/ads/updates/13.0.5_13.0.6/install/sql/enable.sql
  30. 25 0
      modules/boonex/ads/updates/13.0.5_13.0.6/install/sql/install.sql
  31. 323 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsConfig.php
  32. 287 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsFormEntry.php
  33. 128 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsGridOffers.php
  34. 84 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsGridOffersAll.php
  35. 64 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsMenuSnippetMeta.php
  36. 114 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsMenuView.php
  37. 2092 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsModule.php
  38. 24 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsPageListEntry.php
  39. 174 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsTemplate.php
  40. 151 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/install/config.php
  41. 593 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/install/langs/en.xml
  42. 57 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/install/sql/disable.sql
  43. 664 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/install/sql/enable.sql
  44. 908 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/install/sql/install.sql
  45. 51 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/install/sql/uninstall.sql
  46. 117 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/js/entry.js
  47. 111 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/js/form.js
  48. 30 0
      modules/boonex/ads/updates/13.0.5_13.0.6/source/template/images/icons/std-icon.svg
  49. 68 0
      modules/boonex/albums/updates/13.0.3_13.0.4/install/config.php
  50. 13 0
      modules/boonex/albums/updates/13.0.3_13.0.4/install/installer.php
  51. 2 0
      modules/boonex/albums/updates/13.0.3_13.0.4/install/sql/enable.sql
  52. 2 0
      modules/boonex/albums/updates/13.0.3_13.0.4/install/sql/install.sql
  53. 160 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/classes/BxAlbumsContentInfoMedia.php
  54. 1045 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/classes/BxAlbumsModule.php
  55. 120 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/classes/BxAlbumsPageMedia.php
  56. 284 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/classes/BxAlbumsSearchResultMedia.php
  57. 413 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/classes/BxAlbumsTemplate.php
  58. 143 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/install/config.php
  59. 563 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/install/sql/enable.sql
  60. 605 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/install/sql/install.sql
  61. 23 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/template/form_ghost_template.html
  62. 40 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/template/images/icons/std-icon.svg
  63. 28 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/template/unit.html
  64. 17 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/template/unit_gallery.html
  65. 24 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/template/unit_media.html
  66. 23 0
      modules/boonex/albums/updates/13.0.3_13.0.4/source/template/unit_media_gallery.html
  67. 51 0
      modules/boonex/analytics/updates/13.0.0_13.0.1/install/config.php
  68. 13 0
      modules/boonex/analytics/updates/13.0.0_13.0.1/install/installer.php
  69. 77 0
      modules/boonex/analytics/updates/13.0.0_13.0.1/source/install/config.php
  70. 149 0
      modules/boonex/analytics/updates/13.0.0_13.0.1/source/js/analytics.js
  71. 12 0
      modules/boonex/analytics/updates/13.0.0_13.0.1/source/plugins/datatables/datatables.min.css
  72. 40 0
      modules/boonex/analytics/updates/13.0.0_13.0.1/source/template/canvas.html
  73. 88 0
      modules/boonex/analytics/updates/13.0.0_13.0.1/source/template/css/main.css
  74. 40 0
      modules/boonex/analytics/updates/13.0.0_13.0.1/source/template/images/icons/std-icon.svg
  75. 51 0
      modules/boonex/antispam/updates/13.0.1_13.0.2/install/config.php
  76. 13 0
      modules/boonex/antispam/updates/13.0.1_13.0.2/install/installer.php
  77. 6 0
      modules/boonex/antispam/updates/13.0.1_13.0.2/install/sql/enable.sql
  78. 5 0
      modules/boonex/antispam/updates/13.0.1_13.0.2/install/sql/install.sql
  79. 54 0
      modules/boonex/antispam/updates/13.0.1_13.0.2/source/classes/BxAntispamAlertsResponse.php
  80. 554 0
      modules/boonex/antispam/updates/13.0.1_13.0.2/source/classes/BxAntispamModule.php
  81. 37 0
      modules/boonex/antispam/updates/13.0.1_13.0.2/source/classes/BxAntispamStudioPage.php
  82. 68 0
      modules/boonex/antispam/updates/13.0.1_13.0.2/source/install/config.php
  83. 245 0
      modules/boonex/antispam/updates/13.0.1_13.0.2/source/install/sql/enable.sql
  84. 73 0
      modules/boonex/antispam/updates/13.0.1_13.0.2/source/install/sql/install.sql
  85. 30 0
      modules/boonex/antispam/updates/13.0.1_13.0.2/source/template/images/icons/std-icon.svg
  86. 51 0
      modules/boonex/api/updates/12.0.2_13.0.0/install/config.php
  87. 13 0
      modules/boonex/api/updates/12.0.2_13.0.0/install/installer.php
  88. 602 0
      modules/boonex/api/updates/12.0.2_13.0.0/source/classes/BxApiModule.php
  89. 70 0
      modules/boonex/api/updates/12.0.2_13.0.0/source/install/config.php
  90. 65 0
      modules/boonex/api/updates/12.0.2_13.0.0/source/template/images/icons/std-icon.svg
  91. 51 0
      modules/boonex/attendant/updates/13.0.3_13.0.4/install/config.php
  92. 13 0
      modules/boonex/attendant/updates/13.0.3_13.0.4/install/installer.php
  93. 256 0
      modules/boonex/attendant/updates/13.0.3_13.0.4/source/classes/BxAttendantModule.php
  94. 77 0
      modules/boonex/attendant/updates/13.0.3_13.0.4/source/install/config.php
  95. 30 0
      modules/boonex/attendant/updates/13.0.3_13.0.4/source/template/images/icons/std-icon.svg
  96. 67 0
      modules/boonex/channels/updates/13.0.3_13.0.4/install/config.php
  97. 23 0
      modules/boonex/channels/updates/13.0.3_13.0.4/install/installer.php
  98. 11 0
      modules/boonex/channels/updates/13.0.3_13.0.4/install/sql/enable.sql
  99. 1 0
      modules/boonex/channels/updates/13.0.3_13.0.4/install/sql/install.sql
  100. 189 0
      modules/boonex/channels/updates/13.0.3_13.0.4/source/classes/BxCnlConfig.php

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

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Accounts Manager',
+    'version_from' => '13.0.2',
+    'version_to' => '13.0.3',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.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_13.0.2_13.0.3/',
+    'home_uri' => 'accounts_update_1302_1303',
+
+    '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' => 2,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Accounts',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

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

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

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

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

+ 16 - 0
modules/boonex/accounts/updates/13.0.2_13.0.3/install/sql/enable.sql

@@ -0,0 +1,16 @@
+SET @sName = 'bx_accounts';
+
+
+-- GRIDS
+UPDATE `sys_objects_grid` SET `source`='SELECT `ta`.*, `tp`.`status` AS `status`, IFNULL(`ts`.`date`, `ta`.`active`) AS `last_active` FROM `sys_accounts` AS `ta` LEFT JOIN `sys_profiles` AS `tp` ON `ta`.`id`=`tp`.`account_id` AND `tp`.`type`=''system'' LEFT JOIN `sys_sessions` AS `ts` ON `ts`.`user_id` = `ta`.`id` WHERE 1 ', `sorting_fields`='email_confirmed,logged,added,last_active' WHERE `object`='bx_accounts_administration';
+
+DELETE FROM `sys_grid_fields` WHERE `object`='bx_accounts_administration' AND `name`='last_active';
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_accounts_administration', 'last_active', '_bx_accnt_grid_column_title_adm_last_active', '10%', 0, '15', '', 8);
+
+UPDATE `sys_grid_fields` SET `width`='12%' WHERE `object`='bx_accounts_administration' AND `name`='name';
+UPDATE `sys_grid_fields` SET `width`='16%' WHERE `object`='bx_accounts_administration' AND `name`='email';
+UPDATE `sys_grid_fields` SET `width`='4%' WHERE `object`='bx_accounts_administration' AND `name`='is_confirmed';
+UPDATE `sys_grid_fields` SET `width`='24%' WHERE `object`='bx_accounts_administration' AND `name`='profiles';
+UPDATE `sys_grid_fields` SET `order`='9' WHERE `object`='bx_accounts_administration' AND `name`='added';
+UPDATE `sys_grid_fields` SET `order`='10' WHERE `object`='bx_accounts_administration' AND `name`='actions';

+ 779 - 0
modules/boonex/accounts/updates/13.0.2_13.0.3/source/classes/BxAccntGridAdministration.php

@@ -0,0 +1,779 @@
+<?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)
+    {
+        $mixedValue = !empty($mixedValue) ? bx_time_js($mixedValue) : _t('_sys_not_available');
+
+        return parent::_getCellDefault($mixedValue, $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())
+    {
+    	return BxDolAccount::getInstance($iId)->delete(isset($aParams['with_content']) && $aParams['with_content'] === true);
+    }
+    
+    
+
+    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 __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/13.0.2_13.0.3/source/install/config.php

@@ -0,0 +1,71 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    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' => '13.0.3',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.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(),
+
+);
+
+/** @} */

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

@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string name="_bx_accnt"><![CDATA[Accounts]]></string>
+    <string name="_bx_accounts"><![CDATA[Accounts]]></string>
+
+    <string name="_bx_accounts_option_export_to"><![CDATA[Export to]]></string>
+    <string name="_bx_accounts_option_export_fields"><![CDATA[Export fields]]></string>
+
+    <string name="_bx_accounts_form_display_account_settings_email_popup"><![CDATA[Edit Email]]></string>
+    <string name="_bx_accounts_form_display_account_create_popup"><![CDATA[Create new Account]]></string>
+    <string name="_bx_accounts_form_display_account_settings_password_popup"><![CDATA[Reset Password]]></string>
+	 <string name="_bx_accounts_form_display_account_send_message"><![CDATA[Send test email]]></string>
+
+    <string name="_bx_accnt_page_title_sys_manage_administration"><![CDATA[Manage All Accounts]]></string>
+    <string name="_bx_accnt_page_title_manage"><![CDATA[Manage Accounts]]></string>
+    <string name="_bx_accnt_page_title_browse"><![CDATA[Accounts]]></string>
+
+    <string name="_bx_accnt_page_block_title_system_manage_administration"><![CDATA[Manage All Accounts]]></string>
+    <string name="_bx_accnt_page_block_title_manage"><![CDATA[Manage Accounts]]></string>
+
+    <string name="_bx_accnt_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_accnt_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_accnt_menu_item_title_system_resend_cemail"><![CDATA[Resend Confirmation]]></string>
+    <string name="_bx_accnt_menu_item_title_resend_cemail"><![CDATA[Resend Confirmation]]></string>
+    <string name="_bx_accnt_menu_item_title_system_confirm"><![CDATA[Confirm]]></string>
+    <string name="_bx_accnt_menu_item_title_confirm"><![CDATA[Confirm]]></string>
+    <string name="_bx_accnt_menu_item_title_system_edit_email"><![CDATA[Edit Email]]></string>
+    <string name="_bx_accnt_menu_item_title_edit_email"><![CDATA[Edit Email]]></string>
+    <string name="_bx_accnt_menu_item_title_system_reset_password"><![CDATA[Reset Password]]></string>
+    <string name="_bx_accnt_menu_item_title_reset_password"><![CDATA[Reset Password]]></string>
+    <string name="_bx_accnt_menu_item_title_system_resend_remail"><![CDATA[Resend Reset Password]]></string>
+    <string name="_bx_accnt_menu_item_title_resend_remail"><![CDATA[Resend Reset Password]]></string>
+    <string name="_bx_accnt_menu_item_title_system_unlock_account"><![CDATA[Unlock]]></string>
+    <string name="_bx_accnt_menu_item_title_unlock_account"><![CDATA[Unlock]]></string>
+    <string name="_bx_accnt_menu_item_title_system_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_accnt_menu_item_title_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_accnt_menu_item_title_system_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_accnt_menu_item_title_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_accnt_menu_item_title_system_make_operator"><![CDATA[Make Operator]]></string>
+    <string name="_bx_accnt_menu_item_title_make_operator"><![CDATA[Make Operator]]></string>
+    <string name="_bx_accnt_menu_item_title_system_unmake_operator"><![CDATA[Unmake Operator]]></string>
+    <string name="_bx_accnt_menu_item_title_unmake_operator"><![CDATA[Unmake Operator]]></string>
+    <string name="_bx_accnt_menu_item_title_system_set_operator_role"><![CDATA[Set Operator Role]]></string>
+    <string name="_bx_accnt_menu_item_title_set_operator_role"><![CDATA[Set Operator Role]]></string>
+    <string name="_bx_accnt_menu_item_title_system_admt_accounts"><![CDATA[Accounts]]></string>
+    <string name="_bx_accnt_menu_item_title_admt_accounts"><![CDATA[Accounts]]></string>
+    <string name="_bx_accnt_menu_item_title_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_accnt_menu_dashboard_manage_tools_addon_counter1_caption"><![CDATA[unconfirmed]]></string>
+
+    <string name="_bx_accnt_acl_action_edit_any_account"><![CDATA[Edit Any Account]]></string>
+    <string name="_bx_accnt_acl_action_delete_any_account"><![CDATA[Delete Any Account]]></string>
+
+    <string name="_bx_accnt_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+    <string name="_bx_accnt_grid_filter_item_title_adm_select_one_filter2"><![CDATA[All]]></string>
+    <string name="_bx_accnt_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_accnt_grid_filter_item_title_adm_operators"><![CDATA[Operators]]></string>
+    <string name="_bx_accnt_grid_filter_item_title_adm_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_accnt_grid_filter_item_title_adm_suspended"><![CDATA[Suspended]]></string>    
+    <string name="_bx_accnt_grid_filter_item_title_adm_unconfirmed"><![CDATA[Unconfirmed]]></string>
+    <string name="_bx_accnt_grid_filter_item_title_adm_locked"><![CDATA[Locked]]></string>
+    <string name="_bx_accnt_grid_filter_item_title_adm_without_profile"><![CDATA[Without profile]]></string>
+    <string name="_bx_accnt_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_accnt_grid_column_title_adm_name"><![CDATA[Name]]></string>
+    <string name="_bx_accnt_grid_column_title_adm_email"><![CDATA[Email]]></string>
+    <string name="_bx_accnt_grid_column_title_adm_ip"><![CDATA[IP]]></string>
+
+    <string name="_bx_accnt_grid_column_title_adm_is_confirmed"><![CDATA[Confirmed]]></string>
+    <string name="_bx_accnt_grid_column_title_adm_profiles"><![CDATA[Profiles]]></string>
+    <string name="_bx_accnt_grid_column_title_adm_logged"><![CDATA[Last Logged]]></string>
+    <string name="_bx_accnt_grid_column_title_adm_last_active"><![CDATA[Last Active]]></string>
+    <string name="_bx_accnt_grid_column_title_adm_added"><![CDATA[Created]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_activate"><![CDATA[Activate]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_suspend"><![CDATA[Suspend]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_confirm"><![CDATA[Confirm]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_edit_email"><![CDATA[Edit Email]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_export"><![CDATA[Export]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_resend_cemail"><![CDATA[Resend Confirmation]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_resend_remail"><![CDATA[Resend Reset Password]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_reset_password"><![CDATA[Reset Password]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_unlock_account"><![CDATA[Unlock]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_delete_with_content"><![CDATA[Delete With Content]]></string>
+	<string name="_bx_accnt_grid_action_title_adm_send_message"><![CDATA[Send email]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_accnt_grid_action_title_adm_more_add"><![CDATA[Add new]]></string>
+    <string name="_bx_accnt_grid_action_err_delete"><![CDATA[Cannot delete the selected account(s).]]></string>
+    <string name="_bx_accnt_grid_action_err_perform"><![CDATA[Cannot perform the action for selected account(s).]]></string>
+    <string name="_bx_accnt_grid_action_unlock_successed"><![CDATA[Successfully unlocked]]></string>
+    <string name="_bx_accnt_grid_action_unlock_error"><![CDATA[Account is not blocked]]></string>
+    <string name="_bx_accnt_grid_confirmation_status_none"><![CDATA[No]]></string>
+    <string name="_bx_accnt_grid_confirmation_status_email"><![CDATA[Email]]></string>
+    <string name="_bx_accnt_grid_confirmation_status_phone"><![CDATA[Phone]]></string>
+    <string name="_bx_accnt_grid_confirmation_status_email_and_phone"><![CDATA[All]]></string>
+
+    <string name="_bx_accnt_form_login_input_caption_system_email_confirmed"><![CDATA[Email confirmed]]></string>
+    <string name="_bx_accnt_form_account_input_email_confirmed"><![CDATA[Email confirmed]]></string>
+	<string name="_bx_accnt_form_account_input_caption_system_message_subject"><![CDATA[Subject]]></string>
+    <string name="_bx_accnt_form_account_input_caption_message_subject"><![CDATA[Subject]]></string>
+	<string name="_bx_accnt_form_account_input_message_subject_error"><![CDATA[Subject can't be empty]]></string>
+	<string name="_bx_accnt_form_account_input_caption_system_message_text"><![CDATA[Text]]></string>
+    <string name="_bx_accnt_form_account_input_caption_message_text"><![CDATA[Text]]></string>
+	<string name="_bx_accnt_form_account_input_message_text_error"><![CDATA[Text can't be empty]]></string>
+	<string name="_bx_accnt_form_display_send_message"><![CDATA[Send email]]></string>
+ 
+    <string name="_bx_accnt_txt_more"><![CDATA[{0} more]]></string>
+    <string name="_bx_accnt_txt_see_more"><![CDATA[See more]]></string>
+    <string name="_bx_accnt_txt_copy_to_clipboard"><![CDATA[Copy to Clipboard]]></string>
+    <string name="_bx_accnt_txt_not_operator"><![CDATA[Not an Operator]]></string>
+    <string name="_bx_accnt_txt_export_to_csv"><![CDATA[CSV]]></string>
+    <string name="_bx_accnt_txt_export_to_xml"><![CDATA[XML]]></string>
+    <string name="_bx_accnt_txt_field_name"><![CDATA[Name]]></string>
+    <string name="_bx_accnt_txt_field_email"><![CDATA[Email]]></string>
+    <string name="_bx_accnt_txt_field_email_confirmed"><![CDATA[Email Confirmed]]></string>
+    <string name="_bx_accnt_txt_field_phone"><![CDATA[Phone]]></string>
+    <string name="_bx_accnt_txt_field_receive_updates"><![CDATA[Receive Updates]]></string>
+    <string name="_bx_accnt_txt_field_receive_news"><![CDATA[Receive News]]></string>
+    <string name="_bx_accnt_txt_field_added"><![CDATA[Added]]></string>
+    <string name="_bx_accnt_txt_field_changed"><![CDATA[Changed]]></string>
+    <string name="_bx_accnt_txt_field_logged"><![CDATA[Logged]]></string>
+    <string name="_bx_accnt_txt_field_ip"><![CDATA[IP]]></string>
+</resources>

+ 114 - 0
modules/boonex/accounts/updates/13.0.2_13.0.3/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', 'at', '', 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', 'far envelope', '', 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', 'fas check', '', 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', 'eraser', '', 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', 'eraser', '', 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', 'unlock', '', 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', 'far trash-alt', '', 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', 'far trash-alt', '', 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', 'wrench', '', 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`, IFNULL(`ts`.`date`, `ta`.`active`) AS `last_active` FROM `sys_accounts` AS `ta` LEFT JOIN `sys_profiles` AS `tp` ON `ta`.`id`=`tp`.`account_id` AND `tp`.`type`=''system'' LEFT JOIN `sys_sessions` AS `ts` ON `ts`.`user_id` = `ta`.`id` WHERE 1 ', 'sys_accounts', 'id', 'logged', 'status', '', 20, NULL, 'start', '', 'name,email,ip,phone', '', 'like', 'email_confirmed,logged,added,last_active', '', 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', 'cog', 1, 0, 2),
+('bx_accounts_administration', 'independent', 'add', '_bx_accnt_grid_action_title_adm_more_add', 'plus', 0, 0, 0),
+('bx_accounts_administration', 'independent', 'export', '_bx_accnt_grid_action_title_adm_export', 'download', 0, 0, 1);

+ 34 - 0
modules/boonex/accounts/updates/13.0.2_13.0.3/source/template/images/icons/std-icon.svg

@@ -0,0 +1,34 @@
+<svg width="320" height="320" viewBox="0 0 320 320" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_910_8302)">
+<path d="M160 0C281.326 0 320 38.6737 320 160C320 281.326 281.326 320 160 320C38.6736 320 0 281.326 0 160C0 38.6737 38.6736 0 160 0Z" fill="url(#paint0_linear_910_8302)"/>
+<g clip-path="url(#clip1_910_8302)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M165.417 158.971C167.919 162.042 171.824 163.873 175.623 162.75C198.389 156.017 215 134.949 215 110C215 79.6243 190.376 55 160 55C129.624 55 105 79.6243 105 110C105 117.648 106.561 124.931 109.381 131.548C110.322 133.754 112.602 135 115 135V135C135.34 135 153.498 144.343 165.417 158.971Z" fill="url(#paint1_linear_910_8302)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M148.434 167.957C150.935 163.552 150.645 157.808 146.494 154.904C137.573 148.662 126.714 145 115 145C84.6243 145 60 169.624 60 200C60 230.376 84.6243 255 115 255C126.714 255 137.573 251.338 146.494 245.096C150.645 242.192 150.935 236.448 148.434 232.043C143.065 222.586 140 211.651 140 200C140 188.349 143.065 177.414 148.434 167.957Z" fill="url(#paint2_linear_910_8302)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M160 175C157.602 175 155.321 176.247 154.381 178.453C151.561 185.07 150 192.353 150 200C150 230.376 174.624 255 205 255C235.376 255 260 230.376 260 200C260 175.052 243.389 153.983 220.623 147.251C216.824 146.127 212.919 147.958 210.417 151.029C198.498 165.658 180.34 175 160 175V175Z" fill="url(#paint3_linear_910_8302)"/>
+</g>
+</g>
+<defs>
+<linearGradient id="paint0_linear_910_8302" x1="160" y1="0" x2="160" y2="320" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FB7185"/>
+<stop offset="1" stop-color="#E11D48"/>
+</linearGradient>
+<linearGradient id="paint1_linear_910_8302" x1="186" y1="59.5" x2="144" y2="143" gradientUnits="userSpaceOnUse">
+<stop stop-color="white"/>
+<stop offset="1" stop-color="#FECDD3" stop-opacity="0.6"/>
+</linearGradient>
+<linearGradient id="paint2_linear_910_8302" x1="56.5" y1="200" x2="137.481" y2="214.282" gradientUnits="userSpaceOnUse">
+<stop stop-color="white"/>
+<stop offset="1" stop-color="#FECDD3" stop-opacity="0.6"/>
+</linearGradient>
+<linearGradient id="paint3_linear_910_8302" x1="235.5" y1="244" x2="190" y2="167.5" gradientUnits="userSpaceOnUse">
+<stop stop-color="white"/>
+<stop offset="1" stop-color="#FECDD3" stop-opacity="0.6"/>
+</linearGradient>
+<clipPath id="clip0_910_8302">
+<rect width="320" height="320" fill="white"/>
+</clipPath>
+<clipPath id="clip1_910_8302">
+<rect width="240" height="240" fill="white" transform="translate(40 40)"/>
+</clipPath>
+</defs>
+</svg>

+ 51 - 0
modules/boonex/acl/updates/13.0.1_13.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' => 'Paid Levels',
+    'version_from' => '13.0.1',
+    'version_to' => '13.0.2',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.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/acl/updates/update_13.0.1_13.0.2/',
+    'home_uri' => 'acl_update_1301_1302',
+
+    'module_dir' => 'boonex/acl/',
+    'module_uri' => 'acl',
+
+    'db_prefix' => 'bx_acl_',
+    'class_prefix' => 'BxAcl',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Paid Levels',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 23 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/install/installer.php

@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxAclUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+
+    public function actionExecuteSql($sOperation)
+    {
+        if($sOperation == 'install') {
+            if(!$this->oDb->isFieldExists('bx_acl_level_prices', 'immediate'))
+                $this->oDb->query("ALTER TABLE `bx_acl_level_prices` ADD `immediate` tinyint(4) NOT NULL default '1' AFTER `price`");
+        }
+
+        return parent::actionExecuteSql($sOperation);
+    }
+}

+ 12 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/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_acl_form_price_input_sys_immediate"><![CDATA[Activate immediately]]></string_add>
+    <string_add name="_bx_acl_form_price_input_immediate"><![CDATA[Activate immediately after purchase]]></string_add>
+	<string_add name="_bx_acl_et_txt_name_subscription_cancel_required"><![CDATA[Subscription cancel required.]]></string_add>
+    <string_add name="_bx_acl_et_txt_subject_subscription_cancel_required"><![CDATA[Subscription cancel required.]]></string_add>
+    <string_add name="_bx_acl_et_txt_body_subscription_cancel_required"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>You've paid for a new membership level but your old level's subscription is still active. You need to cancel it manually.</p>
+<p>Old subscription info:<br />Membership level: {level}<br />Order: {order}<br />Date Starts: {date_starts}<br />Date Expires: {date_expires}</p>
+{email_footer}]]></string_add>
+</resources>

+ 7 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/install/sql/enable.sql

@@ -0,0 +1,7 @@
+SET @sName = 'bx_acl';
+
+
+-- EMAIL TEMPLATES
+DELETE FROM `sys_email_templates` WHERE `Name`='bx_acl_subscription_cancel_required';
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES 
+(@sName, '_bx_acl_et_txt_name_subscription_cancel_required', 'bx_acl_subscription_cancel_required', '_bx_acl_et_txt_subject_subscription_cancel_required', '_bx_acl_et_txt_body_subscription_cancel_required');

+ 27 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/install/sql/install.sql

@@ -0,0 +1,27 @@
+SET @sName = 'bx_acl';
+
+
+-- TABLES
+CREATE TABLE IF NOT EXISTS `bx_acl_licenses` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `profile_id` int(11) unsigned NOT NULL default '0',
+  `price_id` int(11) unsigned NOT NULL default '0',
+  `type` varchar(16) NOT NULL default 'single',
+  `order` varchar(32) NOT NULL default '',
+  `license` varchar(32) NOT NULL default '',
+  `added` int(11) unsigned NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `price_id` (`price_id`, `profile_id`),
+  KEY `license` (`license`)
+);
+
+
+-- FORMS
+DELETE FROM `sys_form_inputs` WHERE `object`='bx_acl_price' AND `name`='immediate';
+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_acl_price', @sName, 'immediate', 1, '', 1, 'switcher', '_bx_acl_form_price_input_sys_immediate', '_bx_acl_form_price_input_immediate', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0);
+
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN ('bx_acl_price_add', 'bx_acl_price_edit') AND `input_name`='immediate';
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_acl_price_add', 'immediate', 2147483647, 1, 7),
+('bx_acl_price_edit', 'immediate', 2147483647, 1, 7);

+ 151 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/source/classes/BxAclConfig.php

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

+ 259 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/source/classes/BxAclDb.php

@@ -0,0 +1,259 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    PaidLevels Paid Levels
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxAclDb extends BxDolModuleDb
+{
+    protected $_oConfig;
+
+    public function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+
+        $this->_oConfig = $oConfig;
+    }
+
+    public function getProductsNames ($iVendor = 0, $iLimit = 1000)
+    {
+        return $this->getColumn("SELECT `name` FROM `bx_acl_level_prices` WHERE 1 LIMIT :limit", ['limit' => $iLimit]);
+    }
+
+    public function getLevels($aParams, $bReturnCount = false)
+    {
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        $sSelectClause = "
+            `tal`.`ID` AS `id`,
+            `tal`.`Name` AS `name`,
+            `tal`.`Icon` AS `icon`,
+            `tal`.`Description` AS `description`,
+            `tal`.`Active` AS `active`,
+            `tal`.`Purchasable` AS `purchasable`,
+            `tal`.`Removable` AS `removable`,
+            `tal`.`QuotaSize` AS `quota_size`,
+            `tal`.`QuotaNumber` AS `quota_number`,
+            `tal`.`QuotaMaxFileSize` AS `quota_max_file_size`,
+            `tal`.`Order` AS `order`";
+
+        if(!isset($aParams['order']) || empty($aParams['order']))
+            $sOrderClause = "ORDER BY `tal`.`Order` ASC";
+
+        switch($aParams['type']) {
+            case 'by_id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                    'id' => $aParams['value']
+                );
+
+                $sWhereClause .= "AND `tal`.`id`=:id";
+                break;
+
+            case 'for_selector':
+                $aMethod['name'] = 'getPairs';
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = 'name';
+                $sWhereClause .= "AND `tal`.`Active`='yes' AND (`tal`.`Purchasable`='yes' OR `tal`.`Removable`='yes')";
+                break;
+        }
+
+        $sSql = "SELECT {select} FROM `sys_acl_levels` AS `tal` " . $sJoinClause . " WHERE 1 " . $sWhereClause . " {order} {limit}";
+
+        $aMethod['params'][0] = str_replace(array('{select}', '{order}', '{limit}'), array($sSelectClause, $sOrderClause, $sLimitClause), $sSql);
+        $aItems = call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+
+        if(!$bReturnCount)
+            return $aItems;
+
+        $aMethod['name'] = 'getOne';
+        $aMethod['params'][0] = str_replace(array('{select}', '{order}', '{limit}'), array("COUNT(*)", "", ""), $sSql);
+
+        return array(
+            'items' => $aItems, 
+            'count' => (int)call_user_func_array(array($this, $aMethod['name']), $aMethod['params'])
+        );
+    }
+
+    public function updateLevels($aSet, $aWhere)
+    {
+        $sSql = "UPDATE `sys_acl_levels` SET " . $this->arrayToSQL($aSet, " AND ") . " WHERE " . $this->arrayToSQL($aWhere, " AND ");
+        return (int)$this->query($sSql) > 0;
+    }
+
+    public function getPrices($aParams, $bReturnCount = false)
+    {
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        $sSelectClause = "
+            `tap`.`id` AS `id`,
+            `tap`.`level_id` AS `level_id`,
+            `tap`.`name` AS `name`,
+            `tap`.`period` AS `period`,
+            `tap`.`period_unit` AS `period_unit`,
+            `tap`.`price` AS `price`,
+            `tap`.`trial` AS `trial`,
+            `tap`.`immediate` AS `immediate`,
+            `tap`.`order` AS `order`";
+
+        if(!isset($aParams['order']) || empty($aParams['order']))
+            $sOrderClause = "ORDER BY `tap`.`Order` ASC";
+
+        switch($aParams['type']) {
+            case 'by_id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                    'id' => $aParams['value']
+                );
+
+                $sWhereClause .= "AND `tap`.`id`=:id";
+                break;
+
+            case 'by_id_full':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                    'id' => $aParams['value']
+                );
+
+                $sSelectClause .= ", `tal`.`Name` AS `level_name`, `tal`.`Description` AS `level_description`";
+                $sJoinClause .= "LEFT JOIN `sys_acl_levels` AS `tal` ON `tap`.`level_id`=`tal`.`ID`";
+                $sWhereClause .= "AND `tap`.`id`=:id";
+                break;
+
+            case 'by_name_full':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                    'name' => $aParams['value']
+                );
+
+                $sSelectClause .= ", `tal`.`Name` AS `level_name`, `tal`.`Description` AS `level_description`";
+                $sJoinClause .= "LEFT JOIN `sys_acl_levels` AS `tal` ON `tap`.`level_id`=`tal`.`ID`";
+                $sWhereClause .= "AND `tap`.`name`=:name";
+                break;
+
+            case 'by_level_id':
+                $aMethod['params'][1] = array(
+                    'level_id' => $aParams['value']
+                );
+
+                $sWhereClause .= "AND `tap`.`level_id`=:level_id";
+                break;
+
+            case 'by_level_id_duration':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                    'level_id' => $aParams['level_id'],
+                    'period' => $aParams['period'],
+                    'period_unit' => $aParams['period_unit'],
+                );
+
+                $sWhereClause .= "AND `tap`.`level_id`=:level_id AND `tap`.`period`=:period AND `tap`.`period_unit`=:period_unit";
+                break;
+
+            case 'all_full':
+                $sSelectClause .= ", `tal`.`Name` AS `level_name`, `tal`.`Description` AS `level_description`";
+                $sJoinClause .= "LEFT JOIN `sys_acl_levels` AS `tal` ON `tap`.`level_id`=`tal`.`ID`";
+                break;
+        }
+
+        $sSql = "SELECT {select} FROM `" . $this->_oConfig->CNF['TABLE_PRICES'] . "` AS `tap` " . $sJoinClause . " WHERE 1 " . $sWhereClause . " {order} {limit}";
+
+        $aMethod['params'][0] = str_replace(array('{select}', '{order}', '{limit}'), array($sSelectClause, $sOrderClause, $sLimitClause), $sSql);
+        $aItems = call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+
+        if(!$bReturnCount)
+            return $aItems;
+
+        $aMethod['name'] = 'getOne';
+        $aMethod['params'][0] = str_replace(array('{select}', '{order}', '{limit}'), array("COUNT(*)", "", ""), $sSql);
+
+        return array(
+            'items' => $aItems, 
+            'count' => (int)call_user_func_array(array($this, $aMethod['name']), $aMethod['params'])
+        );
+    }
+
+    public function getPriceOrderMax($iLevelId)
+    {
+        $sSql = $this->prepare("SELECT MAX(`order`) FROM `" . $this->_oConfig->CNF['TABLE_PRICES'] . "` WHERE `level_id`=?", $iLevelId);
+        return (int)$this->getOne($sSql);
+    }
+
+    public function deletePrices($aWhere)
+    {
+        $sSql = "DELETE FROM `" . $this->_oConfig->CNF['TABLE_PRICES'] . "` WHERE " . $this->arrayToSQL($aWhere, " AND ");
+        return (int)$this->query($sSql) > 0;
+    }
+    
+    public function getLicenses($aParams, $bReturnCount = false)
+    {
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+
+        $sSelectClause = "`tl`.*";
+        $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        switch($aParams['type']) {
+            case 'by_order':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = [
+                    'order' => $aParams['order']
+                ];
+
+                $sWhereClause .= "AND `tl`.`order`=:order";
+                break;
+
+            case 'by_license':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = [
+                    'license' => $aParams['license']
+                ];
+
+                $sWhereClause .= "AND `tl`.`license`=:license";
+                break;
+        }
+
+        $sSql = "SELECT {select} FROM `" . $this->_oConfig->CNF['TABLE_LICENSES'] . "` AS `tl` " . $sJoinClause . " WHERE 1 " . $sWhereClause . " {order} {limit}";
+
+        $aMethod['params'][0] = str_replace(['{select}', '{order}', '{limit}'], [$sSelectClause, $sOrderClause, $sLimitClause], $sSql);
+        $aItems = call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+
+        if(!$bReturnCount)
+            return $aItems;
+
+        $aMethod['name'] = 'getOne';
+        $aMethod['params'][0] = str_replace(['{select}', '{order}', '{limit}'], ['COUNT(*)', '', ''], $sSql);
+
+        return [
+            'items' => $aItems, 
+            'count' => (int)call_user_func_array([$this, $aMethod['name']], $aMethod['params'])
+        ];
+    }
+
+    public function insertLicense($aSet)
+    {
+        $sSetClause = $this->arrayToSQL($aSet);
+        return (int)$this->query("INSERT INTO `" . $this->_oConfig->CNF['TABLE_LICENSES'] . "` SET " . $sSetClause) > 0;
+    }
+
+    public function updateLicenses($aSet, $aWhere)
+    {
+        $sSetClause = $this->arrayToSQL($aSet);
+        $sWhereClause = $this->arrayToSQL($aWhere, " AND ");
+        return (int)$this->query("UPDATE `" . $this->_oConfig->CNF['TABLE_LICENSES'] . "` SET " . $sSetClause . " WHERE " . $sWhereClause) > 0;
+    }
+
+    public function deleteLicenses($aWhere)
+    {
+        $sWhereClause = $this->arrayToSQL($aWhere, " AND ");
+        return (int)$this->query("DELETE FROM `" . $this->_oConfig->CNF['TABLE_LICENSES'] . "` WHERE " . $sWhereClause) > 0;
+    }
+}
+
+/** @} */

+ 140 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/source/classes/BxAclGridView.php

@@ -0,0 +1,140 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    PaidLevels Paid Levels
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+require_once('BxAclGridLevels.php');
+
+class BxAclGridView extends BxAclGridLevels
+{
+    /**
+     * Array with check_sum => JS_code pairs of all JS codes 
+     * which should be added to the page.
+     */
+    protected $_aJsCodes;
+
+    protected $_iOwner;
+    protected $_oPayment;
+    protected $_bTypeSingle;
+    protected $_bTypeRecurring;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_aJsCodes = array();
+
+        $this->_iOwner = $this->_oModule->_oConfig->getOwner();
+        $this->_oPayment = BxDolPayments::getInstance();
+        $this->_bTypeSingle = $this->_oPayment->isAcceptingPayments($this->_iOwner, BX_PAYMENT_TYPE_SINGLE);
+        $this->_bTypeRecurring = !$this->_oPayment->isCreditsOnly() && $this->_oPayment->isAcceptingPayments($this->_iOwner, BX_PAYMENT_TYPE_RECURRING);
+    }
+
+    public function performActionChoose()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aIds = $this->_getIds();
+        if($aIds === false)
+            return echoJson(array());
+
+        $aItem = $this->_oModule->_oDb->getPrices(array('type' => 'by_id', 'value' => $aIds[0]));
+        if(!is_array($aItem) || empty($aItem) || (float)$aItem['price'] != 0)
+        	return echoJson(array());
+
+        $aResult = array();
+        $iUserId = bx_get_logged_profile_id();
+        if(BxDolAcl::getInstance()->setMembership($iUserId, $aItem['level_id'], array('period' => $aItem['period'], 'period_unit' => $aItem['period_unit']), true))
+            $aResult = array('grid' => $this->getCode(false), 'blink' => $aItem['id'], 'msg' => _t('_bx_acl_msg_performed'));
+        else
+            $aResult = array('msg' => _t('_bx_acl_err_cannot_perform'));
+
+        return echoJson($aResult);
+    }
+
+    public function getCode($isDisplayHeader = true)
+    {
+    	return parent::getCode($isDisplayHeader) . $this->getJsCode();
+    }
+
+    public function getJsCode()
+    {
+        if(empty($this->_aJsCodes) || !is_array($this->_aJsCodes))
+            return '';
+
+        return implode('', $this->_aJsCodes);
+    }
+
+    protected function _getCellLevelIcon($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = $this->_oModule->_oTemplate->displayLevelIcon($mixedValue);
+    	return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getActionChoose ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if((float)$aRow['price'] != 0 || BxDolAcl::getInstance()->isMemberLevelInSet(array($aRow['level_id'])))
+            return '';
+
+        return  parent::_getActionDefault($sType, $sKey, $a, false, $isDisabled, $aRow);
+    }
+
+    protected function _getActionBuy ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if((float)$aRow['price'] == 0 || !$this->_bTypeSingle || ($this->_bTypeRecurring && getParam($CNF['PARAM_RECURRING_PRIORITIZE']) == 'on' && !$this->_isLifetime($aRow)))
+            return '';
+
+    	$aJs = $this->_oPayment->getAddToCartJs($this->_iOwner, $this->MODULE, $aRow['id'], 1, true);
+    	if(!empty($aJs) && is_array($aJs)) {
+            list($sJsCode, $sJsMethod) = $aJs;
+
+            $sJsCodeCheckSum = md5($sJsCode);
+            if(!isset($this->_aJsCodes[$sJsCodeCheckSum]))
+                $this->_aJsCodes[$sJsCodeCheckSum] = $sJsCode;
+
+            $a['attr'] = array(
+                'title' => bx_html_attribute(_t('_bx_acl_grid_action_buy_title')),
+                'onclick' => $sJsMethod
+            );
+    	}
+
+        return  parent::_getActionDefault($sType, $sKey, $a, false, $isDisabled, $aRow);
+    }
+
+    protected function _getActionSubscribe ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if((float)$aRow['price'] == 0 || !$this->_bTypeRecurring || ($this->_bTypeSingle && $this->_isLifetime($aRow)))
+            return '';
+
+    	$aJs = $this->_oPayment->getSubscribeJs($this->_iOwner, '', $this->MODULE, $aRow['id'], 1);
+        if(!empty($aJs) && is_array($aJs)) {
+            list($sJsCode, $sJsMethod) = $aJs;
+
+            $sJsCodeCheckSum = md5($sJsCode);
+            if(!isset($this->_aJsCodes[$sJsCodeCheckSum]))
+                $this->_aJsCodes[$sJsCodeCheckSum] = $sJsCode;
+
+            $a['attr'] = array(
+                'title' => bx_html_attribute(_t('_bx_acl_grid_action_subscribe_title')),
+                'onclick' => $sJsMethod
+            );
+        }
+
+    	return parent::_getActionDefault($sType, $sKey, $a, false, $isDisabled, $aRow);
+    }
+
+    protected function _isLifetime($aRow)
+    {
+        return empty($aRow['period']) && empty($aRow['period_unit']);
+    }
+}
+
+/** @} */

+ 651 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/source/classes/BxAclModule.php

@@ -0,0 +1,651 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    PaidLevels Paid Levels
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+bx_import('BxDolAcl');
+
+define('BX_ACL_LICENSE_TYPE_SINGLE', 'single'); //--- one-time payment license
+define('BX_ACL_LICENSE_TYPE_RECURRING', 'recurring'); //--- recurring payment license
+
+class BxAclModule extends BxDolModule
+{
+    /**
+     * Constructor
+     */
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_oConfig->init($this->_oDb);
+    }
+
+    /**
+     * ACTION METHODS
+     */
+    public function actionCheckName()
+    {
+        $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)) {
+            $aPrice = $this->_oDb->getPrices(array('type' => 'by_id', 'value' => $iId)); 
+            if(strcmp($sName, $aPrice[$CNF['FIELD_NAME']]) == 0) 
+                $sResult = $sName;
+        }
+
+    	echoJson(array(
+            'name' => !empty($sResult) ? $sResult : $this->_oConfig->getPriceName($sName)
+    	));
+    }
+
+    /**
+     * SERVICE METHODS
+     */
+
+    public function serviceGetSafeServices()
+    {
+        return array (
+            'GetViewUrl' => '',
+            'GetBlockView' => '',
+            'GetMembershipActions' => '',
+        );
+    }
+
+	/**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-other Other
+     * @subsubsection bx_acl-get_view_url get_view_url
+     * 
+     * @code bx_srv('bx_acl', 'get_view_url', [...]); @endcode
+     * 
+     * Get page URL with membership levels list.
+     *
+     * @return string with page URL.
+     * 
+     * @see BxAclModule::serviceGetViewUrl
+     */
+    /** 
+     * @ref bx_acl-get_view_url "get_view_url"
+     */
+	public function serviceGetViewUrl()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	return  bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_VIEW']));
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-page_blocks Page Blocks
+     * @subsubsection bx_acl-get_block_view get_block_view
+     * 
+     * @code bx_srv('bx_acl', 'get_block_view', [...]); @endcode
+     * 
+     * Get page block with a list of available ACL levels to purchase or get for Free. List is represented as table.
+     *
+     * @return HTML string with a list of ACL levels 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 BxAclModule::serviceGetBlockView
+     */
+    /** 
+     * @ref bx_acl-get_block_view "get_block_view"
+     */
+	public function serviceGetBlockView()
+	{
+	    bx_require_authentication(false, false, $this->serviceGetViewUrl());
+
+		$sGrid = $this->_oConfig->getGridObject('view');
+		$oGrid = BxDolGrid::getObjectInstance($sGrid);
+        if(!$oGrid)
+            return '';
+
+        $this->_oTemplate->addCss(array('view.css'));
+		return array(
+            'content' => $oGrid->getCode()
+        );
+	}
+
+	/**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-page_blocks Page Blocks
+     * @subsubsection bx_acl-get_membership_actions get_membership_actions
+     * 
+     * @code bx_srv('bx_acl', 'get_membership_actions', [...]); @endcode
+     * 
+     * Get page block with a list of current membership level's actions.
+     *
+     * @return HTML string with a list of actions 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 BxAclModule::serviceGetMembershipActions
+     */
+    /** 
+     * @ref bx_acl-get_membership_actions "get_membership_actions"
+     */
+	public function serviceGetMembershipActions($iProfileId)
+	{
+		if($iProfileId != $this->getUserId())
+			return '';
+
+		return $this->_oTemplate->displayMembershipActions($iProfileId);
+	}
+
+	/**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-payments Payments
+     * @subsubsection bx_acl-get_payment_data get_payment_data
+     * 
+     * @code bx_srv('bx_acl', '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 BxAclModule::serviceGetPaymentData
+     */
+    /** 
+     * @ref bx_acl-get_payment_data "get_payment_data"
+     */
+	public function serviceGetPaymentData()
+    {
+        return $this->_aModule;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-payments Payments
+     * @subsubsection bx_acl-get_cart_item get_cart_item
+     * 
+     * @code bx_srv('bx_acl', 'get_cart_item', [...]); @endcode
+     * 
+     * Get an array with level's description. Is used in Shopping Cart in payments processing module.
+     * 
+     * @param $mixedItemId level's ID or Unique Name.
+     * @return an array with level's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxAclModule::serviceGetCartItem
+     */
+    /** 
+     * @ref bx_acl-get_cart_item "get_cart_item"
+     */
+    public function serviceGetCartItem($mixedItemId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$mixedItemId)
+            return array();
+
+        if(is_numeric($mixedItemId))
+            $aItem = $this->_oDb->getPrices(array('type' => 'by_id_full', 'value' => (int)$mixedItemId));
+        else 
+            $aItem = $this->_oDb->getPrices(array('type' => 'by_name_full', 'value' => $mixedItemId));
+
+        if(empty($aItem) || !is_array($aItem))
+            return array();
+
+        $sTitle = '';
+        if((int)$aItem['period'] == 0)
+            $sTitle = _t('_bx_acl_txt_cart_item_title_lifetime', _t($aItem['level_name']));
+        else
+            $sTitle = _t('_bx_acl_txt_cart_item_title', _t($aItem['level_name']), $aItem['period'], $aItem['period_unit']);
+
+        $sDescription = _t($aItem['level_description']);
+        if(empty($sDescription))
+            $sDescription = _t('_bx_acl_txt_cart_item_description', getParam('site_title'));
+
+        return array (
+            'id' => $aItem['id'],
+            'author_id' => $this->_oConfig->getOwner(),
+            'name' => $aItem['name'],
+            'title' => $sTitle,
+            'description' => $sDescription,
+            'url' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_VIEW'])),
+            'price_single' => $aItem['price'],
+            'price_recurring' => $aItem['price'],
+            'period_recurring' => $aItem['period'],
+            'period_unit_recurring' => $aItem['period_unit'],
+            'trial_recurring' => $aItem['trial']
+        );
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-payments Payments
+     * @subsubsection bx_acl-get_cart_items get_cart_items
+     * 
+     * @code bx_srv('bx_acl', 'get_cart_items', [...]); @endcode
+     * 
+     * Get an array with levels' descriptions by seller. Is used in Manual Order Processing in payments processing module.
+     * 
+     * @param $iSellerId seller ID.
+     * @return an array with levels' descriptions. Empty array is returned if something is wrong or seller doesn't have any paid level.
+     * 
+     * @see BxAclModule::serviceGetCartItems
+     */
+    /** 
+     * @ref bx_acl-get_cart_items "get_cart_items"
+     */
+    public function serviceGetCartItems($iSellerId)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$iSellerIdSetting = $this->_oConfig->getOwner();
+    	if(empty($iSellerId) || ($iSellerId != $iSellerIdSetting && !isAdmin()))
+    	    return array();
+
+        $aItems = $this->_oDb->getPrices(array('type' => 'all_full'));
+        $sUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_VIEW']));
+
+        $aResult = array();
+        foreach($aItems as $aItem) {
+            $sTitle = '';
+            if((int)$aItem['period'] == 0)
+                $sTitle = _t('_bx_acl_txt_cart_item_title_lifetime', _t($aItem['level_name']));
+            else
+                $sTitle = _t('_bx_acl_txt_cart_item_title', _t($aItem['level_name']), $aItem['period'], $aItem['period_unit']);
+
+            $sDescription = _t($aItem['level_description']);
+            if(empty($sDescription))
+                $sDescription = _t('_bx_acl_txt_cart_item_description', getParam('site_title'));
+            
+            $aResult[] = array(
+                'id' => $aItem['id'],
+                'author_id' => $iSellerIdSetting,
+                'name' => $aItem['name'],
+                'title' => $sTitle,
+                'description' => $sDescription,
+                'url' => $sUrl,
+                'price_single' => $aItem['price'],
+                'price_recurring' => $aItem['price'],
+                'period_recurring' => $aItem['period'],
+                'period_unit_recurring' => $aItem['period_unit'],
+                'trial_recurring' => $aItem['trial']
+           );
+        }
+
+        return $aResult;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-payments Payments
+     * @subsubsection bx_acl-register_cart_item register_cart_item
+     * 
+     * @code bx_srv('bx_acl', 'register_cart_item', [...]); @endcode
+     * 
+     * Register a processed single time payment inside the Paid Levels 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 BxAclModule::serviceRegisterCartItem
+     */
+    /** 
+     * @ref bx_acl-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_ACL_LICENSE_TYPE_SINGLE);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-payments Payments
+     * @subsubsection bx_acl-register_subscription_item register_subscription_item
+     * 
+     * @code bx_srv('bx_acl', 'register_subscription_item', [...]); @endcode
+     * 
+     * Register a processed subscription (recurring payment) inside the Paid Levels 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 BxAclModule::serviceRegisterSubscriptionItem
+     */
+    /** 
+     * @ref bx_acl-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_ACL_LICENSE_TYPE_RECURRING);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-payments Payments
+     * @subsubsection bx_acl-reregister_cart_item reregister_cart_item
+     * 
+     * @code bx_srv('bx_acl', 'reregister_cart_item', [...]); @endcode
+     * 
+     * Reregister a single time payment inside the Paid Levels 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 BxAclModule::serviceReregisterCartItem
+     */
+    /** 
+     * @ref bx_acl-reregister_cart_item "reregister_cart_item"
+     */
+    public function serviceReregisterCartItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
+    {
+        return $this->_serviceReregisterItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder, BX_ACL_LICENSE_TYPE_SINGLE);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-payments Payments
+     * @subsubsection bx_acl-reregister_subscription_item reregister_subscription_item
+     * 
+     * @code bx_srv('bx_acl', 'reregister_subscription_item', [...]); @endcode
+     * 
+     * Reregister a subscription (recurring payment) inside the Paid Levels 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 BxAclModule::serviceReregisterSubscriptionItem
+     */
+    /** 
+     * @ref bx_acl-reregister_subscription_item "reregister_subscription_item"
+     */
+    public function serviceReregisterSubscriptionItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
+    {
+		return $this->_serviceReregisterItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder, BX_ACL_LICENSE_TYPE_RECURRING);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-payments Payments
+     * @subsubsection bx_acl-unregister_cart_item unregister_cart_item
+     * 
+     * @code bx_srv('bx_acl', 'unregister_cart_item', [...]); @endcode
+     * 
+     * Unregister an earlier processed single time payment inside the Paid Levels 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 BxAclModule::serviceUnregisterCartItem
+     */
+    /** 
+     * @ref bx_acl-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_ACL_LICENSE_TYPE_SINGLE);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-payments Payments
+     * @subsubsection bx_acl-unregister_subscription_item unregister_subscription_item
+     * 
+     * @code bx_srv('bx_acl', 'unregister_subscription_item', [...]); @endcode
+     * 
+     * Unregister an earlier processed subscription (recurring payment) inside the Paid Levels 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 BxAclModule::serviceUnregisterSubscriptionItem
+     */
+    /** 
+     * @ref bx_acl-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_ACL_LICENSE_TYPE_RECURRING); 
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-payments Payments
+     * @subsubsection bx_acl-cancel_subscription_item cancel_subscription_item
+     * 
+     * @code bx_srv('bx_acl', 'cancel_subscription_item', [...]); @endcode
+     * 
+     * Cancel an earlier processed subscription (recurring payment) inside the Paid Levels 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 BxAclModule::serviceCancelSubscriptionItem
+     */
+    /** 
+     * @ref bx_acl-cancel_subscription_item "cancel_subscription_item"
+     */
+    public function serviceCancelSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder)
+    {
+    	//TODO: Do something if it's necessary.
+    	return true;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-other Other
+     * @subsubsection bx_acl-get_prices get_prices
+     * 
+     * @code bx_srv('bx_acl', 'get_prices', [...]); @endcode
+     * 
+     * Get array of available price options for membership levels
+     *
+     * @param $iLevelId membership level id
+     * @param $bFreeUnlimitedOnly get unlimited free pricing options only
+     * @return array of levels, or empty array of there are no any pricing options avaiulable
+     * 
+     * @see BxAclModule::serviceGetPrices
+     */
+    /** 
+     * @ref bx_acl-get_prices "get_prices"
+     */
+	public function serviceGetPrices($iLevelId = 0, $bFreeUnlimitedOnly = false)
+    {
+        $aParams = array(
+            'type' => $iLevelId ? 'by_level_id' : 'all_full',
+            'value' => $iLevelId,
+        );
+        $aPrices = $this->_oDb->getPrices($aParams, false);        
+
+        return array_filter($aPrices, function ($r) use ($bFreeUnlimitedOnly) {
+            return $bFreeUnlimitedOnly ? !$r['price'] && !$r['period'] : true;
+        });
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_acl Paid Levels
+     * @subsection bx_acl-other Other
+     * @subsubsection bx_acl-get_products_names get_products_names
+     * 
+     * @code bx_srv('bx_acl', 'get_products_names', [...]); @endcode
+     * 
+     * Get an array of products names.
+     * 
+     * @param $iVendorId return products of 1 vendor only
+     * @param $iLimit limit the result artay
+     * @return an array of products names
+     * 
+     * @see BxAclModule::serviceGetProductsNames
+     */
+    /** 
+     * @ref bx_acl-get_products_names "get_products_names"
+     */
+	public function serviceGetProductsNames($iVendorId = 0, $iLimit = 1000)
+    {
+    	return $this->_oDb->getProductsNames($iVendorId, $iLimit);
+    }
+
+    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 [];
+
+        $oAcl = BxDolAcl::getInstance();
+
+        $aItemInfo = $this->_oDb->getPrices(['type' => 'by_id', 'value' => $iItemId]);
+        $aMembershipInfo = $oAcl->getMemberMembershipInfo($iClientId);
+
+        $aPeriod = ['period' => (int)$aItemInfo['period'], 'period_unit' => $aItemInfo['period_unit']];
+        if($sType == BX_ACL_LICENSE_TYPE_RECURRING && (int)$aItemInfo['trial'] > 0 && (int)$aItemInfo['level_id'] != (int)$aMembershipInfo['id'])
+            $aPeriod = ['period' => (int)$aItemInfo['trial'], 'period_unit' => 'day', 'period_trial' => true];
+
+        $iReserve = (int)getParam($CNF['PARAM_RECURRING_RESERVE']);
+        if(!empty($iReserve))
+            $aPeriod['period_reserve'] = $iReserve;
+
+        $bImmediate = (int)$aItemInfo['immediate'] != 0;
+        if(!$oAcl->setMembership($iClientId, $aItemInfo['level_id'], $aPeriod, $bImmediate, $sLicense))
+            return [];
+
+        $this->_oDb->insertLicense([
+            'profile_id' => $iClientId,
+            'price_id' => $iItemId,
+            'type' => $sType,
+            'order' => $sOrder,
+            'license' => $sLicense,
+            'added' => time()
+        ]);
+
+        if($bImmediate && !empty($aMembershipInfo['transaction_id'])) {
+            $oPayments = BxDolPayments::getInstance();
+
+            $sLicenseOld = $aMembershipInfo['transaction_id'];
+            $aLicenseOld = $this->_oDb->getLicenses(['type' => 'by_license', 'license' => $sLicenseOld]);
+
+            $sPpOrder = '';
+            if(empty($aLicenseOld) || !is_array($aLicenseOld)) {
+                $aOrders = $oPayments->getOrdersInfo(['license' => $sLicenseOld]);
+                if(!empty($aOrders) && is_array($aOrders)) {
+                    $aOrder = reset($aOrders);
+                    $aPendings = $oPayments->getPendingOrdersInfo(['id' => $aOrder['pending_id']]);
+                    if(!empty($aPendings) && is_array($aPendings)) {
+                        $aPpPending = reset($aPendings);
+                        if($aPpPending['type'] == BX_ACL_LICENSE_TYPE_RECURRING)
+                            $sPpOrder = $aPpPending['order'];
+                    }
+                }    
+            }
+            else if($aLicenseOld['type'] == BX_ACL_LICENSE_TYPE_RECURRING)
+                $sPpOrder = $aLicenseOld['order'];
+
+            if(!empty($sPpOrder) && (($aResult = $oPayments->cancelSubscription($sPpOrder)) === false || (int)$aResult['code'] != 0)) {
+                sendMailTemplate($CNF['ETEMPLATE_SBS_CANCEL_REQUIRED'], 0, $iClientId, [
+                    'level' => _t($aMembershipInfo['name']),
+                    'order' => $sPpOrder,
+                    'date_starts' => $this->_oConfig->formatDate($aMembershipInfo['date_starts']),
+                    'date_expires' => $this->_oConfig->formatDate($aMembershipInfo['date_expires']),
+                ], BX_EMAIL_NOTIFY, true);
+            }
+        }
+
+        return $aItem;
+    }
+
+    protected function _serviceReregisterItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder, $sType)
+    {
+        $aItemNew = $this->serviceGetCartItem($iItemIdNew);
+        if(empty($aItemNew) || !is_array($aItemNew))
+			return array();
+
+        /*
+         * Note. Membership level cannot be reregistered immediately.
+         * it will be automatically changed in the end of current period.
+         */
+    	return $aItemNew;
+    }
+
+    protected function _serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense, $sType)
+    {
+    	$aItemInfo = $this->_oDb->getPrices(array('type' => 'by_id', 'value' => $iItemId));
+    	if(empty($aItemInfo) || !is_array($aItemInfo))
+			return false;
+
+    	return BxDolAcl::getInstance()->unsetMembership($iClientId, $aItemInfo['level_id'], $sLicense);
+    }
+
+    /**
+     * COMMON METHODS
+     */
+	public function getUserId()
+    {
+        return isLogged() ? bx_get_logged_profile_id() : 0;
+    }
+
+    public function getUserInfo($iUserId = 0)
+    {
+        $oProfile = BxDolProfile::getInstance($iUserId);
+        if (!$oProfile)
+            $oProfile = BxDolProfileUndefined::getInstance();
+
+        return array(
+            $oProfile->getDisplayName(),
+            $oProfile->getUrl(),
+            $oProfile->getThumb(),
+            $oProfile->getUnit()
+        );
+    }
+}
+
+/** @} */

+ 70 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/source/install/config.php

@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    PaidLevels Paid Levels
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_acl',
+    'title' => 'Paid Levels',
+    'note' => 'Paid Levels module.',
+    'version' => '13.0.2',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.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/acl/',
+    'home_uri' => 'acl',
+
+    'db_prefix' => 'bx_acl_',
+    'class_prefix' => 'BxAcl',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Paid Levels',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 114 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/source/install/langs/en.xml

@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string name="_bx_acl"><![CDATA[Paid Levels]]></string>
+
+
+    <!-- Option -->
+    <string name="_bx_acl_option_recurring_reserve"><![CDATA[Reserve (in days) to accept and process recurring payment notification]]></string>
+    <string name="_bx_acl_option_recurring_prioritize"><![CDATA[Prioritize recurring payments]]></string>
+
+
+    <!-- Pages -->
+    <string name="_bx_acl_page_title_sys_view"><![CDATA[Membership]]></string>
+    <string name="_bx_acl_page_title_view"><![CDATA[Membership]]></string>
+    <string name="_bx_acl_page_block_title_system_view"><![CDATA[Membership]]></string>
+    <string name="_bx_acl_page_block_title_view"><![CDATA[Membership]]></string>
+
+
+    <!-- Menus -->
+    <string name="_bx_acl_lmi_cpt_manage"><![CDATA[Manage]]></string>
+
+
+    <!-- Forms -->
+    <string name="_bx_acl_form_price"><![CDATA[Price]]></string>
+    <string name="_bx_acl_form_price_display_add"><![CDATA[Add]]></string>
+    <string name="_bx_acl_form_price_display_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_acl_form_price_input_sys_id"><![CDATA[ID]]></string>
+    <string name="_bx_acl_form_price_input_sys_level_id"><![CDATA[Level ID]]></string>
+    <string name="_bx_acl_form_price_input_sys_name"><![CDATA[Name]]></string>
+    <string name="_bx_acl_form_price_input_name"><![CDATA[Name]]></string>
+    <string name="_bx_acl_form_price_input_inf_name"><![CDATA[Unique value which will be used in back end and API calls]]></string>
+    <string name="_bx_acl_form_price_input_err_name"><![CDATA[You need to enter a unique value here]]></string>
+    <string name="_bx_acl_form_price_input_sys_period"><![CDATA[Period]]></string>
+    <string name="_bx_acl_form_price_input_period"><![CDATA[Period]]></string>
+    <string name="_bx_acl_form_price_input_inf_period"><![CDATA[Use 0 for lifetime]]></string>
+    <string name="_bx_acl_form_price_input_sys_period_unit"><![CDATA[Period unit]]></string>
+    <string name="_bx_acl_form_price_input_period_unit"><![CDATA[Period unit]]></string>
+    <string name="_bx_acl_form_price_input_inf_period_unit"><![CDATA[Leave empty for lifetime level.]]></string>
+    <string name="_bx_acl_form_price_input_err_period_unit"><![CDATA[You need to select a period unit here.]]></string>
+    <string name="_bx_acl_form_price_input_sys_price"><![CDATA[Price]]></string>
+    <string name="_bx_acl_form_price_input_price"><![CDATA[Price]]></string>
+    <string name="_bx_acl_form_price_input_inf_price"><![CDATA[Use 0 or leave empty to create free level.]]></string>
+    <string name="_bx_acl_form_price_input_sys_trial"><![CDATA[Trial]]></string>
+    <string name="_bx_acl_form_price_input_trial"><![CDATA[Trial]]></string>
+    <string name="_bx_acl_form_price_input_inf_trial"><![CDATA[The number of days new customers should receive a free trial. Leave empty to disable trial period.]]></string>
+    <string name="_bx_acl_form_price_input_sys_immediate"><![CDATA[Activate immediately]]></string>
+    <string name="_bx_acl_form_price_input_immediate"><![CDATA[Activate immediately after purchase]]></string>
+    <string name="_bx_acl_form_price_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_acl_form_price_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_acl_form_price_input_sys_do_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_acl_form_price_input_do_cancel"><![CDATA[Cancel]]></string>
+
+
+    <!-- Pre Lists -->
+    <string name="_bx_acl_pre_lists_period_units"><![CDATA[Billing Interval]]></string>
+    <string name="_bx_acl_pre_values_day"><![CDATA[day]]></string>
+    <string name="_bx_acl_pre_values_week"><![CDATA[week]]></string>
+    <string name="_bx_acl_pre_values_month"><![CDATA[month]]></string>
+    <string name="_bx_acl_pre_values_year"><![CDATA[year]]></string>
+
+
+    <!-- Grids -->
+    <string name="_bx_acl_grid_column_level_icon"><![CDATA[]]></string>
+    <string name="_bx_acl_grid_column_level_name"><![CDATA[Level]]></string>
+    <string name="_bx_acl_grid_column_name"><![CDATA[Name]]></string>
+    <string name="_bx_acl_grid_column_period"><![CDATA[Period]]></string>
+    <string name="_bx_acl_grid_column_price"><![CDATA[Price]]></string>
+    <string name="_bx_acl_grid_column_trial"><![CDATA[Trial]]></string>
+
+    <string name="_bx_acl_grid_action_add"><![CDATA[Add]]></string>
+    <string name="_bx_acl_grid_action_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_acl_grid_action_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_acl_grid_action_buy"><![CDATA[Buy]]></string>
+    <string name="_bx_acl_grid_action_buy_title"><![CDATA[One-time payment]]></string>
+    <string name="_bx_acl_grid_action_subscribe"><![CDATA[Subscribe]]></string>
+    <string name="_bx_acl_grid_action_subscribe_title"><![CDATA[Create a subscription with recurring billing]]></string>
+    <string name="_bx_acl_grid_action_choose"><![CDATA[Choose]]></string>
+    <string name="_bx_acl_grid_action_choose_title"><![CDATA[Switch to the level for free]]></string>
+
+    <string name="_bx_acl_popup_title_price_add"><![CDATA[Add Pricing Plan]]></string>
+    <string name="_bx_acl_popup_title_price_edit"><![CDATA[Edit Pricing Plan]]></string>
+
+
+    <!-- Menus -->
+    <string name="_bx_acl_menu_item_title_system_acl_view"><![CDATA[Membership]]></string>
+    <string name="_bx_acl_menu_item_title_acl_view"><![CDATA[Membership]]></string>
+
+
+    <!-- Email Templates -->
+    <string name="_bx_acl_et_txt_name_subscription_cancel_required"><![CDATA[Subscription cancel required.]]></string>
+    <string name="_bx_acl_et_txt_subject_subscription_cancel_required"><![CDATA[Subscription cancel required.]]></string>
+    <string name="_bx_acl_et_txt_body_subscription_cancel_required"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>You've paid for a new membership level but your old level's subscription is still active. You need to cancel it manually.</p>
+<p>Old subscription info:<br />Membership level: {level}<br />Order: {order}<br />Date Starts: {date_starts}<br />Date Expires: {date_expires}</p>
+{email_footer}]]></string>
+
+
+    <!-- Common Texts -->
+    <string name="_bx_acl_msg_empty_owner"><![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_acl_msg_performed"><![CDATA[The action was successfully performed.]]></string>
+    <string name="_bx_acl_err_price_duplicate"><![CDATA[Similar pricing plan is already exists.]]></string>
+    <string name="_bx_acl_err_cannot_perform"><![CDATA[An error appeared. Please report.]]></string>
+
+    <string name="_bx_acl_txt_select_level"><![CDATA[Select level...]]></string>
+    <string name="_bx_acl_txt_cart_item_title"><![CDATA[{0} ({1} {2})]]></string>
+    <string name="_bx_acl_txt_cart_item_title_lifetime"><![CDATA[{0} (lifetime)]]></string>
+    <string name="_bx_acl_txt_cart_item_description"><![CDATA[Membership level on {0} site.]]></string>
+    <string name="_bx_acl_txt_upgrade"><![CDATA[Upgrade]]></string>
+    <string name="_bx_acl_txt_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_acl_txt_n_unit"><![CDATA[{0} ({1})]]></string>
+    <string name="_bx_acl_txt_none"><![CDATA[none]]></string>
+    <string name="_bx_acl_txt_free"><![CDATA[free]]></string>
+    <string name="_bx_acl_txt_lifetime"><![CDATA[lifetime]]></string>
+</resources>

+ 30 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/source/install/sql/disable.sql

@@ -0,0 +1,30 @@
+SET @sName = 'bx_acl';
+
+
+-- SETTINGS
+SET @iTypeId = (SELECT `ID` FROM `sys_options_types` WHERE `name` = @sName 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` = @sName;
+DELETE FROM `sys_pages_blocks` WHERE `module` = @sName;
+
+
+-- MENU
+DELETE FROM `sys_objects_menu` WHERE `module` = @sName;
+DELETE FROM `sys_menu_sets` WHERE `module` = @sName;
+DELETE FROM `sys_menu_items` WHERE `module` = @sName;
+
+
+-- EMAIL TEMPLATES
+DELETE FROM `sys_email_templates` WHERE `Module` = @sName;
+
+
+-- ALERTS
+SET @iHandlerId = (SELECT `id` FROM `sys_alerts_handlers` WHERE `name` = @sName LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `handler_id` = @iHandlerId;
+DELETE FROM `sys_alerts_handlers` WHERE `id` = @iHandlerId LIMIT 1;

+ 45 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/source/install/sql/enable.sql

@@ -0,0 +1,45 @@
+SET @sName = 'bx_acl';
+
+
+-- 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_acl', 'bx_acl@modules/boonex/acl/|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_acl', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_acl_recurring_reserve', '2', @iCategId, '_bx_acl_option_recurring_reserve', 'digit', '', '', '', 1),
+('bx_acl_recurring_prioritize', 'on', @iCategId, '_bx_acl_option_recurring_prioritize', 'checkbox', '', '', '', 2);
+
+
+-- PAGE: view levels
+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_acl_view', '_bx_acl_page_title_sys_view', '_bx_acl_page_title_view', @sName, 5, 2147483647, 1, 'acl-view', 'page.php?i=acl-view', '', '', '', 0, 1, 0, 'BxAclPageView', 'modules/boonex/acl/classes/BxAclPageView.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_acl_view', 1, @sName, '_bx_acl_page_block_title_system_view', '_bx_acl_page_block_title_view', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:6:\"bx_acl\";s:6:\"method\";s:14:\"get_block_view\";}', 0, 1, 0);
+
+
+-- MENU: account settings menu
+SET @iMoAccountSettings = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_settings' AND `order` < 9999 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_settings', 'bx_acl', 'acl-view', '_bx_acl_menu_item_title_system_acl_view', '_bx_acl_menu_item_title_acl_view', 'page.php?i=acl-view', '', '', 'shield-alt col-red2', '', '', 2147483646, 1, 0, 1, @iMoAccountSettings + 1);
+
+
+-- EMAIL TEMPLATES
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES 
+(@sName, '_bx_acl_et_txt_name_subscription_cancel_required', 'bx_acl_subscription_cancel_required', '_bx_acl_et_txt_subject_subscription_cancel_required', '_bx_acl_et_txt_body_subscription_cancel_required');
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers`(`name`, `class`, `file`, `service_call`) VALUES 
+(@sName, 'BxAclResponse', 'modules/boonex/acl/classes/BxAclResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'page_output_block_acl_level', @iHandler),
+('acl', 'deleted', @iHandler);

+ 136 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/source/install/sql/install.sql

@@ -0,0 +1,136 @@
+SET @sName = 'bx_acl';
+
+
+-- TABLES
+CREATE TABLE `bx_acl_level_prices` (
+  `id` int(11) NOT NULL auto_increment,
+  `level_id` int(11) unsigned NOT NULL default '0',
+  `name` varchar(128) NOT NULL default '',
+  `period` int(11) unsigned NOT NULL default '1',
+  `period_unit` varchar(32) NOT NULL default '',
+  `trial` int(11) unsigned NOT NULL default '0',
+  `price` float unsigned NOT NULL default '1',
+  `immediate` tinyint(4) NOT NULL default '1',
+  `order` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `name` (`name`),
+  UNIQUE KEY `type` (`level_id`,`period`, `period_unit`)
+);
+
+-- TABLE: licenses
+CREATE TABLE IF NOT EXISTS `bx_acl_licenses` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `profile_id` int(11) unsigned NOT NULL default '0',
+  `price_id` int(11) unsigned NOT NULL default '0',
+  `type` varchar(16) NOT NULL default 'single',
+  `order` varchar(32) NOT NULL default '',
+  `license` varchar(32) NOT NULL default '',
+  `added` int(11) unsigned NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `price_id` (`price_id`, `profile_id`),
+  KEY `license` (`license`)
+);
+
+
+-- 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_acl_price', @sName, '_bx_acl_form_price', '', '', 'do_submit', 'bx_acl_level_prices', 'id', '', '', '', 0, 1, 'BxAclFormPrice', 'modules/boonex/acl/classes/BxAclFormPrice.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_acl_price_add', @sName, 'bx_acl_price', '_bx_acl_form_price_display_add', 0),
+('bx_acl_price_edit', @sName, 'bx_acl_price', '_bx_acl_form_price_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_acl_price', @sName, 'id', '', '', 0, 'hidden', '_bx_acl_form_price_input_sys_id', '', '', 1, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_acl_price', @sName, 'level_id', '', '', 0, 'hidden', '_bx_acl_form_price_input_sys_level_id', '', '', 1, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_acl_price', @sName, 'name', '', '', 0, 'text', '_bx_acl_form_price_input_sys_name', '_bx_acl_form_price_input_name', '_bx_acl_form_price_input_inf_name', 1, 0, 0, '', '', '', 'Avail', '', '_bx_acl_form_price_input_err_name', 'Xss', '', 1, 0),
+('bx_acl_price', @sName, 'period', '', '', 0, 'text', '_bx_acl_form_price_input_sys_period', '_bx_acl_form_price_input_period', '_bx_acl_form_price_input_inf_period', 1, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_acl_price', @sName, 'period_unit', '', '#!bx_acl_period_units', 0, 'select', '_bx_acl_form_price_input_sys_period_unit', '_bx_acl_form_price_input_period_unit', '_bx_acl_form_price_input_inf_period_unit', 1, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_acl_price', @sName, 'trial', '', '', 0, 'text', '_bx_acl_form_price_input_sys_trial', '_bx_acl_form_price_input_trial', '_bx_acl_form_price_input_inf_trial', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_acl_price', @sName, 'price', '', '', 0, 'price', '_bx_acl_form_price_input_sys_price', '_bx_acl_form_price_input_price', '_bx_acl_form_price_input_inf_price', 1, 0, 0, '', '', '', '', '', '', 'Float', '', 1, 0),
+('bx_acl_price', @sName, 'immediate', 1, '', 1, 'switcher', '_bx_acl_form_price_input_sys_immediate', '_bx_acl_form_price_input_immediate', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_acl_price', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_acl_price', @sName, 'do_submit', '_bx_acl_form_price_input_do_submit', '', 0, 'submit', '_bx_acl_form_price_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_acl_price', @sName, 'do_cancel', '_bx_acl_form_price_input_do_cancel', '', 0, 'button', '_bx_acl_form_price_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_acl_price_add', 'id', 2147483647, 0, 1),
+('bx_acl_price_add', 'level_id', 2147483647, 1, 2),
+('bx_acl_price_add', 'name', 2147483647, 1, 3),
+('bx_acl_price_add', 'price', 2147483647, 1, 4),
+('bx_acl_price_add', 'period', 2147483647, 1, 5),
+('bx_acl_price_add', 'period_unit', 2147483647, 1, 6),
+('bx_acl_price_add', 'trial', 2147483647, 1, 7),
+('bx_acl_price_add', 'immediate', 2147483647, 1, 8),
+('bx_acl_price_add', 'controls', 2147483647, 1, 9),
+('bx_acl_price_add', 'do_submit', 2147483647, 1, 10),
+('bx_acl_price_add', 'do_cancel', 2147483647, 1, 11),
+
+('bx_acl_price_edit', 'id', 2147483647, 1, 1),
+('bx_acl_price_edit', 'level_id', 2147483647, 1, 2),
+('bx_acl_price_edit', 'name', 2147483647, 1, 3),
+('bx_acl_price_edit', 'price', 2147483647, 1, 4),
+('bx_acl_price_edit', 'period', 2147483647, 1, 5),
+('bx_acl_price_edit', 'period_unit', 2147483647, 1, 6),
+('bx_acl_price_edit', 'trial', 2147483647, 1, 7),
+('bx_acl_price_edit', 'immediate', 2147483647, 1, 8),
+('bx_acl_price_edit', 'controls', 2147483647, 1, 9),
+('bx_acl_price_edit', 'do_submit', 2147483647, 1, 10),
+('bx_acl_price_edit', 'do_cancel', 2147483647, 1, 11);
+
+
+-- PRE-VALUES
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`) VALUES
+('bx_acl_period_units', '_bx_acl_pre_lists_period_units', 'bx_acl', '0');
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_acl_period_units', '', 0, '_sys_please_select', ''),
+('bx_acl_period_units', 'day', 1, '_bx_acl_pre_values_day', ''),
+('bx_acl_period_units', 'week', 2, '_bx_acl_pre_values_week', ''),
+('bx_acl_period_units', 'month', 3, '_bx_acl_pre_values_month', ''),
+('bx_acl_period_units', 'year', 4, '_bx_acl_pre_values_year', '');
+
+
+-- GRIDS
+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_acl_administration', 'Sql', 'SELECT * FROM `bx_acl_level_prices` WHERE 1 ', 'bx_acl_level_prices', 'id', 'order', '', '', 100, NULL, 'start', '', 'period,period_unit,price', '', 'like', '', '', 192, 'BxAclGridAdministration', 'modules/boonex/acl/classes/BxAclGridAdministration.php'),
+('bx_acl_view', 'Sql', 'SELECT `tlp`.*, `tl`.`Name` AS `level_name`, `tl`.`Icon` AS `level_icon` FROM `bx_acl_level_prices` AS `tlp` LEFT JOIN `sys_acl_levels` AS `tl` ON `tlp`.`level_id`=`tl`.`ID` WHERE `tl`.`Active`=''yes'' AND `tl`.`Purchasable`=''yes'' ', 'bx_acl_level_prices', 'id', 'order', '', '', 100, NULL, 'start', '', 'period,period_unit,price', 'tl`.`Name', 'like', '', '', 2147483647, 'BxAclGridView', 'modules/boonex/acl/classes/BxAclGridView.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_acl_administration', 'checkbox', '_sys_select', '1%', 0, '', '', 1),
+('bx_acl_administration', 'order', '', '1%', 0, '', '', 2),
+('bx_acl_administration', 'name', '_bx_acl_grid_column_name', '33%', 0, 32, '', 3),
+('bx_acl_administration', 'price', '_bx_acl_grid_column_price', '15%', 0, 16, '', 4),
+('bx_acl_administration', 'period', '_bx_acl_grid_column_period', '15%', 0, 16, '', 5),
+('bx_acl_administration', 'trial', '_bx_acl_grid_column_trial', '15%', 0, 16, '', 6),
+('bx_acl_administration', 'actions', '', '20%', 0, '', '', 7),
+
+('bx_acl_view', 'level_icon', '_bx_acl_grid_column_level_icon', '5%', 0, 0, '', 1),
+('bx_acl_view', 'level_name', '_bx_acl_grid_column_level_name', '25%', 1, 32, '', 2),
+('bx_acl_view', 'price', '_bx_acl_grid_column_price', '10%', 0, 16, '', 3),
+('bx_acl_view', 'period', '_bx_acl_grid_column_period', '15%', 0, 16, '', 4),
+('bx_acl_view', 'trial', '_bx_acl_grid_column_trial', '15%', 0, 16, '', 5),
+('bx_acl_view', 'actions', '', '30%', 0, '', '', 6);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_acl_administration', 'independent', 'add', '_bx_acl_grid_action_add', '', 0, 0, 1),
+('bx_acl_administration', 'single', 'edit', '_bx_acl_grid_action_edit', 'pencil-alt', 1, 0, 1),
+('bx_acl_administration', 'single', 'delete', '_bx_acl_grid_action_delete', 'remove', 1, 1, 2),
+('bx_acl_administration', 'bulk', 'delete', '_bx_acl_grid_action_delete', '', 0, 1, 1),
+
+('bx_acl_view', 'single', 'buy', '_bx_acl_grid_action_buy', 'cart-plus', 0, 0, 1),
+('bx_acl_view', 'single', 'subscribe', '_bx_acl_grid_action_subscribe', 'credit-card', 0, 0, 2),
+('bx_acl_view', 'single', 'choose', '_bx_acl_grid_action_choose', 'far check-square', 0, 0, 3);
+
+
+-- STUDIO PAGE & WIDGET
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, @sName, '_bx_acl', '_bx_acl', 'bx_acl@modules/boonex/acl/|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, 'users', '{url_studio}module.php?name=bx_acl', '', 'bx_acl@modules/boonex/acl/|std-icon.svg', '_bx_acl', '', '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));

+ 29 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/source/install/sql/uninstall.sql

@@ -0,0 +1,29 @@
+SET @sName = 'bx_acl';
+
+
+-- TABLES
+DROP TABLE IF EXISTS `bx_acl_level_prices`, `bx_acl_licenses`;
+
+
+-- FORMS
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN  (SELECT `display_name` FROM `sys_form_displays` WHERE `module` = @sName);
+DELETE FROM `sys_form_inputs` WHERE `module` = @sName;
+DELETE FROM `sys_form_displays` WHERE `module` = @sName;
+DELETE FROM `sys_objects_form` WHERE `module` = @sName;
+
+
+-- PRE-VALUES
+DELETE FROM `sys_form_pre_lists` WHERE `module` = @sName;
+DELETE FROM `sys_form_pre_values` WHERE `Key` IN('bx_acl_period_units');
+
+
+-- GRIDS
+DELETE FROM `sys_objects_grid` WHERE `object` IN ('bx_acl_administration', 'bx_acl_view');
+DELETE FROM `sys_grid_fields` WHERE `object` IN ('bx_acl_administration', 'bx_acl_view');
+DELETE FROM `sys_grid_actions` WHERE `object` IN ('bx_acl_administration', 'bx_acl_view');
+
+
+-- 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` = @sName;

+ 35 - 0
modules/boonex/acl/updates/13.0.1_13.0.2/source/template/images/icons/std-icon.svg

@@ -0,0 +1,35 @@
+<svg width="320" height="320" viewBox="0 0 320 320" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_1014_7568)">
+<path d="M160 0C281.326 0 320 38.6737 320 160C320 281.326 281.326 320 160 320C38.6736 320 0 281.326 0 160C0 38.6737 38.6736 0 160 0Z" fill="url(#paint0_linear_1014_7568)"/>
+<path d="M160 2C220.573 2 259.85 11.6833 284.083 35.9168C308.317 60.1504 318 99.4272 318 160C318 220.573 308.317 259.85 284.083 284.083C259.85 308.317 220.573 318 160 318C99.4272 318 60.1504 308.317 35.9168 284.083C11.6833 259.85 2 220.573 2 160C2 99.4272 11.6833 60.1504 35.9168 35.9168C60.1504 11.6833 99.4272 2 160 2Z" stroke="#F8FAFC" stroke-opacity="0.2" stroke-width="4"/>
+<g clip-path="url(#clip1_1014_7568)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M178.887 222.293C178.055 219.45 174.68 218.562 172.071 219.966C160.36 226.266 145.791 230 130 230C107.453 230 87.3963 222.386 74.5937 210.562C72.5295 208.655 69.2781 208.481 67.4819 210.642C62.7144 216.378 60 222.978 60 230C60 252.092 86.8629 270 120 270C153.137 270 180 252.092 180 230C180 227.364 179.617 224.787 178.887 222.293Z" fill="url(#paint1_linear_1014_7568)"/>
+<ellipse cx="130" cy="180" rx="60" ry="40" fill="url(#paint2_linear_1014_7568)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M194.047 200.209C192.97 201.947 192.809 204.216 194.222 205.694C197.038 208.642 200.613 209.904 205.087 209.904C220.253 209.904 225.087 195.402 225.087 149.904C225.087 138.284 224.772 128.685 224.05 120.834C223.787 117.975 227.371 116.115 229.545 117.99C246.878 132.939 256.314 134.577 264.945 125.945C275.669 115.221 270.542 103.257 243.732 76.4475C225.316 58.0314 213.905 49.8463 205.089 50.0022C196.273 49.8474 184.862 58.0326 166.448 76.4475C139.638 103.257 134.51 115.221 145.234 125.945C153.865 134.576 163.299 132.939 180.63 117.995C182.804 116.12 186.388 117.979 186.125 120.838C185.465 128.009 185.145 136.637 185.095 146.932C185.088 148.342 185.692 149.68 186.697 150.669C195.065 158.908 200 169.042 200 180C200 187.192 197.874 194.029 194.047 200.209Z" fill="url(#paint3_linear_1014_7568)"/>
+</g>
+</g>
+<defs>
+<linearGradient id="paint0_linear_1014_7568" x1="160" y1="0" x2="160" y2="320" gradientUnits="userSpaceOnUse">
+<stop stop-color="#475569"/>
+<stop offset="1" stop-color="#1E293B"/>
+</linearGradient>
+<linearGradient id="paint1_linear_1014_7568" x1="120" y1="209.076" x2="120" y2="270" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FB923C"/>
+<stop offset="1" stop-color="#EA580C"/>
+</linearGradient>
+<linearGradient id="paint2_linear_1014_7568" x1="130" y1="140" x2="130" y2="220" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FACC15"/>
+<stop offset="1" stop-color="#CA8A04"/>
+</linearGradient>
+<linearGradient id="paint3_linear_1014_7568" x1="205.09" y1="50" x2="205.09" y2="209.904" gradientUnits="userSpaceOnUse">
+<stop stop-color="#60A5FA"/>
+<stop offset="1" stop-color="#2563EB"/>
+</linearGradient>
+<clipPath id="clip0_1014_7568">
+<rect width="320" height="320" fill="white"/>
+</clipPath>
+<clipPath id="clip1_1014_7568">
+<rect width="240" height="240" fill="white" transform="translate(40 40)"/>
+</clipPath>
+</defs>
+</svg>

+ 79 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/install/config.php

@@ -0,0 +1,79 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Ads',
+    'version_from' => '13.0.5',
+    'version_to' => '13.0.6',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.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/ads/updates/update_13.0.5_13.0.6/',
+    'home_uri' => 'ads_update_1305_1306',
+
+    'module_dir' => 'boonex/ads/',
+    'module_uri' => 'ads',
+
+    'db_prefix' => 'bx_ads_',
+    'class_prefix' => 'BxAds',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Ads',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(
+        'classes/BxAdsUploaderSimple.php',
+        'classes/BxAdsUploaderSimpleAttach.php',
+        'template/css/manage_tools.css',
+        'template/attachments.html',
+        'template/author.html',
+        'template/author_link.html',
+        'template/breadcrumb.html',
+        'template/context.html',
+        'template/entry-all-actions.html',
+        'template/entry-location.html',
+        'template/entry-share.html',
+        'template/entry-text.html',
+        'template/form_ghost_template.html',
+        'template/link.html',
+        'template/poll_answer_ve_block.html',
+        'template/poll_form.html',
+        'template/poll_form_answers.html',
+        'template/poll_form_field.html',
+        'template/poll_item.html',
+        'template/poll_item_answers.html',
+        'template/poll_item_results.html',
+        'template/poll_items.html',
+        'template/poll_items_showcase.html',
+        'template/title_link.html',
+        'template/uploader_button_html5_attach.html',
+        'template/uploader_button_record_video_attach.html',
+        'template/uploader_button_simple_attach.html',
+    ),
+);

+ 23 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/install/installer.php

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

+ 10 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/install/langs/en.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_ads_option_per_page_for_favorites_lists"><![CDATA[Number of favorite lists per page]]></string_add>
+	<string_add name="_bx_ads_form_entry_input_category_select_err"><![CDATA[Category field is essential. Please, fill it in.]]></string_add>
+	<string_add name="_bx_ads_form_entry_input_allow_view_favorite_list"><![CDATA[Visibility]]></string_add>
+	<string_add name="_bx_ads_page_title_sys_entries_favorites"><![CDATA[Favorives Reviews]]></string_add>
+    <string_add name="_bx_ads_page_title_entries_favorites"><![CDATA[Favorives Reviews]]></string_add>
+	<string_add name="_bx_ads_page_block_title_favorites_entries"><![CDATA["{title}" List]]></string_add>
+    <string_add name="_bx_ads_page_block_title_favorites_entries_info"><![CDATA[Info]]></string_add>
+</resources>

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

@@ -0,0 +1,34 @@
+-- SETTINGS
+SET @iCategId = (SELECT `id` FROM `sys_options_categories` WHERE `name`='bx_ads' LIMIT 1);
+
+DELETE FROM `sys_options` WHERE `name`='bx_ads_per_page_for_favorites_lists';
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_ads_per_page_for_favorites_lists', '5', @iCategId, '_bx_ads_option_per_page_for_favorites_lists', 'digit', '', '', '', 26);
+
+
+-- PAGES
+UPDATE `sys_pages_blocks` SET `content`='a:3:{s:6:"module";s:6:"bx_ads";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;}}}' WHERE `object`='bx_ads_author' AND `title`='_bx_ads_page_block_title_favorites_of_author';
+
+DELETE FROM `sys_objects_page` WHERE `object`='bx_ads_favorites';
+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_ads_favorites', '_bx_ads_page_title_sys_entries_favorites', '_bx_ads_page_title_entries_favorites', 'bx_ads', 12, 2147483647, 1, 'ads-favorites', 'page.php?i=ads-favorites', '', '', '', 0, 1, 0, 'BxAdsPageListEntry', 'modules/boonex/ads/classes/BxAdsPageListEntry.php');
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_ads_favorites';
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_ads_favorites', 2, 'bx_ads', '_bx_ads_page_block_title_favorites_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";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_ads_favorites', 3, 'bx_ads', '_bx_ads_page_block_title_favorites_entries_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:19:"favorites_list_info";}', 0, 0, 0),
+('bx_ads_favorites', 3, 'bx_ads', '_bx_ads_page_block_title_favorites_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:22:"favorites_list_actions";}', 0, 0, 1);
+
+
+-- PRIVACY 
+DELETE FROM `sys_objects_privacy` WHERE `object`='bx_ads_allow_view_favorite_list';
+INSERT INTO `sys_objects_privacy` (`object`, `module`, `action`, `title`, `default_group`, `table`, `table_field_id`, `table_field_author`, `override_class_name`, `override_class_file`) VALUES
+('bx_ads_allow_view_favorite_list', 'bx_ads', 'view_favorite_list', '_bx_ads_form_entry_input_allow_view_favorite_list', '3', 'bx_ads_favorites_lists', 'id', 'author_id', '', '');
+
+
+-- GRIDS
+UPDATE `sys_objects_grid` SET `source`='SELECT `tl`.`id` AS `id`, `tl`.`profile_id` AS `profile_id`, `tl`.`entry_id` AS `entry_id`, `te`.`title` AS `entry`, `tl`.`count` AS `count`, `tl`.`order` AS `transaction`, `tl`.`license` AS `license`, `tl`.`added` AS `added` FROM `bx_ads_licenses` AS `tl` LEFT JOIN `bx_ads_entries` AS `te` ON `tl`.`entry_id`=`te`.`id` LEFT JOIN `sys_profiles` AS `tup` ON `tl`.`profile_id`=`tup`.`id` LEFT JOIN `sys_accounts` AS `tua` ON `tup`.`account_id`=`tua`.`id` WHERE 1 ', `filter_fields`='te`.`title,tl`.`order,tl`.`license,tua`.`name,tua`.`email' WHERE `object`='bx_ads_licenses_administration';
+
+
+-- UPLOADERS
+DELETE FROM `sys_objects_uploader` WHERE `object` IN ('bx_ads_simple', 'bx_ads_photos_simple', 'bx_ads_videos_simple', 'bx_ads_files_simple');

+ 25 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/install/sql/install.sql

@@ -0,0 +1,25 @@
+-- TABLES
+CREATE TABLE IF NOT EXISTS `bx_ads_favorites_lists` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `title` varchar(255) NOT NULL,
+  `author_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  `allow_view_favorite_list_to` varchar(16) NOT NULL DEFAULT '3',
+   PRIMARY KEY (`id`)
+);
+
+
+-- FORMS
+UPDATE `sys_form_inputs` SET `values`='a:1:{s:12:"bx_ads_html5";s:25:"_sys_uploader_html5_title";}' WHERE `object`='bx_ads' AND `name`='covers';
+UPDATE `sys_form_inputs` SET `values`='a:1:{s:19:"bx_ads_photos_html5";s:25:"_sys_uploader_html5_title";}' WHERE `object`='bx_ads' AND `name`='pictures';
+UPDATE `sys_form_inputs` SET `values`='a:2:{s:19:"bx_ads_videos_html5";s:25:"_sys_uploader_html5_title";s:26:"bx_ads_videos_record_video";s:32:"_sys_uploader_record_video_title";}' WHERE `object`='bx_ads' AND `name`='videos';
+UPDATE `sys_form_inputs` SET `values`='a:1:{s:18:"bx_ads_files_html5";s:25:"_sys_uploader_html5_title";}' WHERE `object`='bx_ads' AND `name`='files';
+UPDATE `sys_form_inputs` SET `attrs`='', `checker_func`='Avail', `checker_error`='_bx_ads_form_entry_input_category_select_err', `db_pass`='Int' WHERE `object`='bx_ads' AND `name`='category_select';
+
+DELETE FROM `sys_form_display_inputs` WHERE `display_name`='bx_ads_entry_add' AND `input_name`='do_submit';
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_ads_entry_add', 'do_submit', 2147483647, 1, 2);
+
+
+-- FAFORITES
+UPDATE `sys_objects_favorite` SET `table_lists`='bx_ads_favorites_lists' WHERE `name`='bx_ads';

+ 323 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsConfig.php

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

+ 287 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsFormEntry.php

@@ -0,0 +1,287 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Ads Ads
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Create/Edit entry form
+ */
+class BxAdsFormEntry extends BxBaseModTextFormEntry
+{
+    protected $_iCategory;
+    protected $_sGhostTemplateCover = 'form_ghost_template_cover.html';
+	
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_ads';
+        parent::__construct($aInfo, $oTemplate);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $this->_initCategoryFields();
+
+        if(isset($this->aInputs[$CNF['FIELD_TITLE']], $this->aInputs[$CNF['FIELD_NAME']])) {
+            $sJsObject = $this->_oModule->_oConfig->getJsObject('form');
+
+            $aMask = array('mask' => "javascript:%s.checkName(this, '%s', '%s');", $sJsObject, $CNF['FIELD_TITLE'], $CNF['FIELD_NAME']);
+            if($this->aParams['display'] == $CNF['OBJECT_FORM_ENTRY_DISPLAY_EDIT'] && bx_get('id') !== false) {
+                $aMask['mask'] = "javascript:%s.checkName(this, '%s', '%s', %d);";
+                $aMask[] = (int)bx_get('id');
+            }
+
+            $sOnBlur = call_user_func_array('sprintf', array_values($aMask)); 
+        	$this->aInputs[$CNF['FIELD_TITLE']]['attrs']['onblur'] = $sOnBlur;
+        	$this->aInputs[$CNF['FIELD_NAME']]['attrs']['onblur'] = $sOnBlur;
+        }
+
+        if(isset($CNF['FIELD_AUCTION']) && isset($this->aInputs[$CNF['FIELD_AUCTION']]) && !$this->_oModule->_oConfig->isAuction())
+            unset($this->aInputs[$CNF['FIELD_AUCTION']]);
+
+    	if(isset($CNF['FIELD_COVER']) && isset($this->aInputs[$CNF['FIELD_COVER']])) {
+            if($this->_oModule->checkAllowedSetThumb() === CHECK_ACTION_RESULT_ALLOWED) {
+                $this->aInputs[$CNF['FIELD_COVER']]['storage_object'] = $CNF['OBJECT_STORAGE'];
+                $this->aInputs[$CNF['FIELD_COVER']]['uploaders'] = !empty($this->aInputs[$CNF['FIELD_COVER']]['value']) ? unserialize($this->aInputs[$CNF['FIELD_COVER']]['value']) : $CNF['OBJECT_UPLOADERS'];
+                $this->aInputs[$CNF['FIELD_COVER']]['upload_buttons_titles'] = array(
+                    'Simple' => _t('_bx_ads_form_entry_input_covers_uploader_simple_title'), 
+                    'HTML5' => _t('_bx_ads_form_entry_input_covers_uploader_html5_title')
+                );
+                $this->aInputs[$CNF['FIELD_COVER']]['images_transcoder'] = $CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW'];
+                $this->aInputs[$CNF['FIELD_COVER']]['storage_private'] = 0;
+                $this->aInputs[$CNF['FIELD_COVER']]['multiple'] = false;
+                $this->aInputs[$CNF['FIELD_COVER']]['content_id'] = 0;
+                $this->aInputs[$CNF['FIELD_COVER']]['ghost_template'] = '';
+            }
+            else
+                unset($this->aInputs[$CNF['FIELD_COVER']]);
+        }
+
+        if(isset($CNF['FIELD_PHOTO']) && isset($this->aInputs[$CNF['FIELD_PHOTO']])) {
+            $this->aInputs[$CNF['FIELD_PHOTO']]['storage_object'] = $CNF['OBJECT_STORAGE_PHOTOS'];
+            $this->aInputs[$CNF['FIELD_PHOTO']]['uploaders'] = !empty($this->aInputs[$CNF['FIELD_PHOTO']]['value']) ? unserialize($this->aInputs[$CNF['FIELD_PHOTO']]['value']) : $CNF['OBJECT_UPLOADERS'];
+            $this->aInputs[$CNF['FIELD_PHOTO']]['images_transcoder'] = $CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW_PHOTOS'];
+            $this->aInputs[$CNF['FIELD_PHOTO']]['storage_private'] = 0;
+            $this->aInputs[$CNF['FIELD_PHOTO']]['multiple'] = true;
+            $this->aInputs[$CNF['FIELD_PHOTO']]['content_id'] = 0;
+            $this->aInputs[$CNF['FIELD_PHOTO']]['ghost_template'] = '';
+            $this->aInputs[$CNF['FIELD_PHOTO']]['tr_attrs'] = array('class'=> 'bx-base-text-attachment-item');
+        }
+
+        if(isset($this->aInputs[$CNF['FIELD_VIDEO']])) {
+            $this->aInputs[$CNF['FIELD_VIDEO']]['storage_object'] = $CNF['OBJECT_STORAGE_VIDEOS'];
+            $this->aInputs[$CNF['FIELD_VIDEO']]['uploaders'] = !empty($this->aInputs[$CNF['FIELD_VIDEO']]['value']) ? unserialize($this->aInputs[$CNF['FIELD_VIDEO']]['value']) : $CNF['OBJECT_UPLOADERS'];
+            $this->aInputs[$CNF['FIELD_VIDEO']]['images_transcoder'] = $CNF['OBJECT_VIDEOS_TRANSCODERS']['poster_preview'];
+            $this->aInputs[$CNF['FIELD_VIDEO']]['storage_private'] = 0;
+            $this->aInputs[$CNF['FIELD_VIDEO']]['multiple'] = true;
+            $this->aInputs[$CNF['FIELD_VIDEO']]['content_id'] = 0;
+            $this->aInputs[$CNF['FIELD_VIDEO']]['ghost_template'] = '';
+            $this->aInputs[$CNF['FIELD_VIDEO']]['tr_attrs'] = array('class'=> 'bx-base-text-attachment-item');
+        }
+
+        if (isset($CNF['FIELD_FILE']) && isset($this->aInputs[$CNF['FIELD_FILE']])) {
+            $this->aInputs[$CNF['FIELD_FILE']]['storage_object'] = $CNF['OBJECT_STORAGE_FILES'];
+            $this->aInputs[$CNF['FIELD_FILE']]['uploaders'] = !empty($this->aInputs[$CNF['FIELD_FILE']]['value']) ? unserialize($this->aInputs[$CNF['FIELD_FILE']]['value']) : $CNF['OBJECT_UPLOADERS'];
+            $this->aInputs[$CNF['FIELD_FILE']]['images_transcoder'] = $CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW_FILES'];
+            $this->aInputs[$CNF['FIELD_FILE']]['storage_private'] = 0;
+            $this->aInputs[$CNF['FIELD_FILE']]['multiple'] = true;
+            $this->aInputs[$CNF['FIELD_FILE']]['content_id'] = 0;
+            $this->aInputs[$CNF['FIELD_FILE']]['ghost_template'] = '';
+            $this->aInputs[$CNF['FIELD_FILE']]['tr_attrs'] = array('class'=> 'bx-base-text-attachment-item');
+        }
+
+        if(isset($this->aInputs[$CNF['FIELD_POLL']])) {
+            $this->aInputs[$CNF['FIELD_POLL']]['tr_attrs'] = array('class'=> 'bx-base-text-attachment-item');
+        }
+
+        if($this->aParams['display'] == $CNF['OBJECT_FORM_ENTRY_DISPLAY_ADD'] && isset($this->aInputs['do_submit'])) {
+            $sJsObject = $this->_oModule->_oConfig->getJsObject('form');
+
+            $this->aInputs['do_submit'] = array_merge($this->aInputs['do_submit'], [
+                'type' => 'button',
+                'attrs' => [
+                    'onclick' => $sJsObject . '.selectCategory(this);'
+                ]
+            ]);
+        }
+    }
+
+    function getCode($bDynamicMode = false)
+    {
+        $sJs = $this->_oModule->_oTemplate->addJs(array('form.js'), $bDynamicMode);
+
+        $sCode = '';
+        if($bDynamicMode)
+            $sCode .= $sJs;
+
+        $sCode .= $this->_oModule->_oTemplate->getJsCode('form');
+        $sCode .= parent::getCode($bDynamicMode);
+
+        return $sCode;
+    }
+
+    function initChecker ($aValues = array (), $aSpecificValues = array())
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aContentInfo = array();
+        if($aValues && !empty($aValues['id']))
+            $aContentInfo = $this->_oModule->_oDb->getContentInfoById($aValues['id']);
+        $bContentInfo = !empty($aContentInfo) && is_array($aContentInfo);
+
+        if($bContentInfo)
+            $this->_initCategoryFields($aContentInfo[$CNF['FIELD_CATEGORY']]);
+
+        if(isset($CNF['FIELD_COVER']) && isset($this->aInputs[$CNF['FIELD_COVER']])) {
+            if($bContentInfo)
+                $this->aInputs[$CNF['FIELD_COVER']]['content_id'] = $aContentInfo[$CNF['FIELD_ID']];
+
+            $this->aInputs[$CNF['FIELD_COVER']]['ghost_template'] = $this->_oModule->_oTemplate->parseHtmlByName($this->_sGhostTemplateCover, $this->_getCoverGhostTmplVars($aContentInfo));
+        }
+
+        parent::initChecker ($aValues, $aSpecificValues);
+    }
+
+    public function insert ($aValsToAdd = array(), $isIgnore = false)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iContentId = parent::insert ($aValsToAdd, $isIgnore);
+        if(!empty($iContentId))
+            $this->processFiles($CNF['FIELD_COVER'], $iContentId, true);
+
+        return $iContentId;
+    }
+
+    public function update ($iContentId, $aValsToAdd = array(), &$aTrackTextFieldsChanges = null)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iResult = parent::update ($iContentId, $aValsToAdd, $aTrackTextFieldsChanges);
+
+        $this->processFiles($CNF['FIELD_COVER'], $iContentId, false);
+
+        return $iResult;
+    }
+
+    public function genInputPrice(&$aInput)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(!isset($aInput['value_currency'])) {
+            $iAuthorId = 0;
+            if(!empty($this->_iContentId)) {
+                $aContentInfo = $this->_oModule->_oDb->getContentInfoById($this->_iContentId);
+                if(!empty($aContentInfo) || is_array($aContentInfo))
+                    $iAuthorId = $aContentInfo[$CNF['FIELD_AUTHOR']];
+            }
+            else
+                $iAuthorId = bx_get_logged_profile_id();
+
+            $aInput['value_currency'] = BxDolPayments::getInstance()->getCurrencyCode($iAuthorId);
+        }
+
+        return parent::genInputPrice($aInput);
+    }
+
+    protected function genCustomInputCategoryView(&$aInput)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(!empty($this->_iCategory)) {
+            $aCategory = $this->_oModule->_oDb->getCategories(array('type' => 'id', 'id' => $this->_iCategory));
+            if(!empty($aCategory) && is_array($aCategory))
+                $aInput['value'] = bx_process_output(_t($aCategory['title']));
+        }
+
+        return $this->genInputStandard($aInput);
+    }
+ 
+    protected function genCustomViewRowValueCategoryView(&$aInput)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(empty($aInput['value']))
+            return '';
+
+        $aCategory = $this->_oModule->_oDb->getCategories(array('type' => 'id', 'id' => $aInput['value']));
+        if(empty($aCategory) || !is_array($aCategory))
+            return '';
+
+        $sLink = bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_CATEGORIES'], array($CNF['GET_PARAM_CATEGORY'] => $aCategory['id'])));
+        return $this->_oModule->_oTemplate->parseLink($sLink, bx_process_output(_t($aCategory['title'])));
+    }
+
+    protected function genCustomViewRowValueQuantity(&$aInput)
+    {
+        return (int)$aInput['value'] > 0 ? (int)$aInput['value'] : 0;
+    }
+
+    protected function _getCoverGhostTmplVars($aContentInfo = array())
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	return array (
+            'name' => $this->aInputs[$CNF['FIELD_COVER']]['name'],
+            'content_id' => $this->aInputs[$CNF['FIELD_COVER']]['content_id'],
+            'editor_id' => isset($CNF['FIELD_TEXT_ID']) ? $CNF['FIELD_TEXT_ID'] : '',
+            'thumb_id' => isset($CNF['FIELD_THUMB']) && isset($aContentInfo[$CNF['FIELD_THUMB']]) ? $aContentInfo[$CNF['FIELD_THUMB']] : 0,
+            'name_thumb' => isset($CNF['FIELD_THUMB']) ? $CNF['FIELD_THUMB'] : ''
+        );
+    }
+
+    protected function _getPhotoGhostTmplVars($aContentInfo = array())
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	return array (
+            'name' => $this->aInputs[$CNF['FIELD_PHOTO']]['name'],
+            'content_id' => (int)$this->aInputs[$CNF['FIELD_PHOTO']]['content_id'],
+            'editor_id' => isset($CNF['FIELD_TEXT_ID']) ? $CNF['FIELD_TEXT_ID'] : '',
+            'bx_if:set_thumb' => [
+				'condition' => false,
+				'content' => []
+			],
+    	);
+    }
+
+    protected function _initCategoryFields($iCategory = 0)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $this->_iCategory = (int)$iCategory;
+        if(empty($this->_iCategory) && bx_get('category') !== false)
+            $this->_iCategory = (int)bx_get('category');
+
+        if(isset($CNF['FIELD_CATEGORY']) && isset($this->aInputs[$CNF['FIELD_CATEGORY']]) && $this->_iCategory != 0)
+            $this->aInputs[$CNF['FIELD_CATEGORY']]['value'] = $this->_iCategory;
+
+        if(isset($CNF['FIELD_CATEGORY_VIEW']) && isset($this->aInputs[$CNF['FIELD_CATEGORY_VIEW']]) && $this->_iCategory != 0)
+            $this->aInputs[$CNF['FIELD_CATEGORY_VIEW']]['value'] = $this->_iCategory;
+
+        if(isset($CNF['FIELD_CATEGORY_SELECT']) && isset($this->aInputs[$CNF['FIELD_CATEGORY_SELECT']]))
+            $this->aInputs[$CNF['FIELD_CATEGORY_SELECT']]['values'] = $this->_oModule->serviceGetCategoryOptions(0, true);
+    }
+
+    protected function _isChangeUserForAdmins($sDisplay)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(!$this->_bAllowChangeUserForAdmins)
+            return false;
+
+        if(strpos($sDisplay, '_add') !== false)
+            return $sDisplay != $CNF['OBJECT_FORM_ENTRY_DISPLAY_ADD'];
+
+        if(strpos($sDisplay, '_edit') !== false)
+            return true;
+
+        return false;
+    }
+}
+
+/** @} */

+ 128 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsGridOffers.php

@@ -0,0 +1,128 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Ads Ads
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxAdsGridOffers extends BxTemplGrid
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_ads';
+    	$this->_oModule = BxDolModule::getInstance($this->_sModule);
+    	if(!$oTemplate)
+            $oTemplate = $this->_oModule->_oTemplate;
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sDefaultSortingOrder = 'DESC';
+
+        if(($iContentId = bx_get('content_id')) !== false)
+            $this->setContentId($iContentId);
+    }
+
+    public function setContentId($iContentId)
+    {
+        $this->_aQueryAppend['content_id'] = (int)$iContentId;
+    }
+
+    public function performActionAccept()
+    {
+        $iId = $this->_getId();
+        if($iId && $this->_oModule->offerAccept($iId))
+            $aResult = array('grid' => $this->getCode(false), 'blick' => $iId);
+        else
+            $aResult = array('msg' => _t('_bx_ads_txt_err_cannot_perform_action'));
+
+        echoJson($aResult);
+    }
+
+    public function performActionDecline()
+    {
+        $iId = $this->_getId();
+        if($iId && $this->_oModule->offerDecline($iId))
+            $aResult = array('grid' => $this->getCode(false), 'blick' => $iId);
+        else
+            $aResult = array('msg' => _t('_bx_ads_txt_err_cannot_perform_action'));
+
+        echoJson($aResult);
+    }
+
+    protected function _getCellAuthorId($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_oModule->_oTemplate->getProfileLink($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellAmount($mixedValue, $sKey, $aField, $aRow)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aContentInfo = $this->_oModule->_oDb->getContentInfoById((int)$aRow[$CNF['FIELD_OFR_CONTENT']]);
+
+        return parent::_getCellDefault(_t_format_currency_ext($mixedValue, [
+            'sign' => BxDolPayments::getInstance()->getCurrencySign((int)$aContentInfo[$CNF['FIELD_AUTHOR']])
+        ]), $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 _getCellStatus($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(_t('_bx_ads_txt_offer_status_' . $mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getActionAccept ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if($aRow[$CNF['FIELD_OFR_STATUS']] != BX_ADS_OFFER_STATUS_AWAITING)
+            return '';
+
+        return parent::_getActionDefault($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getActionDecline ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if($aRow[$CNF['FIELD_OFR_STATUS']] != BX_ADS_OFFER_STATUS_AWAITING)
+            return '';
+
+        return parent::_getActionDefault($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        if(empty($this->_aQueryAppend['content_id']))
+            return array();
+
+        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `content_id`=?", $this->_aQueryAppend['content_id']);
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+
+    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;
+    }
+}
+
+/** @} */

+ 84 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsGridOffersAll.php

@@ -0,0 +1,84 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Ads Ads
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxAdsGridOffersAll extends BxTemplGrid
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_iProfileId;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_ads';
+    	$this->_oModule = BxDolModule::getInstance($this->_sModule);
+    	if(!$oTemplate)
+            $oTemplate = $this->_oModule->_oTemplate;
+
+        parent::__construct ($aOptions, $oTemplate);
+        
+        $this->_sDefaultSortingOrder = 'DESC';
+
+        $this->_iProfileId = bx_get_logged_profile_id();
+    }
+
+    protected function _getCellContentId($mixedValue, $sKey, $aField, $aRow)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $mixedValue = $this->_oModule->_oTemplate->getEntryLink(array(
+            $CNF['FIELD_ID'] => $aRow['content_id'],
+            $CNF['FIELD_TITLE'] => $aRow['content_title'],
+        ));
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getActionView($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $sUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY_OFFERS'], array('id' => $aRow['content_id'])));
+
+    	$a['attr'] = array_merge($a['attr'], array(
+            "onclick" => "window.open('" . $sUrl . "','_self');"
+    	));
+        unset($a['attr']['bx_grid_action_single']);
+
+        return parent::_getActionDefault($sType, $sKey, $a, false, $isDisabled, $aRow);
+    }
+
+    protected function _getDataSqlOrderClause ($sOrderByFilter, $sOrderField, $sOrderDir, $bFieldsOnly = false)
+    {
+        return " GROUP BY `to`.`content_id` " . parent::_getDataSqlOrderClause ($sOrderByFilter, $sOrderField, $sOrderDir, $bFieldsOnly);
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `te`.`author`=?", $this->_iProfileId);
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+
+    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;
+    }
+}
+
+/** @} */

+ 64 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsMenuSnippetMeta.php

@@ -0,0 +1,64 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Ads Ads
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxAdsMenuSnippetMeta extends BxBaseModTextMenuSnippetMeta
+{
+    protected $_sCategoryUrl;
+    
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_ads';
+
+        parent::__construct($aObject, $oTemplate);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $this->_sCategoryUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_CATEGORIES'], array($CNF['GET_PARAM_CATEGORY'] => '')));
+    }
+
+    protected function _getMenuItemCategory($aItem)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(empty($CNF['FIELD_CATEGORY']) || empty($this->_aContentInfo[$CNF['FIELD_CATEGORY']]))
+            return false;
+
+        $iCategory = (int)$this->_aContentInfo[$CNF['FIELD_CATEGORY']];
+        $aCategory = $this->_oModule->_oDb->getCategories(array('type' => 'id', 'id' => $iCategory));
+        if(empty($aCategory) || !is_array($aCategory))
+            return false;
+
+        return $this->getUnitMetaItemLink(_t($aCategory['title']), array(
+            'href' => $this->_sCategoryUrl . $iCategory
+        ));
+    }
+
+    protected function _getMenuItemPrice($aItem)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(empty($CNF['FIELD_PRICE']))
+            return false;
+
+        if(!empty($this->_aContentInfo[$CNF['FIELD_PRICE']]))
+            $sPrice = _t_format_currency_ext((float)$this->_aContentInfo[$CNF['FIELD_PRICE']], [
+                'sign' => BxDolPayments::getInstance()->getCurrencySign((int)$this->_aContentInfo[$CNF['FIELD_AUTHOR']])
+            ]);
+        else
+            $sPrice = _t('_bx_ads_txt_free');
+
+        return $this->getUnitMetaItemText($sPrice, array(
+            'class' => 'price'
+        ));
+    }
+}
+
+/** @} */

+ 114 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsMenuView.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    Ads Ads
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * View entry menu
+ */
+class BxAdsMenuView extends BxBaseModTextMenuView
+{
+    /**
+     * Array with check_sum => JS_code pairs of all JS codes 
+     * which should be added to the page.
+     */
+    protected $_aJsCodes;
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_ads';
+
+        parent::__construct($aObject, $oTemplate);
+
+        $this->_aJsCodes = array();
+
+        $this->addMarkers(array(
+            'js_object' => $this->_oModule->_oConfig->getJsObject('entry')
+        ));
+    }
+
+    public function getCode ()
+    {
+    	return parent::getCode() . $this->getJsCode();
+    }
+
+    public function getJsCode()
+    {
+        if(empty($this->_aJsCodes) || !is_array($this->_aJsCodes))
+            return '';
+
+        return implode('', $this->_aJsCodes);
+    }
+
+    protected function _isVisible ($a)
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(!parent::_isVisible($a))
+            return false;
+
+        $oPayment = BxDolPayments::getInstance();
+
+        $bResult = false;
+        switch ($a['name']) {
+            case 'add-to-cart':
+                if((float)$this->_aContentInfo[$CNF['FIELD_PRICE']] == 0 || (int)$this->_aContentInfo[$CNF['FIELD_QUANTITY']] <= 0) 
+                    break;
+
+                $iAuthorId = (int)$this->_aContentInfo[$CNF['FIELD_AUTHOR']];
+                $aJs = $oPayment->getAddToCartJs($iAuthorId, $this->MODULE, $this->_aContentInfo[$CNF['FIELD_ID']], 1, true);
+                if(empty($aJs) || !is_array($aJs))
+                    break;
+
+                list($sJsCode, $sJsMethod) = $aJs;
+
+                $sJsCodeCheckSum = md5($sJsCode);
+                if(!isset($this->_aJsCodes[$sJsCodeCheckSum]))
+                    $this->_aJsCodes[$sJsCodeCheckSum] = $sJsCode;
+
+                $bResult = true;
+                $this->addMarkers(array(
+                    'add_to_cart_title' => _t('_bx_ads_menu_item_title_add_to_cart', BxDolPayments::getInstance()->getCurrencySign($iAuthorId), $this->_aContentInfo[$CNF['FIELD_PRICE']]),
+                    'add_to_cart_onclick' => $sJsMethod
+                ));
+                break;
+
+            case 'interested':
+                $bResult = $this->_aContentInfo[$CNF['FIELD_AUTHOR']] != bx_get_logged_profile_id();
+                break;
+
+            case 'make-offer':
+                $bResult = $this->_oModule->isAllowedMakeOffer($this->_aContentInfo);
+                break;
+
+            case 'view-offers':
+                $bResult = $this->_oModule->isAllowedViewOffers($this->_aContentInfo);
+                break;
+
+            case 'approve':
+                $bResult = $this->_oModule->isAllowedApprove($this->_aContentInfo);
+                break;
+
+            case 'shipped':
+                $bResult = $this->_oModule->isAllowedMarkShipped($this->_aContentInfo);
+                break;
+
+            case 'received':
+                $bResult = $this->_oModule->isAllowedMarkReceived($this->_aContentInfo);
+                break;
+
+            default:
+                $bResult = true;
+        }
+
+        return $bResult;
+    }
+}
+
+/** @} */

+ 2092 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsModule.php

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

+ 24 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsPageListEntry.php

@@ -0,0 +1,24 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Videos Videos
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * List entry page
+ */
+class BxAdsPageListEntry extends BxBaseModTextPageListEntry
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_ads';
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 174 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/classes/BxAdsTemplate.php

@@ -0,0 +1,174 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Ads Ads
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/*
+ * Module representation.
+ */
+class BxAdsTemplate extends BxBaseModTextTemplate
+{
+    function __construct(&$oConfig, &$oDb)
+    {
+        $this->MODULE = 'bx_ads';
+
+        parent::__construct($oConfig, $oDb);
+
+        $this->aMethodsToCallAddJsCss[] = 'categories';
+    }
+
+    public function entryOfferAccepted($iUserId, $aContent, $aOffer)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oPayments = BxDolPayments::getInstance();
+        $iContentAuthorId = (int)$aContent[$CNF['FIELD_AUTHOR']];
+
+        $sJsCodePay = $sJsMethodPay = '';
+        $aJsPay = $oPayments->getAddToCartJs($iContentAuthorId, $this->MODULE, $aContent[$CNF['FIELD_ID']], $aOffer[$CNF['FIELD_OFR_QUANTITY']], true);
+        if(!empty($aJsPay) && is_array($aJsPay))
+            list($sJsCodePay, $sJsMethodPay) = $aJsPay;
+
+        return $this->parseHtmlByName('entry-offer-accepted.html', array(
+            'js_object' => $this->_oConfig->getJsObject('entry'),
+            'id' => $aOffer['id'],
+            'amount' => _t_format_currency_ext($aOffer['amount'], [
+                'sign' => $oPayments->getCurrencySign($iContentAuthorId)
+            ]),
+            'quantity' => _t('_bx_ads_txt_n_items', $aOffer['quantity']),
+            'bx_if:show_pay' => array(
+                'condition' => !empty($sJsMethodPay),
+                'content' => array(
+                    'js_method_pay' => $sJsMethodPay,
+                )
+            ),
+            'js_code' => $sJsCodePay
+        ));
+    }
+
+    public function entryBreadcrumb($aContentInfo, $aTmplVarsItems = array())
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        $oPermalink = BxDolPermalinks::getInstance();
+
+        $aTmplVarsItems = array();
+        $this->_entryBreadcrumb($aContentInfo[$CNF['FIELD_CATEGORY']], $oPermalink, $aTmplVarsItems);
+        $aTmplVarsItems = array_reverse($aTmplVarsItems);
+        
+        $aTmplVarsItems[] = array(
+            'url' => bx_absolute_url($oPermalink->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']])),
+            'title' => bx_process_output($aContentInfo[$CNF['FIELD_TITLE']])
+        );
+
+    	return parent::entryBreadcrumb($aContentInfo, $aTmplVarsItems);
+    }
+
+    public function categoriesList($aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sResult = $this->_categoriesList(0, array(
+            'url' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_CATEGORIES'], array('category' => '')))
+        ));
+
+        if(empty($sResult) && isset($aParams['show_empty']) && $aParams['show_empty'] === true)
+            $sResult = MsgBox(_t('_Empty'));
+
+        return $sResult;
+    }
+
+    public function getEntryLink($aEntry)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return $this->getLink('entry-link', array(
+            'href' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'], array(
+                'id' => $aEntry[$CNF['FIELD_ID']]
+            ))),
+            'title' => bx_html_attribute($aEntry[$CNF['FIELD_TITLE']]),
+            'content' => $aEntry[$CNF['FIELD_TITLE']]
+        ));
+    }
+
+    /**
+     * Use Gallery image for both because currently there is no Unit types with small thumbnails.
+     */
+    protected function getUnitThumbAndGallery ($aData)
+    {
+        list($sPhotoThumb, $sPhotoGallery) = parent::getUnitThumbAndGallery($aData);
+
+        return array($sPhotoGallery, $sPhotoGallery);
+    }
+
+    protected function _categoriesList($iParentId, $aParams = array())
+    {
+        $aCategories = $this->_oDb->getCategories(array('type' => 'parent_id', 'parent_id' => $iParentId));
+
+        $aTmplVars = array();
+        foreach($aCategories as $aCategory) {
+            $iItems = (int)$aCategory['items'];
+
+            $sSibcategories = $this->_categoriesList($aCategory['id'], $aParams);
+            if($iItems == 0 && empty($sSibcategories))
+                continue;
+
+            $aTmplVars[] = array(
+                'url' => $aParams['url'] . $aCategory['id'],
+                'title' => _t($aCategory['title']),
+                'bx_if:show_icon' => array(
+                    'condition' => !empty($aCategory['icon']),
+                    'content' => array(
+                        'icon' => $aCategory['icon'],
+                    )
+                ),
+                'bx_if:show_counter' => array(
+                    'condition' => $iItems != 0,
+                    'content' => array(
+                        'items' => $iItems,
+                    )
+                ),
+                'bx_if:show_subcategories' => array(
+                    'condition' => !empty($sSibcategories),
+                    'content' => array(
+                        'subcategories' => $sSibcategories
+                    )
+                )
+            );
+        }
+
+        if(empty($aTmplVars))
+            return '';
+
+        return $this->parseHtmlByName('categories.html', array(
+            'bx_repeat:categories' => $aTmplVars
+        ));
+    }
+
+    protected function _entryBreadcrumb($iCategory, &$oPermalink, &$aTmplVarsItems)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aCategory = $this->_oDb->getCategories(array('type' => 'id', 'id' => $iCategory));
+        if(empty($aCategory) || !is_array($aCategory))
+            return;
+
+        $aTmplVarsItems[] = array(
+            'url' => bx_absolute_url($oPermalink->permalink($CNF['URL_CATEGORIES'], array($CNF['GET_PARAM_CATEGORY'] => $aCategory['id']))),
+            'title' => bx_process_output(_t($aCategory['title']))
+        );
+
+        if(empty($aCategory['parent_id']))
+            return;
+
+        $this->_entryBreadcrumb((int)$aCategory['parent_id'], $oPermalink, $aTmplVarsItems);
+    }
+}
+
+/** @} */

+ 151 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/install/config.php

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

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

@@ -0,0 +1,593 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string name="_bx_ads"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_cmts"><![CDATA[Ads' Comments]]></string>
+    <string name="_bx_ads_reactions"><![CDATA[Ads' Reactions]]></string>
+
+    <string name="_bx_ads_option_enable_auto_approve"><![CDATA[Auto approve an ad after creation]]></string>
+    <string name="_bx_ads_option_summary_chars"><![CDATA[Number of characters in auto-cropped ad summary]]></string>
+    <string name="_bx_ads_option_plain_summary_chars"><![CDATA[Number of characters in plain ad description when ad hasn't thumb]]></string>
+    <string name="_bx_ads_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+    <string name="_bx_ads_option_per_page_profile"><![CDATA[Number of items on profile/group page]]></string>
+    <string name="_bx_ads_option_rss_num"><![CDATA[Number of items in RSS feed]]></string>
+    <string name="_bx_ads_option_searchable_fields"><![CDATA[Searchable fields for keyword search]]></string>
+    <string name="_bx_ads_option_per_page_for_favorites_lists"><![CDATA[Number of favorite lists per page]]></string>
+    <string name="_bx_ads_option_lifetime"><![CDATA[Deactivate automatically after (in days)]]></string>
+    <string name="_bx_ads_option_offer_lifetime"><![CDATA[Decline offers automatically after (in hours)]]></string>
+    <string name="_bx_ads_option_internal_interested_notification"><![CDATA[Use internal notification about Interested action]]></string>
+    <string name="_bx_ads_option_enable_auction"><![CDATA[Enable Auction mode]]></string>
+
+    <string name="_bx_ads_form_category"><![CDATA[Category]]></string>
+    <string name="_bx_ads_form_category_display_add"><![CDATA[Add Category]]></string>
+    <string name="_bx_ads_form_category_display_edit"><![CDATA[Edit Category]]></string>
+    <string name="_bx_ads_form_category_display_delete"><![CDATA[Delete Category]]></string>
+    <string name="_bx_ads_form_category_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_ads_form_category_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_ads_form_category_input_sys_do_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_ads_form_category_input_do_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_ads_form_category_input_sys_parent_id"><![CDATA[Parent]]></string>
+    <string name="_bx_ads_form_category_input_parent_id"><![CDATA[Parent category]]></string>
+    <string name="_bx_ads_form_category_input_parent_id_empty"><![CDATA[No parent]]></string>
+    <string name="_bx_ads_form_category_input_sys_title"><![CDATA[Title]]></string>
+    <string name="_bx_ads_form_category_input_title"><![CDATA[Title]]></string>
+    <string name="_bx_ads_form_category_input_title_err"><![CDATA[Title is essential. Please, fill in this field.]]></string>
+    <string name="_bx_ads_form_category_input_sys_text"><![CDATA[Text]]></string>
+    <string name="_bx_ads_form_category_input_text"><![CDATA[Text]]></string>
+    <string name="_bx_ads_form_category_input_sys_type"><![CDATA[Type]]></string>
+    <string name="_bx_ads_form_category_input_type"><![CDATA[Type]]></string>
+    <string name="_bx_ads_form_category_input_type_err"><![CDATA[Type is essential. Please, select a value for this field.]]></string>
+    <string name="_bx_ads_form_category_input_type_info"><![CDATA[Type determines a set of fields for entries in this category.]]></string>
+    <string name="_bx_ads_form_category_input_sys_type_clone"><![CDATA[Clone type]]></string>
+    <string name="_bx_ads_form_category_input_type_clone"><![CDATA[Clone type]]></string>
+    <string name="_bx_ads_form_category_input_sys_type_title"><![CDATA[Type title]]></string>
+    <string name="_bx_ads_form_category_input_type_title"><![CDATA[Type title]]></string>
+    <string name="_bx_ads_form_category_input_sys_icon"><![CDATA[Icon]]></string>
+    <string name="_bx_ads_form_category_input_icon"><![CDATA[Icon]]></string>
+    <string name="_bx_ads_form_category_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+    <string name="_bx_ads_form_category_input_delete_confirm"><![CDATA[I am sure I want to delete this category]]></string>
+    <string name="_bx_ads_form_category_input_delete_confirm_info"><![CDATA[This action can not be undone]]></string>
+    <string name="_bx_ads_form_category_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete the category]]></string>
+
+    <string name="_bx_ads_form_entry"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_form_entry_display_add"><![CDATA[Add Ad]]></string>
+    <string name="_bx_ads_form_entry_display_delete"><![CDATA[Delete Ad]]></string>
+
+    <string name="_bx_ads_form_entry_price_display_add"><![CDATA[With Price: Add]]></string>
+    <string name="_bx_ads_form_entry_price_display_edit"><![CDATA[With Price: Edit]]></string>
+    <string name="_bx_ads_form_entry_price_display_view"><![CDATA[With Price: View]]></string>
+
+    <string name="_bx_ads_form_entry_price_year_display_add"><![CDATA[With Price and Year: Add]]></string>
+    <string name="_bx_ads_form_entry_price_year_display_edit"><![CDATA[With Price and Year: Edit]]></string>
+    <string name="_bx_ads_form_entry_price_year_display_view"><![CDATA[With Price and Year: View]]></string>
+
+    <string name="_bx_ads_form_entry_input_author"><![CDATA[Author]]></string>
+    <string name="_bx_ads_form_entry_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_ads_form_entry_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_ads_form_entry_input_sys_title"><![CDATA[Title]]></string>
+    <string name="_bx_ads_form_entry_input_title"><![CDATA[Title]]></string>
+    <string name="_bx_ads_form_entry_input_title_err"><![CDATA[Title is essential. Please, fill in this field]]></string>
+    <string name="_bx_ads_form_entry_input_sys_name"><![CDATA[Name]]></string>
+    <string name="_bx_ads_form_entry_input_name"><![CDATA[Name]]></string>
+    <string name="_bx_ads_form_entry_input_name_err"><![CDATA[Name should be unique and is needed for internal usage. Please, fill in this field]]></string>
+    <string name="_bx_ads_form_entry_input_sys_price"><![CDATA[Price]]></string>
+    <string name="_bx_ads_form_entry_input_price"><![CDATA[Price]]></string>
+    <string name="_bx_ads_form_entry_input_sys_auction"><![CDATA[Auction]]></string>
+    <string name="_bx_ads_form_entry_input_auction"><![CDATA[Use auction]]></string>
+    <string name="_bx_ads_form_entry_input_auction_info"><![CDATA[Allow buyers not only to pay a defined price but to make offers too.]]></string>
+    <string name="_bx_ads_form_entry_input_sys_quantity"><![CDATA[Quantity]]></string>
+    <string name="_bx_ads_form_entry_input_quantity"><![CDATA[Quantity]]></string>
+    <string name="_bx_ads_form_entry_input_quantity_err"><![CDATA[Quantity is essential. Please, fill in this field]]></string>
+    <string name="_bx_ads_form_entry_input_sys_year"><![CDATA[Year]]></string>
+    <string name="_bx_ads_form_entry_input_year"><![CDATA[Year]]></string>
+    <string name="_bx_ads_form_entry_input_sys_category"><![CDATA[Category]]></string>
+    <string name="_bx_ads_form_entry_input_sys_category_view"><![CDATA[Category]]></string>
+    <string name="_bx_ads_form_entry_input_category_view"><![CDATA[Category]]></string>
+    <string name="_bx_ads_form_entry_input_sys_category_select"><![CDATA[Category]]></string>
+    <string name="_bx_ads_form_entry_input_category_select"><![CDATA[Category]]></string>
+    <string name="_bx_ads_form_entry_input_category_select_err"><![CDATA[Category field is essential. Please, fill it in.]]></string>
+    <string name="_bx_ads_form_entry_input_sys_text"><![CDATA[Text]]></string>
+    <string name="_bx_ads_form_entry_input_text"><![CDATA[Text]]></string>
+    <string name="_bx_ads_form_entry_input_text_err"><![CDATA[Text field can't be empty]]></string>
+    <string name="_bx_ads_form_entry_input_sys_notes_purchased"><![CDATA[After purchase notes]]></string>
+    <string name="_bx_ads_form_entry_input_notes_purchased"><![CDATA[After purchase notes]]></string>
+    <string name="_bx_ads_form_entry_input_notes_purchased_inf"><![CDATA[Will be attached to email message which is sent to buyer after purchase.]]></string>
+    <string name="_bx_ads_form_entry_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+    <string name="_bx_ads_form_entry_input_delete_confirm"><![CDATA[I am sure I want to delete this ad]]></string>
+    <string name="_bx_ads_form_entry_input_delete_confirm_info"><![CDATA[This action can not be undone]]></string>
+    <string name="_bx_ads_form_entry_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete the ad]]></string>
+    <string name="_bx_ads_form_entry_input_sys_covers"><![CDATA[Header Image]]></string>
+    <string name="_bx_ads_form_entry_input_covers"><![CDATA[Header Image]]></string>
+    <string name="_bx_ads_form_entry_input_covers_uploader_simple_title"><![CDATA[Upload]]></string>
+    <string name="_bx_ads_form_entry_input_covers_uploader_html5_title"><![CDATA[Upload]]></string>
+    <string name="_bx_ads_form_entry_input_sys_pictures"><![CDATA[Images]]></string>
+    <string name="_bx_ads_form_entry_input_pictures"><![CDATA[]]></string>
+    <string name="_bx_ads_form_entry_input_sys_videos"><![CDATA[Videos]]></string>
+    <string name="_bx_ads_form_entry_input_videos"><![CDATA[]]></string>
+    <string name="_bx_ads_form_entry_input_sys_files"><![CDATA[Files]]></string>
+    <string name="_bx_ads_form_entry_input_files"><![CDATA[]]></string>
+    <string name="_bx_ads_form_entry_input_sys_polls"><![CDATA[Polls]]></string>
+    <string name="_bx_ads_form_entry_input_sys_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_ads_form_entry_input_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_ads_form_entry_input_allow_view_favorite_list"><![CDATA[Visibility]]></string>
+    <string name="_bx_ads_form_entry_input_sys_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_ads_form_entry_input_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_ads_form_entry_input_sys_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_ads_form_entry_input_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_ads_form_entry_input_sys_attachments"><![CDATA[Attachments]]></string>
+
+    <string name="_bx_ads_form_poll"><![CDATA[Polls]]></string>
+    <string name="_bx_ads_form_poll_display_add"><![CDATA[Add Poll]]></string>
+    <string name="_bx_ads_form_poll_input_sys_text"><![CDATA[Question]]></string>
+    <string name="_bx_ads_form_poll_input_text"><![CDATA[Question]]></string>
+    <string name="_bx_ads_form_poll_input_text_err"><![CDATA[Question is essential. Please, fill in this field]]></string>
+    <string name="_bx_ads_form_poll_input_sys_answers"><![CDATA[Answers]]></string>
+    <string name="_bx_ads_form_poll_input_answers"><![CDATA[Answers]]></string>
+    <string name="_bx_ads_form_poll_input_answers_err"><![CDATA[Poll should have at least 2 non-empty answers.]]></string>
+    <string name="_bx_ads_form_poll_input_answers_add"><![CDATA[Add More]]></string>
+    <string name="_bx_ads_form_poll_input_sys_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_ads_form_poll_input_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_ads_form_poll_input_do_cancel"><![CDATA[Close]]></string>
+    
+    <string name="_bx_ads_form_offer"><![CDATA[Offer]]></string>
+    <string name="_bx_ads_form_offer_display_add"><![CDATA[Add Offer]]></string>
+    <string name="_bx_ads_form_offer_display_view"><![CDATA[View Offer]]></string>
+    <string name="_bx_ads_form_offer_input_sys_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_ads_form_offer_input_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_ads_form_offer_input_amount_err"><![CDATA[Amount is essential. Please, fill in this field.]]></string>
+    <string name="_bx_ads_form_offer_input_sys_quantity"><![CDATA[Quantity]]></string>
+    <string name="_bx_ads_form_offer_input_quantity"><![CDATA[Quantity]]></string>
+    <string name="_bx_ads_form_offer_input_quantity_err"><![CDATA[Quantity is essential. Please, fill in this field.]]></string>
+    <string name="_bx_ads_form_offer_input_sys_message"><![CDATA[Message]]></string>
+    <string name="_bx_ads_form_offer_input_message"><![CDATA[Message]]></string>
+    <string name="_bx_ads_form_offer_input_sys_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_ads_form_offer_input_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_ads_form_offer_input_sys_do_cancel"><![CDATA[Add]]></string>
+    <string name="_bx_ads_form_offer_input_do_cancel"><![CDATA[Close]]></string>
+
+    <string name="_bx_ads_acl_action_create_entry"><![CDATA[Create Ad]]></string>
+    <string name="_bx_ads_acl_action_delete_entry"><![CDATA[Delete Ad]]></string>
+    <string name="_bx_ads_acl_action_view_entry"><![CDATA[View Ad]]></string>
+    <string name="_bx_ads_acl_action_set_thumb"><![CDATA[Set Ad Header Image]]></string>
+    <string name="_bx_ads_acl_action_edit_any_entry"><![CDATA[Edit Any Ad]]></string>
+    <string name="_bx_ads_acl_action_delete_any_entry"><![CDATA[Delete Any Ad]]></string>
+    <string name="_bx_ads_acl_action_make_offer"><![CDATA[Make Offer]]></string>
+
+    <string name="_bx_ads_page_title_sys_create_entry"><![CDATA[New Ad]]></string>
+    <string name="_bx_ads_page_title_create_entry"><![CDATA[New Ad]]></string>
+    <string name="_bx_ads_page_block_title_create_entry"><![CDATA[New Ad]]></string>
+    <string name="_bx_ads_page_title_sys_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_ads_page_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_ads_page_block_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_ads_page_title_sys_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_ads_page_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_ads_page_block_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_ads_page_title_sys_view_entry"><![CDATA[View Ad]]></string>
+    <string name="_bx_ads_page_title_view_entry"><![CDATA[{title}]]></string>
+    <string name="_bx_ads_page_block_title_entry_breadcrumb"><![CDATA[Breadcrumb]]></string>
+    <string name="_bx_ads_page_block_title_entry_text"><![CDATA[Ad Text]]></string>
+    <string name="_bx_ads_page_title_browse"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_page_title_search_results"><![CDATA[Ads matching "{0}"]]></string>
+    <string name="_bx_ads_page_title_browse_by_author"><![CDATA[Ads of {display_name}]]></string>
+    <string name="_bx_ads_page_title_browse_by_context"><![CDATA[Ads in {display_name}]]></string>
+    <string name="_bx_ads_page_title_browse_featured"><![CDATA[Featured Ads]]></string>
+    <string name="_bx_ads_page_title_browse_recent"><![CDATA[Latest Ads]]></string>
+    <string name="_bx_ads_page_title_browse_popular"><![CDATA[Popular Ads]]></string>
+    <string name="_bx_ads_page_title_browse_updated"><![CDATA[Updated Ads]]></string>
+    <string name="_bx_ads_page_title_browse_category"><![CDATA[Ads in {display_name}]]]]></string>
+    <string name="_bx_ads_page_title_sys_home"><![CDATA[Ads Home]]></string>
+    <string name="_bx_ads_page_title_home"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_page_block_title_featured_entries_view_extended"><![CDATA[Featured Ads]]></string>
+    <string name="_bx_ads_page_block_title_recent_entries"><![CDATA[Latest Ads (Gallery View)]]></string>
+    <string name="_bx_ads_page_block_title_recent_entries_view_extended"><![CDATA[Latest Ads]]></string>
+    <string name="_bx_ads_page_block_title_recent_entries_view_full"><![CDATA[Latest Ads (Full View)]]></string>
+    <string name="_bx_ads_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+    <string name="_bx_ads_page_block_title_entry_author"><![CDATA[Author]]></string>
+    <string name="_bx_ads_page_block_title_entry_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_ads_page_block_title_entry_comments"><![CDATA[Comments]]></string>
+	<string name="_bx_ads_page_block_title_entry_reports"><![CDATA[Reports]]></string>
+    <string name="_bx_ads_page_block_title_entry_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_ads_page_block_title_entry_reviews"><![CDATA[Reviews]]></string>
+    <string name="_bx_ads_page_block_title_entry_reviews_link"><![CDATA[Reviews to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_ads_page_block_title_entry_reviews_rating"><![CDATA[Rating]]></string>
+    <string name="_bx_ads_page_block_title_entry_location"><![CDATA[Location]]></string>
+    <string name="_bx_ads_page_block_title_entry_attachments"><![CDATA[Attachments]]></string>
+    <string name="_bx_ads_page_block_title_entry_polls"><![CDATA[Polls]]></string>
+    <string name="_bx_ads_page_block_title_entry_all_actions"><![CDATA[All Actions]]></string>
+    <string name="_bx_ads_page_title_sys_entries_popular"><![CDATA[Popular Ads]]></string>
+    <string name="_bx_ads_page_title_entries_popular"><![CDATA[Popular Ads]]></string>
+    <string name="_bx_ads_page_title_sys_entries_updated"><![CDATA[Updated Ads]]></string>
+    <string name="_bx_ads_page_title_entries_updated"><![CDATA[Updated Ads]]></string>
+    <string name="_bx_ads_page_title_sys_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_ads_page_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_ads_page_title_sys_entries_favorites"><![CDATA[Favorives Reviews]]></string>
+    <string name="_bx_ads_page_title_entries_favorites"><![CDATA[Favorives Reviews]]></string>
+    <string name="_bx_ads_page_block_title_search_form"><![CDATA[Search Form]]></string>
+    <string name="_bx_ads_page_block_title_search_results"><![CDATA[Search Results]]></string>
+    <string name="_bx_ads_page_block_title_search_form_cmts"><![CDATA[Comments Search Form]]></string>
+    <string name="_bx_ads_page_block_title_search_results_cmts"><![CDATA[Comments Search Results]]></string>
+    <string name="_bx_ads_page_block_title_popular_entries"><![CDATA[Popular Ads]]></string>
+    <string name="_bx_ads_page_block_title_popular_entries_view_extended"><![CDATA[Popular Ads (Extended View)]]></string>
+    <string name="_bx_ads_page_block_title_popular_entries_view_full"><![CDATA[Popular Ads (Full View)]]></string>
+    <string name="_bx_ads_page_block_title_updated_entries"><![CDATA[Updated Ads]]></string>
+    <string name="_bx_ads_page_block_title_favorites_entries"><![CDATA["{title}" List]]></string>
+    <string name="_bx_ads_page_block_title_favorites_entries_info"><![CDATA[Info]]></string>
+    <string name="_bx_ads_page_title_sys_view_entry_comments"><![CDATA[Ad Comments]]></string>
+    <string name="_bx_ads_page_title_view_entry_comments"><![CDATA[Comments to {title}]]></string>
+    <string name="_bx_ads_page_title_sys_entries_of_author"><![CDATA[Ads of author]]></string>
+    <string name="_bx_ads_page_title_entries_of_author"><![CDATA[Ads by {display_name}]]></string>
+    <string name="_bx_ads_page_title_sys_entries_in_context"><![CDATA[Ads in context]]></string>
+    <string name="_bx_ads_page_title_entries_in_context"><![CDATA[Ads in {display_name}]]></string>
+    <string name="_bx_ads_page_block_title_favorites_of_author"><![CDATA[Favorites by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_ads_page_block_title_sys_favorites_of_author"><![CDATA[Favorites of author]]></string>
+    <string name="_bx_ads_page_block_title_entries_of_author"><![CDATA[Ads by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_ads_page_block_title_sys_entries_of_author"><![CDATA[Ads of author]]></string>
+    <string name="_bx_ads_page_block_title_entries_in_context"><![CDATA[Ads in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_ads_page_block_title_sys_entries_in_context"><![CDATA[Ads in context]]></string>
+    <string name="_bx_ads_page_block_title_entries_actions"><![CDATA[Ads actions]]></string>
+    <string name="_bx_ads_page_block_title_browse_cmts"><![CDATA[Ads' Comments]]></string>
+    <string name="_bx_ads_page_title_sys_manage"><![CDATA[Manage Own]]></string>
+    <string name="_bx_ads_page_title_sys_manage_administration"><![CDATA[Manage All]]></string>
+    <string name="_bx_ads_page_title_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_ads_page_block_title_system_manage"><![CDATA[Manage Own]]></string>
+    <string name="_bx_ads_page_block_title_system_manage_administration"><![CDATA[Manage All]]></string>
+    <string name="_bx_ads_page_block_title_manage"><![CDATA[Manage]]></string>    
+    <string name="_bx_ads_page_block_title_popular_keywords"><![CDATA[Popular Hashtags]]></string>
+    <string name="_bx_ads_page_block_title_categories"><![CDATA[Ads Categories]]></string>
+    <string name="_bx_ads_page_block_title_entry_info"><![CDATA[Info]]></string>
+    <string name="_bx_ads_page_block_title_sys_my_entries"><![CDATA[User Ads]]></string>
+    <string name="_bx_ads_page_block_title_my_entries"><![CDATA[{display_name} Ads]]></string>
+    <string name="_bx_ads_page_block_title_sys_recent_entries_view_showcase"><![CDATA[Latest Ads (Showcase View)]]></string>
+    <string name="_bx_ads_page_block_title_recent_entries_view_showcase"><![CDATA[Latest Ads]]></string>
+    <string name="_bx_ads_page_block_title_sys_popular_entries_view_showcase"><![CDATA[Popular Ads (Showcase View)]]></string>
+    <string name="_bx_ads_page_block_title_popular_entries_view_showcase"><![CDATA[Popular Ads]]></string>
+    <string name="_bx_ads_page_block_title_sys_featured_entries_view_showcase"><![CDATA[Featured Ads (Showcase View)]]></string>
+    <string name="_bx_ads_page_block_title_featured_entries_view_showcase"><![CDATA[Featured Ads]]></string>
+    <string name="_bx_ads_page_block_title_entry_offer_accepted"><![CDATA[Offer]]></string>
+    <string name="_bx_ads_page_block_title_sys_entry_context"><![CDATA[Posted in]]></string>
+    <string name="_bx_ads_page_block_title_entry_context"><![CDATA[Posted in]]></string>
+    <string name="_bx_ads_page_title_sys_entries_categories"><![CDATA[Ads Categories]]></string>
+    <string name="_bx_ads_page_title_entries_categories"><![CDATA[Ads Categories]]></string>
+    <string name="_bx_ads_page_block_title_entries_by_category"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_page_block_title_entries_by_category_mask"><![CDATA[Ads in: {0}]]></string>
+    <string name="_bx_ads_page_title_sys_licenses_administration"><![CDATA[Licenses]]></string>
+    <string name="_bx_ads_page_title_licenses_administration"><![CDATA[Licenses]]></string>
+    <string name="_bx_ads_page_block_title_licenses_administration"><![CDATA[Licenses]]></string>
+    <string name="_bx_ads_page_title_sys_licenses"><![CDATA[Licenses]]></string>
+    <string name="_bx_ads_page_title_licenses"><![CDATA[Licenses]]></string>
+    <string name="_bx_ads_page_block_title_licenses"><![CDATA[Licenses]]></string>
+    <string name="_bx_ads_page_block_title_licenses_note"><![CDATA[Note]]></string>
+    <string name="_bx_ads_page_block_content_licenses_note"><![CDATA[The licenses are for reference only.]]></string>
+    <string name="_bx_ads_page_title_sys_offers"><![CDATA[Offers]]></string>
+    <string name="_bx_ads_page_title_offers"><![CDATA[Offers]]></string>
+    <string name="_bx_ads_page_block_title_offers"><![CDATA[Offers]]></string>
+    <string name="_bx_ads_page_title_sys_offers_all"><![CDATA[All Offers]]></string>
+    <string name="_bx_ads_page_title_offers_all"><![CDATA[All Offers]]></string>
+    <string name="_bx_ads_page_block_title_offers_all"><![CDATA[All Offers]]></string>
+
+    <string name="_bx_ads_menu_title_entry_attachments"><![CDATA[Form Attachments]]></string>
+    <string name="_bx_ads_menu_set_title_entry_attachments"><![CDATA[Form Attachments]]></string>
+    <string name="_bx_ads_menu_item_title_system_cpa_photo_simple"><![CDATA[Add Photo (simple)]]></string>
+    <string name="_bx_ads_menu_item_title_cpa_photo_simple"><![CDATA[Add Photo]]></string>
+    <string name="_bx_ads_menu_item_title_system_cpa_photo_html5"><![CDATA[Add Photo (html5)]]></string>
+    <string name="_bx_ads_menu_item_title_cpa_photo_html5"><![CDATA[Add Photos]]></string>
+    <string name="_bx_ads_menu_item_title_system_cpa_video_simple"><![CDATA[Add Video (simple)]]></string>
+    <string name="_bx_ads_menu_item_title_cpa_video_simple"><![CDATA[Add Video]]></string>
+    <string name="_bx_ads_menu_item_title_system_cpa_video_html5"><![CDATA[Add Video (html5)]]></string>
+    <string name="_bx_ads_menu_item_title_cpa_video_html5"><![CDATA[Add Videos]]></string>
+    <string name="_bx_ads_menu_item_title_system_cpa_video_record"><![CDATA[Record Video]]></string>
+    <string name="_bx_ads_menu_item_title_cpa_video_record"><![CDATA[Record Video]]></string>
+    <string name="_bx_ads_menu_item_title_system_cpa_file_simple"><![CDATA[Add File (simple)]]></string>
+    <string name="_bx_ads_menu_item_title_cpa_file_simple"><![CDATA[Add File]]></string>
+    <string name="_bx_ads_menu_item_title_system_cpa_file_html5"><![CDATA[Add File (html5)]]></string>
+    <string name="_bx_ads_menu_item_title_cpa_file_html5"><![CDATA[Add Files]]></string>
+    <string name="_bx_ads_menu_item_title_system_cpa_poll"><![CDATA[Add Poll]]></string>
+    <string name="_bx_ads_menu_item_title_cpa_poll"><![CDATA[Add Poll]]></string>
+
+    <string name="_bx_ads_menu_set_title_view_entry"><![CDATA[Ad Actions]]></string>
+    <string name="_bx_ads_menu_title_view_entry"><![CDATA[Ad Actions]]></string>
+    <string name="_bx_ads_menu_title_submenu"><![CDATA[Ads Submenu]]></string>
+    <string name="_bx_ads_menu_set_title_submenu"><![CDATA[Ads Submenu]]></string>
+    <string name="_bx_ads_menu_item_title_system_create_entry"><![CDATA[Ad]]></string>
+    <string name="_bx_ads_menu_item_title_create_entry"><![CDATA[Ad]]></string>
+    <string name="_bx_ads_menu_item_title_system_interested_entry"><![CDATA[Interested]]></string>
+    <string name="_bx_ads_menu_item_title_interested_entry"><![CDATA[I'm interested]]></string>
+    <string name="_bx_ads_menu_item_title_system_add_to_cart"><![CDATA[Add to Cart]]></string>
+    <string name="_bx_ads_menu_item_title_add_to_cart"><![CDATA[Buy for {0}{1}]]></string>
+    <string name="_bx_ads_menu_item_title_system_make_offer"><![CDATA[Make offer]]></string>
+    <string name="_bx_ads_menu_item_title_make_offer"><![CDATA[Make offer]]></string>
+    <string name="_bx_ads_menu_item_title_system_view_offers"><![CDATA[Оffers]]></string>
+    <string name="_bx_ads_menu_item_title_view_offers"><![CDATA[Оffers]]></string>
+    <string name="_bx_ads_menu_item_title_system_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_ads_menu_item_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_ads_menu_item_title_system_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_ads_menu_item_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_ads_menu_item_title_system_mark_shipped"><![CDATA[Shipped]]></string>
+    <string name="_bx_ads_menu_item_title_mark_shipped"><![CDATA[Shipped]]></string>
+    <string name="_bx_ads_menu_item_title_system_mark_received"><![CDATA[Received]]></string>
+    <string name="_bx_ads_menu_item_title_mark_received"><![CDATA[Received]]></string>
+    <string name="_bx_ads_menu_item_title_system_review_entry"><![CDATA[Review]]></string>
+    <string name="_bx_ads_menu_item_title_system_view_entry"><![CDATA[View Ad]]></string>
+    <string name="_bx_ads_menu_item_title_system_entries_home"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_menu_item_title_entries_home"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_menu_item_title_system_entries_public"><![CDATA[Latest]]></string>
+    <string name="_bx_ads_menu_item_title_entries_public"><![CDATA[Latest]]></string>
+    <string name="_bx_ads_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_ads_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_ads_menu_item_title_system_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_ads_menu_item_title_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_ads_menu_item_title_system_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_ads_menu_item_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_ads_menu_title_view_entry_submenu"><![CDATA[View Ad Submenu]]></string>
+    <string name="_bx_ads_menu_set_title_view_entry_submenu"><![CDATA[View Ad Submenu]]></string>
+    <string name="_bx_ads_menu_item_title_view_entry_submenu_entry"><![CDATA[Ad]]></string>
+    <string name="_bx_ads_menu_item_title_view_entry_submenu_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_ads_menu_item_title_system_view_entry_comments"><![CDATA[Ad Comments]]></string>
+    <string name="_bx_ads_menu_item_title_system_view_entries_author"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_menu_item_title_view_entries_author"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_menu_item_title_system_view_entries_in_context"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_menu_item_title_view_entries_in_context"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_menu_title_entries_my"><![CDATA[My Ads Action Menu]]></string>
+    <string name="_bx_ads_menu_set_title_entries_my"><![CDATA[My Ads Menu]]></string>
+    <string name="_bx_ads_menu_item_title_system_manage_my_posts"><![CDATA[My ads]]></string>
+    <string name="_bx_ads_menu_item_title_manage_my_posts"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_ads_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_ads_menu_item_title_system_manage_account"><![CDATA[Manage account]]></string>
+    <string name="_bx_ads_menu_item_title_manage_account"><![CDATA[Manage account]]></string>
+    <string name="_bx_ads_menu_item_title_system_admt_ads"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_menu_item_title_admt_ads"><![CDATA[Ads]]></string>
+    <string name="_bx_ads_menu_item_title_manage_my"><![CDATA[My Ads]]></string>
+    <string name="_bx_ads_menu_item_title_manage_all"><![CDATA[All Ads]]></string>
+    <string name="_bx_ads_menu_item_title_categories"><![CDATA[Categories]]></string>
+    <string name="_bx_ads_menu_item_title_system_entries_categories"><![CDATA[Categories]]></string>
+    <string name="_bx_ads_menu_item_title_entries_categories"><![CDATA[Categories]]></string>
+    <string name="_bx_ads_menu_item_title_system_sm_price"><![CDATA[Price]]></string>
+    <string name="_bx_ads_menu_item_title_sm_price"><![CDATA[Price]]></string>
+    <string name="_bx_ads_menu_title_licenses_submenu"><![CDATA[Licenses Submenu]]></string>
+    <string name="_bx_ads_menu_set_title_licenses_submenu"><![CDATA[Licenses Submenu]]></string>
+    <string name="_bx_ads_menu_item_title_system_ads_licenses_administration"><![CDATA[All Licenses]]></string>
+    <string name="_bx_ads_menu_item_title_ads_licenses_administration"><![CDATA[All Licenses]]></string>
+    <string name="_bx_ads_menu_item_title_system_ads_licenses"><![CDATA[My Licenses]]></string>
+    <string name="_bx_ads_menu_item_title_ads_licenses"><![CDATA[My Licenses]]></string>
+    <string name="_bx_ads_menu_item_title_system_licenses"><![CDATA[Ads Licenses]]></string>
+    <string name="_bx_ads_menu_item_title_licenses"><![CDATA[Ads Licenses]]></string>
+    <string name="_bx_ads_menu_item_title_system_offers_all"><![CDATA[Ads Offers]]></string>
+    <string name="_bx_ads_menu_item_title_offers_all"><![CDATA[Offers]]></string>
+
+    <string name="_bx_ads_grid_column_title_icon"><![CDATA[Icon]]></string>
+    <string name="_bx_ads_grid_column_title_title"><![CDATA[Title]]></string>
+    <string name="_bx_ads_grid_column_title_subcategories"><![CDATA[Subcategories]]></string>
+    <string name="_bx_ads_grid_column_value_subcategories"><![CDATA[{0} subcategories]]></string>
+    <string name="_bx_ads_grid_column_info_subcategories"><![CDATA[View subcategories]]></string>
+    <string name="_bx_ads_grid_action_title_add"><![CDATA[Add New]]></string>
+    <string name="_bx_ads_grid_action_title_back"><![CDATA[Back]]></string>
+    <string name="_bx_ads_grid_action_title_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_ads_grid_popup_title_add"><![CDATA[Add New Category]]></string>
+    <string name="_bx_ads_grid_popup_title_edit"><![CDATA[Edit '{0}' Category]]></string>
+    <string name="_bx_ads_grid_action_err_add_category"><![CDATA[Cannot add a category.]]></string>
+    <string name="_bx_ads_grid_action_err_edit_category"><![CDATA[Cannot edit the category.]]></string>
+
+    <string name="_bx_ads_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+    <string name="_bx_ads_grid_filter_item_title_adm_select_one_filter2"><![CDATA[Any Audience]]></string>
+    <string name="_bx_ads_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_ads_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+    <string name="_bx_ads_grid_filter_item_title_adm_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_ads_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_ads_grid_column_title_adm_title"><![CDATA[Title]]></string>
+    <string name="_bx_ads_grid_column_title_adm_added"><![CDATA[Added]]></string>
+    <string name="_bx_ads_grid_column_title_adm_author"><![CDATA[Author]]></string>
+    <string name="_bx_ads_grid_action_title_adm_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_ads_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_ads_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_ads_grid_action_title_adm_audit_content"><![CDATA[Audit]]></string>
+    <string name="_bx_ads_grid_column_title_adm_status_admin"><![CDATA[Moderation]]></string>
+    <string name="_bx_ads_grid_action_err_delete"><![CDATA[Cannot delete the selected ad(s).]]></string>
+    <string name="_bx_ads_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_ads_grid_column_title_lcs_profile_id"><![CDATA[Owner]]></string>
+    <string name="_bx_ads_grid_column_title_lcs_transaction"><![CDATA[Order]]></string>
+    <string name="_bx_ads_grid_column_title_lcs_entry"><![CDATA[Ad]]></string>
+    <string name="_bx_ads_grid_column_title_lcs_count"><![CDATA[Qt.]]></string>
+    <string name="_bx_ads_grid_column_title_lcs_license"><![CDATA[License]]></string>
+    <string name="_bx_ads_grid_column_title_lcs_added"><![CDATA[Date]]></string>
+
+    <string name="_bx_ads_grid_column_title_ofr_author_id"><![CDATA[Offerer]]></string>
+    <string name="_bx_ads_grid_column_title_ofr_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_ads_grid_column_title_ofr_quantity"><![CDATA[Quantity]]></string>
+    <string name="_bx_ads_grid_column_title_ofr_message"><![CDATA[Message]]></string>
+    <string name="_bx_ads_grid_column_title_ofr_added"><![CDATA[Added]]></string>
+    <string name="_bx_ads_grid_column_title_ofr_status"><![CDATA[Status]]></string>
+    <string name="_bx_ads_grid_action_title_ofr_accept"><![CDATA[Accept the offer]]></string>
+    <string name="_bx_ads_grid_action_title_ofr_decline"><![CDATA[Decline the offer]]></string>
+
+    <string name="_bx_ads_grid_column_title_ofrs_content_id"><![CDATA[Ad]]></string>
+    <string name="_bx_ads_grid_column_title_ofrs_offers_awating"><![CDATA[Awating]]></string>
+    <string name="_bx_ads_grid_column_title_ofrs_offers_total"><![CDATA[Total]]></string>
+    <string name="_bx_ads_grid_action_title_ofr_view"><![CDATA[View offers]]></string>
+
+    <string name="_bx_ads_chart_growth"><![CDATA[Ads: Growth]]></string>
+    <string name="_bx_ads_chart_growth_speed"><![CDATA[Ads: Growth Speed]]></string>
+
+    <string name="_bx_ads_search_extended"><![CDATA[Ads Search]]></string>
+    <string name="_bx_ads_search_extended_cmts"><![CDATA[Ads Comments Search]]></string>
+    <string name="_bx_ads_search_extended_reviews"><![CDATA[Ads Reviews Search]]></string>
+
+    <!-- Ctegories -->
+    <string name="_bx_ads_cat_type_price"><![CDATA[With price]]></string>
+    <string name="_bx_ads_cat_type_price_year"><![CDATA[With price and year]]></string>
+
+    <string name="_bx_ads_cat_title_job"><![CDATA[Jobs]]></string>
+    <string name="_bx_ads_cat_title_accounting_finance"><![CDATA[Accounting / finance jobs]]></string>
+    <string name="_bx_ads_cat_title_education_nonprofit"><![CDATA[Education / nonprofit jobs]]></string>
+    <string name="_bx_ads_cat_title_government_legal"><![CDATA[Government / legal jobs]]></string>
+    <string name="_bx_ads_cat_title_programming_web_design"><![CDATA[Programming / web design jobs]]></string>
+
+    <string name="_bx_ads_cat_title_music"><![CDATA[Music Exchange]]></string>
+    <string name="_bx_ads_cat_title_instrument_sale"><![CDATA[Music instruments for sale]]></string>
+    <string name="_bx_ads_cat_title_instrument_wanted"><![CDATA[Music instruments wanted]]></string>
+    
+    <string name="_bx_ads_cat_title_housing"><![CDATA[Housing & Rentals]]></string>
+    <string name="_bx_ads_cat_title_apartments_housing"><![CDATA[Apartments / housing]]></string>
+    <string name="_bx_ads_cat_title_office_commercial"><![CDATA[Office / commercial]]></string>
+    <string name="_bx_ads_cat_title_real_estate_sale"><![CDATA[Real estate for sale]]></string>
+    <string name="_bx_ads_cat_title_roommate"><![CDATA[Roommates]]></string>
+    <string name="_bx_ads_cat_title_temporary_rental"><![CDATA[Temporary rental]]></string>
+    
+    <string name="_bx_ads_cat_title_service"><![CDATA[Services]]></string>
+    <string name="_bx_ads_cat_title_automotive"><![CDATA[Automotive services]]></string>
+    <string name="_bx_ads_cat_title_educational"><![CDATA[Educational services]]></string>
+    <string name="_bx_ads_cat_title_financial"><![CDATA[Financial services]]></string>
+    <string name="_bx_ads_cat_title_labor_move"><![CDATA[Labor / move services]]></string>
+    <string name="_bx_ads_cat_title_legal"><![CDATA[Legal services]]></string>
+
+    <string name="_bx_ads_cat_title_casting"><![CDATA[Casting Calls]]></string>
+    <string name="_bx_ads_cat_title_acting"><![CDATA[Acting castings]]></string>
+    <string name="_bx_ads_cat_title_dance"><![CDATA[Dance castings]]></string>
+    <string name="_bx_ads_cat_title_modeling"><![CDATA[Modeling castings]]></string>
+    <string name="_bx_ads_cat_title_musician"><![CDATA[Musicians castings]]></string>
+    <string name="_bx_ads_cat_title_reality_show"><![CDATA[Reality shows castings]]></string>
+
+    <string name="_bx_ads_cat_title_personal"><![CDATA[Personals]]></string>
+    <string name="_bx_ads_cat_title_men_women"><![CDATA[Men seeking women]]></string>
+    <string name="_bx_ads_cat_title_women_men"><![CDATA[Women seeking men]]></string>
+    <string name="_bx_ads_cat_title_missed_connection"><![CDATA[Missed connections]]></string>
+
+    <string name="_bx_ads_cat_title_sale"><![CDATA[For Sale]]></string>
+    <string name="_bx_ads_cat_title_barter"><![CDATA[Barter]]></string>
+    <string name="_bx_ads_cat_title_clothing"><![CDATA[Sale clothing]]></string>
+    <string name="_bx_ads_cat_title_collectible"><![CDATA[Sale collectibles]]></string>
+
+    <string name="_bx_ads_cat_title_sale_car"><![CDATA[Cars For Sale]]></string>
+    <string name="_bx_ads_cat_title_auto_part"><![CDATA[Sale auto parts]]></string>
+    <string name="_bx_ads_cat_title_auto_truck"><![CDATA[Sale autos / trucks]]></string>
+    <string name="_bx_ads_cat_title_motorcycle"><![CDATA[Sale motorcycles]]></string>
+
+    <string name="_bx_ads_et_txt_name_interested"><![CDATA[I'm interested.]]></string>
+    <string name="_bx_ads_et_txt_subject_interested"><![CDATA[{viewer_name} is interested in your ad.]]></string>
+    <string name="_bx_ads_et_txt_body_interested"><![CDATA[{email_header}
+<p>Hello, {profile_name}.</p>
+<p><b><a href="{viewer_url}">{viewer_name}</a></b> is interested in your ad <b><a href="{ad_url}">{ad_name}</a></b>.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_ads_et_txt_name_purchased"><![CDATA[Ad was purchased.]]></string>
+    <string name="_bx_ads_et_txt_subject_purchased"><![CDATA[You've purchased {entry_name} ad.]]></string>
+    <string name="_bx_ads_et_txt_body_purchased"><![CDATA[{email_header}
+<p>Hello, {client_name}.</p>
+<p>You've purchased <a href="{entry_url}">{entry_name}</a> ad ({count} item(s)) from <a href="{vendor_url}">{vendor_name}</a>.<br />Your license is <b>{license}</b>.</p>
+<p>{notes}</p>
+{email_footer}]]></string>
+
+    <string name="_bx_ads_et_txt_name_shipped"><![CDATA[Ad was shipped.]]></string>
+    <string name="_bx_ads_et_txt_subject_shipped"><![CDATA[Ad {entry_name} was shipped.]]></string>
+    <string name="_bx_ads_et_txt_body_shipped"><![CDATA[{email_header}
+<p>Hello, {profile_name}.</p>
+<p>The <a href="{entry_url}">{entry_name}</a> ad was shipped by <a href="{vendor_url}">{vendor_name}</a>.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_ads_et_txt_name_received"><![CDATA[Ad received.]]></string>
+    <string name="_bx_ads_et_txt_subject_received"><![CDATA[Ad {entry_name} was received.]]></string>
+    <string name="_bx_ads_et_txt_body_received"><![CDATA[{email_header}
+<p>Hello, {profile_name}.</p>
+<p>The <a href="{entry_url}">{entry_name}</a> ad was received by <a href="{client_url}">{client_name}</a>.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_ads_et_txt_name_offer_added"><![CDATA[New offer was added.]]></string>
+    <string name="_bx_ads_et_txt_subject_offer_added"><![CDATA[{viewer_name} added an offer for your ad.]]></string>
+    <string name="_bx_ads_et_txt_body_offer_added"><![CDATA[{email_header}
+<p>Hello, {profile_name}.</p>
+<p><b><a href="{viewer_url}">{viewer_name}</a></b> added an offer for your ad <b><a href="{entry_url}">{entry_name}</a></b>.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_ads_et_txt_name_offer_accepted"><![CDATA[The offer was accepted.]]></string>
+    <string name="_bx_ads_et_txt_subject_offer_accepted"><![CDATA[Your offer for {entry_name} ad was accepted.]]></string>
+    <string name="_bx_ads_et_txt_body_offer_accepted"><![CDATA[{email_header}
+<p>Hello, {offerer_name}.</p>
+<p>Your offer for <b><a href="{entry_url}">{entry_name}</a></b> ad was accepted.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_ads_et_txt_name_offer_declined"><![CDATA[The offer was declined.]]></string>
+    <string name="_bx_ads_et_txt_subject_offer_declined"><![CDATA[Your offer for {entry_name} ad was declined.]]></string>
+    <string name="_bx_ads_et_txt_body_offer_declined"><![CDATA[{email_header}
+<p>Hello, {offerer_name}.</p>
+<p>Your offer for <b><a href="{entry_url}">{entry_name}</a></b> ad was declined.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_ads_et_txt_name_offer_canceled"><![CDATA[The offer was canceled.]]></string>
+    <string name="_bx_ads_et_txt_subject_offer_canceled"><![CDATA[{offerer_name} canceled the offer for {entry_name} ad.]]></string>
+    <string name="_bx_ads_et_txt_body_offer_canceled"><![CDATA[{email_header}
+<p>Hello, {profile_name}.</p>
+<p><a href="{offerer_url}">{offerer_name}</a> canceled the offer for <b><a href="{entry_url}">{entry_name}</a></b> ad.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_ads_txt_all_entries_in"><![CDATA[<a href="{0}">All Ads in {1} ({2})</a>]]></string>
+    <string name="_bx_ads_txt_all_entries_by"><![CDATA[{0} ads]]></string>
+    <string name="_bx_ads_txt_sample_single"><![CDATA[ad]]></string>
+    <string name="_bx_ads_txt_sample_single_with_article"><![CDATA[an ad]]></string>
+    <string name="_bx_ads_txt_sample_comment_single"><![CDATA[comment to ad]]></string>
+    <string name="_bx_ads_txt_sample_vote_single"><![CDATA[vote to ad]]></string>
+    <string name="_bx_ads_txt_sample_reaction_single"><![CDATA['{0}' reaction to ad]]></string>
+    <string name="_bx_ads_txt_sample_score_up_single"><![CDATA[score up vote to ad]]></string>
+    <string name="_bx_ads_txt_sample_score_down_single"><![CDATA[score down vote to ad]]></string>
+    <string name="_bx_ads_txt_sample_interest_single"><![CDATA[interested in ad]]></string>
+    <string name="_bx_ads_txt_display_title_add"><![CDATA[{0}: Add]]></string>
+    <string name="_bx_ads_txt_display_title_edit"><![CDATA[{0}: Edit]]></string>
+    <string name="_bx_ads_txt_display_title_view"><![CDATA[{0}: View]]></string>
+    <string name="_bx_ads_txt_processing_awaiting"><![CDATA[Ad will be published as soon as video is converted]]></string>
+    <string name="_bx_ads_txt_processing_failed"><![CDATA[Ad isn't published because video conversion failed, edit video to fix the issue.]]></string>
+    <string name="_bx_ads_txt_free"><![CDATA[Free]]></string>
+    <string name="_bx_ads_txt_purchased_note"><![CDATA[Contact <a href="{0}">{1}</a> if you have any questions or need support.]]></string>
+    <string name="_bx_ads_txt_offer_status_awaiting"><![CDATA[Awaiting]]></string>
+    <string name="_bx_ads_txt_offer_status_accepted"><![CDATA[Accepted]]></string>
+    <string name="_bx_ads_txt_offer_status_declined"><![CDATA[Declined]]></string>
+    <string name="_bx_ads_txt_offer_status_canceled"><![CDATA[Canceled]]></string>
+    <string name="_bx_ads_txt_your_offer"><![CDATA[Your offer]]></string>
+    <string name="_bx_ads_txt_accepted"><![CDATA[was accepted]]></string>
+    <string name="_bx_ads_txt_n_items"><![CDATA[{0} item(s)]]></string>
+    <string name="_bx_ads_txt_pay"><![CDATA[Pay]]></string>
+    <string name="_bx_ads_txt_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_ads_txt_msg_status_hidden"><![CDATA[This ad was hidden.]]></string>
+    <string name="_bx_ads_txt_msg_status_pending"><![CDATA[This ad is pending approval.]]></string>
+    <string name="_bx_ads_txt_msg_auction_offer"><![CDATA[This ad is under offer.]]></string>
+    <string name="_bx_ads_txt_msg_auction_sold"><![CDATA[This ad was sold.]]></string>
+    <string name="_bx_ads_txt_msg_author_notified"><![CDATA[Advertiser was notified, that you're interested in his ad. Please wait.]]></string>
+    <string name="_bx_ads_txt_msg_offer_added"><![CDATA[Your offer was added. Advertiser will be notified about it. Please wait.]]></string>
+    <string name="_bx_ads_txt_msg_offer_accepted"><![CDATA[The offer was accepted.]]></string>
+    <string name="_bx_ads_txt_msg_offer_declined"><![CDATA[The offer was declined.]]></string>
+    <string name="_bx_ads_txt_msg_offer_canceled"><![CDATA[The offer was canceled.]]></string>
+    <string name="_bx_ads_txt_err_offer_duplicate"><![CDATA[You already made an offer. Please wait for the results.]]></string>
+    <string name="_bx_ads_txt_err_offer_accepted"><![CDATA[Your offer was already accepted.]]></string>
+    <string name="_bx_ads_txt_err_your_own"><![CDATA[You cannot do the action because it's your own ad.]]></string>
+    <string name="_bx_ads_txt_err_duplicate"><![CDATA[You already performed the action.]]></string>
+    <string name="_bx_ads_txt_err_cannot_perform_action"><![CDATA[Cannot perform action. Please report.]]></string>
+
+    <string name="_bx_ads_txt_poll_view_answers"><![CDATA[poll]]></string>
+    <string name="_bx_ads_txt_poll_view_results"><![CDATA[results]]></string>
+    <string name="_bx_ads_txt_poll_answer_vote_do_by"><![CDATA[Voted for]]></string>
+    <string name="_bx_ads_txt_poll_answer_vote_counter"><![CDATA[{0} votes]]></string>
+    <string name="_bx_ads_txt_poll_answer_vote_percent"><![CDATA[({0}%)]]></string>
+
+    <string name="_bx_ads_alert_action_doInterest_personal"><![CDATA[Someone interested in your ad]]></string>
+    <string name="_bx_ads_txt_ntfs_subobject_interested"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> {subentry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+
+    <string name="_bx_ads_alert_action_license_register_personal"><![CDATA[Your ad was purchased]]></string>
+    <string name="_bx_ads_txt_ntfs_object_license_register"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> purchased your ad <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+
+    <string name="_bx_ads_alert_action_shipped_personal"><![CDATA[Ad was shipped]]></string>
+    <string name="_bx_ads_txt_ntfs_object_shipped"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> shipped the ad <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+
+    <string name="_bx_ads_alert_action_received_personal"><![CDATA[Ad was received]]></string>
+    <string name="_bx_ads_txt_ntfs_object_received"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> received the ad <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+
+    <string name="_bx_ads_alert_action_offer_added_personal"><![CDATA[Offer was added]]></string>
+    <string name="_bx_ads_txt_ntfs_offer_added"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> added an offer to your ad <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+
+    <string name="_bx_ads_alert_action_offer_accepted_personal"><![CDATA[Offer was accepted]]></string>
+    <string name="_bx_ads_txt_ntfs_offer_accepted"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> accepted your offer for the ad <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+
+    <string name="_bx_ads_alert_action_offer_declined_personal"><![CDATA[Offer was declined]]></string>
+    <string name="_bx_ads_txt_ntfs_offer_declined"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> declined your offer for the ad <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+
+    <string name="_bx_ads_alert_action_offer_canceled_personal"><![CDATA[Offer was canceled]]></string>
+    <string name="_bx_ads_txt_ntfs_offer_canceled"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> canceled the offer for your ad <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+</resources>

+ 57 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/install/sql/disable.sql

@@ -0,0 +1,57 @@
+
+-- SETTINGS
+SET @iTypeId = (SELECT `ID` FROM `sys_options_types` WHERE `name` = 'bx_ads' 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_ads';
+DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_ads' OR `object` IN ('bx_ads_create_entry', 'bx_ads_edit_entry', 'bx_ads_delete_entry', 'bx_ads_view_entry', 'bx_ads_view_entry_comments', 'bx_ads_home', 'bx_ads_popular', 'bx_ads_updated', 'bx_ads_categories', 'bx_ads_author', 'bx_ads_context', 'bx_ads_search', 'bx_ads_manage', 'bx_ads_administration', 'bx_ads_licenses', 'bx_ads_licenses_administration', 'bx_ads_offers', 'bx_ads_offers_all');
+
+-- MENU
+DELETE FROM `sys_objects_menu` WHERE `module` = 'bx_ads';
+DELETE FROM `sys_menu_sets` WHERE `module` = 'bx_ads';
+DELETE FROM `sys_menu_items` WHERE `module` = 'bx_ads' OR `set_name` IN ('bx_ads_create_post_attachments', 'bx_ads_view', 'bx_ads_view_actions', 'bx_ads_submenu', 'bx_ads_view_submenu', 'bx_ads_snippet_meta', 'bx_ads_licenses_submenu', 'bx_ads_my', 'bx_ads_menu_manage_tools');
+
+-- PRIVACY 
+DELETE FROM `sys_objects_privacy` WHERE `object` IN ('bx_ads_allow_view_to', 'bx_ads_allow_view_favorite_list');
+
+-- ACL
+DELETE `sys_acl_actions`, `sys_acl_matrix` FROM `sys_acl_actions`, `sys_acl_matrix` WHERE `sys_acl_matrix`.`IDAction` = `sys_acl_actions`.`ID` AND `sys_acl_actions`.`Module` = 'bx_ads';
+DELETE FROM `sys_acl_actions` WHERE `Module` = 'bx_ads';
+
+-- SEARCH
+DELETE FROM `sys_objects_search` WHERE `ObjectName` IN ('bx_ads', 'bx_ads_cmts');
+
+-- METATAGS
+DELETE FROM `sys_objects_metatags` WHERE `object` = 'bx_ads';
+
+-- STATS
+DELETE FROM `sys_statistics` WHERE `module` = 'bx_ads';
+
+-- CHARTS
+DELETE FROM `sys_objects_chart` WHERE `object` LIKE 'bx_ads_%';
+
+-- GRIDS
+DELETE FROM `sys_objects_grid` WHERE `object` LIKE 'bx_ads_%';
+DELETE FROM `sys_grid_fields` WHERE `object` LIKE 'bx_ads_%';
+DELETE FROM `sys_grid_actions` WHERE `object` LIKE 'bx_ads_%';
+
+-- UPLOADERS
+DELETE FROM `sys_objects_uploader` WHERE `object` LIKE 'bx_ads_%';
+
+-- LIVE UPDATES
+DELETE FROM `sys_objects_live_updates` WHERE `name` = 'bx_ads';
+
+-- ALERTS
+SET @iHandler := (SELECT `id` FROM `sys_alerts_handlers` WHERE `name` = 'bx_ads' LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `handler_id` = @iHandler;
+DELETE FROM `sys_alerts_handlers` WHERE `id` = @iHandler;
+
+-- CRON
+DELETE FROM `sys_cron_jobs` WHERE `name` LIKE 'bx_ads_%';
+
+-- EMAIL TEMPLATES
+DELETE FROM `sys_email_templates` WHERE `Module` = 'bx_ads';

+ 664 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/install/sql/enable.sql

@@ -0,0 +1,664 @@
+
+-- 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_ads', '_bx_ads', 'bx_ads@modules/boonex/ads/|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_ads', '_bx_ads', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_ads_enable_auto_approve', 'on', @iCategId, '_bx_ads_option_enable_auto_approve', 'checkbox', '', '', '', 0),
+('bx_ads_enable_auction', '', @iCategId, '_bx_ads_option_enable_auction', 'checkbox', '', '', '', 2),
+('bx_ads_internal_interested_notification', '', @iCategId, '_bx_ads_option_internal_interested_notification', 'checkbox', '', '', '', 3),
+
+('bx_ads_summary_chars', '700', @iCategId, '_bx_ads_option_summary_chars', 'digit', '', '', '', 10),
+('bx_ads_plain_summary_chars', '240', @iCategId, '_bx_ads_option_plain_summary_chars', 'digit', '', '', '', 12),
+
+('bx_ads_per_page_browse', '12', @iCategId, '_bx_ads_option_per_page_browse', 'digit', '', '', '', 20),
+('bx_ads_per_page_profile', '6', @iCategId, '_bx_ads_option_per_page_profile', 'digit', '', '', '', 22),
+('bx_ads_per_page_browse_showcase', '32', @iCategId, '_sys_option_per_page_browse_showcase', 'digit', '', '', '', 24),
+('bx_ads_per_page_for_favorites_lists', '5', @iCategId, '_bx_ads_option_per_page_for_favorites_lists', 'digit', '', '', '', 26),
+('bx_ads_rss_num', '10', @iCategId, '_bx_ads_option_rss_num', 'digit', '', '', '', 28),
+
+('bx_ads_searchable_fields', 'title,text', @iCategId, '_bx_ads_option_searchable_fields', 'list', '', '', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:21:"get_searchable_fields";}', 30),
+
+('bx_ads_lifetime', '30', @iCategId, '_bx_ads_option_lifetime', 'digit', '', '', '', 40),
+('bx_ads_offer_lifetime', '72', @iCategId, '_bx_ads_option_offer_lifetime', 'digit', '', '', '', 41);
+
+
+-- PAGE: create entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_create_entry', '_bx_ads_page_title_sys_create_entry', '_bx_ads_page_title_create_entry', 'bx_ads', 5, 2147483647, 1, 'create-ad', 'page.php?i=create-ad', '', '', '', 0, 1, 0, 'BxAdsPageBrowse', 'modules/boonex/ads/classes/BxAdsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_ads_create_entry', 1, 'bx_ads', '_bx_ads_page_block_title_create_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:13:"entity_create";}', 0, 1, 1);
+
+-- PAGE: edit entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_edit_entry', '_bx_ads_page_title_sys_edit_entry', '_bx_ads_page_title_edit_entry', 'bx_ads', 5, 2147483647, 1, 'edit-ad', '', '', '', '', 0, 1, 0, 'BxAdsPageEntry', 'modules/boonex/ads/classes/BxAdsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_ads_edit_entry', 1, 'bx_ads', '_bx_ads_page_block_title_edit_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:11:"entity_edit";}', 0, 0, 0);
+
+-- PAGE: delete entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_delete_entry', '_bx_ads_page_title_sys_delete_entry', '_bx_ads_page_title_delete_entry', 'bx_ads', 5, 2147483647, 1, 'delete-ad', '', '', '', '', 0, 1, 0, 'BxAdsPageEntry', 'modules/boonex/ads/classes/BxAdsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_ads_delete_entry', 1, 'bx_ads', '_bx_ads_page_block_title_delete_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:13:"entity_delete";}', 0, 0, 0);
+
+-- PAGE: view entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_view_entry', '_bx_ads_page_title_sys_view_entry', '_bx_ads_page_title_view_entry', 'bx_ads', 12, 2147483647, 1, 'view-ad', '', '', '', '', 0, 1, 0, 'BxAdsPageEntry', 'modules/boonex/ads/classes/BxAdsPageEntry.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_ads_view_entry', 1, 'bx_ads', '', '_bx_ads_page_block_title_entry_breadcrumb', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:17:"entity_breadcrumb";}', 0, 0, 1, 1),
+('bx_ads_view_entry', 2, 'bx_ads', '', '_bx_ads_page_block_title_entry_comments', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:15:"entity_comments";}', 0, 0, 0, 0),
+('bx_ads_view_entry', 2, 'bx_ads', '', '_bx_ads_page_block_title_entry_author', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:13:"entity_author";}', 0, 0, 1, 1),
+('bx_ads_view_entry', 2, 'bx_ads', '', '_bx_ads_page_block_title_entry_text', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:17:"entity_text_block";}', 0, 0, 1, 10),
+('bx_ads_view_entry', 2, 'bx_ads', '', '_bx_ads_page_block_title_entry_all_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:18:"entity_all_actions";}', 0, 0, 1, 20),
+('bx_ads_view_entry', 2, 'bx_ads', '', '_bx_ads_page_block_title_entry_attachments', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:18:"entity_attachments";}', 0, 0, 1, 30),
+('bx_ads_view_entry', 2, 'bx_ads', '', '_bx_ads_page_block_title_entry_reviews', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:14:"entity_reviews";}', 0, 0, 1, 50),
+('bx_ads_view_entry', 3, 'bx_ads', '', '_bx_ads_page_block_title_entry_location', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:15:"entity_location";}', 0, 0, 0, 0),
+('bx_ads_view_entry', 3, 'bx_ads', '', '_bx_ads_page_block_title_entry_offer_accepted', 13, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:21:"entity_offer_accepted";s:6:"params";a:1:{i:0;s:4:"{id}";}}', 0, 0, 1, 10),
+('bx_ads_view_entry', 3, 'bx_ads', '_bx_ads_page_block_title_sys_entry_context', '_bx_ads_page_block_title_entry_context', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:14:"entity_context";}', 0, 0, 1, 20),
+('bx_ads_view_entry', 3, 'bx_ads', '', '_bx_ads_page_block_title_entry_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:11:"entity_info";}', 0, 0, 1, 30),
+('bx_ads_view_entry', 3, 'bx_ads', '', '_bx_ads_page_block_title_entry_reviews_rating', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:21:"entity_reviews_rating";}', 0, 0, 1, 40),
+('bx_ads_view_entry', 3, 'bx_ads', '', '_bx_ads_page_block_title_entry_location', 3, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:13:"locations_map";s:6:"params";a:2:{i:0;s:6:"bx_ads";i:1;s:4:"{id}";}s:5:"class";s:20:"TemplServiceMetatags";}', 0, 0, 1, 50),
+('bx_ads_view_entry', 2, 'bx_ads', '', '_bx_ads_page_block_title_entry_polls', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:12:"entity_polls";}', 0, 0, 1, 60),
+('bx_ads_view_entry', 3, 'bx_ads', '', '_bx_ads_page_block_title_featured_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 0, 1, 70),
+('bx_ads_view_entry', 4, 'bx_ads', '', '_bx_ads_page_block_title_entry_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:14:"entity_actions";}', 0, 0, 0, 0),
+('bx_ads_view_entry', 4, 'bx_ads', '', '_bx_ads_page_block_title_entry_social_sharing', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:21:"entity_social_sharing";}', 0, 0, 0, 0),
+('bx_ads_view_entry', 2, 'bx_ads', '', '_bx_ads_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:6:\"bx_ads\";s:6:\"method\";s:14:\"entity_reports\";}', 0, 0, 1, 6);
+
+-- 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_ads_view_entry_comments', '_bx_ads_page_title_sys_view_entry_comments', '_bx_ads_page_title_view_entry_comments', 'bx_ads', 5, 2147483647, 1, 'view-ad-comments', '', '', '', '', 0, 1, 0, 'BxAdsPageEntry', 'modules/boonex/ads/classes/BxAdsPageEntry.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_ads_view_entry_comments', 1, 'bx_ads', '_bx_ads_page_block_title_entry_comments', '_bx_ads_page_block_title_entry_comments_link', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:15:"entity_comments";}', 0, 0, 1);
+
+-- PAGE: popular 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_ads_popular', '_bx_ads_page_title_sys_entries_popular', '_bx_ads_page_title_entries_popular', 'bx_ads', 5, 2147483647, 1, 'ads-popular', 'page.php?i=ads-popular', '', '', '', 0, 1, 0, 'BxAdsPageBrowse', 'modules/boonex/ads/classes/BxAdsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_ads_popular', 1, 'bx_ads', '_bx_ads_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:14:"browse_popular";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1);
+
+-- PAGE: recently updated 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_ads_updated', '_bx_ads_page_title_sys_entries_updated', '_bx_ads_page_title_entries_updated', 'bx_ads', 5, 2147483647, 1, 'ads-updated', 'page.php?i=ads-updated', '', '', '', 0, 1, 0, 'BxAdsPageBrowse', 'modules/boonex/ads/classes/BxAdsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_ads_updated', 1, 'bx_ads', '_bx_ads_page_block_title_updated_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:14:"browse_updated";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1);
+
+-- PAGE:  entries' categories 
+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_ads_categories', '_bx_ads_page_title_sys_entries_categories', '_bx_ads_page_title_entries_categories', 'bx_ads', 1, 2147483647, 1, 'ads-categories', 'page.php?i=ads-categories', '', '', '', 0, 1, 0, 'BxAdsPageBrowse', 'modules/boonex/ads/classes/BxAdsPageBrowse.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_ads_categories', 1, 'bx_ads', '', '_bx_ads_page_block_title_categories', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:15:"categories_list";s:6:"params";a:1:{i:0;a:1:{s:10:"show_empty";b:1;}}}', 0, 0, 1, 1),
+('bx_ads_categories', 2, 'bx_ads', '', '_bx_ads_page_block_title_entries_by_category', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:15:"browse_category";s:6:"params";a:2:{i:0;i:0;i:1;a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1, 1);
+
+-- PAGE: entries of author
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_author', 'ads-author', '_bx_ads_page_title_sys_entries_of_author', '_bx_ads_page_title_entries_of_author', 'bx_ads', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxAdsPageAuthor', 'modules/boonex/ads/classes/BxAdsPageAuthor.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_ads_author', 1, 'bx_ads', '', '_bx_ads_page_block_title_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:18:"my_entries_actions";}', 0, 0, 1, 1),
+('bx_ads_author', 1, 'bx_ads', '_bx_ads_page_block_title_sys_favorites_of_author', '_bx_ads_page_block_title_favorites_of_author', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";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_ads_author', 1, 'bx_ads', '_bx_ads_page_block_title_sys_entries_of_author', '_bx_ads_page_block_title_entries_of_author', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:13:"browse_author";}', 0, 0, 1, 3),
+('bx_ads_author', 1, 'bx_ads', '_bx_ads_page_block_title_sys_entries_in_context', '_bx_ads_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:14:"browse_context";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";i:0;a:1:{s:13:"empty_message";b:0;}}}', 0, 0, 1, 4);
+
+
+-- PAGE: favorites by list
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_favorites', '_bx_ads_page_title_sys_entries_favorites', '_bx_ads_page_title_entries_favorites', 'bx_ads', 12, 2147483647, 1, 'ads-favorites', 'page.php?i=ads-favorites', '', '', '', 0, 1, 0, 'BxAdsPageListEntry', 'modules/boonex/ads/classes/BxAdsPageListEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_ads_favorites', 2, 'bx_ads', '_bx_ads_page_block_title_favorites_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";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_ads_favorites', 3, 'bx_ads', '_bx_ads_page_block_title_favorites_entries_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:19:"favorites_list_info";}', 0, 0, 0),
+('bx_ads_favorites', 3, 'bx_ads', '_bx_ads_page_block_title_favorites_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:22:"favorites_list_actions";}', 0, 0, 1);
+
+
+-- PAGE: entries in context
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_context', 'ads-context', '_bx_ads_page_title_sys_entries_in_context', '_bx_ads_page_title_entries_in_context', 'bx_ads', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxAdsPageAuthor', 'modules/boonex/ads/classes/BxAdsPageAuthor.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_ads_context', 1, 'bx_ads', '_bx_ads_page_block_title_sys_entries_in_context', '_bx_ads_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:14:"browse_context";}', 0, 0, 1, 1);
+
+-- 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_ads_home', 'ads-home', '_bx_ads_page_title_sys_home', '_bx_ads_page_title_home', 'bx_ads', 2, 2147483647, 1, 'page.php?i=ads-home', '', '', '', 0, 1, 0, 'BxAdsPageBrowse', 'modules/boonex/ads/classes/BxAdsPageBrowse.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_ads_home', 1, 'bx_ads', '', '_bx_ads_page_block_title_featured_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 1, 1, 0),
+('bx_ads_home', 1, 'bx_ads', '', '_bx_ads_page_block_title_recent_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:13:"browse_public";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 1, 1, 1),
+('bx_ads_home', 2, 'bx_ads', '', '_bx_ads_page_block_title_popular_keywords', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:14:"keywords_cloud";s:6:"params";a:2:{i:0;s:6:"bx_ads";i:1;s:6:"bx_ads";}s:5:"class";s:20:"TemplServiceMetatags";}', 0, 1, 1, 0),
+('bx_ads_home', 2, 'bx_ads', '', '_bx_ads_page_block_title_categories', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:15:"categories_list";s:6:"params";a:1:{i:0;a:1:{s:10:"show_empty";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_ads_search', '_bx_ads_page_title_sys_entries_search', '_bx_ads_page_title_entries_search', 'bx_ads', 5, 2147483647, 1, 'ads-search', 'page.php?i=ads-search', '', '', '', 0, 1, 0, 'BxAdsPageBrowse', 'modules/boonex/ads/classes/BxAdsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_ads_search', 1, 'bx_ads', '_bx_ads_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:6:"bx_ads";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1),
+('bx_ads_search', 1, 'bx_ads', '_bx_ads_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:6:"bx_ads";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 2),
+('bx_ads_search', 1, 'bx_ads', '_bx_ads_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:11:"bx_ads_cmts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 3),
+('bx_ads_search', 1, 'bx_ads', '_bx_ads_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:11:"bx_ads_cmts";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 4);
+
+-- 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_ads_manage', '_bx_ads_page_title_sys_manage', '_bx_ads_page_title_manage', 'bx_ads', 5, 2147483647, 1, 'ads-manage', 'page.php?i=ads-manage', '', '', '', 0, 1, 0, 'BxAdsPageBrowse', 'modules/boonex/ads/classes/BxAdsPageBrowse.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_ads_manage', 1, 'bx_ads', '_bx_ads_page_block_title_system_manage', '_bx_ads_page_block_title_manage', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";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_ads_administration', '_bx_ads_page_title_sys_manage_administration', '_bx_ads_page_title_manage', 'bx_ads', 5, 192, 1, 'ads-administration', 'page.php?i=ads-administration', '', '', '', 0, 1, 0, 'BxAdsPageBrowse', 'modules/boonex/ads/classes/BxAdsPageBrowse.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_ads_administration', 1, 'bx_ads', '_bx_ads_page_block_title_system_manage_administration', '_bx_ads_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:12:"manage_tools";s:6:"params";a:1:{i:0;s:14:"administration";}}', 0, 1, 0);
+
+-- PAGE: manage own licenses
+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_ads_licenses', '_bx_ads_page_title_sys_licenses', '_bx_ads_page_title_licenses', 'bx_ads', 5, 2147483647, 1, 'ads-licenses', '', '', '', '', 0, 1, 0, 'BxAdsPageLicenses', 'modules/boonex/ads/classes/BxAdsPageLicenses.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_ads_licenses', 1, 'bx_ads', '', '_bx_ads_page_block_title_licenses_note', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:19:"block_licenses_note";}', 0, 0, 1, 0),
+('bx_ads_licenses', 1, 'bx_ads', '', '_bx_ads_page_block_title_licenses', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:14:"block_licenses";}', 0, 0, 1, 1);
+
+-- PAGE: manage all licenses
+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_ads_licenses_administration', '_bx_ads_page_title_sys_licenses_administration', '_bx_ads_page_title_licenses_administration', 'bx_ads', 5, 192, 1, 'ads-licenses-administration', '', '', '', '', 0, 1, 0, 'BxAdsPageLicenses', 'modules/boonex/ads/classes/BxAdsPageLicenses.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_ads_licenses_administration', 1, 'bx_ads', '', '_bx_ads_page_block_title_licenses_administration', 11, 192, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:29:"block_licenses_administration";}', 0, 0, 1, 0);
+
+-- PAGE: view offers for entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_offers', '_bx_ads_page_title_sys_offers', '_bx_ads_page_title_offers', 'bx_ads', 5, 2147483647, 1, 'view-ad-offers', '', '', '', '', 0, 1, 0, 'BxAdsPageOffers', 'modules/boonex/ads/classes/BxAdsPageOffers.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_ads_offers', 1, 'bx_ads', '', '_bx_ads_page_block_title_entry_breadcrumb', 13, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:17:"entity_breadcrumb";s:6:"params";a:1:{i:0;s:4:"{id}";}}', 0, 0, 1, 1),
+('bx_ads_offers', 1, 'bx_ads', '', '_bx_ads_page_block_title_offers', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:13:"entity_offers";s:6:"params";a:1:{i:0;s:4:"{id}";}}', 0, 0, 1, 2);
+
+-- PAGE: view all offers
+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_ads_offers_all', '_bx_ads_page_title_sys_offers_all', '_bx_ads_page_title_offers_all', 'bx_ads', 5, 2147483647, 1, 'ads-offers', '', '', '', '', 0, 1, 0, '', '');
+
+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_ads_offers_all', 1, 'bx_ads', '', '_bx_ads_page_block_title_offers_all', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:6:"offers";}', 0, 0, 1, 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`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('sys_home', 1, 'bx_ads', '_bx_ads_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:13:"browse_public";s:6:"params";a:2:{i:0;b:0;i:1;b:0;}}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1);
+
+-- PAGES: add page block to profiles modules (trigger* page objects are processed separately upon modules enable/disable)
+SET @iPBCellProfile = 3;
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_ads', '_bx_ads_page_block_title_sys_my_entries', '_bx_ads_page_block_title_my_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:13:"browse_author";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:2:{s:8:"per_page";s:23:"bx_ads_per_page_profile";s:13:"empty_message";b:0;}}}', 0, 0, 0);
+
+-- PAGE: service blocks
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = '' AND `cell_id` = 0 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system` , `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('', 0, 'bx_ads', '', '_bx_ads_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:13:"browse_public";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 1),
+
+('', 0, 'bx_ads', '', '_bx_ads_page_block_title_recent_entries_view_full', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:13:"browse_public";s:6:"params";a:1:{i:0;s:4:"full";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 2),
+('', 0, 'bx_ads', '', '_bx_ads_page_block_title_popular_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:14:"browse_popular";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 3),
+('', 0, 'bx_ads', '', '_bx_ads_page_block_title_popular_entries_view_full', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:14:"browse_popular";s:6:"params";a:1:{i:0;s:4:"full";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 4),
+('', 0, 'bx_ads', '_bx_ads_page_block_title_sys_recent_entries_view_showcase', '_bx_ads_page_block_title_recent_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:13:"browse_public";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) + 5),
+('', 0, 'bx_ads', '_bx_ads_page_block_title_sys_popular_entries_view_showcase', '_bx_ads_page_block_title_popular_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:14:"browse_popular";s:6:"params";a:3:{s:9:"unit_view";s:8:"showcase";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 6),
+('', 0, 'bx_ads', '_bx_ads_page_block_title_sys_featured_entries_view_showcase', '_bx_ads_page_block_title_featured_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";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) + 7);
+
+
+-- 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_ads', 'ads-home', '_bx_ads_menu_item_title_system_entries_home', '_bx_ads_menu_item_title_entries_home', 'page.php?i=ads-home', '', '', 'ad col-green2', 'bx_ads_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_ads', 'ads-home', '_bx_ads_menu_item_title_system_entries_home', '_bx_ads_menu_item_title_entries_home', 'page.php?i=ads-home', '', '', 'ad col-green2', 'bx_ads_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_ads', 'create-ad', '_bx_ads_menu_item_title_system_create_entry', '_bx_ads_menu_item_title_create_entry', 'page.php?i=create-ad', '', '', 'ad col-green2', '', 2147483647, 1, 1, IFNULL(@iAddMenuOrder, 0) + 1);
+
+-- MENU: create ad form attachments (link, photo, video, etc)
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_entry_attachments', '_bx_ads_menu_title_entry_attachments', 'bx_ads_entry_attachments', 'bx_ads', 23, 0, 1, 'BxAdsMenuAttachments', 'modules/boonex/ads/classes/BxAdsMenuAttachments.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_ads_entry_attachments', 'bx_ads', '_bx_ads_menu_set_title_entry_attachments', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_ads_entry_attachments', 'bx_ads', 'photo_simple', '_bx_ads_menu_item_title_system_cpa_photo_simple', '_bx_ads_menu_item_title_cpa_photo_simple', 'javascript:void(0)', 'javascript:{js_object_uploader_photos_simple}.showUploaderForm();', '_self', 'camera', '', '', 2147483647, '', 0, 0, 1, 1),
+('bx_ads_entry_attachments', 'bx_ads', 'photo_html5', '_bx_ads_menu_item_title_system_cpa_photo_html5', '_bx_ads_menu_item_title_cpa_photo_html5', 'javascript:void(0)', 'javascript:{js_object_uploader_photos_html5}.showUploaderForm();', '_self', 'camera', '', '', 2147483647, '', 1, 0, 1, 2),
+('bx_ads_entry_attachments', 'bx_ads', 'video_simple', '_bx_ads_menu_item_title_system_cpa_video_simple', '_bx_ads_menu_item_title_cpa_video_simple', 'javascript:void(0)', 'javascript:{js_object_uploader_videos_simple}.showUploaderForm();', '_self', 'video', '', '', 2147483647, '', 0, 0, 1, 3),
+('bx_ads_entry_attachments', 'bx_ads', 'video_html5', '_bx_ads_menu_item_title_system_cpa_video_html5', '_bx_ads_menu_item_title_cpa_video_html5', 'javascript:void(0)', 'javascript:{js_object_uploader_videos_html5}.showUploaderForm();', '_self', 'video', '', '', 2147483647, '', 1, 0, 1, 4),
+('bx_ads_entry_attachments', 'bx_ads', 'record_video', '_bx_ads_menu_item_title_system_cpa_video_record', '_bx_ads_menu_item_title_cpa_video_record', 'javascript:void(0)', 'javascript:{js_object_uploader_videos_record_video}.showUploaderForm();', '_self', 'fas circle', '', '', 2147483647, '', 1, 0, 1, 5),
+('bx_ads_entry_attachments', 'bx_ads', 'file_simple', '_bx_ads_menu_item_title_system_cpa_file_simple', '_bx_ads_menu_item_title_cpa_file_simple', 'javascript:void(0)', 'javascript:{js_object_uploader_files_simple}.showUploaderForm();', '_self', 'file', '', '', 2147483647, '', 0, 0, 1, 6),
+('bx_ads_entry_attachments', 'bx_ads', 'file_html5', '_bx_ads_menu_item_title_system_cpa_file_html5', '_bx_ads_menu_item_title_cpa_file_html5', 'javascript:void(0)', 'javascript:{js_object_uploader_files_html5}.showUploaderForm();', '_self', 'file', '', '', 2147483647, '', 1, 0, 1, 7),
+('bx_ads_entry_attachments', 'bx_ads', 'poll', '_bx_ads_menu_item_title_system_cpa_poll', '_bx_ads_menu_item_title_cpa_poll', 'javascript:void(0)', 'javascript:{js_object}.showPollForm(this);', '_self', 'tasks', '', '', 2147483647, '', 1, 0, 1, 7);
+
+-- MENU: actions menu for view entry 
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_view', '_bx_ads_menu_title_view_entry', 'bx_ads_view', 'bx_ads', 9, 0, 1, 'BxAdsMenuView', 'modules/boonex/ads/classes/BxAdsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_ads_view', 'bx_ads', '_bx_ads_menu_set_title_view_entry', 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_ads_view', 'bx_ads', 'interested', '_bx_ads_menu_item_title_system_interested_entry', '_bx_ads_menu_item_title_interested_entry', 'javascript:void(0)', 'javascript:{js_object}.interested(this, {content_id})', '', 'map-marker', '', 2147483646, 1, 0, 10),
+('bx_ads_view', 'bx_ads', 'add-to-cart', '_bx_ads_menu_item_title_system_add_to_cart', '{add_to_cart_title}', 'javascript:void(0);', 'javascript:{add_to_cart_onclick}', '', 'cart-plus', '', 2147483647, 1, 0, 15),
+('bx_ads_view', 'bx_ads', 'make-offer', '_bx_ads_menu_item_title_system_make_offer', '_bx_ads_menu_item_title_make_offer', 'javascript:void(0);', 'javascript:{js_object}.makeOffer(this, {content_id})', '', 'hand-holding-usd', '', 2147483647, 1, 0, 16),
+('bx_ads_view', 'bx_ads', 'view-offers', '_bx_ads_menu_item_title_system_view_offers', '_bx_ads_menu_item_title_view_offers', 'page.php?i=view-ad-offers&id={content_id}', '', '', '', '', 2147483647, 1, 0, 17),
+('bx_ads_view', 'bx_ads', 'edit-ad', '_bx_ads_menu_item_title_system_edit_entry', '_bx_ads_menu_item_title_edit_entry', 'page.php?i=edit-ad&id={content_id}', '', '', 'pencil-alt', '', 2147483647, 1, 0, 20),
+('bx_ads_view', 'bx_ads', 'delete-ad', '_bx_ads_menu_item_title_system_delete_entry', '_bx_ads_menu_item_title_delete_entry', 'page.php?i=delete-ad&id={content_id}', '', '', 'remove', '', 2147483647, 1, 0, 30),
+('bx_ads_view', 'bx_ads', 'approve', '_sys_menu_item_title_system_va_approve', '_sys_menu_item_title_va_approve', 'javascript:void(0)', 'javascript:bx_approve(this,  ''{module_uri}'', {content_id});', '', 'check', '', 2147483647, 1, 0, 40),
+('bx_ads_view', 'bx_ads', 'shipped', '_bx_ads_menu_item_title_system_mark_shipped', '_bx_ads_menu_item_title_mark_shipped', 'javascript:void(0)', 'javascript:{js_object}.shipped(this, {content_id})', '', 'truck', '', 2147483647, 1, 0, 50),
+('bx_ads_view', 'bx_ads', 'received', '_bx_ads_menu_item_title_system_mark_received', '_bx_ads_menu_item_title_mark_received', 'javascript:void(0)', 'javascript:{js_object}.received(this, {content_id})', '', 'clipboard-check', '', 2147483647, 1, 0, 55);
+
+-- MENU: all actions menu for view entry 
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_view_actions', '_sys_menu_title_view_actions', 'bx_ads_view_actions', 'bx_ads', 15, 0, 1, 'BxAdsMenuViewActions', 'modules/boonex/ads/classes/BxAdsMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_ads_view_actions', 'bx_ads', '_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_ads_view_actions', 'bx_ads', 'interested', '_bx_ads_menu_item_title_system_interested_entry', '', '', '', '', '', '', '', 0, 2147483646, 1, 0, 10),
+('bx_ads_view_actions', 'bx_ads', 'add-to-cart', '_bx_ads_menu_item_title_system_add_to_cart', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 15),
+('bx_ads_view_actions', 'bx_ads', 'make-offer', '_bx_ads_menu_item_title_system_make_offer', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 16),
+('bx_ads_view_actions', 'bx_ads', 'view-offers', '_bx_ads_menu_item_title_system_view_offers', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 17),
+('bx_ads_view_actions', 'bx_ads', 'edit-ad', '_bx_ads_menu_item_title_system_edit_entry', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 20),
+('bx_ads_view_actions', 'bx_ads', 'delete-ad', '_bx_ads_menu_item_title_system_delete_entry', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 30),
+('bx_ads_view_actions', 'bx_ads', 'approve', '_sys_menu_item_title_system_va_approve', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 40),
+('bx_ads_view_actions', 'bx_ads', 'shipped', '_bx_ads_menu_item_title_system_mark_shipped', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 50),
+('bx_ads_view_actions', 'bx_ads', 'received', '_bx_ads_menu_item_title_system_mark_received', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 55),
+('bx_ads_view_actions', 'bx_ads', 'review', '_bx_ads_menu_item_title_system_review_entry', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 190),
+('bx_ads_view_actions', 'bx_ads', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 200),
+('bx_ads_view_actions', 'bx_ads', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 210),
+('bx_ads_view_actions', 'bx_ads', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 220),
+('bx_ads_view_actions', 'bx_ads', 'reaction', '_sys_menu_item_title_system_va_reaction', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 225),
+('bx_ads_view_actions', 'bx_ads', 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 230),
+('bx_ads_view_actions', 'bx_ads', 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 240),
+('bx_ads_view_actions', 'bx_ads', 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 250),
+('bx_ads_view_actions', 'bx_ads', 'repost', '_sys_menu_item_title_system_va_repost', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 260),
+('bx_ads_view_actions', 'bx_ads', 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 270),
+('bx_ads_view_actions', 'bx_ads', 'notes', '_sys_menu_item_title_system_va_notes', '_sys_menu_item_title_va_notes', 'javascript:void(0)', 'javascript:bx_get_notes(this,  ''{module_uri}'', {content_id});', '', 'exclamation-triangle', '', '', 0, 2147483647, 1, 0, 280),
+('bx_ads_view_actions', 'bx_ads', 'audit', '_sys_menu_item_title_system_va_audit', '_sys_menu_item_title_va_audit', 'page.php?i=dashboard-audit&module=bx_courses&content_id={content_id}', '', '', 'history', '', '', 0, 192, 1, 0, 290),
+('bx_ads_view_actions', 'bx_ads', '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_ads_view_actions', 'bx_ads', '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_ads_my', '_bx_ads_menu_title_entries_my', 'bx_ads_my', 'bx_ads', 9, 0, 1, 'BxAdsMenu', 'modules/boonex/ads/classes/BxAdsMenu.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_ads_my', 'bx_ads', '_bx_ads_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_ads_my', 'bx_ads', 'create-ad', '_bx_ads_menu_item_title_system_create_entry', '_bx_ads_menu_item_title_create_entry', 'page.php?i=create-ad', '', '', '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_ads_submenu', '_bx_ads_menu_title_submenu', 'bx_ads_submenu', 'bx_ads', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_ads_submenu', 'bx_ads', '_bx_ads_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_ads_submenu', 'bx_ads', 'ads-home', '_bx_ads_menu_item_title_system_entries_public', '_bx_ads_menu_item_title_entries_public', 'page.php?i=ads-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_ads_submenu', 'bx_ads', 'ads-popular', '_bx_ads_menu_item_title_system_entries_popular', '_bx_ads_menu_item_title_entries_popular', 'page.php?i=ads-popular', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_ads_submenu', 'bx_ads', 'ads-categories', '_bx_ads_menu_item_title_system_entries_categories', '_bx_ads_menu_item_title_entries_categories', 'page.php?i=ads-categories', '', '', '', '', 2147483647, 1, 1, 3),
+('bx_ads_submenu', 'bx_ads', 'ads-search', '_bx_ads_menu_item_title_system_entries_search', '_bx_ads_menu_item_title_entries_search', 'page.php?i=ads-search', '', '', '', '', 2147483647, 1, 1, 4),
+('bx_ads_submenu', 'bx_ads', 'ads-manage', '_bx_ads_menu_item_title_system_entries_manage', '_bx_ads_menu_item_title_entries_manage', 'page.php?i=ads-manage', '', '', '', '', 2147483646, 1, 1, 5);
+
+-- MENU: sub-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_ads_view_submenu', '_bx_ads_menu_title_view_entry_submenu', 'bx_ads_view_submenu', 'bx_ads', 8, 0, 1, 'BxAdsMenuView', 'modules/boonex/ads/classes/BxAdsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_ads_view_submenu', 'bx_ads', '_bx_ads_menu_set_title_view_entry_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_ads_view_submenu', 'bx_ads', 'view-ad', '_bx_ads_menu_item_title_system_view_entry', '_bx_ads_menu_item_title_view_entry_submenu_entry', 'page.php?i=view-ad&id={content_id}', '', '', '', '', 2147483647, 0, 0, 1),
+('bx_ads_view_submenu', 'bx_ads', 'view-ad-comments', '_bx_ads_menu_item_title_system_view_entry_comments', '_bx_ads_menu_item_title_view_entry_submenu_comments', 'page.php?i=view-ad-comments&id={content_id}', '', '', '', '', 2147483647, 0, 0, 2);
+
+-- 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_ads_snippet_meta', '_sys_menu_title_snippet_meta', 'bx_ads_snippet_meta', 'bx_ads', 15, 0, 1, 'BxAdsMenuSnippetMeta', 'modules/boonex/ads/classes/BxAdsMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_ads_snippet_meta', 'bx_ads', '_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_ads_snippet_meta', 'bx_ads', 'date', '_sys_menu_item_title_system_sm_date', '_sys_menu_item_title_sm_date', '', '', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_ads_snippet_meta', 'bx_ads', 'author', '_sys_menu_item_title_system_sm_author', '_sys_menu_item_title_sm_author', '', '', '', '', '', 2147483647, 1, 0, 1, 2),
+('bx_ads_snippet_meta', 'bx_ads', 'category', '_sys_menu_item_title_system_sm_category', '_sys_menu_item_title_sm_category', '', '', '', '', '', 2147483647, 1, 0, 1, 3),
+('bx_ads_snippet_meta', 'bx_ads', 'price', '_bx_ads_menu_item_title_system_sm_price', '_bx_ads_menu_item_title_sm_price', '', '', '', '', '', 2147483647, 1, 0, 1, 4),
+('bx_ads_snippet_meta', 'bx_ads', 'tags', '_sys_menu_item_title_system_sm_tags', '_sys_menu_item_title_sm_tags', '', '', '', '', '', 2147483647, 0, 0, 1, 5),
+('bx_ads_snippet_meta', 'bx_ads', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 2147483647, 0, 0, 1, 6),
+('bx_ads_snippet_meta', 'bx_ads', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 2147483647, 0, 0, 1, 7);
+
+-- MENU: licenses submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_licenses_submenu', '_bx_ads_menu_title_licenses_submenu', 'bx_ads_licenses_submenu', 'bx_ads', 6, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_ads_licenses_submenu', 'bx_ads', '_bx_ads_menu_set_title_licenses_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_ads_licenses_submenu', 'bx_ads', 'ads-licenses-administration', '_bx_ads_menu_item_title_system_ads_licenses_administration', '_bx_ads_menu_item_title_ads_licenses_administration', 'page.php?i=ads-licenses-administration', '', '_self', '', '', '', 192, 1, 0, 1, 1),
+('bx_ads_licenses_submenu', 'bx_ads', 'ads-licenses', '_bx_ads_menu_item_title_system_ads_licenses', '_bx_ads_menu_item_title_ads_licenses', 'page.php?i=ads-licenses', '', '_self', '', '', '', 2147483646, 1, 0, 1, 2);
+
+-- MENU: notifications menu in account popup
+SET @iNotifMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name` = 'sys_account_notifications' 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`, `addon`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES
+('sys_account_notifications', 'bx_ads', 'notifications-ads-offers', '_bx_ads_menu_item_title_system_offers_all', '_bx_ads_menu_item_title_offers_all', 'page.php?i=ads-offers&profile_id={member_id}', '', '', 'ad col-green2', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:16:"get_offers_count";s:6:"params";a:1:{i:0;s:8:"awaiting";}}', '', 2147483646, '', 1, 0, @iNotifMenuOrder + 1);
+
+-- 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_ads', 'profile-stats-my-ads', '_bx_ads_menu_item_title_system_manage_my_posts', '_bx_ads_menu_item_title_manage_my_posts', 'page.php?i=ads-author&profile_id={member_id}', '', '_self', 'ad col-green2', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:41:"get_menu_addon_manage_tools_profile_stats";}', '', 2147483646, 1, 0, @iNotifMenuOrder + 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_ads_menu_manage_tools', '_bx_ads_menu_title_manage_tools', 'bx_ads_menu_manage_tools', 'bx_ads', 6, 0, 1, 'BxAdsMenuManageTools', 'modules/boonex/ads/classes/BxAdsMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_ads_menu_manage_tools', 'bx_ads', '_bx_ads_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_ads_menu_manage_tools', 'bx_ads', 'delete-with-content', '_bx_ads_menu_item_title_system_delete_with_content', '_bx_ads_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'far trash-alt', '', 128, 1, 0, 0);
+
+-- 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_ads', 'ads-administration', '_bx_ads_menu_item_title_system_admt_ads', '_bx_ads_menu_item_title_admt_ads', 'page.php?i=ads-administration', '', '_self', 'ad', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
+
+-- MENU: account dashboard
+SET @iDashboardMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard' LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES
+('sys_account_dashboard', 'bx_ads', 'dashboard-ads-licenses', '_bx_ads_menu_item_title_system_licenses', '_bx_ads_menu_item_title_licenses', 'page.php?i=ads-licenses', '', '', 'ad col-green2', '', '', 2147483646, 1, 0, 1, @iDashboardMenuOrder + 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_ads', 'ads-author', '_bx_ads_menu_item_title_system_view_entries_author', '_bx_ads_menu_item_title_view_entries_author', 'page.php?i=ads-author&profile_id={profile_id}', '', '', 'ad col-green2', '', 2147483647, 1, 0, 0),
+('trigger_group_view_submenu', 'bx_ads', 'ads-context', '_bx_ads_menu_item_title_system_view_entries_in_context', '_bx_ads_menu_item_title_view_entries_in_context', 'page.php?i=ads-context&profile_id={profile_id}', '', '', 'ad col-green2', '', 2147483647, 1, 0, 0);
+
+
+-- PRIVACY 
+INSERT INTO `sys_objects_privacy` (`object`, `module`, `action`, `title`, `default_group`, `table`, `table_field_id`, `table_field_author`, `override_class_name`, `override_class_file`) VALUES
+('bx_ads_allow_view_to', 'bx_ads', 'view', '_bx_ads_form_entry_input_allow_view_to', '3', 'bx_ads_entries', 'id', 'author', '', ''),
+('bx_ads_allow_view_favorite_list', 'bx_ads', 'view_favorite_list', '_bx_ads_form_entry_input_allow_view_favorite_list', '3', 'bx_ads_favorites_lists', 'id', 'author_id', '', '');
+
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_ads', 'create entry', NULL, '_bx_ads_acl_action_create_entry', '', 1, 3);
+SET @iIdActionEntryCreate = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_ads', 'delete entry', NULL, '_bx_ads_acl_action_delete_entry', '', 1, 3);
+SET @iIdActionEntryDelete = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_ads', 'view entry', NULL, '_bx_ads_acl_action_view_entry', '', 1, 0);
+SET @iIdActionEntryView = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_ads', 'set thumb', NULL, '_bx_ads_acl_action_set_thumb', '', 1, 3);
+SET @iIdActionSetThumb = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_ads', 'edit any entry', NULL, '_bx_ads_acl_action_edit_any_entry', '', 1, 3);
+SET @iIdActionEntryEditAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_ads', 'delete any entry', NULL, '_bx_ads_acl_action_delete_any_entry', '', 1, 3);
+SET @iIdActionEntryDeleteAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_ads', 'make offer', NULL, '_bx_ads_acl_action_make_offer', '', 1, 3);
+SET @iIdActionMakeOffer = LAST_INSERT_ID();
+
+SET @iUnauthenticated = 1;
+SET @iAccount = 2;
+SET @iStandard = 3;
+SET @iUnconfirmed = 4;
+SET @iPending = 5;
+SET @iSuspended = 6;
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+
+-- entry create
+(@iStandard, @iIdActionEntryCreate),
+(@iModerator, @iIdActionEntryCreate),
+(@iAdministrator, @iIdActionEntryCreate),
+(@iPremium, @iIdActionEntryCreate),
+
+-- entry delete
+(@iStandard, @iIdActionEntryDelete),
+(@iModerator, @iIdActionEntryDelete),
+(@iAdministrator, @iIdActionEntryDelete),
+(@iPremium, @iIdActionEntryDelete),
+
+-- entry view
+(@iUnauthenticated, @iIdActionEntryView),
+(@iAccount, @iIdActionEntryView),
+(@iStandard, @iIdActionEntryView),
+(@iUnconfirmed, @iIdActionEntryView),
+(@iPending, @iIdActionEntryView),
+(@iModerator, @iIdActionEntryView),
+(@iAdministrator, @iIdActionEntryView),
+(@iPremium, @iIdActionEntryView),
+
+-- set entry thumb
+(@iStandard, @iIdActionSetThumb),
+(@iModerator, @iIdActionSetThumb),
+(@iAdministrator, @iIdActionSetThumb),
+(@iPremium, @iIdActionSetThumb),
+
+-- edit any entry
+(@iModerator, @iIdActionEntryEditAny),
+(@iAdministrator, @iIdActionEntryEditAny),
+
+-- delete any entry
+(@iAdministrator, @iIdActionEntryDeleteAny),
+
+-- make offer
+(@iStandard, @iIdActionMakeOffer),
+(@iModerator, @iIdActionMakeOffer),
+(@iAdministrator, @iIdActionMakeOffer),
+(@iPremium, @iIdActionMakeOffer);
+
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+('bx_ads', '_bx_ads', @iSearchOrder + 1, 'BxAdsSearchResult', 'modules/boonex/ads/classes/BxAdsSearchResult.php'),
+('bx_ads_cmts', '_bx_ads_cmts', @iSearchOrder + 2, 'BxAdsCmtsSearchResult', 'modules/boonex/ads/classes/BxAdsCmtsSearchResult.php');
+
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `module`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_ads', 'bx_ads', 'bx_ads_meta_keywords', 'bx_ads_meta_locations', 'bx_ads_meta_mentions', '', '');
+
+
+-- STATS
+SET @iMaxOrderStats = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_statistics`);
+INSERT INTO `sys_statistics` (`module`, `name`, `title`, `link`, `icon`, `query`, `order`) VALUES 
+('bx_ads', 'bx_ads', '_bx_ads', 'page.php?i=ads-home', 'ad col-green2', 'SELECT COUNT(*) FROM `bx_ads_entries` WHERE 1 AND `status` = ''active'' AND `status_admin` = ''active''', @iMaxOrderStats + 1);
+
+
+-- CHARTS
+SET @iMaxOrderCharts = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_objects_chart`);
+INSERT INTO `sys_objects_chart` (`object`, `title`, `table`, `field_date_ts`, `field_date_dt`, `field_status`, `query`, `active`, `order`, `class_name`, `class_file`) VALUES
+('bx_ads_growth', '_bx_ads_chart_growth', 'bx_ads_entries', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 1, 'BxDolChartGrowth', ''),
+('bx_ads_growth_speed', '_bx_ads_chart_growth_speed', 'bx_ads_entries', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 2, 'BxDolChartGrowthSpeed', '');
+
+
+-- GRIDS: moderation tools
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_ads_administration', 'Sql', 'SELECT * FROM `bx_ads_entries` WHERE 1 ', 'bx_ads_entries', 'id', 'added', 'status_admin', '', 20, NULL, 'start', '', 'title,text', '', 'like', 'reports', '', 192, 'BxAdsGridAdministration', 'modules/boonex/ads/classes/BxAdsGridAdministration.php'),
+('bx_ads_common', 'Sql', 'SELECT * FROM `bx_ads_entries` WHERE 1 ', 'bx_ads_entries', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'title,text', '', 'like', '', '', 2147483647, 'BxAdsGridCommon', 'modules/boonex/ads/classes/BxAdsGridCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_ads_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_ads_administration', 'switcher', '_bx_ads_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_ads_administration', 'reports', '_sys_txt_reports_title', '5%', 0, '', '', 3),
+('bx_ads_administration', 'title', '_bx_ads_grid_column_title_adm_title', '25%', 0, '25', '', 4),
+('bx_ads_administration', 'added', '_bx_ads_grid_column_title_adm_added', '20%', 1, '25', '', 5),
+('bx_ads_administration', 'author', '_bx_ads_grid_column_title_adm_author', '20%', 0, '25', '', 6),
+('bx_ads_administration', 'actions', '', '20%', 0, '', '', 7),
+
+('bx_ads_common', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_ads_common', 'switcher', '_bx_ads_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_ads_common', 'title', '_bx_ads_grid_column_title_adm_title', '40%', 0, '35', '', 3),
+('bx_ads_common', 'added', '_bx_ads_grid_column_title_adm_added', '15%', 0, '25', '', 4),
+('bx_ads_common', 'status_admin', '_bx_ads_grid_column_title_adm_status_admin', '15%', 0, '16', '', 5),
+('bx_ads_common', 'actions', '', '20%', 0, '', '', 6);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_ads_administration', 'bulk', 'delete', '_bx_ads_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_ads_administration', 'single', 'edit', '_bx_ads_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_ads_administration', 'single', 'delete', '_bx_ads_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_ads_administration', 'single', 'settings', '_bx_ads_grid_action_title_adm_more_actions', 'cog', 1, 0, 3),
+('bx_ads_administration', 'single', 'audit_content', '_bx_ads_grid_action_title_adm_audit_content', 'search', 1, 0, 4),
+
+('bx_ads_common', 'bulk', 'delete', '_bx_ads_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_ads_common', 'single', 'edit', '_bx_ads_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_ads_common', 'single', 'delete', '_bx_ads_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_ads_common', 'single', 'settings', '_bx_ads_grid_action_title_adm_more_actions', 'cog', 1, 0, 3);
+
+-- GRIDS: licenses
+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_ads_licenses_administration', 'Sql', 'SELECT `tl`.`id` AS `id`, `tl`.`profile_id` AS `profile_id`, `tl`.`entry_id` AS `entry_id`, `te`.`title` AS `entry`, `tl`.`count` AS `count`, `tl`.`order` AS `transaction`, `tl`.`license` AS `license`, `tl`.`added` AS `added` FROM `bx_ads_licenses` AS `tl` LEFT JOIN `bx_ads_entries` AS `te` ON `tl`.`entry_id`=`te`.`id` LEFT JOIN `sys_profiles` AS `tup` ON `tl`.`profile_id`=`tup`.`id` LEFT JOIN `sys_accounts` AS `tua` ON `tup`.`account_id`=`tua`.`id` WHERE 1 ', 'bx_ads_licenses', 'id', 'added', '', '', 20, NULL, 'start', '', 'te`.`title,tl`.`order,tl`.`license,tua`.`name,tua`.`email', '', 'like', '', '', 192, 'BxAdsGridLicensesAdministration', 'modules/boonex/ads/classes/BxAdsGridLicensesAdministration.php'),
+('bx_ads_licenses', 'Sql', 'SELECT `tl`.`id` AS `id`, `tl`.`profile_id` AS `profile_id`, `tl`.`entry_id` AS `entry_id`, `te`.`title` AS `entry`, `tl`.`count` AS `count`, `tl`.`order` AS `transaction`, `tl`.`license` AS `license`, `tl`.`added` AS `added` FROM `bx_ads_licenses` AS `tl` LEFT JOIN `bx_ads_entries` AS `te` ON `tl`.`entry_id`=`te`.`id` WHERE 1 ', 'bx_ads_licenses', 'id', 'added', '', '', 20, NULL, 'start', '', 'te`.`title,tl`.`order,tl`.`license', '', 'like', '', '', 2147483647, 'BxAdsGridLicenses', 'modules/boonex/ads/classes/BxAdsGridLicenses.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_ads_licenses_administration', 'profile_id', '_bx_ads_grid_column_title_lcs_profile_id', '20%', 0, '0', '', 1),
+('bx_ads_licenses_administration', 'entry', '_bx_ads_grid_column_title_lcs_entry', '20%', 0, '0', '', 2),
+('bx_ads_licenses_administration', 'count', '_bx_ads_grid_column_title_lcs_count', '5%', 0, '0', '', 3),
+('bx_ads_licenses_administration', 'transaction', '_bx_ads_grid_column_title_lcs_transaction', '20%', 0, '32', '', 4),
+('bx_ads_licenses_administration', 'license', '_bx_ads_grid_column_title_lcs_license', '15%', 0, '8', '', 5),
+('bx_ads_licenses_administration', 'added', '_bx_ads_grid_column_title_lcs_added', '10%', 1, '25', '', 6),
+('bx_ads_licenses_administration', 'actions', '', '10%', 0, '0', '', 7),
+
+('bx_ads_licenses', 'entry', '_bx_ads_grid_column_title_lcs_entry', '25%', 0, '0', '', 1),
+('bx_ads_licenses', 'count', '_bx_ads_grid_column_title_lcs_count', '5%', 0, '0', '', 2),
+('bx_ads_licenses', 'transaction', '_bx_ads_grid_column_title_lcs_transaction', '25%', 0, '32', '', 3),
+('bx_ads_licenses', 'license', '_bx_ads_grid_column_title_lcs_license', '15%', 0, '8', '', 4),
+('bx_ads_licenses', 'added', '_bx_ads_grid_column_title_lcs_added', '20%', 1, '25', '', 5),
+('bx_ads_licenses', 'actions', '', '10%', 0, '0', '', 6);
+
+-- GRIDS: offers
+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_ads_offers', 'Sql', 'SELECT * FROM `bx_ads_offers` WHERE 1 ', 'bx_ads_offers', 'id', 'added', '', '', 20, NULL, 'start', '', 'message', '', 'like', '', '', 2147483647, 1, 'BxAdsGridOffers', 'modules/boonex/ads/classes/BxAdsGridOffers.php'),
+('bx_ads_offers_all', 'Sql', 'SELECT `to`.*, SUM(IF(`to`.`status`=''awaiting'', 1, 0)) AS `offers_awating`, COUNT(`to`.`id`) AS `offers_total`, `te`.`title` AS `content_title` FROM `bx_ads_offers` AS `to` LEFT JOIN `bx_ads_entries` AS `te` ON `to`.`content_id`=`te`.`id` WHERE 1 ', 'bx_ads_offers', 'id', 'added', '', '', 20, NULL, 'start', '', '', '', 'like', '', '', 2147483647, 0, 'BxAdsGridOffersAll', 'modules/boonex/ads/classes/BxAdsGridOffersAll.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_ads_offers', 'checkbox', '_sys_select', '2%', 0, 0, '', 1),
+('bx_ads_offers', 'author_id', '_bx_ads_grid_column_title_ofr_author_id', '20%', 0, 0, '', 2),
+('bx_ads_offers', 'amount', '_bx_ads_grid_column_title_ofr_amount', '14%', 0, 0, '', 3),
+('bx_ads_offers', 'quantity', '_bx_ads_grid_column_title_ofr_quantity', '5%', 0, 0, '', 4),
+('bx_ads_offers', 'message', '_bx_ads_grid_column_title_ofr_message', '24%', 0, '32', '', 5),
+('bx_ads_offers', 'added', '_bx_ads_grid_column_title_ofr_added', '10%', 0, 0, '', 6),
+('bx_ads_offers', 'status', '_bx_ads_grid_column_title_ofr_status', '5%', 0, 8, '', 7),
+('bx_ads_offers', 'actions', '', '20%', 0, '', '', 8),
+
+('bx_ads_offers_all', 'content_id', '_bx_ads_grid_column_title_ofrs_content_id', '60%', 0, 0, '', 1),
+('bx_ads_offers_all', 'offers_awating', '_bx_ads_grid_column_title_ofrs_offers_awating', '10%', 0, 0, '', 2),
+('bx_ads_offers_all', 'offers_total', '_bx_ads_grid_column_title_ofrs_offers_total', '10%', 0, 0, '', 3),
+('bx_ads_offers_all', 'actions', '', '20%', 0, '', '', 4);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_ads_offers', 'single', 'accept', '_bx_ads_grid_action_title_ofr_accept', 'check', 1, 1, 1),
+('bx_ads_offers', 'single', 'decline', '_bx_ads_grid_action_title_ofr_decline', 'times', 1, 1, 2),
+
+('bx_ads_offers_all', 'single', 'view', '_bx_ads_grid_action_title_ofr_view', 'share-square', 1, 0, 1);
+
+-- GRIDS: categories manager
+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_mode`, `sorting_fields`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_ads_categories', 'Sql', 'SELECT * FROM `bx_ads_categories` WHERE 1 ', 'bx_ads_categories', 'id', 'order', 'active', '', 20, NULL, 'start', '', 'title,text', 'auto', '', 128, 'BxAdsGridCategories', 'modules/boonex/ads/classes/BxAdsGridCategories.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_ads_categories', 'order', '', '1%', 0, '', '', 1),
+('bx_ads_categories', 'checkbox', '_sys_select', '1%', 0, '', '', 2),
+('bx_ads_categories', 'switcher', '', '8%', 0, '', '', 3),
+('bx_ads_categories', 'icon', '_bx_ads_grid_column_title_icon', '5%', 0, '', '', 4),
+('bx_ads_categories', 'title', '_bx_ads_grid_column_title_title', '50%', 1, '32', '', 5),
+('bx_ads_categories', 'subcategories', '_bx_ads_grid_column_title_subcategories', '15%', 0, '16', '', 6),
+('bx_ads_categories', 'actions', '', '20%', 0, '', '', 7);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_ads_categories', 'bulk', 'delete', '_bx_ads_grid_action_title_delete', '', 1, 1),
+('bx_ads_categories', 'single', 'edit', '', 'pencil-alt', 0, 1),
+('bx_ads_categories', 'single', 'delete', '', 'remove', 1, 2),
+('bx_ads_categories', 'independent', 'back', '_bx_ads_grid_action_title_back', '', 0, 1),
+('bx_ads_categories', 'independent', 'add', '_bx_ads_grid_action_title_add', '', 0, 2);
+
+
+-- UPLOADERS
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_ads_html5', 1, 'BxAdsUploaderHTML5', 'modules/boonex/ads/classes/BxAdsUploaderHTML5.php'),
+('bx_ads_record_video', 1, 'BxAdsUploaderRecordVideo', 'modules/boonex/ads/classes/BxAdsUploaderRecordVideo.php'),
+('bx_ads_photos_html5', 1, 'BxAdsUploaderHTML5Attach', 'modules/boonex/ads/classes/BxAdsUploaderHTML5Attach.php'),
+('bx_ads_videos_html5', 1, 'BxAdsUploaderHTML5Attach', 'modules/boonex/ads/classes/BxAdsUploaderHTML5Attach.php'),
+('bx_ads_videos_record_video', 1, 'BxAdsUploaderRecordVideoAttach', 'modules/boonex/ads/classes/BxAdsUploaderRecordVideoAttach.php'),
+('bx_ads_files_html5', 1, 'BxAdsUploaderHTML5Attach', 'modules/boonex/ads/classes/BxAdsUploaderHTML5Attach.php');
+
+
+-- LIVE UPDATES
+INSERT INTO `sys_objects_live_updates`(`name`, `frequency`, `service_call`, `active`) VALUES
+('bx_ads', 1, 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:16:"get_live_updates";s:6:"params";a:4:{i:0;s:8:"awaiting";i:1;a:2:{s:11:"menu_object";s:18:"sys_toolbar_member";s:9:"menu_item";s:7:"account";}i:2;a:2:{s:11:"menu_object";s:25:"sys_account_notifications";s:9:"menu_item";s:24:"notifications-ads-offers";}i:3;s:7:"{count}";}}', 1);
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_ads', 'BxAdsAlertsResponse', 'modules/boonex/ads/classes/BxAdsAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('profile', 'approve', @iHandler),
+('profile', 'activate', @iHandler),
+('profile', 'disapprove', @iHandler),
+('profile', 'suspend', @iHandler),
+('profile', 'delete', @iHandler),
+
+('bx_ads_videos_mp4', 'transcoded', @iHandler);
+
+
+-- CRON
+INSERT INTO `sys_cron_jobs` (`name`, `time`, `class`, `file`, `service_call`) VALUES
+('bx_ads_offers', '0 * * * *', 'BxAdsCronOffers', 'modules/boonex/ads/classes/BxAdsCronOffers.php', ''),
+('bx_ads_pruning', '0 0 * * *', 'BxAdsCronPruning', 'modules/boonex/ads/classes/BxAdsCronPruning.php', ''),
+('bx_ads_publishing', '* * * * *', 'BxAdsCronPublishing', 'modules/boonex/ads/classes/BxAdsCronPublishing.php', '');
+
+
+-- EMAIL TEMPLATES
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES 
+('bx_ads', '_bx_ads_et_txt_name_interested', 'bx_ads_interested', '_bx_ads_et_txt_subject_interested', '_bx_ads_et_txt_body_interested'),
+('bx_ads', '_bx_ads_et_txt_name_purchased', 'bx_ads_purchased', '_bx_ads_et_txt_subject_purchased', '_bx_ads_et_txt_body_purchased'),
+('bx_ads', '_bx_ads_et_txt_name_shipped', 'bx_ads_shipped', '_bx_ads_et_txt_subject_shipped', '_bx_ads_et_txt_body_shipped'),
+('bx_ads', '_bx_ads_et_txt_name_received', 'bx_ads_received', '_bx_ads_et_txt_subject_received', '_bx_ads_et_txt_body_received'),
+('bx_ads', '_bx_ads_et_txt_name_offer_added', 'bx_ads_offer_added', '_bx_ads_et_txt_subject_offer_added', '_bx_ads_et_txt_body_offer_added'),
+('bx_ads', '_bx_ads_et_txt_name_offer_accepted', 'bx_ads_offer_accepted', '_bx_ads_et_txt_subject_offer_accepted', '_bx_ads_et_txt_body_offer_accepted'),
+('bx_ads', '_bx_ads_et_txt_name_offer_declined', 'bx_ads_offer_declined', '_bx_ads_et_txt_subject_offer_declined', '_bx_ads_et_txt_body_offer_declined'),
+('bx_ads', '_bx_ads_et_txt_name_offer_canceled', 'bx_ads_offer_canceled', '_bx_ads_et_txt_subject_offer_canceled', '_bx_ads_et_txt_body_offer_canceled');

+ 908 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/install/sql/install.sql

@@ -0,0 +1,908 @@
+-- TABLE: entries
+CREATE TABLE IF NOT EXISTS `bx_ads_entries` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `author` int(11) NOT NULL,
+  `added` int(11) NOT NULL,
+  `changed` int(11) NOT NULL,
+  `sold` int(11) NOT NULL,
+  `shipped` int(11) NOT NULL,
+  `received` int(11) NOT NULL,
+  `category` int(11) NOT NULL,
+  `thumb` int(11) NOT NULL,
+  `name` varchar(255) NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `price` float NOT NULL,
+  `auction` tinyint(4) NOT NULL DEFAULT '0',
+  `quantity` int(11) NOT NULL default '1',
+  `year` int(11) NOT NULL,
+  `text` mediumtext NOT NULL,
+  `notes_purchased` text NOT NULL,
+  `labels` text NOT NULL,
+  `location` text NOT NULL,
+  `views` int(11) NOT NULL default '0',
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `rrate` float NOT NULL default '0',
+  `rvotes` 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',
+  `reviews` int(11) NOT NULL default '0',
+  `reviews_avg` float 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(16) NOT NULL DEFAULT '3',
+  `status` enum('active','awaiting','offer','sold','hidden') NOT NULL DEFAULT 'active',
+  `status_admin` enum('active','hidden','pending') NOT NULL DEFAULT 'active',
+  PRIMARY KEY (`id`),
+  FULLTEXT KEY `title_text` (`title`,`text`)
+);
+
+-- TABLE: types of categories
+CREATE TABLE IF NOT EXISTS `bx_ads_categories_types` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `name` varchar(64) NOT NULL DEFAULT '',
+  `title` varchar(255) NOT NULL DEFAULT '',
+  `display_add` varchar(255) NOT NULL DEFAULT '',
+  `display_edit` varchar(255) NOT NULL DEFAULT '',
+  `display_view` varchar(255) NOT NULL DEFAULT '',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `name` (`name`)
+);
+
+INSERT INTO `bx_ads_categories_types` (`id`, `name`, `title`, `display_add`, `display_edit`, `display_view`) VALUES
+(1, 'price', '_bx_ads_cat_type_price', 'bx_ads_entry_price_add', 'bx_ads_entry_price_edit', 'bx_ads_entry_price_view'),
+(2, 'price_year', '_bx_ads_cat_type_price_year', 'bx_ads_entry_price_year_add', 'bx_ads_entry_price_year_edit', 'bx_ads_entry_price_year_view');
+
+-- TABLE: categories
+CREATE TABLE IF NOT EXISTS `bx_ads_categories` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `parent_id` int(11) unsigned NOT NULL DEFAULT '0',
+  `level` tinyint(11) unsigned NOT NULL DEFAULT '0',
+  `type` int(11) NOT NULL DEFAULT '0',
+  `name` varchar(64) NOT NULL DEFAULT '',
+  `title` varchar(255) NOT NULL DEFAULT '',
+  `text` text NOT NULL,
+  `icon` varchar(255) NOT NULL DEFAULT '',
+  `items` int(11) NOT NULL DEFAULT '0',
+  `active` tinyint(4) NOT NULL DEFAULT '1',
+  `order` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `name` (`name`),
+  FULLTEXT KEY `title_text` (`title`,`text`)
+);
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(0, 0, 1, 'job', '_bx_ads_cat_title_job', '', 'user-md', 1, 1);
+SET @iParentId = LAST_INSERT_ID();
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(@iParentId, 1, 1, 'job_finance', '_bx_ads_cat_title_accounting_finance', '', '', 1, 1),
+(@iParentId, 1, 1, 'job_education', '_bx_ads_cat_title_education_nonprofit', '', '', 1, 2),
+(@iParentId, 1, 1, 'job_legal', '_bx_ads_cat_title_government_legal', '', '', 1, 3),
+(@iParentId, 1, 1, 'job_programming', '_bx_ads_cat_title_programming_web_design', '', '', 1, 4);
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(0, 0, 2, 'music', '_bx_ads_cat_title_music', '', 'music', 1, 2);
+SET @iParentId = LAST_INSERT_ID();
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(@iParentId, 1, 2, 'music_isale', '_bx_ads_cat_title_instrument_sale', '', '', 1, 1),
+(@iParentId, 1, 2, 'music_iwanted', '_bx_ads_cat_title_instrument_wanted', '', '', 1, 2);
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(0, 0, 1, 'housing', '_bx_ads_cat_title_housing', '', 'home', 1, 3);
+SET @iParentId = LAST_INSERT_ID();
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(@iParentId, 1, 1, 'housing_apartments', '_bx_ads_cat_title_apartments_housing', '', '', 1, 1),
+(@iParentId, 1, 1, 'housing_office', '_bx_ads_cat_title_office_commercial', '', '', 1, 2),
+(@iParentId, 1, 1, 'housing_re_sale', '_bx_ads_cat_title_real_estate_sale', '', '', 1, 3),
+(@iParentId, 1, 1, 'housing_roommate', '_bx_ads_cat_title_roommate', '', '', 1, 4),
+(@iParentId, 1, 1, 'housing_temp_rental', '_bx_ads_cat_title_temporary_rental', '', '', 1, 5);
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(0, 0, 1, 'service', '_bx_ads_cat_title_service', '', 'wrench', 1, 4);
+SET @iParentId = LAST_INSERT_ID();
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(@iParentId, 1, 1, 'service_automotive', '_bx_ads_cat_title_automotive', '', '', 1, 1),
+(@iParentId, 1, 1, 'service_educational', '_bx_ads_cat_title_educational', '', '', 1, 2),
+(@iParentId, 1, 1, 'service_financial', '_bx_ads_cat_title_financial', '', '', 1, 3),
+(@iParentId, 1, 1, 'service_labor', '_bx_ads_cat_title_labor_move', '', '', 1, 4),
+(@iParentId, 1, 1, 'service_legal', '_bx_ads_cat_title_legal', '', '', 1, 5);
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(0, 0, 1, 'casting', '_bx_ads_cat_title_casting', '', 'eye', 1, 5);
+SET @iParentId = LAST_INSERT_ID();
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(@iParentId, 1, 1, 'casting_acting', '_bx_ads_cat_title_acting', '', '', 1, 1),
+(@iParentId, 1, 1, 'casting_dance', '_bx_ads_cat_title_dance', '', '', 1, 2),
+(@iParentId, 1, 1, 'casting_modeling', '_bx_ads_cat_title_modeling', '', '', 1, 3),
+(@iParentId, 1, 1, 'casting_musician', '_bx_ads_cat_title_musician', '', '', 1, 4),
+(@iParentId, 1, 1, 'casting_rshow', '_bx_ads_cat_title_reality_show', '', '', 1, 5);
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(0, 0, 2, 'personal', '_bx_ads_cat_title_personal', '', 'user', 1, 6);
+SET @iParentId = LAST_INSERT_ID();
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(@iParentId, 1, 2, 'personal_mw', '_bx_ads_cat_title_men_women', '', '', 1, 1),
+(@iParentId, 1, 2, 'personal_wm', '_bx_ads_cat_title_women_men', '', '', 1, 2),
+(@iParentId, 1, 2, 'personal_missed', '_bx_ads_cat_title_missed_connection', '', '', 1, 3);
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(0, 0, 2, 'sale', '_bx_ads_cat_title_sale', '', 'shopping-cart', 1, 7);
+SET @iParentId = LAST_INSERT_ID();
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(@iParentId, 1, 2, 'sale_barter', '_bx_ads_cat_title_barter', '', '', 1, 1),
+(@iParentId, 1, 2, 'sale_clothing', '_bx_ads_cat_title_clothing', '', '', 1, 1),
+(@iParentId, 1, 2, 'sale_collectible', '_bx_ads_cat_title_collectible', '', '', 1, 1);
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(0, 0, 2, 'sale_car', '_bx_ads_cat_title_sale_car', '', 'truck', 1, 8);
+SET @iParentId = LAST_INSERT_ID();
+
+INSERT INTO `bx_ads_categories` (`parent_id`, `level`, `type`, `name`, `title`, `text`, `icon`, `active`, `order`) VALUES 
+(@iParentId, 1, 2, 'sale_car_part', '_bx_ads_cat_title_auto_part', '', '', 1, 1),
+(@iParentId, 1, 2, 'sale_car_auto', '_bx_ads_cat_title_auto_truck', '', '', 1, 2),
+(@iParentId, 1, 2, 'sale_car_motorcycle', '_bx_ads_cat_title_motorcycle', '', '', 1, 3);
+
+CREATE TABLE IF NOT EXISTS `bx_ads_interested_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `entry_id` int(11) NOT NULL default '0',
+  `profile_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `interested` (`entry_id`, `profile_id`)
+);
+
+-- TABLE: licenses
+CREATE TABLE IF NOT EXISTS `bx_ads_licenses` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `profile_id` int(11) unsigned NOT NULL default '0',
+  `entry_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 '',
+  `added` int(11) unsigned NOT NULL default '0',
+  `new` tinyint(1) NOT NULL default '1',
+  PRIMARY KEY (`id`),
+  KEY `product_id` (`entry_id`, `profile_id`),
+  KEY `license` (`license`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_ads_licenses_deleted` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `profile_id` int(11) unsigned NOT NULL default '0',
+  `entry_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 '',
+  `added` 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 `product_id` (`entry_id`,`profile_id`),
+  KEY `license` (`license`)
+);
+
+-- TABLE: storages & transcoders
+CREATE TABLE IF NOT EXISTS `bx_ads_covers` (
+  `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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_ads_files` (
+  `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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_ads_photos` (
+  `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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_ads_photos_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_ads_videos` (
+  `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 IF NOT EXISTS `bx_ads_videos_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_ads_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_ads_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: reviews
+CREATE TABLE IF NOT EXISTS `bx_ads_reviews` (
+  `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`)
+);
+
+-- TABLE: votes
+CREATE TABLE IF NOT EXISTS `bx_ads_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_ads_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_ads_reactions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `reaction` varchar(32) NOT NULL default '',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),    
+  UNIQUE KEY `reaction` (`object_id`, `reaction`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_ads_reactions_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',
+  `reaction` varchar(32) NOT NULL default '',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+-- TABLE: views
+CREATE TABLE IF NOT EXISTS `bx_ads_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: metas
+CREATE TABLE IF NOT EXISTS `bx_ads_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 IF NOT EXISTS `bx_ads_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_ads_meta_locations` (
+  `object_id` int(10) unsigned NOT NULL,
+  `lat` double NOT NULL,
+  `lng` double NOT NULL,
+  `country` varchar(2) NOT NULL,
+  `state` varchar(255) NOT NULL,
+  `city` varchar(255) NOT NULL,
+  `zip` varchar(255) NOT NULL,
+  `street` varchar(255) NOT NULL,
+  `street_number` varchar(255) NOT NULL,
+  PRIMARY KEY (`object_id`),
+  KEY `country_state_city` (`country`,`state`(8),`city`(8))
+);
+
+-- TABLE: reports
+CREATE TABLE IF NOT EXISTS `bx_ads_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_ads_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`)
+);
+
+-- TABLES: favorites
+CREATE TABLE IF NOT EXISTS `bx_ads_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',
+  `list_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+   PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`author_id`)
+);
+
+CREATE TABLE `bx_ads_favorites_lists` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `title` varchar(255) NOT NULL,
+  `author_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  `allow_view_favorite_list_to` varchar(16) NOT NULL DEFAULT '3',
+   PRIMARY KEY (`id`)
+);
+
+-- TABLE: scores
+CREATE TABLE IF NOT EXISTS `bx_ads_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_ads_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`)
+);
+
+-- TABLE: polls
+CREATE TABLE IF NOT EXISTS `bx_ads_polls` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `author_id` int(11) NOT NULL default '0',
+  `content_id` int(11) NOT NULL default '0',
+  `text` text NOT NULL,
+  PRIMARY KEY (`id`),
+  FULLTEXT KEY `search_fields` (`text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_ads_polls_answers` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `poll_id` int(11) unsigned NOT NULL default '0',
+  `title` varchar(255) NOT NULL,
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `order` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  FULLTEXT KEY `title` (`title`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_ads_polls_answers_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_ads_polls_answers_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: offers
+CREATE TABLE IF NOT EXISTS `bx_ads_offers` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `content_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `added` int(11) NOT NULL default '0',
+  `changed` int(11) NOT NULL default '0',
+  `amount` float NOT NULL default '0',
+  `quantity` int(11) NOT NULL default '0',
+  `message` text NOT NULL,
+  `status` enum('accepted','awaiting','declined','canceled') NOT NULL DEFAULT 'awaiting',
+  PRIMARY KEY (`id`)
+);
+
+
+-- STORAGES & TRANSCODERS
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+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_ads_covers', @sStorageEngine, '', 360, 2592000, 3, 'bx_ads_covers', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+
+('bx_ads_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_ads_photos', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+('bx_ads_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_ads_photos_resized', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+
+('bx_ads_videos', @sStorageEngine, 'a:1:{s:6:"fields";a:1:{s:10:"dimensions";s:17:"getFileDimensions";}}', 360, 2592000, 3, 'bx_ads_videos', 'allow-deny', '{video}', '', 0, 0, 0, 0, 0, 0),
+('bx_ads_videos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_ads_videos_resized', 'allow-deny', '{imagevideo}', '', 0, 0, 0, 0, 0, 0),
+
+('bx_ads_files', @sStorageEngine, '', 360, 2592000, 3, 'bx_ads_files', 'deny-allow', '', '{dangerous}', 0, 0, 0, 0, 0, 0);
+
+INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`, `override_class_name`, `override_class_file`) VALUES 
+('bx_ads_preview', 'bx_ads_photos_resized', 'Storage', 'a:1:{s:6:"object";s:13:"bx_ads_covers";}', 'no', '1', '2592000', '0', '', ''),
+('bx_ads_gallery', 'bx_ads_photos_resized', 'Storage', 'a:1:{s:6:"object";s:13:"bx_ads_covers";}', 'no', '1', '2592000', '0', '', ''),
+('bx_ads_cover', 'bx_ads_photos_resized', 'Storage', 'a:1:{s:6:"object";s:13:"bx_ads_covers";}', 'no', '1', '2592000', '0', '', ''),
+
+('bx_ads_preview_photos', 'bx_ads_photos_resized', 'Storage', 'a:1:{s:6:"object";s:13:"bx_ads_photos";}', 'no', '1', '2592000', '0', '', ''),
+('bx_ads_gallery_photos', 'bx_ads_photos_resized', 'Storage', 'a:1:{s:6:"object";s:13:"bx_ads_photos";}', 'no', '1', '2592000', '0', '', ''),
+('bx_ads_view_photos', 'bx_ads_photos_resized', 'Storage', 'a:1:{s:6:"object";s:13:"bx_ads_photos";}', 'no', '1', '2592000', '0', '', ''),
+
+('bx_ads_videos_poster', 'bx_ads_videos_resized', 'Storage', 'a:1:{s:6:"object";s:13:"bx_ads_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+('bx_ads_videos_poster_preview', 'bx_ads_videos_resized', 'Storage', 'a:1:{s:6:"object";s:13:"bx_ads_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+('bx_ads_videos_mp4', 'bx_ads_videos_resized', 'Storage', 'a:1:{s:6:"object";s:13:"bx_ads_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+('bx_ads_videos_mp4_hd', 'bx_ads_videos_resized', 'Storage', 'a:1:{s:6:"object";s:13:"bx_ads_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+
+('bx_ads_preview_files', 'bx_ads_photos_resized', 'Storage', 'a:1:{s:6:"object";s:12:"bx_ads_files";}', 'no', '1', '2592000', '0', '', ''),
+('bx_ads_gallery_files', 'bx_ads_photos_resized', 'Storage', 'a:1:{s:6:"object";s:12:"bx_ads_files";}', 'no', '1', '2592000', '0', '', '');
+
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES 
+('bx_ads_preview', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:11:"crop_resize";s:1:"1";}', '0'),
+('bx_ads_gallery', 'Resize', 'a:1:{s:1:"w";s:3:"500";}', '0'),
+('bx_ads_cover', 'Resize', 'a:1:{s:1:"w";s:4:"2000";}', '0'),
+
+('bx_ads_preview_photos', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:11:"crop_resize";s:1:"1";}', '0'),
+('bx_ads_gallery_photos', 'Resize', 'a:4:{s:1:"w";s:3:"600";s:1:"h";s:3:"600";s:13:"square_resize";s:1:"1";s:10:"force_type";s:3:"jpg";}', '0'),
+('bx_ads_view_photos', 'Resize',  'a:2:{s:1:"w";s:4:"2000";s:1:"h";s:4:"2000";}', '0'),
+
+('bx_ads_videos_poster_preview', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:13:"square_resize";s:1:"1";}', 10),
+('bx_ads_videos_poster_preview', 'Poster', 'a:2:{s:1:"h";s:3:"480";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_ads_videos_poster', 'Poster', 'a:2:{s:1:"h";s:3:"318";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_ads_videos_mp4', 'Mp4', 'a:2:{s:1:"h";s:3:"318";s:10:"force_type";s:3:"mp4";}', 0),
+('bx_ads_videos_mp4_hd', 'Mp4', 'a:3:{s:1:"h";s:3:"720";s:13:"video_bitrate";s:4:"1536";s:10:"force_type";s:3:"mp4";}', 0),
+
+('bx_ads_preview_files', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:11:"crop_resize";s:1:"1";}', '0'),
+('bx_ads_gallery_files', 'Resize', 'a:4:{s:1:"w";s:3:"600";s:1:"h";s:3:"600";s:13:"square_resize";s:1:"1";s:10:"force_type";s:3:"jpg";}', '0');
+
+
+-- FORMS: category
+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_ads_category', 'bx_ads', '_bx_ads_form_category', '', 'a:1:{s:7:"enctype";s:19:"multipart/form-data";}', 'bx_ads_categories', 'id', '', '', 'a:1:{i:0;s:9:"do_submit";}', '', 0, 1, 'BxAdsFormCategory', 'modules/boonex/ads/classes/BxAdsFormCategory.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_ads_category', 'bx_ads_category_add', 'bx_ads', 0, '_bx_ads_form_category_display_add'),
+('bx_ads_category', 'bx_ads_category_delete', 'bx_ads', 0, '_bx_ads_form_category_display_delete'),
+('bx_ads_category', 'bx_ads_category_edit', 'bx_ads', 0, '_bx_ads_form_category_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_ads_category', 'bx_ads', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_ads_form_category_input_sys_delete_confirm', '_bx_ads_form_category_input_delete_confirm', '_bx_ads_form_category_input_delete_confirm_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ads_form_category_input_delete_confirm_error', '', '', 1, 0),
+('bx_ads_category', 'bx_ads', 'parent_id', '', '', 0, 'select', '_bx_ads_form_category_input_sys_parent_id', '_bx_ads_form_category_input_parent_id', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_ads_category', 'bx_ads', 'title', '', '', 0, 'text_translatable', '_bx_ads_form_category_input_sys_title', '_bx_ads_form_category_input_title', '', 1, 0, 0, '', '', '', 'AvailTranslatable', 'a:1:{i:0;s:5:"title";}', '_bx_ads_form_category_input_title_err', 'Xss', '', 1, 0),
+('bx_ads_category', 'bx_ads', 'text', '', '', 0, 'textarea_translatable', '_bx_ads_form_category_input_sys_text', '_bx_ads_form_category_input_text', '', 0, 0, 2, '', '', '', '', '', '', 'XssHtml', '', 1, 0),
+('bx_ads_category', 'bx_ads', 'type', '', '', 0, 'select', '_bx_ads_form_category_input_sys_type', '_bx_ads_form_category_input_type', '_bx_ads_form_category_input_type_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ads_form_category_input_type_err', 'Int', '', 0, 0),
+('bx_ads_category', 'bx_ads', 'type_clone', 'on', '', 0, 'switcher', '_bx_ads_form_category_input_sys_type_clone', '_bx_ads_form_category_input_type_clone', '', 0, 0, 0, 'a:1:{s:8:"onchange";s:33:"oBxAdsStudio.onChangeClone(this);";}', '', '', '', '', '', '', '', 0, 0),
+('bx_ads_category', 'bx_ads', 'type_title', '', '', 0, 'text_translatable', '_bx_ads_form_category_input_sys_type_title', '_bx_ads_form_category_input_type_title', '', 0, 0, 0, 'a:1:{s:8:"disabled";s:8:"disabled";}', 'a:1:{s:5:"style";s:13:"display:none;";}', '', '', '', '', '', '', 0, 0),
+('bx_ads_category', 'bx_ads', 'icon', '', '', 0, 'text', '_bx_ads_form_category_input_sys_icon', '_bx_ads_form_category_input_icon', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_ads_category', 'bx_ads', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_ads_category', 'bx_ads', 'do_submit', '_bx_ads_form_category_input_do_submit', '', 0, 'submit', '_bx_ads_form_category_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_ads_category', 'bx_ads', 'do_cancel', '_bx_ads_form_category_input_do_cancel', '', 0, 'button', '_bx_ads_form_category_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_ads_category_add', 'parent_id', 2147483647, 1, 1),
+('bx_ads_category_add', 'type', 2147483647, 1, 2),
+('bx_ads_category_add', 'type_clone', 2147483647, 1, 3),
+('bx_ads_category_add', 'type_title', 2147483647, 1, 4),
+('bx_ads_category_add', 'title', 2147483647, 1, 5),
+('bx_ads_category_add', 'text', 2147483647, 1, 6),
+('bx_ads_category_add', 'icon', 2147483647, 1, 7),
+('bx_ads_category_add', 'controls', 2147483647, 1, 8),
+('bx_ads_category_add', 'do_submit', 2147483647, 1, 9),
+('bx_ads_category_add', 'do_cancel', 2147483647, 1, 10),
+
+('bx_ads_category_delete', 'delete_confirm', 2147483647, 1, 1),
+('bx_ads_category_delete', 'do_submit', 2147483647, 1, 2),
+
+('bx_ads_category_edit', 'parent_id', 2147483647, 1, 1),
+('bx_ads_category_edit', 'title', 2147483647, 1, 2),
+('bx_ads_category_edit', 'text', 2147483647, 1, 3),
+('bx_ads_category_edit', 'icon', 2147483647, 1, 4),
+('bx_ads_category_edit', 'controls', 2147483647, 1, 5),
+('bx_ads_category_edit', 'do_submit', 2147483647, 1, 6),
+('bx_ads_category_edit', 'do_cancel', 2147483647, 1, 7);
+
+
+-- FORMS: entry (ad)
+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_ads', 'bx_ads', '_bx_ads_form_entry', '', 'a:1:{s:7:"enctype";s:19:"multipart/form-data";}', 'bx_ads_entries', 'id', '', '', 'a:1:{i:0;s:9:"do_submit";}', '', 0, 1, 'BxAdsFormEntry', 'modules/boonex/ads/classes/BxAdsFormEntry.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_ads', 'bx_ads_entry_add', 'bx_ads', 0, '_bx_ads_form_entry_display_add'),
+('bx_ads', 'bx_ads_entry_delete', 'bx_ads', 0, '_bx_ads_form_entry_display_delete'),
+
+('bx_ads', 'bx_ads_entry_price_add', 'bx_ads', 0, '_bx_ads_form_entry_price_display_add'),
+('bx_ads', 'bx_ads_entry_price_edit', 'bx_ads', 0, '_bx_ads_form_entry_price_display_edit'),
+('bx_ads', 'bx_ads_entry_price_view', 'bx_ads', 1, '_bx_ads_form_entry_price_display_view'),
+
+('bx_ads', 'bx_ads_entry_price_year_add', 'bx_ads', 0, '_bx_ads_form_entry_price_year_display_add'),
+('bx_ads', 'bx_ads_entry_price_year_edit', 'bx_ads', 0, '_bx_ads_form_entry_price_year_display_edit'),
+('bx_ads', 'bx_ads_entry_price_year_view', 'bx_ads', 1, '_bx_ads_form_entry_price_year_display_view');
+
+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_ads', 'bx_ads', '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_ads', 'bx_ads', 'allow_view_to', '', '', 0, 'custom', '_bx_ads_form_entry_input_sys_allow_view_to', '_bx_ads_form_entry_input_allow_view_to', '', 1, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_ads_form_entry_input_sys_delete_confirm', '_bx_ads_form_entry_input_delete_confirm', '_bx_ads_form_entry_input_delete_confirm_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ads_form_entry_input_delete_confirm_error', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'do_submit', '_bx_ads_form_entry_input_do_submit', '', 0, 'submit', '_bx_ads_form_entry_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'location', '', '', 0, 'location', '_sys_form_input_sys_location', '_sys_form_input_location', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'covers', 'a:1:{i:0;s:12:"bx_ads_html5";}', 'a:1:{s:12:"bx_ads_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_ads_form_entry_input_sys_covers', '_bx_ads_form_entry_input_covers', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'pictures', 'a:1:{i:0;s:19:"bx_ads_photos_html5";}', 'a:1:{s:19:"bx_ads_photos_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_ads_form_entry_input_sys_pictures', '_bx_ads_form_entry_input_pictures', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'videos', 'a:2:{i:0;s:19:"bx_ads_videos_html5";i:1;s:26:"bx_ads_videos_record_video";}', 'a:2:{s:19:"bx_ads_videos_html5";s:25:"_sys_uploader_html5_title";s:26:"bx_ads_videos_record_video";s:32:"_sys_uploader_record_video_title";}', 0, 'files', '_bx_ads_form_entry_input_sys_videos', '_bx_ads_form_entry_input_videos', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'files', 'a:1:{i:0;s:18:"bx_ads_files_html5";}', 'a:1:{s:18:"bx_ads_files_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_ads_form_entry_input_sys_files', '_bx_ads_form_entry_input_files', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'polls', '', '', 0, 'custom', '_bx_ads_form_entry_input_sys_polls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'text', '', '', 0, 'textarea', '_bx_ads_form_entry_input_sys_text', '_bx_ads_form_entry_input_text', '', 1, 0, 2, '', '', '', 'Avail', '', '_bx_ads_form_entry_input_text_err', 'XssHtml', '', 1, 0),
+('bx_ads', 'bx_ads', 'title', '', '', 0, 'text', '_bx_ads_form_entry_input_sys_title', '_bx_ads_form_entry_input_title', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ads_form_entry_input_title_err', 'Xss', '', 1, 0),
+('bx_ads', 'bx_ads', 'name', '', '', 0, 'text', '_bx_ads_form_entry_input_sys_name', '_bx_ads_form_entry_input_name', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ads_form_entry_input_name_err', 'Xss', '', 1, 0),
+('bx_ads', 'bx_ads', 'price', '', '', 0, 'price', '_bx_ads_form_entry_input_sys_price', '_bx_ads_form_entry_input_price', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_ads', 'bx_ads', 'auction', 1, '', 0, 'checkbox', '_bx_ads_form_entry_input_sys_auction', '_bx_ads_form_entry_input_auction', '_bx_ads_form_entry_input_auction_info', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_ads', 'bx_ads', 'quantity', '', '', 0, 'text', '_bx_ads_form_entry_input_sys_quantity', '_bx_ads_form_entry_input_quantity', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ads_form_entry_input_quantity_err', 'Xss', '', 1, 0),
+('bx_ads', 'bx_ads', 'year', '', '', 0, 'text', '_bx_ads_form_entry_input_sys_year', '_bx_ads_form_entry_input_year', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_ads', 'bx_ads', 'category', '', '', 0, 'hidden', '_bx_ads_form_entry_input_sys_category', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_ads', 'bx_ads', 'category_view', '', '', 0, 'text', '_bx_ads_form_entry_input_sys_category_view', '_bx_ads_form_entry_input_category_view', '', 0, 0, 0, 'a:1:{s:8:"disabled";s:8:"disabled";}', '', '', '', '', '', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'category_select', '', '', 0, 'select', '_bx_ads_form_entry_input_sys_category_select', '_bx_ads_form_entry_input_category_select', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ads_form_entry_input_category_select_err', 'Int', '', 0, 0),
+('bx_ads', 'bx_ads', 'notes_purchased', '', '', 0, 'textarea', '_bx_ads_form_entry_input_sys_notes_purchased', '_bx_ads_form_entry_input_notes_purchased', '_bx_ads_form_entry_input_notes_purchased_inf', 0, 0, 3, '', '', '', '', '', '', 'XssHtml', '', 1, 0),
+('bx_ads', 'bx_ads', 'added', '', '', 0, 'datetime', '_bx_ads_form_entry_input_sys_date_added', '_bx_ads_form_entry_input_date_added', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'changed', '', '', 0, 'datetime', '_bx_ads_form_entry_input_sys_date_changed', '_bx_ads_form_entry_input_date_changed', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'attachments', '', '', 0, 'custom', '_bx_ads_form_entry_input_sys_attachments', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_ads', 'bx_ads', 'labels', '', '', 0, 'custom', '_sys_form_input_sys_labels', '_sys_form_input_labels', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0);
+
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_ads_entry_add', 'category_select', 2147483647, 1, 1),
+('bx_ads_entry_add', 'do_submit', 2147483647, 1, 2),
+
+('bx_ads_entry_delete', 'delete_confirm', 2147483647, 1, 1),
+('bx_ads_entry_delete', 'do_submit', 2147483647, 1, 2),
+
+('bx_ads_entry_price_add', 'category', 2147483647, 1, 1),
+('bx_ads_entry_price_add', 'category_view', 2147483647, 1, 2),
+('bx_ads_entry_price_add', 'title', 2147483647, 1, 3),
+('bx_ads_entry_price_add', 'name', 2147483647, 1, 4),
+('bx_ads_entry_price_add', 'price', 2147483647, 1, 5),
+('bx_ads_entry_price_add', 'auction', 2147483647, 1, 6),
+('bx_ads_entry_price_add', 'quantity', 2147483647, 1, 7),
+('bx_ads_entry_price_add', 'text', 2147483647, 1, 8),
+('bx_ads_entry_price_add', 'attachments', 2147483647, 1, 9),
+('bx_ads_entry_price_add', 'pictures', 2147483647, 1, 10),
+('bx_ads_entry_price_add', 'videos', 2147483647, 1, 11),
+('bx_ads_entry_price_add', 'files', 2147483647, 1, 12),
+('bx_ads_entry_price_add', 'polls', 2147483647, 1, 13),
+('bx_ads_entry_price_add', 'covers', 2147483647, 1, 14),
+('bx_ads_entry_price_add', 'allow_view_to', 2147483647, 1, 15),
+('bx_ads_entry_price_add', 'cf', 2147483647, 1, 16),
+('bx_ads_entry_price_add', 'notes_purchased', 2147483647, 1, 17),
+('bx_ads_entry_price_add', 'location', 2147483647, 1, 18),
+('bx_ads_entry_price_add', 'do_submit', 2147483647, 1, 19),
+
+('bx_ads_entry_price_edit', 'category_view', 2147483647, 1, 1),
+('bx_ads_entry_price_edit', 'title', 2147483647, 1, 2),
+('bx_ads_entry_price_edit', 'name', 2147483647, 1, 3),
+('bx_ads_entry_price_edit', 'price', 2147483647, 1, 4),
+('bx_ads_entry_price_edit', 'auction', 2147483647, 1, 5),
+('bx_ads_entry_price_edit', 'quantity', 2147483647, 1, 6),
+('bx_ads_entry_price_edit', 'text', 2147483647, 1, 7),
+('bx_ads_entry_price_edit', 'attachments', 2147483647, 1, 8),
+('bx_ads_entry_price_edit', 'pictures', 2147483647, 1, 9),
+('bx_ads_entry_price_edit', 'videos', 2147483647, 1, 10),
+('bx_ads_entry_price_edit', 'files', 2147483647, 1, 11),
+('bx_ads_entry_price_edit', 'polls', 2147483647, 1, 12),
+('bx_ads_entry_price_edit', 'covers', 2147483647, 1, 13),
+('bx_ads_entry_price_edit', 'allow_view_to', 2147483647, 1, 14),
+('bx_ads_entry_price_edit', 'cf', 2147483647, 1, 15),
+('bx_ads_entry_price_edit', 'notes_purchased', 2147483647, 1, 16),
+('bx_ads_entry_price_edit', 'location', 2147483647, 1, 17),
+('bx_ads_entry_price_edit', 'do_submit', 2147483647, 1, 18),
+
+('bx_ads_entry_price_view', 'category_view', 2147483647, 1, 1),
+('bx_ads_entry_price_view', 'price', 2147483647, 1, 2),
+('bx_ads_entry_price_view', 'added', 2147483647, 1, 3),
+('bx_ads_entry_price_view', 'changed', 2147483647, 1, 4),
+
+('bx_ads_entry_price_year_add', 'category', 2147483647, 1, 1),
+('bx_ads_entry_price_year_add', 'category_view', 2147483647, 1, 2),
+('bx_ads_entry_price_year_add', 'title', 2147483647, 1, 3),
+('bx_ads_entry_price_year_add', 'name', 2147483647, 1, 4),
+('bx_ads_entry_price_year_add', 'price', 2147483647, 1, 5),
+('bx_ads_entry_price_year_add', 'auction', 2147483647, 1, 6),
+('bx_ads_entry_price_year_add', 'quantity', 2147483647, 1, 7),
+('bx_ads_entry_price_year_add', 'year', 2147483647, 1, 8),
+('bx_ads_entry_price_year_add', 'text', 2147483647, 1, 9),
+('bx_ads_entry_price_year_add', 'attachments', 2147483647, 1, 10),
+('bx_ads_entry_price_year_add', 'pictures', 2147483647, 1, 11),
+('bx_ads_entry_price_year_add', 'videos', 2147483647, 1, 12),
+('bx_ads_entry_price_year_add', 'files', 2147483647, 1, 13),
+('bx_ads_entry_price_year_add', 'polls', 2147483647, 1, 14),
+('bx_ads_entry_price_year_add', 'covers', 2147483647, 1, 15),
+('bx_ads_entry_price_year_add', 'allow_view_to', 2147483647, 1, 16),
+('bx_ads_entry_price_year_add', 'cf', 2147483647, 1, 17),
+('bx_ads_entry_price_year_add', 'notes_purchased', 2147483647, 1, 18),
+('bx_ads_entry_price_year_add', 'location', 2147483647, 1, 19),
+('bx_ads_entry_price_year_add', 'do_submit', 2147483647, 1, 20),
+
+('bx_ads_entry_price_year_edit', 'category_view', 2147483647, 1, 1),
+('bx_ads_entry_price_year_edit', 'title', 2147483647, 1, 2),
+('bx_ads_entry_price_year_edit', 'name', 2147483647, 1, 3),
+('bx_ads_entry_price_year_edit', 'price', 2147483647, 1, 4),
+('bx_ads_entry_price_year_edit', 'auction', 2147483647, 1, 5),
+('bx_ads_entry_price_year_edit', 'quantity', 2147483647, 1, 6),
+('bx_ads_entry_price_year_edit', 'year', 2147483647, 1, 7),
+('bx_ads_entry_price_year_edit', 'text', 2147483647, 1, 8),
+('bx_ads_entry_price_year_edit', 'attachments', 2147483647, 1, 9),
+('bx_ads_entry_price_year_edit', 'pictures', 2147483647, 1, 10),
+('bx_ads_entry_price_year_edit', 'videos', 2147483647, 1, 11),
+('bx_ads_entry_price_year_edit', 'files', 2147483647, 1, 12),
+('bx_ads_entry_price_year_edit', 'polls', 2147483647, 1, 13),
+('bx_ads_entry_price_year_edit', 'covers', 2147483647, 1, 14),
+('bx_ads_entry_price_year_edit', 'allow_view_to', 2147483647, 1, 15),
+('bx_ads_entry_price_year_edit', 'cf', 2147483647, 1, 16),
+('bx_ads_entry_price_year_edit', 'notes_purchased', 2147483647, 1, 17),
+('bx_ads_entry_price_year_edit', 'location', 2147483647, 1, 18),
+('bx_ads_entry_price_year_edit', 'do_submit', 2147483647, 1, 19),
+
+('bx_ads_entry_price_year_view', 'category_view', 2147483647, 1, 1),
+('bx_ads_entry_price_year_view', 'price', 2147483647, 1, 2),
+('bx_ads_entry_price_year_view', 'quantity', 2147483647, 1, 3),
+('bx_ads_entry_price_year_view', 'year', 2147483647, 1, 4),
+('bx_ads_entry_price_year_view', 'added', 2147483647, 1, 5),
+('bx_ads_entry_price_year_view', 'changed', 2147483647, 1, 6);
+
+-- FORMS: poll
+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_ads_poll', 'bx_ads', '_bx_ads_form_poll', '', '', 'do_submit', 'bx_ads_polls', 'id', '', '', 'a:1:{s:14:"checker_helper";s:26:"BxAdsFormPollCheckerHelper";}', 0, 1, 'BxAdsFormPoll', 'modules/boonex/ads/classes/BxAdsFormPoll.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_ads_poll_add', 'bx_ads', 'bx_ads_poll', '_bx_ads_form_poll_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_ads_poll', 'bx_ads', 'text', '', '', 0, 'text', '_bx_ads_form_poll_input_sys_text', '_bx_ads_form_poll_input_text', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ads_form_poll_input_text_err', 'Xss', '', 1, 0),
+('bx_ads_poll', 'bx_ads', 'answers', '', '', 0, 'custom', '_bx_ads_form_poll_input_sys_answers', '_bx_ads_form_poll_input_answers', '', 1, 0, 0, '', '', '', 'AvailAnswers', '', '_bx_ads_form_poll_input_answers_err', '', '', 1, 0),
+('bx_ads_poll', 'bx_ads', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_ads_poll', 'bx_ads', 'do_submit', '_bx_ads_form_poll_input_do_submit', '', 0, 'submit', '_bx_ads_form_poll_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_ads_poll', 'bx_ads', 'do_cancel', '_bx_ads_form_poll_input_do_cancel', '', 0, 'button', '_bx_ads_form_poll_input_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";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_ads_poll_add', 'text', 2147483647, 1, 1),
+('bx_ads_poll_add', 'answers', 2147483647, 1, 2),
+('bx_ads_poll_add', 'controls', 2147483647, 1, 3),
+('bx_ads_poll_add', 'do_submit', 2147483647, 1, 4),
+('bx_ads_poll_add', 'do_cancel', 2147483647, 1, 5);
+
+-- FORMS: offer
+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_ads_offer', 'bx_ads', '_bx_ads_form_offer', '', '', 'do_submit', 'bx_ads_offers', 'id', '', '', '', 0, 1, 'BxAdsFormOffer', 'modules/boonex/ads/classes/BxAdsFormOffer.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_ads_offer_add', 'bx_ads', 'bx_ads_offer', '_bx_ads_form_offer_display_add', 0),
+('bx_ads_offer_view', 'bx_ads', 'bx_ads_offer', '_bx_ads_form_offer_display_view', 1);
+
+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_ads_offer', 'bx_ads', 'amount', '', '', 0, 'text', '_bx_ads_form_offer_input_sys_amount', '_bx_ads_form_offer_input_amount', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ads_form_offer_input_amount_err', 'Xss', '', 1, 0),
+('bx_ads_offer', 'bx_ads', 'quantity', '1', '', 0, 'text', '_bx_ads_form_offer_input_sys_quantity', '_bx_ads_form_offer_input_quantity', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ads_form_offer_input_quantity_err', 'Xss', '', 1, 0),
+('bx_ads_offer', 'bx_ads', 'message', '', '', 0, 'textarea', '_bx_ads_form_offer_input_sys_message', '_bx_ads_form_offer_input_message', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_ads_offer', 'bx_ads', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_ads_offer', 'bx_ads', 'do_submit', '_bx_ads_form_offer_input_do_submit', '', 0, 'submit', '_bx_ads_form_offer_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_ads_offer', 'bx_ads', 'do_cancel', '_bx_ads_form_offer_input_do_cancel', '', 0, 'button', '_bx_ads_form_offer_input_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";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_ads_offer_add', 'amount', 2147483647, 1, 1),
+('bx_ads_offer_add', 'quantity', 2147483647, 1, 2),
+('bx_ads_offer_add', 'message', 2147483647, 1, 3),
+('bx_ads_offer_add', 'controls', 2147483647, 1, 4),
+('bx_ads_offer_add', 'do_submit', 2147483647, 1, 5),
+('bx_ads_offer_add', 'do_cancel', 2147483647, 1, 6),
+
+('bx_ads_offer_view', 'amount', 2147483647, 1, 1),
+('bx_ads_offer_view', 'quantity', 2147483647, 1, 2),
+('bx_ads_offer_view', 'message', 2147483647, 1, 3);
+
+
+-- 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_ads', 'bx_ads', 'bx_ads_cmts', 1, 5000, 1000, 3, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-ad&id={object_id}', '', 'bx_ads_entries', 'id', 'author', 'title', 'comments', '', ''),
+('bx_ads_notes', 'bx_ads', 'bx_ads_cmts_notes', 1, 5000, 1000, 0, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-ad&id={object_id}', '', 'bx_ads_entries', 'id', 'author', 'title', '', 'BxTemplCmtsNotes', ''),
+('bx_ads_reviews', 'bx_ads', 'bx_ads_reviews', 1, 5000, 1000, 3, 5, 3, 'tail', 1, 'bottom', 1, 0, 1, -3, 1, 'cmt', 'page.php?i=view-ad&id={object_id}', '', 'bx_ads_entries', 'id', 'author', 'title', 'reviews', 'BxTemplCmtsReviews', '');
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_ads', 'bx_ads_votes', 'bx_ads_votes_track', '604800', '1', '1', '0', '1', 'bx_ads_entries', 'id', 'author', 'rate', 'votes', '', ''),
+('bx_ads_reactions', 'bx_ads_reactions', 'bx_ads_reactions_track', '604800', '1', '1', '1', '1', 'bx_ads_entries', 'id', 'author', 'rrate', 'rvotes', 'BxTemplVoteReactions', ''),
+('bx_ads_poll_answers', 'bx_ads_polls_answers_votes', 'bx_ads_polls_answers_votes_track', '604800', '1', '1', '0', '1', 'bx_ads_polls_answers', 'id', 'author_id', 'rate', 'votes', 'BxAdsVotePollAnswers', 'modules/boonex/ads/classes/BxAdsVotePollAnswers.php');
+
+-- 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_ads', 'bx_ads', 'bx_ads_scores', 'bx_ads_scores_track', '604800', '0', 'bx_ads_entries', '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_ads', 'bx_ads', 'bx_ads_reports', 'bx_ads_reports_track', '1', 'page.php?i=view-ad&id={object_id}', 'bx_ads_notes', 'bx_ads_entries', 'id', 'author', 'reports', '', '');
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_ads', 'bx_ads_views_track', '86400', '1', 'bx_ads_entries', 'id', 'author', 'views', '', '');
+
+-- FAFORITES
+INSERT INTO `sys_objects_favorite` (`name`, `table_track`, `table_lists`, `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_ads', 'bx_ads_favorites_track', 'bx_ads_favorites_lists', '1', '1', '1', 'page.php?i=view-ad&id={object_id}', 'bx_ads_entries', '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_ads', 'bx_ads', '1', '1', 'page.php?i=view-ad&id={object_id}', 'bx_ads_entries', '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_ads', '_bx_ads', 'bx_ads', 'added', 'edited', 'deleted', '', ''),
+('bx_ads_cmts', '_bx_ads_cmts', 'bx_ads', 'commentPost', 'commentUpdated', 'commentRemoved', 'BxDolContentInfoCmts', ''),
+('bx_ads_reviews', '_bx_ads_reviews', 'bx_ads_reviews', 'commentPost', 'commentUpdated', 'commentRemoved', 'BxDolContentInfoCmts', '');
+
+INSERT INTO `sys_content_info_grids` (`object`, `grid_object`, `grid_field_id`, `condition`, `selection`) VALUES
+('bx_ads', 'bx_ads_administration', 'id', '', ''),
+('bx_ads', 'bx_ads_common', 'id', '', '');
+
+-- SEARCH EXTENDED
+INSERT INTO `sys_objects_search_extended` (`object`, `object_content_info`, `module`, `title`, `active`, `class_name`, `class_file`) VALUES
+('bx_ads', 'bx_ads', 'bx_ads', '_bx_ads_search_extended', 1, '', ''),
+('bx_ads_cmts', 'bx_ads_cmts', 'bx_ads', '_bx_ads_search_extended_cmts', 1, 'BxTemplSearchExtendedCmts', ''),
+('bx_ads_reviews', 'bx_ads_reviews', 'bx_ads', '_bx_ads_search_extended_reviews', 1, 'BxTemplSearchExtendedCmts', '');
+
+-- STUDIO: page & widget
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_ads', '_bx_ads', '_bx_ads', 'bx_ads@modules/boonex/ads/|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_ads', 'content', '{url_studio}module.php?name=bx_ads', '', 'bx_ads@modules/boonex/ads/|std-icon.svg', '_bx_ads', '', '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/ads/updates/13.0.5_13.0.6/source/install/sql/uninstall.sql

@@ -0,0 +1,51 @@
+
+-- TABLES
+DROP TABLE IF EXISTS `bx_ads_entries`, `bx_ads_categories_types`, `bx_ads_categories`, `bx_ads_interested_track`, `bx_ads_licenses`, `bx_ads_licenses_deleted`, `bx_ads_covers`, `bx_ads_files`, `bx_ads_photos`, `bx_ads_photos_resized`, `bx_ads_videos`, `bx_ads_videos_resized`, `bx_ads_cmts`, `bx_ads_cmts_notes`, `bx_ads_reviews`, `bx_ads_votes`, `bx_ads_votes_track`, `bx_ads_reactions`, `bx_ads_reactions_track`, `bx_ads_views_track`, `bx_ads_meta_keywords`, `bx_ads_meta_locations`, `bx_ads_meta_mentions`, `bx_ads_reports`, `bx_ads_reports_track`, `bx_ads_favorites_track`, `bx_ads_favorites_lists`, `bx_ads_scores`, `bx_ads_scores_track`, `bx_ads_polls`, `bx_ads_polls_answers`, `bx_ads_polls_answers_votes`, `bx_ads_polls_answers_votes_track`, `bx_ads_offers`;
+
+-- STORAGES & TRANSCODERS
+DELETE FROM `sys_objects_storage` WHERE `object` LIKE 'bx_ads_%';
+DELETE FROM `sys_storage_tokens` WHERE `object` LIKE 'bx_ads_%';
+
+DELETE FROM `sys_objects_transcoder` WHERE `object` LIKE 'bx_ads_%';
+DELETE FROM `sys_transcoder_filters` WHERE `transcoder_object` LIKE 'bx_ads_%';
+DELETE FROM `sys_transcoder_images_files` WHERE `transcoder_object` LIKE 'bx_ads_%';
+
+-- FORMS
+DELETE FROM `sys_objects_form` WHERE `module` = 'bx_ads';
+DELETE FROM `sys_form_displays` WHERE `module` = 'bx_ads';
+DELETE FROM `sys_form_inputs` WHERE `module` = 'bx_ads';
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` LIKE 'bx_ads_%';
+
+-- COMMENTS
+DELETE FROM `sys_objects_cmts` WHERE `Name` LIKE 'bx_ads%';
+
+-- VOTES
+DELETE FROM `sys_objects_vote` WHERE `Name` LIKE 'bx_ads%';
+
+-- SCORES
+DELETE FROM `sys_objects_score` WHERE `name` = 'bx_ads';
+
+-- REPORTS
+DELETE FROM `sys_objects_report` WHERE `name` = 'bx_ads';
+
+-- VIEWS
+DELETE FROM `sys_objects_view` WHERE `name` = 'bx_ads';
+
+-- FAFORITES
+DELETE FROM `sys_objects_favorite` WHERE `name` = 'bx_ads';
+
+-- FEATURED
+DELETE FROM `sys_objects_feature` WHERE `name` = 'bx_ads';
+
+-- CONTENT INFO
+DELETE FROM `sys_objects_content_info` WHERE `name` LIKE 'bx_ads%';
+
+DELETE FROM `sys_content_info_grids` WHERE `object` LIKE 'bx_ads%';
+
+-- SEARCH EXTENDED
+DELETE FROM `sys_objects_search_extended` WHERE `module` = 'bx_ads';
+
+-- 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_ads';

+ 117 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/js/entry.js

@@ -0,0 +1,117 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Ads Ads
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxAdsEntry(oOptions) {
+    this._sActionsUri = oOptions.sActionUri;
+    this._sActionsUrl = oOptions.sActionUrl;
+    this._sObjName = oOptions.sObjName == undefined ? 'oBxAdsEntry' : oOptions.sObjName;
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'slide' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+    this._aHtmlIds = oOptions.aHtmlIds == undefined ? {} : oOptions.aHtmlIds;
+    this._oRequestParams = oOptions.oRequestParams == undefined ? {} : oOptions.oRequestParams;
+}
+
+BxAdsEntry.prototype.interested = function(oElement, iContentId) {
+    this._performAction(oElement, 'interested', iContentId);
+};
+
+BxAdsEntry.prototype.show = function(oElement, iContentId) {
+    this._performAction(oElement, 'show', iContentId);
+};
+
+BxAdsEntry.prototype.hide = function(oElement, iContentId) {
+    this._performAction(oElement, 'hide', iContentId);
+};
+
+BxAdsEntry.prototype.makeOffer = function(oElement, iContentId) {
+    this._performAction(oElement, 'make_offer', iContentId, 'content_id');
+};
+
+BxAdsEntry.prototype.onMakeOffer = function(oData) {};
+
+BxAdsEntry.prototype.viewOffer = function(oElement, iOfferId) {
+    this._performAction(oElement, 'view_offer', iOfferId);
+};
+
+BxAdsEntry.prototype.acceptOffer = function(oElement, iOfferId) {
+    var $this = this;
+
+    bx_confirm('', function() {
+        $this._performAction(oElement, 'accept_offer', iOfferId);
+    });
+};
+
+BxAdsEntry.prototype.declineOffer = function(oElement, iOfferId) {
+    var $this = this;
+
+    bx_confirm('', function() {
+        $this._performAction(oElement, 'decline_offer', iOfferId);
+    });
+};
+
+BxAdsEntry.prototype.cancelOffer = function(oElement, iOfferId) {
+    var $this = this;
+
+    bx_confirm('', function() {
+        $this._performAction(oElement, 'cancel_offer', iOfferId);
+    });
+};
+
+BxAdsEntry.prototype.payOffer = function(oElement, iOfferId) {
+    this._performAction(oElement, 'pay_offer', iOfferId);
+};
+
+BxAdsEntry.prototype.shipped = function(oElement, iContentId) {
+    this._performAction(oElement, 'shipped', iContentId);
+};
+
+BxAdsEntry.prototype.received = function(oElement, iContentId) {
+    this._performAction(oElement, 'received', iContentId);
+};
+
+BxAdsEntry.prototype.loadingInButton = function(e, bShow) {
+    if($(e).length)
+        bx_loading_btn($(e), bShow);
+    else
+        bx_loading($('body'), bShow);	
+};
+
+BxAdsEntry.prototype.loadingInBox = function(e, bShow) {
+    var oParent = $(e).length ? $(e).parents('.bx-base-text-poll:first') : $('body'); 
+    bx_loading(oParent, bShow);
+};
+
+BxAdsEntry.prototype._performAction = function(oElement, sAction, iContentId, sContentIdKey) {
+    var $this = this;
+    var oParams = this._getDefaultData();
+    oParams[sContentIdKey ? sContentIdKey : 'id'] = iContentId;
+
+    if(oElement)
+        this.loadingInButton(oElement, true);
+
+    jQuery.get (
+        this._sActionsUrl + sAction,
+        oParams,
+        function(oData) {
+            if(oElement)
+                $this.loadingInButton(oElement, false);
+
+            processJsonData(oData);
+        },
+        'json'
+    );
+};
+
+BxAdsEntry.prototype._getDefaultData = function() {
+    var oDate = new Date();
+    return jQuery.extend({}, this._oRequestParams, {_t:oDate.getTime()});
+};
+
+/** @} */

+ 111 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/js/form.js

@@ -0,0 +1,111 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Ads Ads
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxAdsForm(oOptions) {
+    this._sActionsUri = oOptions.sActionUri;
+    this._sActionsUrl = oOptions.sActionUrl;
+    this._sObjName = oOptions.sObjName == undefined ? 'oBxAdsForm' : oOptions.sObjName;
+    this._iOwnerId = oOptions.iOwnerId == undefined ? 0 : oOptions.iOwnerId;
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'slide' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+    this._aHtmlIds = oOptions.aHtmlIds == undefined ? {} : oOptions.aHtmlIds;
+    this._oRequestParams = oOptions.oRequestParams == undefined ? {} : oOptions.oRequestParams;
+}
+
+BxAdsForm.prototype.selectCategory = function(oButton) {   
+    var oCategory = $(oButton).parents('form:first').find("[name='category_select']");
+    if(!oCategory || oCategory.length == 0)
+        return;
+
+    var $this = this;
+    var oParams = this._getDefaultData();
+    oParams['category'] = oCategory.val();
+
+    this.loadingInBlock(oButton, true);
+
+    jQuery.get (
+        this._sActionsUrl + 'get_category_form',
+        oParams,
+        function(oData) {
+            if(oButton)
+                $this.loadingInBlock(oButton, false);
+
+            processJsonData(oData);
+        },
+        'json'
+    );
+};
+
+BxAdsForm.prototype.onSelectCategory = function(oData) {
+    if(!oData || !oData.content && oData.content.length == 0) 
+        return;
+
+    var oContent = $(oData.content);
+    var sFormId = oContent.filter('form').attr('id');
+    if(!sFormId)
+        return;
+
+    $('form#' + sFormId).replaceWith(oContent);
+};
+
+BxAdsForm.prototype.checkName = function(oSource, sTitleId, sNameId, iId) {
+    var oDate = new Date();
+    var oForm = jQuery(oSource).parents('.bx-form-advanced:first');
+
+    var oName = oForm.find("[name='" + sNameId + "']");
+    var sName = oName.val();
+    var bName = sName.length != 0;
+
+    var oTitle = oForm.find("[name='" + sTitleId + "']");
+    var sTitle = oTitle.val();
+    var bTitle = sTitle.length != 0;
+
+    if(!bName && !bTitle)
+        return;
+
+    var sTitleCheck = '';
+    if(bName)
+        sTitleCheck = sName;
+    else if(bTitle) {
+        sTitleCheck = sTitle;
+
+        sTitle = sTitle.replace(/[^A-Za-z0-9_]/g, '-');
+        sTitle = sTitle.replace(/[-]{2,}/g, '-');
+        oName.val(sTitle);
+    }
+
+    jQuery.get(
+        this._sActionsUrl + 'check_name',
+        {
+            title: sTitleCheck,
+            id: iId && parseInt(iId) > 0 ? iId : 0,
+            _t: oDate.getTime()
+        },
+        function(oData) {
+            if(!oData || oData.name == undefined)
+                return;
+
+            oName.val(oData.name);
+        },
+        'json'
+    );
+};
+
+BxAdsForm.prototype.loadingInBlock = function(e, bShow) {
+    var oParent = $(e).length ? $(e).parents('.bx-db-container:first') : $('body'); 
+    bx_loading(oParent, bShow);
+};
+
+BxAdsForm.prototype._getDefaultData = function() {
+    var oDate = new Date();
+    return jQuery.extend({}, this._oRequestParams, {_t:oDate.getTime()});
+};
+
+/** @} */

+ 30 - 0
modules/boonex/ads/updates/13.0.5_13.0.6/source/template/images/icons/std-icon.svg

@@ -0,0 +1,30 @@
+<svg width="320" height="320" viewBox="0 0 320 320" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_922_6670)">
+<path d="M160 0C281.326 0 320 38.6737 320 160C320 281.326 281.326 320 160 320C38.6736 320 0 281.326 0 160C0 38.6737 38.6736 0 160 0Z" fill="url(#paint0_linear_922_6670)"/>
+<path d="M160 2C220.573 2 259.85 11.6833 284.083 35.9168C308.317 60.1504 318 99.4272 318 160C318 220.573 308.317 259.85 284.083 284.083C259.85 308.317 220.573 318 160 318C99.4272 318 60.1504 308.317 35.9168 284.083C11.6833 259.85 2 220.573 2 160C2 99.4272 11.6833 60.1504 35.9168 35.9168C60.1504 11.6833 99.4272 2 160 2Z" stroke="#0F172A" stroke-opacity="0.2" stroke-width="4"/>
+<g clip-path="url(#clip1_922_6670)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M93.3463 153.225C92.6673 150.479 89.948 148.665 87.23 149.447C60.5372 157.129 50.9995 175.183 50.9995 209.799C50.9995 259.088 70.3364 274.799 131 274.799C191.663 274.799 211 259.088 211 209.799C211 207.835 210.969 205.924 210.906 204.065C210.811 201.267 208.354 199.184 205.56 199.372C199.2 199.798 192.356 200 185 200C176.217 200 168.164 199.712 160.793 199.098C156.644 198.752 153.655 203.24 155.737 206.846L167.373 227C170.452 232.333 166.603 239 160.445 239H101.555C95.3967 239 91.5477 232.333 94.6269 227L114.895 191.894C116.265 189.522 115.451 186.512 113.236 184.901C103.166 177.577 96.8156 167.254 93.3463 153.225Z" fill="url(#paint1_linear_922_6670)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M185 190C249.455 190 270 173.08 270 120C270 66.9197 249.455 50 185 50C120.545 50 100 66.9197 100 120C100 173.08 120.545 190 185 190ZM199.303 94.9805L192.174 80.5359C189.239 74.5899 180.761 74.5899 177.826 80.5359L170.697 94.9805C169.532 97.3416 167.279 98.9782 164.674 99.3568L148.733 101.673C142.171 102.627 139.551 110.69 144.299 115.319L155.834 126.562C157.72 128.4 158.58 131.048 158.135 133.643L155.412 149.519C154.291 156.055 161.151 161.038 167.02 157.953L181.277 150.457C183.608 149.232 186.392 149.232 188.723 150.457L202.98 157.953C208.849 161.038 215.709 156.055 214.588 149.519L211.865 133.643C211.42 131.048 212.28 128.4 214.166 126.562L225.701 115.319C230.449 110.69 227.829 102.627 221.267 101.673L205.326 99.3568C202.721 98.9782 200.468 97.3416 199.303 94.9805Z" fill="url(#paint2_linear_922_6670)"/>
+</g>
+</g>
+<defs>
+<linearGradient id="paint0_linear_922_6670" x1="160" y1="0" x2="160" y2="320" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F8FAFC"/>
+<stop offset="1" stop-color="#E2E8F0"/>
+</linearGradient>
+<linearGradient id="paint1_linear_922_6670" x1="131" y1="149.265" x2="131" y2="274.799" gradientUnits="userSpaceOnUse">
+<stop stop-color="#7DD3FC"/>
+<stop offset="1" stop-color="#0EA5E9"/>
+</linearGradient>
+<linearGradient id="paint2_linear_922_6670" x1="185" y1="50" x2="185" y2="190" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FB923C"/>
+<stop offset="1" stop-color="#EA580C"/>
+</linearGradient>
+<clipPath id="clip0_922_6670">
+<rect width="320" height="320" fill="white"/>
+</clipPath>
+<clipPath id="clip1_922_6670">
+<rect width="240" height="240" fill="white" transform="translate(40 40)"/>
+</clipPath>
+</defs>
+</svg>

+ 68 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/install/config.php

@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Albums',
+    'version_from' => '13.0.3',
+    'version_to' => '13.0.4',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.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_13.0.3_13.0.4/',
+    'home_uri' => 'albums_update_1303_1304',
+
+    'module_dir' => 'boonex/albums/',
+    'module_uri' => 'albums',
+
+    'db_prefix' => 'bx_albums_',
+    'class_prefix' => 'BxAlbums',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Albums',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(
+        'classes/BxAlbumsUploaderSimple.php',
+        'template/css/manage_tools.css',
+        'template/attachments.html',
+        'template/author.html',
+        'template/author_link.html',
+        'template/comments-item.html',
+        'template/context.html',
+        'template/entry-all-actions.html',
+        'template/entry-location.html',
+        'template/entry-share.html',
+        'template/entry-text.html',
+        'template/favorite-list-info.html',
+        'template/favorite-lists.html',
+        'template/media-exif-value.html',
+        'template/media-exif.html',
+        'template/title_link.html'
+    ),
+);

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

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

+ 2 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/install/sql/enable.sql

@@ -0,0 +1,2 @@
+-- UPLOADERS
+DELETE FROM `sys_objects_uploader` WHERE `object`='bx_albums_simple';

+ 2 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/install/sql/install.sql

@@ -0,0 +1,2 @@
+-- FORMS
+UPDATE `sys_form_inputs` SET `values`='a:3:{s:15:"bx_albums_html5";s:25:"_sys_uploader_html5_title";s:22:"bx_albums_record_video";s:32:"_sys_uploader_record_video_title";s:14:"bx_albums_crop";s:24:"_sys_uploader_crop_title";}' WHERE `object`='bx_albums' AND `name`='pictures';

+ 160 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/classes/BxAlbumsContentInfoMedia.php

@@ -0,0 +1,160 @@
+<?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
+ *
+ * @{
+ */
+
+class BxAlbumsContentInfoMedia extends BxDolContentInfo
+{
+    protected $MODULE;
+	protected $_oModule;
+
+    protected function __construct($sSystem)
+    {
+        $this->MODULE = 'bx_albums';
+        $this->_oModule = BxDolModule::getInstance($this->MODULE);
+
+        parent::__construct($sSystem);
+    }  
+
+    public function getContentAuthor ($iContentId)
+    {
+        $aMedia = $this->_oModule->_oDb->getMediaInfoById($iContentId);
+        if(empty($aMedia) || !is_array($aMedia))
+            return 0;
+
+        return $aMedia['author'];
+    }
+    
+    public function getContentEmbed ($iContentId)
+    {
+        $aMedia = $this->_oModule->_oDb->getMediaInfoById($iContentId);
+        if(empty($aMedia) || !is_array($aMedia))
+            return '';
+        
+        $sTitle = $this->getContentTitle($iContentId);
+        return $this->_oModule->_oTemplate->parseHtmlByName('embed_media.html', [
+            'title' => $sTitle,
+            'url' => BX_DOL_URL_ROOT . $this->_oModule->_oConfig->getBaseUri() . 'embed_media/' . $iContentId . '/'
+        ]);
+    }
+
+    public function getContentDateAdded ($iContentId)
+    {
+        $aMedia = $this->_oModule->_oDb->getMediaInfoById($iContentId);
+        if(empty($aMedia) || !is_array($aMedia))
+            return 0;
+
+        return $aMedia['added'];
+    }
+
+    public function getContentDateChanged ($iContentId)
+    {
+        return 0;
+    }
+
+    public function getContentTitle ($iContentId)
+    {
+        $aMedia = $this->_oModule->_oDb->getMediaInfoById($iContentId);
+        if(empty($aMedia) || !is_array($aMedia))
+            return '';
+
+        return $aMedia['title'];
+    }
+
+    public function getContentThumb ($iContentId)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aMedia = $this->_oModule->_oDb->getMediaInfoById($iContentId);
+        if(empty($aMedia) || !is_array($aMedia))
+            return '';
+
+        $sTranscoder = $CNF['OBJECT_TRANSCODER_BROWSE'];
+        $oTranscoder = BxDolTranscoderImage::getObjectInstance($sTranscoder);
+        if(!$oTranscoder)
+            return '';
+
+        return $oTranscoder->getFileUrl($aMedia['file_id']);
+    }
+
+    public function getContentLink ($iContentId)
+    {
+        $aMedia = $this->_oModule->_oDb->getMediaInfoById($iContentId);
+        if(empty($aMedia) || !is_array($aMedia))
+            return '';
+
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $this->_oModule->_oConfig->CNF['URI_VIEW_MEDIA'] . '&id=' . $iContentId));
+    }
+
+    public function getContentText ($iContentId)
+    {
+        return '';
+    }
+
+    public function getContentInfo ($iContentId, $bSearchableFieldsOnly = true)
+    {
+        $aMedia = $this->_oModule->_oDb->getMediaInfoById($iContentId);
+        if(empty($aMedia) || !is_array($aMedia))
+            return array();
+
+        return $aMedia;
+    }
+
+    public function getContentSearchResultUnit ($iContentId, $sUnitTemplate = '')
+    {
+        $aMedia = $this->_oModule->_oDb->getMediaInfoById($iContentId);
+        if(empty($aMedia) || !is_array($aMedia))
+            return '';
+
+        if(empty($sUnitTemplate))
+            $sUnitTemplate = 'unit_media.html';
+
+        return $this->_oModule->_oTemplate->unitMedia($aMedia, true, $sUnitTemplate);
+    }
+
+    public function getAll ($aParams = array())
+    {
+        if(empty($aParams) || !is_array($aParams))
+            $aParams = array('type' => 'all');
+
+        return $this->_oModule->_oDb->getMediaBy($aParams);
+    }
+
+    public function getSearchableFieldsExtended ()
+    {
+        return array(
+            'author' => array(
+            	'type' => 'text_auto', 
+            	'caption' => '_bx_albums_form_entry_input_author',
+        		'info' => '',
+        		'value' => '',
+            	'values' => '',
+        		'pass' => ''
+            ),
+            'title' => array(
+            	'type' => 'text', 
+            	'caption' => '_bx_albums_form_entry_file_title',
+            	'info' => '',
+        		'value' => '',
+            	'values' => '',
+            	'pass' => 'Xss'
+            )
+        );
+    }
+
+    public function getSearchResultExtended ($aParams, $iStart = 0, $iPerPage = 0, $bFilterMode = false)
+    {
+        if((empty($aParams) || !is_array($aParams)) && !$bFilterMode)
+            return array();
+
+        return $this->_oModule->_oDb->getMediaBy(array('type' => 'search_ids', 'search_params' => $aParams, 'start' => $iStart, 'per_page' => $iPerPage));
+    }
+}
+
+/** @} */

+ 1045 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/classes/BxAlbumsModule.php

@@ -0,0 +1,1045 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Albums Albums
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+bx_import('BxDolAcl');
+
+/**
+ * Albums module
+ */
+class BxAlbumsModule extends BxBaseModTextModule
+{
+    protected $_aContexts = array('popular', 'public', 'author');
+
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+
+    public function serviceGetSafeServices()
+    {
+        $a = parent::serviceGetSafeServices();
+        return array_merge($a, array (
+            'EntityAddFiles' => '',
+            'MediaComments' => '',
+            'BrowseRecentMedia' => '',
+            'BrowseFeaturedMedia' => '',
+            'BrowsePopularMedia' => '',
+            'BrowseTopMedia' => '',
+            'BrowseFavoriteMedia' => '',
+        ));
+    }
+    
+    public function actionEmbed($iContentId, $sUnitTemplate = '', $sAddCode = '')
+    {
+        return $this->_oTemplate->getJsCode('main') . parent::actionEmbed($iContentId);
+    }
+
+    public function actionEmbedMedia($iContentId)
+    {
+        $oTemplate = BxDolTemplate::getInstance();
+        
+        $aContentInfo = $this->_oDb->getMediaInfoById($iContentId);
+        if(empty($aContentInfo))
+            $oTemplate->getEmbed(false);
+
+        if(empty($sUnitTemplate))
+            $sUnitTemplate = 'unit_media_gallery.html';
+
+        $oTemplate->getEmbed($this->_oTemplate->unit($aContentInfo, true, $sUnitTemplate));
+    }
+    
+    /**
+     * Entry actions and social sharing block
+     */
+    public function serviceEntityAllActions ($mixedContent = false, $aParams = array())
+    {
+        if(!empty($mixedContent)) {
+            if(!is_array($mixedContent))
+               $mixedContent = array((int)$mixedContent, array());
+        }
+        else {
+            $mixedContent = $this->_getContent();
+            if($mixedContent === false)
+                return false;
+        }
+        
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        $aMedias = $this->_oDb->getMediaListByContentId($iContentId);
+        if(!empty($aMedias) && is_array($aMedias)) {
+            $aMedia = array_shift($aMedias);
+            if(!empty($aMedia['file_id']))
+                $aParams = array_merge(array(
+                    'entry_thumb' => $aMedia['file_id']
+                ), $aParams);
+        }
+
+        return parent::serviceEntityAllActions(array($iContentId, $aContentInfo), $aParams);
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_albums Albums
+     * @subsection bx_albums-forms Forms
+     * @subsubsection bx_albums-entity_add_files entity_add_files
+     * 
+     * @code bx_srv('bx_albums', 'entity_add_files', [...]); @endcode
+     * 
+     * Display form for adding media to the album.
+     * @param $iContentId album content id where media will be added, if it's not provided then it's determined from 'id' GET variable
+     * @return HTML string with form, all necessary CSS and JS files are automatically added to the HEAD section of the site HTML. On error false or empty string is returned.
+     * 
+     * @see BxAlbumsModule::serviceEntityAddFiles
+     */
+    /** 
+     * @ref bx_albums-entity_add_files "entity_add_files"
+     */
+    public function serviceEntityAddFiles ($iContentId = 0)
+    {
+        return $this->_serviceEntityForm ('editDataForm', $iContentId, 'bx_albums_entry_add_images');
+    }
+
+    /**
+     * Delete file and album association, also file views, votes, comments, meta data are also deleted
+     * @param $iFileId file ID
+     * @return true on success of false on error
+     */ 
+    public function serviceDeleteFileAssociations($iFileId)
+    {        
+        $CNF = &$this->_oConfig->CNF;
+
+        if (!($aMediaInfo = $this->_oDb->getMediaInfoSimpleByFileId($iFileId))) // file is already deleted
+            return true; 
+    
+        if (!$this->_oDb->deassociateFileWithContent(0, $iFileId))
+            return false;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($aMediaInfo['content_id']);
+        $iSender = isLogged() ? bx_get_logged_profile_id() : $aMediaInfo['author'];
+        $iAuthor = isset($aContentInfo[$CNF['FIELD_AUTHOR']]) ? $aContentInfo[$CNF['FIELD_AUTHOR']] : $aMediaInfo['author'];
+        bx_alert($this->getName(), 'media_deleted', $aMediaInfo['content_id'], $iSender, array(
+            'object_author_id' => $iAuthor,
+
+            'subobject_id' => $aMediaInfo['id'],
+
+            'media_id' => $aMediaInfo['id'], 
+            'media_info' => $aMediaInfo,
+        ));
+
+        bx_alert($this->getName() . '_media', 'deleted', $aMediaInfo['id'], $iSender, array(
+            'object_id' => $aMediaInfo['content_id'],
+            'object_author_id' => $iAuthor,
+
+            'media_info' => $aMediaInfo,
+        ));        
+
+        if (!empty($CNF['OBJECT_VIEWS_MEDIA'])) {
+            $o = BxDolView::getObjectInstance($CNF['OBJECT_VIEWS_MEDIA'], $aMediaInfo['id']);
+            if ($o) $o->onObjectDelete();
+        }
+
+        if (!empty($CNF['OBJECT_VOTES_MEDIA'])) {
+            $o = BxDolVote::getObjectInstance($CNF['OBJECT_VOTES_MEDIA'], $aMediaInfo['id']);
+            if ($o) $o->onObjectDelete();
+        }
+
+        if (!empty($CNF['OBJECT_SCORES_MEDIA'])) {
+            $o = BxDolScore::getObjectInstance($CNF['OBJECT_SCORES_MEDIA'], $aMediaInfo['id']);
+            if ($o) $o->onObjectDelete();
+        }
+
+        if (!empty($CNF['OBJECT_COMMENTS_MEDIA'])) {
+            $o = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS_MEDIA'], $aMediaInfo['id']);
+            if ($o) $o->onObjectDelete();
+        }
+
+        if (!empty($CNF['OBJECT_METATAGS_MEDIA'])) {
+            $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS_MEDIA']);
+            $oMetatags->onDeleteContent($aMediaInfo['id']);
+        }
+
+        if (!empty($CNF['OBJECT_METATAGS_MEDIA_CAMERA'])) {
+            $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS_MEDIA_CAMERA']);
+            $oMetatags->onDeleteContent($aMediaInfo['id']);
+        }
+
+        BxDolPage::deleteSeoLink ($this->getName(), 'bx_albums_media', $aMediaInfo['id']);
+
+        return true;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_albums Albums
+     * @subsection bx_albums-page_blocks Page Blocks
+     * @subsubsection bx_albums-media_comments media_comments
+     * 
+     * @code bx_srv('bx_albums', 'media_comments', [...]); @endcode
+     * 
+     * Display media comments block.
+     * @param $iMediaId media ID, if it's omitted then it's taken from 'id' GET variable.
+     * @return HTML string with comments. On error false or empty string is returned.
+     * 
+     * @see BxAlbumsModule::serviceMediaComments
+     */
+    /** 
+     * @ref bx_albums-media_comments "media_comments"
+     */
+    public function serviceMediaComments ($iMediaId = 0)
+    {
+        return $this->_entityComments($this->_oConfig->CNF['OBJECT_COMMENTS_MEDIA'], $iMediaId);
+    }
+
+    /**
+     * Display media author block.
+     * @param $iMediaId media ID, if it's omitted then it's taken from 'id' GET variable.
+     * @return HTML string with block content. On error false or empty string is returned.
+     */
+    public function serviceMediaAuthor ($iMediaId = 0)
+    {
+        return $this->_serviceTemplateFunc ('mediaAuthor', $iMediaId, 'getMediaInfoById');
+    }
+
+    /**
+     * Entry actions and social sharing block
+     */
+    public function serviceMediaAllActions ($mixedContent = false, $aParams = array())
+    {
+        $iMediaId = 0;
+        $aMediaInfo = array();
+
+        $bContent = !empty($mixedContent);
+        if($bContent && is_array($mixedContent))
+            list($iMediaId, $aMediaInfo) = $mixedContent;
+        else {
+            if($bContent)
+                $iMediaId = (int)$mixedContent;
+            else
+                $iMediaId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+            if(!$iMediaId)
+                return false;
+
+            $aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        }
+
+        if(!$iMediaId || !$aMediaInfo)
+            return false;
+
+        $CNF = &$this->_oConfig->CNF;
+
+        return parent::serviceEntityAllActions (array($iMediaId, $aMediaInfo), array_merge(array(
+            'object_menu' => $CNF['OBJECT_MENU_ACTIONS_VIEW_MEDIA_ALL'],
+            'object_transcoder' => $CNF['OBJECT_IMAGES_TRANSCODER_BIG'],
+            'entry_url' => bx_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(
+            '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(
+            '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(
+            '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;
+    }
+}
+
+/** @} */

+ 120 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/classes/BxAlbumsPageMedia.php

@@ -0,0 +1,120 @@
+<?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');
+
+/**
+ * Entry create/edit pages
+ */
+class BxAlbumsPageMedia extends BxTemplPage
+{
+    protected $MODULE;
+    protected $_oModule;
+    protected $_aAlbumInfo = false;
+    protected $_aMediaInfo = false;
+    protected $_mixedContext = false;
+
+    public function __construct($aObject, $oTemplate = false)
+    {        
+        parent::__construct($aObject, $oTemplate);
+        $this->MODULE = 'bx_albums';
+        $this->_oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iMediaId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if ($iMediaId)
+            $this->_aMediaInfo = $this->_oModule->_oDb->getMediaInfoById($iMediaId);
+
+        if ($this->_aMediaInfo)
+            $this->_aAlbumInfo = $this->_oModule->_oDb->getContentInfoById($this->_aMediaInfo['content_id']);
+
+        if ($this->_aAlbumInfo) {
+            $this->addMarkers(array_merge($this->_aAlbumInfo, $this->_aMediaInfo)); // every field can be used as marker
+            $this->addMarkers(array(
+                'title' => !empty($this->_aMediaInfo['title']) ? $this->_aMediaInfo['title'] : _t('_bx_albums_txt_media_title_alt', $this->_aAlbumInfo[$CNF['FIELD_TITLE']]),
+            ));
+
+            $sTitle = isset($this->_aAlbumInfo[$CNF['FIELD_TITLE']]) ? $this->_aAlbumInfo[$CNF['FIELD_TITLE']] : strmaxtextlen($this->_aAlbumInfo[$CNF['FIELD_TEXT']], 20, '...');
+            $sUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $this->_aAlbumInfo[$CNF['FIELD_ID']]));
+
+            // select view entry submenu
+            $oMenuSubmenu = BxDolMenu::getObjectInstance('sys_site_submenu');
+            if($oMenuSubmenu)
+                $oMenuSubmenu->setObjectSubmenu($CNF['OBJECT_MENU_SUBMENU_VIEW_ENTRY'], array (
+                    'title' => '',
+                    'link' => '',
+                    'icon' => '',
+                ));
+        }
+    }
+
+    public function getCode ()
+    {
+        // check if content exists
+        if (!$this->_aAlbumInfo || !$this->_aMediaInfo) { // if entry is not found - display standard "404 page not found" page
+            $this->_oTemplate->displayPageNotFound();
+            exit;
+        }
+
+        // permissions check 
+        if (CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $this->_oModule->checkAllowedView($this->_aAlbumInfo))) {
+            $this->_oTemplate->displayAccessDenied($sMsg);
+            exit;
+        }
+        $this->_oModule->checkAllowedView($this->_aAlbumInfo, true);
+
+        // count views
+        $CNF = &$this->_oModule->_oConfig->CNF;
+        if (!empty($CNF['OBJECT_VIEWS_MEDIA']))
+            BxDolView::getObjectInstance($CNF['OBJECT_VIEWS_MEDIA'], $this->_aMediaInfo['id'])->doView();
+
+        // add content metatags
+        if(!empty($CNF['OBJECT_METATAGS_MEDIA'])) {
+            $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS_MEDIA']);
+            if($oMetatags)
+                $oMetatags->addPageMetaInfo($this->_aMediaInfo['id'], $this->_getThumbForMetaObject());
+        }
+
+        $aVars = array();
+        $this->_oTemplate->addInjection ('injection_footer', 'text', $this->_oModule->_oTemplate->parseHtmlByName('photoswipe.html', $aVars));
+
+        return parent::getCode ();
+    }
+
+    protected function _getThumbForMetaObject ()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;        
+        
+        if(empty($this->_aMediaInfo['file_id']) || empty($CNF['OBJECT_TRANSCODER_COVER']))
+            return false;
+
+        return array('id' => $this->_aMediaInfo['file_id'], 'transcoder' => $CNF['OBJECT_TRANSCODER_COVER']);
+    }
+    
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+
+        $this->_oModule->_oTemplate->addCss(array(
+            BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'photo-swipe/|photoswipe.css',
+            BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'photo-swipe/default-skin/|default-skin.css',
+        ));
+
+        $this->_oModule->_oTemplate->addJs(array(
+            'media_view.js',
+            'history.js',
+            'photo-swipe/photoswipe.min.js',
+            'photo-swipe/photoswipe-ui-default.min.js',
+        ));
+    }
+}
+
+/** @} */

+ 284 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/classes/BxAlbumsSearchResultMedia.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    Albums Albums
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxAlbumsSearchResultMedia extends BxBaseModTextSearchResult
+{
+    protected $sOrderDirection = 'DESC';
+
+    function __construct($sMode = '', $aParams = array())
+    {
+        $this->sUnitTemplateLiveSearch = 'unit_media_live_search.html';
+
+        $aParams['unit_views'] = array('gallery' => 'unit_media.html', 'showcase' => 'unit_showcase.html');
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent = array(
+            'name' => 'bx_albums_media',
+            'module_name' => 'bx_albums',
+            'object_metatags' => 'bx_albums_media',
+            'title' => _t('_bx_albums_media'),
+            'table' => 'bx_albums_files2albums',
+            'ownFields' => array('id', 'title', 'data', 'content_id', 'file_id', 'order', 'views'),
+            'searchFields' => array('title'),
+            'restriction_sql' => '',
+            'restriction' => array(
+                'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
+                'album' => array('value' => '', 'field' => 'content_id', 'operator' => '='),
+                'featured' => array('value' => '', 'field' => 'featured', 'operator' => '<>'),
+            ),
+            'join' => array(
+                'albums' => array(
+                    'type' => 'INNER',
+                    'table' => 'bx_albums_albums',
+                    'mainField' => 'content_id',
+                    'onField' => 'id',
+                    'joinFields' => array(),
+                ),
+                'files' => array(
+                    'type' => 'INNER',
+                    'table' => 'bx_albums_files',
+                    'table_alias' => 'f',
+                    'mainField' => 'file_id',
+                    'onField' => 'id',
+                    'joinFields' => array('added'),
+                ),
+            ),
+            'paginate' => array('perPage' => getParam('bx_albums_per_page_browse'), 'start' => 0),
+            'sorting' => 'last',
+            'rss' => array(
+                'title' => '',
+                'link' => '',
+                'image' => '',
+                'profile' => 0,
+                'fields' => array (
+                    'Guid' => 'link',
+                    'Link' => 'link',
+                    'Title' => 'title',
+                    'DateTimeUTS' => 'added',
+                    'Desc' => 'title',
+                ),
+            ),
+            'ident' => 'id',
+        );
+
+        $this->sFilterName = 'bx_albums_filter';
+        $this->oModule = $this->getMain();
+
+        $oProfileAuthor = isset($aParams['author']) ? BxDolProfile::getInstance((int)$aParams['author']) : null;
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        switch ($sMode) {
+            case 'album':
+                $iAlbumId = (int)$aParams['album_id'];
+                $this->aCurrent['restriction']['album']['value'] = $iAlbumId;
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iAlbumId);
+                $this->aCurrent['title'] = _t('_bx_albums_page_title_browse_media_in_album');
+                $this->aCurrent['rss']['link'] = 'modules/?r=albums/rss_media/' . $sMode . '/' . $iAlbumId;
+                $this->aCurrent['sorting'] = 'order';
+                $this->sOrderDirection = 'ASC';
+                $this->setProcessPrivateContent(true);
+
+                if($CNF['PARAM_ORDER_BY_GHOSTS'])
+                    $this->_updateCurrentForOrderByGhosts();
+                break;
+
+            case 'favorite':
+                if(!$this->_updateCurrentForFavorite($sMode, array_merge($aParams, array('system' => $CNF['OBJECT_FAVORITES_MEDIA'])), $oProfileAuthor)) {
+                    $this->isError = true;
+                    break;
+                }
+                $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+                break;
+
+            case 'recent':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_RECENT_MEDIA']);
+                $this->aCurrent['title'] = _t('_bx_albums_page_title_browse_recent_media');
+                $this->aCurrent['rss']['link'] = 'modules/?r=albums/rss_media/' . $sMode; 
+                $this->aCurrent['sorting'] = 'last';
+                $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+                break;
+
+            case 'featured':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_RECENT_MEDIA']);
+                $this->aCurrent['title'] = _t('_bx_albums_page_title_browse_featured_media');
+                $this->aCurrent['restriction']['featured']['value'] = '0';
+                $this->aCurrent['rss']['link'] = 'modules/?r=albums/rss_media/' . $sMode;
+                $this->aCurrent['sorting'] = 'featured';
+                $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+                break;
+
+            case 'popular':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_POPULAR_MEDIA']);
+                $this->aCurrent['title'] = _t('_bx_albums_page_title_browse_popular_media');
+                $this->aCurrent['rss']['link'] = BxDolPermalinks::getInstance()->permalink('modules/?r=albums/rss_media/' . $sMode);
+                $this->aCurrent['sorting'] = 'popular';
+                $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+                break;
+
+            case 'top':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_TOP_MEDIA']);
+                $this->aCurrent['title'] = _t('_bx_albums_page_title_browse_top_media');
+                $this->aCurrent['rss']['link'] = BxDolPermalinks::getInstance()->permalink('modules/?r=albums/rss_media/' . $sMode);
+                $this->aCurrent['sorting'] = 'top';
+                $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+                break;
+
+            case '': // search results
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                unset($this->aCurrent['paginate']['perPage'], $this->aCurrent['rss']);
+                break;
+
+            default:
+                $sMode = '';
+                $this->isError = true;
+        }
+
+        $this->sBrowseUrl = $this->_replaceMarkers($this->sBrowseUrl);
+        $this->aCurrent['title'] = $this->_replaceMarkers($this->aCurrent['title']); 
+
+        $this->removeContainerClass('bx-def-margin-bottom-neg');
+        $this->addContainerClass(array('bx-def-margin-sec-lefttopright-neg', 'bx-def-margin-sec-bottom-neg', 'bx-albums-medias-wrapper'));
+
+        $this->addCustomConditions($CNF, $oProfileAuthor, $sMode, $aParams);
+    }
+
+    function getAlterOrder()
+    {
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        $sTable = $this->aCurrent['table'];
+        $sWay = $this->sOrderDirection;
+
+        $aSql = array();
+        switch ($this->aCurrent['sorting']) {
+            case 'order':
+                $aSql['order'] = " ORDER BY `" . $sTable . "`.`order` " . $sWay . ", `" . $sTable . "`.`id` " . $sWay . " ";
+                break;
+
+            case 'order_by_ghosts':
+                $aSql['order'] = " ORDER BY `g`.`order` " . $sWay . ", `" . $sTable . "`.`id` " . $sWay . " ";
+                break;
+
+            case 'last':
+                $aSql['order'] = " ORDER BY `f`.`added` " . $sWay . ", `" . $sTable . "`.`id` " . $sWay . " ";
+                break;
+
+            case 'featured':
+                $aSql['order'] = " ORDER BY `" . $sTable . "`.`featured` " . $sWay . ", `" . $sTable . "`.`id` " . $sWay . "";
+                break;
+
+            case 'popular':
+                $aSql['order'] = " ORDER BY `" . $sTable . "`.`views` " . $sWay . ", `" . $sTable . "`.`id` " . $sWay . "";
+                break;
+
+            case 'top':
+                $aSql['order'] = '';
+
+                $aPartsUp = $aPartsDown = array();
+                if(!empty($CNF['OBJECT_VOTES_MEDIA']) && ($oVote = BxDolVote::getObjectInstance($CNF['OBJECT_VOTES_MEDIA'], 0, false)) !== false) {
+                    $aVote = $oVote->getSystemInfo();
+                    if(!empty($aVote['trigger_table']) && !empty($aVote['trigger_field_count']))
+                        $aPartsUp[] = '`' . $aVote['trigger_table'] . '`.`' . $aVote['trigger_field_count'] . '`';
+                }
+
+                if(!empty($CNF['OBJECT_SCORES_MEDIA']) && ($oScore = BxDolScore::getObjectInstance($CNF['OBJECT_SCORES_MEDIA'], 0, false)) !== false) {
+                    $aScore = $oScore->getSystemInfo();
+                    if(!empty($aScore['trigger_table']) && !empty($aScore['trigger_field_cup']) && !empty($aScore['trigger_field_cdown'])) {
+                        $aPartsUp[] = '`' . $aScore['trigger_table'] . '`.`' . $aScore['trigger_field_cup'] . '`';
+                        $aPartsDown[] = '`' . $aScore['trigger_table'] . '`.`' . $aScore['trigger_field_cdown'] . '`';
+                    }
+                }
+
+                if(empty($aPartsUp) && empty($aPartsDown))
+                    break;
+
+                $aSql['order'] = ' ORDER BY ' . pow(10, 8) . ' * ((' . implode(' + ', $aPartsUp) . ') - (' . implode(' + ', $aPartsDown) . ')) / (UNIX_TIMESTAMP() - `f`.`added`) ' . $sWay;
+                break;
+        }
+
+        return $aSql;
+    }
+
+    public function getNextPrevItem($aMediaInfo, $isNext)
+    {
+        $sOper = $isNext ? '<' : '>';
+
+        $this->sOrderDirection = $isNext ? 'DESC' : 'ASC';
+        $this->aCurrent['paginate']['perPage'] = 1;
+        $this->aCurrent['restriction']['next_prev2'] = array('value' => $aMediaInfo['id'], 'field' => 'id', 'operator' => '!=');
+
+        $this->setProcessPrivateContent(true);
+        $aRestrictions = array_keys($this->aCurrent['restriction']);
+        foreach ($aRestrictions as $sKey) 
+            if (0 === strpos($sKey, 'privacy_'))
+                unset($this->aCurrent['restriction'][$sKey]);
+
+        switch ($this->aCurrent['sorting']) {
+            case 'order':
+                $this->sOrderDirection = $isNext ? 'ASC' : 'DESC';
+                $sOper = $isNext ? '>' : '<';
+                $this->aCurrent['restriction_sql'] = " AND (`{$this->aCurrent['table']}`.`order` {$sOper} {$aMediaInfo['order']} OR (`{$this->aCurrent['table']}`.`order` = {$aMediaInfo['order']} AND `{$this->aCurrent['table']}`.`id` {$sOper} {$aMediaInfo['id']})) ";
+                break;
+            case 'order_by_ghosts':
+                $this->sOrderDirection = $isNext ? 'ASC' : 'DESC';
+                $sOper = $isNext ? '>' : '<';
+                $this->aCurrent['restriction_sql'] = " AND (`g`.`order` {$sOper} {$aMediaInfo['gorder']} OR (`g`.`order` = {$aMediaInfo['gorder']} AND `{$this->aCurrent['table']}`.`id` {$sOper} {$aMediaInfo['id']})) ";
+                break;
+            case 'last':
+                $this->aCurrent['restriction_sql'] = " AND (`f`.`added` {$sOper} {$aMediaInfo['added']} OR (`f`.`added` = {$aMediaInfo['added']} AND `{$this->aCurrent['table']}`.`id` {$sOper} {$aMediaInfo['id']})) ";
+                break;
+            case 'featured':
+                $this->aCurrent['restriction_sql'] = " AND (`{$this->aCurrent['table']}`.`featured` {$sOper} {$aMediaInfo['featured']} OR (`{$this->aCurrent['table']}`.`featured` = {$aMediaInfo['featured']} AND `{$this->aCurrent['table']}`.`id` {$sOper} {$aMediaInfo['id']})) ";
+                break;
+            case 'popular':
+                $this->aCurrent['restriction_sql'] = " AND (`{$this->aCurrent['table']}`.`views` {$sOper} {$aMediaInfo['views']} OR (`{$this->aCurrent['table']}`.`views` = {$aMediaInfo['views']} AND `{$this->aCurrent['table']}`.`id` {$sOper} {$aMediaInfo['id']})) ";
+                break;
+        }
+
+        $aData = $this->getSearchData();
+        if (count($aData) > 0)
+            return array_shift($aData);
+
+        return false;
+    }
+
+    function getRssUnitLink (&$a)
+    {
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $this->oModule->_oConfig->CNF['URI_VIEW_MEDIA'] . '&id=' . $a['id']));
+    }
+
+    protected function _updateCurrentForOrderByGhosts()
+    {
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        $this->aCurrent['join']['ghosts'] = [
+            'type' => 'INNER',
+            'table' => 'sys_storage_ghosts',
+            'table_alias' => 'g',
+            'mainField' => 'file_id',
+            'on_sql' => $this->oModule->_oDb->prepareAsString(" `g`.`id`=`bx_albums_files2albums`.`file_id` AND `g`.`content_id`=`bx_albums_files2albums`.`content_id` AND `g`.`object`=? ", $CNF['OBJECT_STORAGE']),
+            'joinFields' => array('order'),
+        ];
+        $this->aCurrent['sorting'] = 'order_by_ghosts';
+        $this->sOrderDirection = 'ASC';
+    }
+
+/*
+    function displaySearchUnit ($aData)
+    {
+        $oMain = $this->getMain();
+        return $oMain->_oTemplate->unit($aData, $this->bProcessPrivateContent, $this->_bLiveSearch ? $this->sUnitTemplateLiveSearch : $this->sUnitTemplate, $this->aUnitParams);
+    }
+*/
+}
+
+/** @} */

+ 413 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/classes/BxAlbumsTemplate.php

@@ -0,0 +1,413 @@
+<?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
+ *
+ * @{
+ */
+
+/*
+ * Module representation.
+ */
+class BxAlbumsTemplate extends BxBaseModTextTemplate
+{
+    /**
+     * Constructor
+     */
+    function __construct(&$oConfig, &$oDb)
+    {
+        $this->MODULE = 'bx_albums';
+        parent::__construct($oConfig, $oDb);
+
+        $this->addCss(array(BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'flickity/|flickity.css'));
+        $this->addJs(array('flickity/flickity.pkgd.min.js', 'main.js'));
+    }
+
+    function unit ($aData, $isCheckPrivateContent = true, $sTemplateName = 'unit.html', $aParams = array())
+    {
+        if ('unit_media.html' == $sTemplateName || 'unit_media_live_search.html' == $sTemplateName || 'unit_showcase.html' == $sTemplateName || 'unit_media_gallery.html' == $sTemplateName)
+            return $this->unitMedia($aData, $isCheckPrivateContent, $sTemplateName, $aParams);
+
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        if ($s = $this->checkPrivacy ($aData, $isCheckPrivateContent, $oModule))
+            return $s;
+
+        // get entry url        
+        $sUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aData[$CNF['FIELD_ID']]));
+
+        $oProfile = BxDolProfile::getInstance($aData[$CNF['FIELD_AUTHOR']]);
+        if (!$oProfile) 
+            $oProfile = BxDolProfileUndefined::getInstance();
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        $oTranscoder = BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_TRANSCODER_BROWSE']);
+        $oTranscoderPoster = $CNF['OBJECT_VIDEOS_TRANSCODERS'] ? BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['poster']) : false;
+
+        $aBrowseUnits = array ();
+        $aMediaList = $oModule->_oDb->getMediaListByContentId($aData[$CNF['FIELD_ID']], getParam('bx_albums_album_browsing_unit'));
+        foreach ($aMediaList as $k => $a) {
+            $aFileInfo = $oStorage->getFile($a['file_id']);
+
+            $bVideo = $oTranscoderPoster && strncmp('video/', $aFileInfo['mime_type'], 6) === 0 && $oTranscoderPoster->isMimeTypeSupported($aFileInfo['mime_type']);            
+            $iVideoDuration = $bVideo ? $oModule->getMediaDuration($aFileInfo) : 0;
+
+            $aBrowseUnits[] = array (
+                'img_url' => $oTranscoder->getFileUrl($a['file_id']),
+                'url' => $this->getViewMediaUrl($CNF, $a['id']),
+                'title_attr' => bx_html_attribute($a['title']),
+                'bx_if:show_play' => array(
+                    'condition' => $bVideo,
+                    'content' => array()
+                ),
+                'bx_if:show_duration' => array(
+                    'condition' => $iVideoDuration > 0,
+                    'content' => array(
+                        'duration' => _t_format_duration($iVideoDuration)
+                    )
+                )
+
+            );
+        }
+
+        // get summary
+        $sLinkMore = ' <a title="' . bx_html_attribute(_t('_sys_read_more', $aData[$CNF['FIELD_TITLE']])) . '" href="' . $sUrl . '"><i class="sys-icon ellipsis-h"></i></a>';
+        $sSummary = strmaxtextlen($aData[$CNF['FIELD_TEXT']], (int)getParam($CNF['PARAM_CHARS_SUMMARY']), $sLinkMore);
+        $sSummaryPlain = BxTemplFunctions::getInstance()->getStringWithLimitedLength(strip_tags($sSummary), (int)getParam($CNF['PARAM_CHARS_SUMMARY_PLAIN']));
+
+        $sMeta = '';
+        if(!empty($CNF['OBJECT_MENU_SNIPPET_META'])) {
+            $oMenuMeta = BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_SNIPPET_META'], $this);
+            if($oMenuMeta) {
+                $oMenuMeta->setContentId($aData[$CNF['FIELD_ID']]);
+                $aTmplVarsMeta = array(
+                    'meta' => $oMenuMeta->getCode()
+                );
+            }
+        }
+
+        // generate html
+        $aVars = array (
+            'id' => $aData[$CNF['FIELD_ID']],
+            'content_url' => $sUrl,
+            'title' => bx_process_output($aData[$CNF['FIELD_TITLE']]),
+        	'summary' => $sSummary,
+            'author' => $oProfile->getDisplayName(),
+            'author_url' => $oProfile->getUrl(),
+            'entry_posting_date' => bx_time_js($aData[$CNF['FIELD_ADDED']], BX_FORMAT_DATE),
+            'module_name' => _t($CNF['T']['txt_sample_single']),
+            'ts' => $aData[$CNF['FIELD_ADDED']],
+        	'bx_if:meta' => array(
+                'condition' => !empty($aTmplVarsMeta),
+                'content' => $aTmplVarsMeta
+            ),
+            'bx_repeat:browse' => $aBrowseUnits,
+            'bx_if:thumb' => array (
+                'condition' => $aBrowseUnits,
+                'content' => array (
+                    'title' => bx_process_output($aData[$CNF['FIELD_TITLE']]),
+                    'summary_attr' => '',
+                    'content_url' => $sUrl,
+                    'thumb_url' => $aBrowseUnits ? $aBrowseUnits[0]['img_url'] : '',
+                    'gallery_url' => '',
+                    'strecher' => '',
+                ),
+            ),
+            'bx_if:no_thumb' => array (
+                'condition' => !$aBrowseUnits,
+                'content' => array (
+                    'content_url' => $sUrl,
+                    'summary_plain' => '',
+                    'strecher' => '',
+                ),
+            ),
+
+        );
+
+        return $this->parseHtmlByName($sTemplateName, $aVars);
+    }
+
+    function unitMedia ($aData, $isCheckPrivateContent = true, $sTemplateName = 'unit.html', $aParams = array())
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        if (!($aMediaInfo = $oModule->_oDb->getMediaInfoById($aData['id'])))
+            return '';
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        if (!($aFile = $oStorage->getFile($aMediaInfo['file_id'])))
+            return '';
+
+        $aVars = $this->mediaVars($aMediaInfo, $CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW'], $CNF['OBJECT_VIDEOS_TRANSCODERS']['poster_preview'], $aParams);
+
+        $aVarsTmp = $aVars['bx_if:image']['condition'] ? $aVars['bx_if:image']['content'] : $aVars['bx_if:video']['content'];
+
+        $aVars = array_merge($aVars, array (
+            'class' => $this->_getUnitClass($aData, $sTemplateName),
+            'module_name' => _t($CNF['T']['txt_media_single']),
+            'content_url' => $aVars['url'],
+            'ts' => $aFile['added'],
+            'actions' => $oModule->serviceMediaAllActions(array($aData['id'], $aMediaInfo), array(
+                'object_menu' => $CNF['OBJECT_MENU_ACTIONS_VIEW_MEDIA_UNIT']
+            )),
+            'bx_if:thumb' => array (
+                'condition' => isset($aData['file_id']) && $aData['file_id'],
+                'content' => array (
+                    'title' => bx_process_output($aData['title']),
+                    'summary_attr' => '',
+                    'content_url' => $aVarsTmp['url'],
+                    'thumb_url' => $aVarsTmp['url_img'],
+                    'gallery_url' => '',
+                    'strecher' => '',
+                ),
+            ),
+            'bx_if:no_thumb' => array (
+                'condition' => false,
+                'content' => array (),
+            ),
+        ));
+
+        return $this->parseHtmlByName($sTemplateName, $aVars);
+    }
+
+    public function entryText ($aData, $sTemplateName = 'entry-text.html')
+    {
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+        $aVars = $this->getTmplVarsText($aData);
+        if(empty($aVars[$CNF['FIELD_TITLE']]) && empty($aVars[$CNF['FIELD_TEXT']]))
+            return false;
+
+        return $this->parseHtmlByName($sTemplateName, $aVars);
+    }
+
+    function entryMediaView ($iMediaId, $aParams = array())
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        if (!($aMediaInfo = $oModule->_oDb->getMediaInfoById($iMediaId)))
+            return '';
+
+        if (!($aAlbumInfo = $oModule->_oDb->getContentInfoById($aMediaInfo['content_id'])))
+            return '';        
+
+        $sUrlAlbum = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aAlbumInfo[$CNF['FIELD_ID']]));
+
+        $iProfileId = $aAlbumInfo[$CNF['FIELD_AUTHOR']];
+        $oProfile = BxDolProfile::getInstance($iProfileId);
+        if (!$oProfile) 
+            $oProfile = BxDolProfileUndefined::getInstance();
+
+        $aVars = array(
+            'album' => _t('_bx_albums_txt_media_album_link', $sUrlAlbum,  bx_process_output($aAlbumInfo[$CNF['FIELD_TITLE']]), $oProfile->getUrl(), $oProfile->getDisplayName()),
+            'js_code' => $this->getJsCode('main')
+        );
+
+        $mixedContext = isset($aParams['context']) ? $aParams['context'] : false;
+
+        $aNextPrev = array (
+            'next' => $this->getNextPrevMedia($aMediaInfo, true, $mixedContext),
+            'prev' => $this->getNextPrevMedia($aMediaInfo, false, $mixedContext),
+        );
+
+        foreach ($aNextPrev as $k => $a) {
+            $aVars['bx_if:' . $k] = array (
+                'condition' => $a,
+                'content' => $a,
+            );
+            $aVars['bx_if:' . $k . '-na'] = array (
+                'condition' => !$a,
+                'content' => array(),
+            );
+        }
+
+        $aVars = array_merge($aVars, $this->mediaVars($aMediaInfo, $CNF['OBJECT_IMAGES_TRANSCODER_BIG'], $CNF['OBJECT_VIDEOS_TRANSCODERS']['poster'], $aParams));
+
+        return $this->parseHtmlByName('media-view.html', $aVars);
+    }
+
+    protected function mediaVars ($aMediaInfo, $sImageTranscoder = false, $sVideoPosterTranscoder = false, $aParams = array())
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        $oTranscoder = BxDolTranscoderImage::getObjectInstance($sImageTranscoder);
+        $aTranscodersVideo = false;
+
+        if ($CNF['OBJECT_VIDEOS_TRANSCODERS'])
+            $aTranscodersVideo = array (
+                'poster' => BxDolTranscoderImage::getObjectInstance($sVideoPosterTranscoder),
+                'mp4' => BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['mp4']),
+                'mp4_hd' => BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['mp4_hd']),
+            );
+        
+        $aFileInfo = $oStorage->getFile ($aMediaInfo['file_id']);
+        if (!$aFileInfo)
+            return '';
+
+        $isImage = 0 === strncmp('image/', $aFileInfo['mime_type'], 6) && $oTranscoder->isMimeTypeSupported($aFileInfo['mime_type']); // preview for images, transcoder object for preview must be defined
+        $isVideo = $aTranscodersVideo && (0 === strncmp('video/', $aFileInfo['mime_type'], 6)) && $aTranscodersVideo['poster']->isMimeTypeSupported($aFileInfo['mime_type']); // preview for videos, transcoder object for video must be defined
+
+        $sMediaTitle = $this->getMediaTitle($aMediaInfo);
+        $sMediaTitleAttr = bx_html_attribute($sMediaTitle);
+        $mixedContext = isset($aParams['context']) ? $aParams['context'] : '';
+        $sUrl = $this->getViewMediaUrl($CNF, $aMediaInfo['id'], $mixedContext);
+
+        $aTmplVarsImage = array();
+        if($isImage) {
+            $aSize = $aMediaInfo['data'] ? explode('x', $aMediaInfo['data']) : array(0, 0);
+
+            $aTmplVarsImage = array (
+                'title_attr' => $sMediaTitleAttr,
+                'title' => $sMediaTitle,
+                'url' => $sUrl,
+                'url_img' => $oTranscoder ? $oTranscoder->getFileUrl($aFileInfo['id']) : $oStorage->getFileUrlById($aFileInfo['id']),
+                'media_id' => $aMediaInfo['id'],
+                'w' => $aSize[0],
+                'h' => $aSize[1],
+                'context' => $mixedContext,
+            );
+        }
+
+        $aTmplVarsVideo = array();
+        if($isVideo) {
+            $mixedAttrs = false;
+            if(!empty($aParams['autoplay']))
+                $mixedAttrs = array('autoplay' => 'autoplay');
+
+            $iVideoDuration = $oModule->getMediaDuration($aFileInfo);
+            $sVideoDuration = _t_format_duration($iVideoDuration);
+
+            $sVideoUrl = $oStorage->getFileUrlById($aMediaInfo['file_id']);
+            $aVideoFile = $oStorage->getFile($aMediaInfo['file_id']);
+
+            $sVideoUrlHd = '';
+            if (!empty($aVideoFile['dimensions']) && $aTranscodersVideo['mp4_hd']->isProcessHD($aVideoFile['dimensions']))
+                $sVideoUrlHd = $aTranscodersVideo['mp4_hd']->getFileUrl($aMediaInfo['file_id']);
+
+            $aTmplVarsVideo = array (
+                'title_attr' => $sMediaTitleAttr,
+                'title' => $sMediaTitle,
+                'url' => bx_append_url_params($sUrl, array('autoplay' => 1)),
+                'url_img' => $isVideo ? $aTranscodersVideo['poster']->getFileUrl($aMediaInfo['file_id']) : '',
+                'video' => $isVideo && $aTranscodersVideo ? BxTemplFunctions::getInstance()->videoPlayer(
+                    $aTranscodersVideo['poster']->getFileUrl($aMediaInfo['file_id']), 
+                    $aTranscodersVideo['mp4']->getFileUrl($aMediaInfo['file_id']), 
+                    $sVideoUrlHd, $mixedAttrs, 'max-height:' . $CNF['OBJECT_VIDEO_TRANSCODER_HEIGHT']
+                ) : '',
+                'duration' => $sVideoDuration,
+                'bx_if:show_duration' => array(
+                    'condition' => $iVideoDuration > 0,
+                    'content' => array(
+                        'duration' => $sVideoDuration
+                    )
+                )
+            );
+        }
+
+        $aVars = array(
+            'bx_if:image' => array (
+                'condition' => $isImage,
+                'content' => $aTmplVarsImage,
+            ),
+            'bx_if:video' => array (
+                'condition' => $isVideo,
+                'content' => $aTmplVarsVideo,
+            ),
+            'title_attr' => $sMediaTitleAttr,
+            'title' => $sMediaTitle,
+            'url' => $sUrl,
+        );
+
+        return $aVars;
+    }
+
+    public function getViewMediaUrl($CNF, $iMediaId, $sContext = '')
+    {
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_MEDIA'] . '&id=' . $iMediaId . (!empty($sContext) ? '&context=' . $sContext : '')));
+    }
+
+    public function getNextPrevMedia($aMediaInfo, $isNext, $sContext, $aParamsSearchResult = array())
+    {
+        if (!$sContext) {
+            $sContext = 'album';
+            $aParamsSearchResult = array('album_id' => $aMediaInfo['content_id']);
+        }
+
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        bx_import('SearchResultMedia', $oModule->_aModule);
+        $sClass = $oModule->_aModule['class_prefix'] . 'SearchResultMedia';
+        $o = new $sClass($sContext, $aParamsSearchResult);
+        if ($o->isError)
+            return false;
+
+        $o->setUnitParams(array('context' => $sContext));
+
+        $a = $o->getNextPrevItem($aMediaInfo, $isNext);
+    
+        if ($a) {
+
+            $aVars = $this->mediaVars($a, $CNF['OBJECT_IMAGES_TRANSCODER_BIG'], $CNF['OBJECT_VIDEOS_TRANSCODERS']['poster'], array('context' => $sContext));
+            $aMedia = $aVars['bx_if:image']['condition'] ? $aVars['bx_if:image']['content'] : $aVars['bx_if:video']['content'];
+
+            $a['url'] = $aMedia['url'];
+            $a['url_img'] = $aMedia['url_img'];
+            $a['title_attr'] = $aMedia['title_attr'];
+            $a['title_js_string'] = bx_js_string($aMedia['title']);
+            $a['w'] = $aVars['bx_if:image']['condition'] ? $aVars['bx_if:image']['content']['w'] : 0;
+            $a['h'] = $aVars['bx_if:image']['condition'] ? $aVars['bx_if:image']['content']['h'] : 0;
+            $a['html'] = $aVars['bx_if:video']['condition'] ? '<div class="pswp__video">' . $aVars['bx_if:video']['content']['video'] . '</div>': 0;
+        }
+
+        return $a;
+    }
+
+    function entryAttachments ($aData, $aParams = array())
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        return $oModule->_serviceBrowse ('album', array('unit_view' => 'gallery', 'album_id' => $aData[$CNF['FIELD_ID']], 'author' => $aData[$CNF['FIELD_AUTHOR']]), BX_DB_PADDING_DEF, true, true, 'SearchResultMedia');
+    }
+
+    function mediaAuthor ($aMediaInfo, $iProfileId = false, $sFuncAuthorDesc = '', $sTemplateName = '') 
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        if (!($aAlbumInfo = $oModule->_oDb->getContentInfoById($aMediaInfo['content_id'])))
+            return '';
+
+        return $this->entryAuthor ($aMediaInfo, $aAlbumInfo[$CNF['FIELD_AUTHOR']]);
+    }
+
+    function getMediaTitle ($aMediaInfo)
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        if(!empty($aMediaInfo['title'])) {
+            $sText = bx_process_output($aMediaInfo['title']);
+            if(!empty($CNF['OBJECT_METATAGS_MEDIA'])) {
+                $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS_MEDIA']);
+                if($oMetatags && $oMetatags->keywordsIsEnabled())
+                    $sText = $oMetatags->keywordsParse($aMediaInfo['id'], $sText);
+            }
+        }
+        else 
+            $sText = _t('_bx_albums_txt_media_title_empty');
+
+        return $sText;
+    }
+}
+
+/** @} */

+ 143 - 0
modules/boonex/albums/updates/13.0.3_13.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' => '13.0.4',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.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'
+    ),
+
+);
+
+/** @} */

+ 563 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/install/sql/enable.sql

@@ -0,0 +1,563 @@
+
+-- 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_albums', '_bx_albums', 'bx_albums@modules/boonex/albums/|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_albums', '_bx_albums', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_albums_enable_auto_approve', 'on', @iCategId, '_bx_albums_option_enable_auto_approve', 'checkbox', '', '', '', 0),
+('bx_albums_summary_chars', '700', @iCategId, '_bx_albums_option_summary_chars', 'digit', '', '', '', 1),
+('bx_albums_plain_summary_chars', '200', @iCategId, '_bx_albums_option_plain_summary_chars', 'digit', '', '', '', 2),
+('bx_albums_per_page_browse', '12', @iCategId, '_bx_albums_option_per_page_browse', 'digit', '', '', '', 10),
+('bx_albums_per_page_profile', '6', @iCategId, '_bx_albums_option_per_page_profile', 'digit', '', '', '', 12),
+('bx_albums_per_page_browse_showcase', '32', @iCategId, '_sys_option_per_page_browse_showcase', 'digit', '', '', '', 15),
+('bx_albums_per_page_for_favorites_lists', '5', @iCategId, '_bx_albums_option_per_page_for_favorites_lists', 'digit', '', '', '', 17),
+('bx_albums_album_browsing_unit', '10', @iCategId, '_bx_albums_option_album_browsing_unit', 'digit', '', '', '', 20),
+('bx_albums_rss_num', '10', @iCategId, '_bx_albums_option_rss_num', 'digit', '', '', '', 20),
+('bx_albums_searchable_fields', 'title,text', @iCategId, '_bx_albums_option_searchable_fields', 'list', '', '', 'a:2:{s:6:"module";s:9:"bx_albums";s:6:"method";s:21:"get_searchable_fields";}', 30);
+
+-- PAGE: create entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_albums_create_entry', '_bx_albums_page_title_sys_create_entry', '_bx_albums_page_title_create_entry', 'bx_albums', 5, 2147483647, 1, 'create-album', 'page.php?i=create-album', '', '', '', 0, 1, 0, 'BxAlbumsPageBrowse', 'modules/boonex/albums/classes/BxAlbumsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_albums_create_entry', 1, 'bx_albums', '_bx_albums_page_block_title_create_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_albums";s:6:"method";s:13:"entity_create";}', 0, 1, 1);
+
+-- PAGE: add images
+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_albums_add_images', '_bx_albums_page_title_sys_add_images', '_bx_albums_page_title_add_images', 'bx_albums', 5, 2147483647, 1, 'add-images', '', '', '', '', 0, 1, 0, 'BxAlbumsPageEntry', 'modules/boonex/albums/classes/BxAlbumsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_albums_add_images', 1, 'bx_albums', '_bx_albums_page_block_title_add_images', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_albums";s:6:"method";s:16:"entity_add_files";}', 0, 0, 0);
+
+-- PAGE: edit entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_albums_edit_entry', '_bx_albums_page_title_sys_edit_entry', '_bx_albums_page_title_edit_entry', 'bx_albums', 5, 2147483647, 1, 'edit-album', '', '', '', '', 0, 1, 0, 'BxAlbumsPageEntry', 'modules/boonex/albums/classes/BxAlbumsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_albums_edit_entry', 1, 'bx_albums', '_bx_albums_page_block_title_edit_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_albums";s:6:"method";s:11:"entity_edit";}', 0, 0, 0);
+
+-- PAGE: delete entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_albums_delete_entry', '_bx_albums_page_title_sys_delete_entry', '_bx_albums_page_title_delete_entry', 'bx_albums', 5, 2147483647, 1, 'delete-album', '', '', '', '', 0, 1, 0, 'BxAlbumsPageEntry', 'modules/boonex/albums/classes/BxAlbumsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_albums_delete_entry', 1, 'bx_albums', '_bx_albums_page_block_title_delete_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_albums";s:6:"method";s:13:"entity_delete";}', 0, 0, 0);
+
+-- PAGE: view entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_albums_view_entry', '_bx_albums_page_title_sys_view_entry', '_bx_albums_page_title_view_entry', 'bx_albums', 12, 2147483647, 1, 'view-album', '', '', '', '', 0, 1, 0, 'BxAlbumsPageEntry', 'modules/boonex/albums/classes/BxAlbumsPageEntry.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_albums_view_entry', 2, 'bx_albums','' , '_bx_albums_page_block_title_entry_text', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:17:\"entity_text_block\";}', 0, 0, 1, 1),
+('bx_albums_view_entry', 2, 'bx_albums','' , '_bx_albums_page_block_title_entry_attachments', 0, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:18:\"entity_attachments\";}', 0, 0, 1, 3),
+('bx_albums_view_entry', 4, 'bx_albums','' , '_bx_albums_page_block_title_entry_social_sharing', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:21:\"entity_social_sharing\";}', 0, 0, 0, 0),
+('bx_albums_view_entry', 2, 'bx_albums','' , '_bx_albums_page_block_title_entry_comments', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 1, 4),
+('bx_albums_view_entry', 3, 'bx_albums','' , '_bx_albums_page_block_title_entry_location', 3, 2147483647, 'service', 'a:4:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:13:\"locations_map\";s:6:\"params\";a:2:{i:0;s:9:\"bx_albums\";i:1;s:4:\"{id}\";}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 0, 0, 1, 4),
+('bx_albums_view_entry', 3, 'bx_albums','' , '_bx_albums_page_block_title_entry_author', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:13:\"entity_author\";}', 0, 0, 1, 2),
+('bx_albums_view_entry', 3, 'bx_albums', '_bx_albums_page_block_title_sys_entry_context', '_bx_albums_page_block_title_entry_context', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:14:\"entity_context\";}', 0, 0, 1, 1),
+('bx_albums_view_entry', 3, 'bx_albums','' , '_bx_albums_page_block_title_entry_info', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:11:\"entity_info\";}', 0, 0, 1, 3),
+('bx_albums_view_entry', 3, 'bx_albums', '', '_bx_albums_page_block_title_entry_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:14:\"entity_actions\";}', 0, 0, 0, 0),
+('bx_albums_view_entry', 2, 'bx_albums','' , '_bx_albums_page_block_title_entry_all_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:18:\"entity_all_actions\";}', 0, 0, 1, 2),
+('bx_albums_view_entry', 2, 'bx_albums', '', '_bx_albums_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:14:\"entity_reports\";}', 0, 0, 1, 6);
+
+-- PAGE: view media
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `content_info`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_albums_view_media', 'view-album-media', '_bx_albums_page_title_sys_view_media', '_bx_albums_page_title_view_media', 'bx_albums', 12, 2147483647, 1, '', 'bx_albums_media', '', '', '', 0, 1, 0, 'BxAlbumsPageMedia', 'modules/boonex/albums/classes/BxAlbumsPageMedia.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_albums_view_media', 2, 'bx_albums', '', '_bx_albums_page_block_title_entry_view_media', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:10:\"media_view\";}', 0, 0, 1, 1),
+('bx_albums_view_media', 3, 'bx_albums', '', '_bx_albums_page_block_title_entry_author', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:12:\"media_author\";}', 0, 0, 1, 1),
+('bx_albums_view_media', 3, 'bx_albums', '', '_bx_albums_page_block_title_entry_social_sharing', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:20:\"media_social_sharing\";}', 0, 0, 0, 0),
+('bx_albums_view_media', 2, 'bx_albums', '', '_bx_albums_page_block_title_entry_comments', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:14:\"media_comments\";}', 0, 0, 1, 3),
+('bx_albums_view_media', 3, 'bx_albums', '', '_bx_albums_page_block_title_entry_view_media_exif', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:10:\"media_exif\";}', 0, 0, 1, 2),
+('bx_albums_view_media', 3, 'bx_albums', '', '_bx_albums_page_block_title_entry_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:13:\"media_actions\";}', 0, 0, 0, 0),
+('bx_albums_view_media', 2, 'bx_albums', '', '_bx_albums_page_block_title_entry_all_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:17:\"media_all_actions\";}', 0, 0, 1, 2),
+('bx_albums_view_media', 3, 'bx_albums', '', '_bx_albums_page_block_title_featured_entries_view_gallery_media', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:21:"browse_featured_media";s:6:"params";a:1:{i:0;s:7:"gallery";}}', 0, 1, 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_albums_view_entry_comments', '_bx_albums_page_title_sys_view_entry_comments', '_bx_albums_page_title_view_entry_comments', 'bx_albums', 5, 2147483647, 1, 'view-album-comments', '', '', '', '', 0, 1, 0, 'BxAlbumsPageEntry', 'modules/boonex/albums/classes/BxAlbumsPageEntry.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_albums_view_entry_comments', 1, 'bx_albums', '_bx_albums_page_block_title_entry_comments', '_bx_albums_page_block_title_entry_comments_link', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 1);
+
+-- PAGE: popular albums
+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_albums_popular', '_bx_albums_page_title_sys_entries_popular', '_bx_albums_page_title_entries_popular', 'bx_albums', 5, 2147483647, 1, 'albums-popular', 'page.php?i=albums-popular', '', '', '', 0, 1, 0, 'BxAlbumsPageBrowse', 'modules/boonex/albums/classes/BxAlbumsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_albums_popular', 1, 'bx_albums', '_bx_albums_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:14:"browse_popular";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1);
+
+-- PAGE: popular media
+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_albums_popular_media', '_bx_albums_page_title_sys_entries_popular_media', '_bx_albums_page_title_entries_popular_media', 'bx_albums', 5, 2147483647, 1, 'albums-popular-media', 'page.php?i=albums-popular-media', '', '', '', 0, 1, 0, 'BxAlbumsPageBrowseMedia', 'modules/boonex/albums/classes/BxAlbumsPageBrowseMedia.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_albums_popular_media', 1, 'bx_albums', '_bx_albums_page_block_title_popular_media', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:20:"browse_popular_media";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1);
+
+-- PAGE: top albums
+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_albums_top', '_bx_albums_page_title_sys_entries_top', '_bx_albums_page_title_entries_top', 'bx_albums', 5, 2147483647, 1, 'albums-top', 'page.php?i=albums-top', '', '', '', 0, 1, 0, 'BxAlbumsPageBrowse', 'modules/boonex/albums/classes/BxAlbumsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_albums_top', 1, 'bx_albums', '_bx_albums_page_block_title_top_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:10:"browse_top";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1);
+
+-- PAGE: top media
+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_albums_top_media', '_bx_albums_page_title_sys_entries_top_media', '_bx_albums_page_title_entries_top_media', 'bx_albums', 5, 2147483647, 1, 'albums-top-media', 'page.php?i=albums-top-media', '', '', '', 0, 1, 0, 'BxAlbumsPageBrowseMedia', 'modules/boonex/albums/classes/BxAlbumsPageBrowseMedia.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_albums_top_media', 1, 'bx_albums', '_bx_albums_page_block_title_top_media', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:16:"browse_top_media";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1);
+
+-- PAGE: entries of author
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_albums_author', 'albums-author', '_bx_albums_page_title_sys_entries_of_author', '_bx_albums_page_title_entries_of_author', 'bx_albums', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxAlbumsPageAuthor', 'modules/boonex/albums/classes/BxAlbumsPageAuthor.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_albums_author', 1, 'bx_albums', '', '_bx_albums_page_block_title_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:18:\"my_entries_actions\";}', 0, 0, 1, 1),
+('bx_albums_author', 1, 'bx_albums', '_bx_albums_page_block_title_sys_favorites_of_author', '_bx_albums_page_block_title_favorites_of_author', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";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_albums_author', 1, 'bx_albums', '_bx_albums_page_block_title_sys_favorites_of_author_media', '_bx_albums_page_block_title_favorites_of_author_media', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:21:\"browse_favorite_media\";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 0, 1, 1, 3),
+('bx_albums_author', 1, 'bx_albums', '_bx_albums_page_block_title_sys_entries_of_author', '_bx_albums_page_block_title_entries_of_author', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:13:\"browse_author\";}', 0, 0, 1, 4),
+('bx_albums_author', 1, 'bx_albums', '_bx_albums_page_block_title_sys_entries_in_context', '_bx_albums_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:14:"browse_context";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";i:0;a:1:{s:13:"empty_message";b:0;}}}', 0, 0, 1, 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_albums_favorites', '_bx_albums_page_title_sys_entries_favorites', '_bx_albums_page_title_entries_favorites', 'bx_albums', 12, 2147483647, 1, 'albums-favorites', 'page.php?i=albums-favorites', '', '', '', 0, 1, 0, 'BxAlbumsPageListEntry', 'modules/boonex/albums/classes/BxAlbumsPageListEntry.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_albums_favorites', 2, 'bx_albums', '_bx_albums_page_block_title_sys_favorites_entries', '_bx_albums_page_block_title_favorites_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";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_albums_favorites', 3, 'bx_albums', '', '_bx_albums_page_block_title_favorites_entries_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_albums";s:6:"method";s:19:"favorites_list_info";}', 0, 0, 0),
+('bx_albums_favorites', 3, 'bx_albums', '', '_bx_albums_page_block_title_favorites_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_albums";s:6:"method";s:22:"favorites_list_actions";}', 0, 0, 1);
+
+
+
+-- PAGE: entries in context
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_albums_context', 'albums-context', '_bx_albums_page_title_sys_entries_in_context', '_bx_albums_page_title_entries_in_context', 'bx_albums', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxAlbumsPageAuthor', 'modules/boonex/albums/classes/BxAlbumsPageAuthor.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_albums_context', 1, 'bx_albums', '_bx_albums_page_block_title_sys_entries_in_context', '_bx_albums_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:14:\"browse_context\";}', 0, 0, 1, 1);
+
+-- 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_albums_home', 'albums-home', '_bx_albums_page_title_sys_home', '_bx_albums_page_title_home', 'bx_albums', 2, 2147483647, 1, 'page.php?i=albums-home', '', '', '', 0, 1, 0, 'BxAlbumsPageBrowse', 'modules/boonex/albums/classes/BxAlbumsPageBrowse.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_albums_home', 1, 'bx_albums', '', '_bx_albums_page_block_title_featured_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 1, 1, 0),
+('bx_albums_home', 1, 'bx_albums', '', '_bx_albums_page_block_title_featured_entries_view_gallery_media', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:21:"browse_featured_media";s:6:"params";a:1:{i:0;s:7:"gallery";}}', 0, 1, 1, 1),
+('bx_albums_home', 1, 'bx_albums', '', '_bx_albums_page_block_title_updated_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:14:\"browse_updated\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"extended\";s:13:\"empty_message\";b:1;s:13:\"ajax_paginate\";b:0;}}', 0, 1, 1, 2),
+('bx_albums_home', 2, 'bx_albums', '', '_bx_albums_page_block_title_popular_keywords_albums', 11, 2147483647, 'service', 'a:4:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:14:\"keywords_cloud\";s:6:\"params\";a:3:{i:0;s:9:\"bx_albums\";i:1;s:9:\"bx_albums\";i:2;a:1:{s:10:\"show_empty\";b:1;}}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 1, 0, 1, 0),
+('bx_albums_home', 2, 'bx_albums', '', '_bx_albums_page_block_title_popular_keywords_media', 11, 2147483647, 'service', 'a:4:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:14:\"keywords_cloud\";s:6:\"params\";a:2:{i:0;s:15:\"bx_albums_media\";i:1;s:15:\"bx_albums_media\";}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 1, 0, 1, 1),
+('bx_albums_home', 2, 'bx_albums', '', '_bx_albums_page_block_title_popular_keywords_media_camera', 11, 2147483647, 'service', 'a:4:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:14:\"keywords_cloud\";s:6:\"params\";a:2:{i:0;s:22:\"bx_albums_media_camera\";i:1;s:22:\"bx_albums_media_camera\";}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 1, 0, 1, 2);
+
+-- 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_albums_search', '_bx_albums_page_title_sys_entries_search', '_bx_albums_page_title_entries_search', 'bx_albums', 11, 2147483647, 1, 'albums-search', 'page.php?i=albums-search', '', '', '', 0, 1, 0, 'BxAlbumsPageBrowse', 'modules/boonex/albums/classes/BxAlbumsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_albums_search', 2, 'bx_albums', '_bx_albums_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_albums";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1),
+('bx_albums_search', 1, 'bx_albums', '_bx_albums_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_albums";s:10:"show_empty";b:0;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1),
+('bx_albums_search', 3, 'bx_albums', '_bx_albums_page_block_title_search_form_media', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:15:"bx_albums_media";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1),
+('bx_albums_search', 1, 'bx_albums', '_bx_albums_page_block_title_search_results_media', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:15:"bx_albums_media";s:10:"show_empty";b:0;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 2),
+('bx_albums_search', 2, 'bx_albums', '_bx_albums_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_albums_cmts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 2),
+('bx_albums_search', 1, 'bx_albums', '_bx_albums_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_albums_cmts";s:10:"show_empty";b:0;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 3),
+('bx_albums_search', 3, 'bx_albums', '_bx_albums_page_block_title_search_form_media_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:20:"bx_albums_media_cmts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 2),
+('bx_albums_search', 1, 'bx_albums', '_bx_albums_page_block_title_search_results_media_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:20:"bx_albums_media_cmts";s:10:"show_empty";b:0;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 4);
+
+-- 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_albums_manage', '_bx_albums_page_title_sys_manage', '_bx_albums_page_title_manage', 'bx_albums', 5, 2147483647, 1, 'albums-manage', 'page.php?i=albums-manage', '', '', '', 0, 1, 0, 'BxAlbumsPageBrowse', 'modules/boonex/albums/classes/BxAlbumsPageBrowse.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_albums_manage', 1, 'bx_albums', '_bx_albums_page_block_title_system_manage', '_bx_albums_page_block_title_manage', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";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_albums_administration', '_bx_albums_page_title_sys_manage_administration', '_bx_albums_page_title_manage', 'bx_albums', 5, 192, 1, 'albums-administration', 'page.php?i=albums-administration', '', '', '', 0, 1, 0, 'BxAlbumsPageBrowse', 'modules/boonex/albums/classes/BxAlbumsPageBrowse.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_albums_administration', 1, 'bx_albums', '_bx_albums_page_block_title_system_manage_administration', '_bx_albums_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:12:\"manage_tools\";s:6:\"params\";a:1:{i:0;s:14:\"administration\";}}', 0, 1, 0);
+
+-- PAGE: add block to homepage
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = 'sys_home' AND `cell_id` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('sys_home', 1, 'bx_albums', '_bx_albums_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:13:"browse_public";s:6:"params";a:2:{i:0;b:0;i:1;b:0;}}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1),
+('sys_home', 1, 'bx_albums', '_bx_albums_page_block_title_updated_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:14:"browse_updated";s:6:"params";a:2:{i:0;b:0;i:1;b:0;}}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 2);
+
+-- 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_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_albums', '_bx_albums_page_block_title_sys_my_entries', '_bx_albums_page_block_title_my_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:13:"browse_author";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:2:{s:8:"per_page";s:26:"bx_albums_per_page_profile";s:13:"empty_message";b:0;}}}', 0, 0, 0);
+
+-- PAGE: service blocks
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = '' AND `cell_id` = 0 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('', 0, 'bx_albums', '', '_bx_albums_page_block_title_recent_media', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:19:"browse_recent_media";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:1;}}', 0, 1, 1, @iBlockOrder + 1),
+('', 0, 'bx_albums', '', '_bx_albums_page_block_title_popular_keywords_albums', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:14:"keywords_cloud";s:6:"params";a:2:{i:0;s:9:"bx_albums";i:1;s:9:"bx_albums";}s:5:"class";s:20:"TemplServiceMetatags";}', 0, 1, 1, @iBlockOrder + 2),
+('', 0, 'bx_albums', '', '_bx_albums_page_block_title_popular_keywords_media', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:14:"keywords_cloud";s:6:"params";a:2:{i:0;s:15:"bx_albums_media";i:1;s:15:"bx_albums_media";}s:5:"class";s:20:"TemplServiceMetatags";}', 0, 1, 1, @iBlockOrder + 3),
+('', 0, 'bx_albums', '', '_bx_albums_page_block_title_popular_keywords_media_camera', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:14:"keywords_cloud";s:6:"params";a:2:{i:0;s:22:"bx_albums_media_camera";i:1;s:22:"bx_albums_media_camera";}s:5:"class";s:20:"TemplServiceMetatags";}', 0, 1, 1, @iBlockOrder + 4),
+('', 0, 'bx_albums', '', '_bx_albums_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:13:"browse_public";s:6:"params";a:3:{s:9:"unit_view";s:8:"extended";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1, @iBlockOrder + 5),
+('', 0, 'bx_albums', '_bx_albums_page_block_title_sys_recent_media_view_showcase', '_bx_albums_page_block_title_recent_media_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:19:"browse_recent_media";s:6:"params";a:3:{s:9:"unit_view";s:8:"showcase";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1, @iBlockOrder + 6),
+('', 0, 'bx_albums', '_bx_albums_page_block_title_sys_popular_media_view_showcase', '_bx_albums_page_block_title_popular_media_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:20:"browse_popular_media";s:6:"params";a:3:{s:9:"unit_view";s:8:"showcase";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1,@iBlockOrder + 7),
+('', 0, 'bx_albums', '_bx_albums_page_block_title_sys_featured_media_view_showcase', '_bx_albums_page_block_title_featured_media_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_albums";s:6:"method";s:21:"browse_featured_media";s:6:"params";a:3:{s:9:"unit_view";s:8:"showcase";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1,@iBlockOrder + 8);
+
+-- 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_albums', 'albums-home', '_bx_albums_menu_item_title_system_entries_home', '_bx_albums_menu_item_title_entries_home', 'page.php?i=albums-home', '', '', 'far image col-blue1', 'bx_albums_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_albums', 'albums-home', '_bx_albums_menu_item_title_system_entries_home', '_bx_albums_menu_item_title_entries_home', 'page.php?i=albums-home', '', '', 'far image col-blue1', 'bx_albums_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_albums', 'create-album', '_bx_albums_menu_item_title_system_create_entry', '_bx_albums_menu_item_title_create_entry', 'page.php?i=create-album', '', '', 'far image col-blue1', '', 2147483647, 1, 1, IFNULL(@iAddMenuOrder, 0) + 1);
+
+-- MENU: actions menu for view entry 
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_albums_view', '_bx_albums_menu_title_view_entry', 'bx_albums_view', 'bx_albums', 9, 0, 1, 'BxAlbumsMenuView', 'modules/boonex/albums/classes/BxAlbumsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_albums_view', 'bx_albums', '_bx_albums_menu_set_title_view_entry', 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_albums_view', 'bx_albums', 'add-images-to-album', '_bx_albums_menu_item_title_system_add_images', '_bx_albums_menu_item_title_add_images', 'page.php?i=add-images&id={content_id}', '', '', 'plus', '', 2147483647, 1, 0, 10),
+('bx_albums_view', 'bx_albums', 'edit-album', '_bx_albums_menu_item_title_system_edit_entry', '_bx_albums_menu_item_title_edit_entry', 'page.php?i=edit-album&id={content_id}', '', '', 'pencil-alt', '', 2147483647, 1, 0, 20),
+('bx_albums_view', 'bx_albums', 'delete-album', '_bx_albums_menu_item_title_system_delete_entry', '_bx_albums_menu_item_title_delete_entry', 'page.php?i=delete-album&id={content_id}', '', '', 'remove', '', 2147483647, 1, 0, 30),
+('bx_albums_view', 'bx_albums', 'approve', '_sys_menu_item_title_system_va_approve', '_sys_menu_item_title_va_approve', 'javascript:void(0)', 'javascript:bx_approve(this, ''{module_uri}'', {content_id});', '', 'check', '', 2147483647, 1, 0, 40);
+
+-- MENU: all actions menu for view entry 
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_albums_view_actions', '_sys_menu_title_view_actions', 'bx_albums_view_actions', 'bx_albums', 15, 0, 1, 'BxAlbumsMenuViewActions', 'modules/boonex/albums/classes/BxAlbumsMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_albums_view_actions', 'bx_albums', '_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_albums_view_actions', 'bx_albums', 'add-images-to-album', '_bx_albums_menu_item_title_system_add_images', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 10),
+('bx_albums_view_actions', 'bx_albums', 'edit-album', '_bx_albums_menu_item_title_system_edit_entry', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 20),
+('bx_albums_view_actions', 'bx_albums', 'delete-album', '_bx_albums_menu_item_title_system_delete_entry', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 30),
+('bx_albums_view_actions', 'bx_albums', 'approve', '_sys_menu_item_title_system_va_approve', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 40),
+('bx_albums_view_actions', 'bx_albums', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 200),
+('bx_albums_view_actions', 'bx_albums', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 210),
+('bx_albums_view_actions', 'bx_albums', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 220),
+('bx_albums_view_actions', 'bx_albums', 'reaction', '_sys_menu_item_title_system_va_reaction', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 225),
+('bx_albums_view_actions', 'bx_albums', 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 230),
+('bx_albums_view_actions', 'bx_albums', 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 240),
+('bx_albums_view_actions', 'bx_albums', 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 250),
+('bx_albums_view_actions', 'bx_albums', 'repost', '_sys_menu_item_title_system_va_repost', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 260),
+('bx_albums_view_actions', 'bx_albums', 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 270),
+('bx_albums_view_actions', 'bx_albums', 'notes', '_sys_menu_item_title_system_va_notes', '_sys_menu_item_title_va_notes', 'javascript:void(0)', 'javascript:bx_get_notes(this,  ''{module_uri}'', {content_id});', '', 'exclamation-triangle', '', '', 0, 2147483647, 1, 0, 280),
+('bx_albums_view_actions', 'bx_albums', 'audit', '_sys_menu_item_title_system_va_audit', '_sys_menu_item_title_va_audit', 'page.php?i=dashboard-audit&module=bx_albums&content_id={content_id}', '', '', 'history', '', '', 0, 192, 1, 0, 290),
+('bx_albums_view_actions', 'bx_albums', '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_albums_view_actions', 'bx_albums', '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 view media
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_albums_view_media', '_bx_albums_menu_title_view_media', 'bx_albums_view_media', 'bx_albums', 9, 0, 1, 'BxAlbumsMenuView', 'modules/boonex/albums/classes/BxAlbumsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_albums_view_media', 'bx_albums', '_bx_albums_menu_set_title_view_media', 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_albums_view_media', 'bx_albums', 'add-images-to-album', '_bx_albums_menu_item_title_system_add_images', '_bx_albums_menu_item_title_add_images', 'page.php?i=add-images&id={content_id}', '', '', 'plus', '', 2147483647, 1, 0, 10),
+('bx_albums_view_media', 'bx_albums', 'edit-album', '_bx_albums_menu_item_title_system_edit_album', '_bx_albums_menu_item_title_edit_album', 'page.php?i=edit-album&id={content_id}', '', '', 'pencil-alt', '', 2147483647, 1, 0, 20),
+('bx_albums_view_media', 'bx_albums', 'edit-image', '_bx_albums_menu_item_title_system_edit_image', '_bx_albums_menu_item_title_edit_image', 'javascript:void(0)', 'javascript:{js_object}.editMedia(this, {media_id});', '', 'pencil-alt', '', 2147483647, 1, 0, 30),
+('bx_albums_view_media', 'bx_albums', 'delete-image', '_bx_albums_menu_item_title_system_delete_image', '_bx_albums_menu_item_title_delete_image', 'javascript:void(0)', 'javascript:{js_object}.deleteMedia(this, {media_id});', '', 'remove', '', 2147483647, 1, 0, 40),
+('bx_albums_view_media', 'bx_albums', 'move-image', '_bx_albums_menu_item_title_system_move_image', '_bx_albums_menu_item_title_move_image', 'javascript:void(0)', 'javascript:{js_object}.moveMedia(this, {media_id});', '', 'exchange-alt', '', 2147483647, 1, 0, 50);
+
+
+-- MENU: all actions menu for view media page 
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_albums_view_actions_media', '_bx_albums_menu_title_view_actions_media', 'bx_albums_view_actions_media', 'bx_albums', 15, 0, 1, 'BxAlbumsMenuViewActionsMedia', 'modules/boonex/albums/classes/BxAlbumsMenuViewActionsMedia.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_albums_view_actions_media', 'bx_albums', '_bx_albums_menu_set_title_view_actions_media', 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_albums_view_actions_media', 'bx_albums', 'add-images-to-album', '_bx_albums_menu_item_title_system_add_images', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 10),
+('bx_albums_view_actions_media', 'bx_albums', 'edit-album', '_bx_albums_menu_item_title_system_edit_album', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 20),
+('bx_albums_view_actions_media', 'bx_albums', 'edit-image', '_bx_albums_menu_item_title_system_edit_image', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 30),
+('bx_albums_view_actions_media', 'bx_albums', 'delete-image', '_bx_albums_menu_item_title_system_delete_image', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 40),
+('bx_albums_view_actions_media', 'bx_albums', 'move-image', '_bx_albums_menu_item_title_system_move_image', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 50),
+('bx_albums_view_actions_media', 'bx_albums', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 200),
+('bx_albums_view_actions_media', 'bx_albums', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 210),
+('bx_albums_view_actions_media', 'bx_albums', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 220),
+('bx_albums_view_actions_media', 'bx_albums', 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 230),
+('bx_albums_view_actions_media', 'bx_albums', 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 240),
+('bx_albums_view_actions_media', 'bx_albums', 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 250),
+('bx_albums_view_actions_media', 'bx_albums', 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 260),
+('bx_albums_view_actions_media', 'bx_albums', '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_albums_view_actions_media', 'bx_albums', '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 media unit
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_albums_view_actions_media_unit', '_bx_albums_menu_title_view_actions_media_unit', 'bx_albums_view_actions_media_unit', 'bx_albums', 15, 0, 1, 'BxAlbumsMenuViewActionsMedia', 'modules/boonex/albums/classes/BxAlbumsMenuViewActionsMedia.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_albums_view_actions_media_unit', 'bx_albums', '_bx_albums_menu_set_title_view_actions_media_unit', 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_albums_view_actions_media_unit', 'bx_albums', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 200),
+('bx_albums_view_actions_media_unit', 'bx_albums', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 210),
+('bx_albums_view_actions_media_unit', 'bx_albums', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 220),
+('bx_albums_view_actions_media_unit', 'bx_albums', 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 230),
+('bx_albums_view_actions_media_unit', 'bx_albums', 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 240),
+('bx_albums_view_actions_media_unit', 'bx_albums', 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 250),
+('bx_albums_view_actions_media_unit', 'bx_albums', 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 260),
+('bx_albums_view_actions_media_unit', 'bx_albums', '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_albums_my', '_bx_albums_menu_title_entries_my', 'bx_albums_my', 'bx_albums', 9, 0, 1, 'BxAlbumsMenu', 'modules/boonex/albums/classes/BxAlbumsMenu.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_albums_my', 'bx_albums', '_bx_albums_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_albums_my', 'bx_albums', 'create-album', '_bx_albums_menu_item_title_system_create_entry', '_bx_albums_menu_item_title_create_entry', 'page.php?i=create-album', '', '', '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_albums_submenu', '_bx_albums_menu_title_submenu', 'bx_albums_submenu', 'bx_albums', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_albums_submenu', 'bx_albums', '_bx_albums_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_albums_submenu', 'bx_albums', 'albums-home', '_bx_albums_menu_item_title_system_entries_recent', '_bx_albums_menu_item_title_entries_recent', 'page.php?i=albums-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_albums_submenu', 'bx_albums', 'albums-popular', '_bx_albums_menu_item_title_system_entries_popular', '_bx_albums_menu_item_title_entries_popular', 'page.php?i=albums-popular', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_albums_submenu', 'bx_albums', 'albums-top', '_bx_albums_menu_item_title_system_entries_top', '_bx_albums_menu_item_title_entries_top', 'page.php?i=albums-top', '', '', '', '', 2147483647, 1, 1, 3),
+('bx_albums_submenu', 'bx_albums', 'albums-popular-media', '_bx_albums_menu_item_title_system_entries_popular_media', '_bx_albums_menu_item_title_entries_popular_media', 'page.php?i=albums-popular-media', '', '', '', '', 2147483647, 1, 1, 4),
+('bx_albums_submenu', 'bx_albums', 'albums-top-media', '_bx_albums_menu_item_title_system_entries_top_media', '_bx_albums_menu_item_title_entries_top_media', 'page.php?i=albums-top-media', '', '', '', '', 2147483647, 1, 1, 5),
+('bx_albums_submenu', 'bx_albums', 'albums-search', '_bx_albums_menu_item_title_system_entries_search', '_bx_albums_menu_item_title_entries_search', 'page.php?i=albums-search', '', '', '', '', 2147483647, 1, 1, 6),
+('bx_albums_submenu', 'bx_albums', 'albums-manage', '_bx_albums_menu_item_title_system_entries_manage', '_bx_albums_menu_item_title_entries_manage', 'page.php?i=albums-manage', '', '', '', '', 2147483646, 1, 1, 7);
+
+-- MENU: sub-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_albums_view_submenu', '_bx_albums_menu_title_view_entry_submenu', 'bx_albums_view_submenu', 'bx_albums', 8, 0, 1, 'BxAlbumsMenuView', 'modules/boonex/albums/classes/BxAlbumsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_albums_view_submenu', 'bx_albums', '_bx_albums_menu_set_title_view_entry_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_albums_view_submenu', 'bx_albums', 'view-album', '_bx_albums_menu_item_title_system_view_entry', '_bx_albums_menu_item_title_view_entry_submenu_entry', 'page.php?i=view-album&id={content_id}', '', '', '', '', 2147483647, 1, 0, 1),
+('bx_albums_view_submenu', 'bx_albums', 'view-album-comments', '_bx_albums_menu_item_title_system_view_entry_comments', '_bx_albums_menu_item_title_view_entry_submenu_comments', 'page.php?i=view-album-comments&id={content_id}', '', '', '', '', 2147483647, 1, 0, 2);
+
+-- 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_albums_snippet_meta', '_sys_menu_title_snippet_meta', 'bx_albums_snippet_meta', 'bx_albums', 15, 0, 1, 'BxAlbumsMenuSnippetMeta', 'modules/boonex/albums/classes/BxAlbumsMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_albums_snippet_meta', 'bx_albums', '_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_albums_snippet_meta', 'bx_albums', 'date', '_sys_menu_item_title_system_sm_date', '_sys_menu_item_title_sm_date', '', '', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_albums_snippet_meta', 'bx_albums', 'author', '_sys_menu_item_title_system_sm_author', '_sys_menu_item_title_sm_author', '', '', '', '', '', 2147483647, 1, 0, 1, 2),
+('bx_albums_snippet_meta', 'bx_albums', 'tags', '_sys_menu_item_title_system_sm_tags', '_sys_menu_item_title_sm_tags', '', '', '', '', '', 2147483647, 0, 0, 1, 3),
+('bx_albums_snippet_meta', 'bx_albums', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 2147483647, 0, 0, 1, 4),
+('bx_albums_snippet_meta', 'bx_albums', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 2147483647, 0, 0, 1, 5),
+('bx_albums_snippet_meta', 'bx_albums', 'items', '_bx_albums_menu_item_title_system_sm_items', '_bx_albums_menu_item_title_sm_items', '', '', '', '', '', 2147483647, 0, 0, 1, 6);
+
+-- 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_albums', 'profile-stats-my-albums', '_bx_albums_menu_item_title_system_manage_my_albums', '_bx_albums_menu_item_title_manage_my_albums', 'page.php?i=albums-author&profile_id={member_id}', '', '_self', 'far image col-blue1', 'a:2:{s:6:"module";s:9:"bx_albums";s:6:"method";s:41:"get_menu_addon_manage_tools_profile_stats";}', '', 2147483646, 1, 0, @iNotifMenuOrder + 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_albums_menu_manage_tools', '_bx_albums_menu_title_manage_tools', 'bx_albums_menu_manage_tools', 'bx_albums', 6, 0, 1, 'BxAlbumsMenuManageTools', 'modules/boonex/albums/classes/BxAlbumsMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_albums_menu_manage_tools', 'bx_albums', '_bx_albums_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_albums_menu_manage_tools', 'bx_albums', 'delete-with-content', '_bx_albums_menu_item_title_system_delete_with_content', '_bx_albums_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'far trash-alt', '', 128, 1, 0, 0);
+
+-- 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_albums', 'albums-administration', '_bx_albums_menu_item_title_system_admt_albums', '_bx_albums_menu_item_title_admt_albums', 'page.php?i=albums-administration', '', '_self', 'far image', 'a:2:{s:6:"module";s:9:"bx_albums";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
+
+-- MENU: add menu item to profiles modules (trigger* menu sets are processed separately upon modules enable/disable)
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('trigger_profile_view_submenu', 'bx_albums', 'albums-author', '_bx_albums_menu_item_title_system_view_entries_author', '_bx_albums_menu_item_title_view_entries_author', 'page.php?i=albums-author&profile_id={profile_id}', '', '', 'far image col-blue1', '', 2147483647, 1, 0, 0),
+('trigger_group_view_submenu', 'bx_albums', 'albums-context', '_bx_albums_menu_item_title_system_view_entries_in_context', '_bx_albums_menu_item_title_view_entries_in_context', 'page.php?i=albums-context&profile_id={profile_id}', '', '', 'far image col-blue1', '', 2147483647, 1, 0, 0);
+
+
+-- PRIVACY 
+INSERT INTO `sys_objects_privacy` (`object`, `module`, `action`, `title`, `default_group`, `table`, `table_field_id`, `table_field_author`, `override_class_name`, `override_class_file`) VALUES
+('bx_albums_allow_view_to', 'bx_albums', 'view', '_bx_albums_form_entry_input_allow_view_to', '3', 'bx_albums_albums', 'id', 'author', '', ''),
+('bx_albums_allow_view_favorite_list', 'bx_albums', 'view_favorite_list', '_bx_albums_form_entry_input_allow_view_favorite_list', '3', 'bx_albums_favorites_lists', 'id', 'author_id', '', '');
+
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_albums', 'create entry', NULL, '_bx_albums_acl_action_create_entry', '', 1, 3);
+SET @iIdActionEntryCreate = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_albums', 'delete entry', NULL, '_bx_albums_acl_action_delete_entry', '', 1, 3);
+SET @iIdActionEntryDelete = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_albums', 'view entry', NULL, '_bx_albums_acl_action_view_entry', '', 1, 0);
+SET @iIdActionEntryView = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_albums', 'set thumb', NULL, '_bx_albums_acl_action_set_thumb', '', 1, 3);
+SET @iIdActionSetThumb = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_albums', 'edit any entry', NULL, '_bx_albums_acl_action_edit_any_entry', '', 1, 3);
+SET @iIdActionEntryEditAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_albums', 'delete any entry', NULL, '_bx_albums_acl_action_delete_any_entry', '', 1, 3);
+SET @iIdActionEntryDeleteAny = LAST_INSERT_ID();
+
+SET @iUnauthenticated = 1;
+SET @iAccount = 2;
+SET @iStandard = 3;
+SET @iUnconfirmed = 4;
+SET @iPending = 5;
+SET @iSuspended = 6;
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+
+-- entry create
+(@iStandard, @iIdActionEntryCreate),
+(@iModerator, @iIdActionEntryCreate),
+(@iAdministrator, @iIdActionEntryCreate),
+(@iPremium, @iIdActionEntryCreate),
+
+-- entry delete
+(@iStandard, @iIdActionEntryDelete),
+(@iModerator, @iIdActionEntryDelete),
+(@iAdministrator, @iIdActionEntryDelete),
+(@iPremium, @iIdActionEntryDelete),
+
+-- entry view
+(@iUnauthenticated, @iIdActionEntryView),
+(@iAccount, @iIdActionEntryView),
+(@iStandard, @iIdActionEntryView),
+(@iUnconfirmed, @iIdActionEntryView),
+(@iPending, @iIdActionEntryView),
+(@iModerator, @iIdActionEntryView),
+(@iAdministrator, @iIdActionEntryView),
+(@iPremium, @iIdActionEntryView),
+
+-- set entry thumb
+(@iStandard, @iIdActionSetThumb),
+(@iModerator, @iIdActionSetThumb),
+(@iAdministrator, @iIdActionSetThumb),
+(@iPremium, @iIdActionSetThumb),
+
+-- edit any entry
+(@iModerator, @iIdActionEntryEditAny),
+(@iAdministrator, @iIdActionEntryEditAny),
+
+-- delete any entry
+(@iAdministrator, @iIdActionEntryDeleteAny);
+
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `GlobalSearch`, `ClassName`, `ClassPath`) VALUES
+('bx_albums', '_bx_albums', @iSearchOrder + 1, 1, 'BxAlbumsSearchResult', 'modules/boonex/albums/classes/BxAlbumsSearchResult.php'),
+('bx_albums_cmts', '_bx_albums_cmts', @iSearchOrder + 2, 1, 'BxAlbumsCmtsSearchResult', 'modules/boonex/albums/classes/BxAlbumsCmtsSearchResult.php'),
+('bx_albums_media', '_bx_albums_media', @iSearchOrder + 3, 1, 'BxAlbumsSearchResultMedia', 'modules/boonex/albums/classes/BxAlbumsSearchResultMedia.php'),
+('bx_albums_media_cmts', '_bx_albums_media_cmts', @iSearchOrder + 4, 1, 'BxAlbumsCmtsSearchResultMedia', 'modules/boonex/albums/classes/BxAlbumsCmtsSearchResultMedia.php'),
+('bx_albums_media_camera', '_bx_albums_media', @iSearchOrder + 5, 0, 'BxAlbumsSearchResultMediaCamera', 'modules/boonex/albums/classes/BxAlbumsSearchResultMediaCamera.php');
+
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `module`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_albums', 'bx_albums', 'bx_albums_meta_keywords', 'bx_albums_meta_locations', 'bx_albums_meta_mentions', '', ''),
+('bx_albums_media', 'bx_albums', 'bx_albums_meta_keywords_media', '', '', '', ''),
+('bx_albums_media_camera', 'bx_albums', 'bx_albums_meta_keywords_media_camera', '', '', '', '');
+
+
+-- STATS
+SET @iMaxOrderStats = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_statistics`);
+INSERT INTO `sys_statistics` (`module`, `name`, `title`, `link`, `icon`, `query`, `order`) VALUES 
+('bx_albums', 'bx_albums', '_bx_albums', 'page.php?i=albums-home', 'far image col-blue1', 'SELECT COUNT(*) FROM `bx_albums_albums` WHERE 1 AND `status` = ''active'' AND `status_admin` = ''active''', @iMaxOrderStats + 1),
+('bx_albums', 'bx_albums_media', '_bx_albums_media', '', 'far image col-blue1', 'SELECT COUNT(*) FROM `bx_albums_files` WHERE 1', @iMaxOrderStats + 2);
+
+
+-- 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_albums_growth', '_bx_albums_chart_growth', 'bx_albums_albums', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 1, 'BxDolChartGrowth', ''),
+('bx_albums_growth_speed', '_bx_albums_chart_growth_speed', 'bx_albums_albums', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 2, 'BxDolChartGrowthSpeed', ''),
+('bx_albums_growth_media', '_bx_albums_chart_growth_media', 'bx_albums_files', 'added', '', '', '', 1, @iMaxOrderCharts + 3, 'BxDolChartGrowth', ''),
+('bx_albums_growth_speed_media', '_bx_albums_chart_growth_speed_media', 'bx_albums_files', 'added', '', '', '', 1, @iMaxOrderCharts + 4, 'BxDolChartGrowthSpeed', '');
+
+
+-- GRIDS: moderation tools
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_albums_administration', 'Sql', 'SELECT * FROM `bx_albums_albums` WHERE 1 ', 'bx_albums_albums', 'id', 'added', 'status_admin', '', 20, NULL, 'start', '', 'title,text', '', 'like', 'reports', '', 192, 'BxAlbumsGridAdministration', 'modules/boonex/albums/classes/BxAlbumsGridAdministration.php'),
+('bx_albums_common', 'Sql', 'SELECT * FROM `bx_albums_albums` WHERE 1 ', 'bx_albums_albums', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'title,text', '', 'like', '', '', 2147483647, 'BxAlbumsGridCommon', 'modules/boonex/albums/classes/BxAlbumsGridCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_albums_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_albums_administration', 'switcher', '_bx_albums_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_albums_administration', 'reports', '_sys_txt_reports_title', '5%', 0, '', '', 3),
+('bx_albums_administration', 'title', '_bx_albums_grid_column_title_adm_title', '25%', 0, '', '', 4),
+('bx_albums_administration', 'added', '_bx_albums_grid_column_title_adm_added', '20%', 1, '25', '', 5),
+('bx_albums_administration', 'author', '_bx_albums_grid_column_title_adm_author', '20%', 0, '25', '', 6),
+('bx_albums_administration', 'actions', '', '20%', 0, '', '', 7),
+
+('bx_albums_common', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_albums_common', 'switcher', '', '8%', 0, '', '', 2),
+('bx_albums_common', 'title', '_bx_albums_grid_column_title_adm_title', '40%', 0, '', '', 3),
+('bx_albums_common', 'added', '_bx_albums_grid_column_title_adm_added', '15%', 1, '25', '', 4),
+('bx_albums_common', 'status_admin', '_bx_albums_grid_column_title_adm_status_admin', '15%', 0, '16', '', 5),
+('bx_albums_common', 'actions', '', '20%', 0, '', '', 6);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_albums_administration', 'bulk', 'delete', '_bx_albums_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_albums_administration', 'bulk', 'clear_reports', '_bx_albums_grid_action_title_adm_clear_reports', '', 0, 1, 2),
+('bx_albums_administration', 'single', 'edit', '_bx_albums_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_albums_administration', 'single', 'delete', '_bx_albums_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_albums_administration', 'single', 'settings', '_bx_albums_grid_action_title_adm_more_actions', 'cog', 1, 0, 3),
+('bx_albums_administration', 'single', 'audit_content', '_bx_albums_grid_action_title_adm_audit_content', 'search', 1, 0, 4),
+('bx_albums_administration', 'single', 'clear_reports', '_bx_albums_grid_action_title_adm_clear_reports', 'eraser', 1, 0, 5),
+('bx_albums_common', 'bulk', 'delete', '_bx_albums_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_albums_common', 'single', 'edit', '_bx_albums_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_albums_common', 'single', 'delete', '_bx_albums_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_albums_common', 'single', 'settings', '_bx_albums_grid_action_title_adm_more_actions', 'cog', 1, 0, 3);
+
+
+-- UPLOADERS
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_albums_html5', 1, 'BxAlbumsUploaderHTML5', 'modules/boonex/albums/classes/BxAlbumsUploaderHTML5.php'),
+('bx_albums_record_video', 1, 'BxAlbumsUploaderRecordVideo', 'modules/boonex/albums/classes/BxAlbumsUploaderRecordVideo.php'),
+('bx_albums_crop', 1, 'BxAlbumsUploaderCrop', 'modules/boonex/albums/classes/BxAlbumsUploaderCrop.php');
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_albums', 'BxAlbumsAlertsResponse', 'modules/boonex/albums/classes/BxAlbumsAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('profile', 'delete', @iHandler),
+
+('bx_albums_files', 'file_deleted', @iHandler),
+('bx_albums_video_mp4', 'transcoded', @iHandler);

+ 605 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/install/sql/install.sql

@@ -0,0 +1,605 @@
+-- TABLE: entries
+CREATE TABLE IF NOT EXISTS `bx_albums_albums` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `author` int(10) unsigned NOT NULL,
+  `added` int(11) NOT NULL,
+  `changed` int(11) NOT NULL,
+  `thumb` int(11) NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `text` text NOT NULL,
+  `labels` text NOT NULL,
+  `location` text NOT NULL,
+  `views` int(11) NOT NULL default '0',
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `rrate` float NOT NULL default '0',
+  `rvotes` 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(16) NOT NULL DEFAULT '3',
+  `status` enum('active','awaiting','failed','hidden') NOT NULL DEFAULT 'active',
+  `status_admin` enum('active','hidden','pending') NOT NULL DEFAULT 'active',
+  PRIMARY KEY (`id`),
+  FULLTEXT KEY `title_text` (`title`,`text`)
+);
+
+-- TABLE: storages & transcoders
+CREATE TABLE IF NOT EXISTS `bx_albums_files` (
+  `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,
+  `duration` int(11) 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 IF NOT EXISTS `bx_albums_photos_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_albums_files2albums` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `content_id` int(10) unsigned NOT NULL,
+  `file_id` int(11) NOT NULL,
+  `author` int(10) unsigned NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `views` int(11) NOT NULL,
+  `rate` float NOT NULL,
+  `votes` int(11) NOT NULL,
+  `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,
+  `reports` int(11) NOT NULL default '0',
+  `featured` int(11) NOT NULL default '0',
+  `cf` int(11) NOT NULL default '1',
+  `data` text NOT NULL,
+  `exif` text NOT NULL,
+  `order` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `file_content` (`file_id`,`content_id`),
+  KEY `content_id` (`content_id`),
+  FULLTEXT KEY `search_fields` (`title`)
+);
+
+-- TABLE: comments
+CREATE TABLE IF NOT EXISTS `bx_albums_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_albums_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_albums_cmts_media` (
+  `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`)
+);
+
+-- TABLE: votes
+CREATE TABLE IF NOT EXISTS `bx_albums_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_albums_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_albums_votes_media` (
+  `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_albums_votes_media_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_albums_reactions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `reaction` varchar(32) NOT NULL default '',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `reaction` (`object_id`, `reaction`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_albums_reactions_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',
+  `reaction` varchar(32) NOT NULL default '',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+-- TABLE: views
+CREATE TABLE `bx_albums_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`)
+);
+
+CREATE TABLE `bx_albums_views_media_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: metas
+CREATE TABLE `bx_albums_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_albums_meta_keywords_media` (
+  `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_albums_meta_keywords_media_camera` (
+  `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_albums_meta_locations` (
+  `object_id` int(10) unsigned NOT NULL,
+  `lat` double NOT NULL,
+  `lng` double NOT NULL,
+  `country` varchar(2) NOT NULL,
+  `state` varchar(255) NOT NULL,
+  `city` varchar(255) NOT NULL,
+  `zip` varchar(255) NOT NULL,
+  `street` varchar(255) NOT NULL,
+  `street_number` varchar(255) NOT NULL,
+  PRIMARY KEY (`object_id`),
+  KEY `country_state_city` (`country`,`state`(8),`city`(8))
+);
+
+CREATE TABLE `bx_albums_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: reports
+CREATE TABLE IF NOT EXISTS `bx_albums_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_albums_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_albums_reports_media` (
+  `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_albums_reports_media_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: favorites
+CREATE TABLE `bx_albums_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',
+  `list_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`author_id`)
+);
+
+CREATE TABLE `bx_albums_favorites_media_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`)
+);
+
+CREATE TABLE `bx_albums_favorites_lists` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `title` varchar(255) NOT NULL,
+  `author_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  `allow_view_favorite_list_to` varchar(16) NOT NULL DEFAULT '3',
+   PRIMARY KEY (`id`)
+);
+
+-- TABLE: scores
+CREATE TABLE IF NOT EXISTS `bx_albums_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_albums_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_albums_scores_media` (
+  `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_albums_scores_media_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
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+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_albums_files', @sStorageEngine, 'a:1:{s:6:"fields";a:1:{s:10:"dimensions";s:17:"getFileDimensions";}}', 360, 2592000, 3, 'bx_albums_files', 'allow-deny', '{imagevideo}', '', 0, 0, 0, 0, 0, 0),
+('bx_albums_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_albums_photos_resized', 'allow-deny', '{imagevideo}', '', 0, 0, 0, 0, 0, 0);
+
+INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`, `override_class_name`, `override_class_file`) VALUES
+('bx_albums_preview', 'bx_albums_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_albums_files";}', 'no', '1', '2592000', '0', '', ''),
+('bx_albums_browse', 'bx_albums_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_albums_files";}', 'no', '1', '2592000', '0', '', ''),
+('bx_albums_big', 'bx_albums_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_albums_files";}', 'no', '1', '2592000', '0', '', ''),
+('bx_albums_video_poster_browse', 'bx_albums_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_albums_files";}', 'no', 0, 0, 0, 'BxDolTranscoderVideo', ''),
+('bx_albums_video_poster_preview', 'bx_albums_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_albums_files";}', 'no', 0, 0, 0, 'BxDolTranscoderVideo', ''),
+('bx_albums_video_poster_big', 'bx_albums_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_albums_files";}', 'no', 0, 0, 0, 'BxDolTranscoderVideo', ''),
+('bx_albums_video_mp4', 'bx_albums_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_albums_files";}', 'no', 0, 0, 0, 'BxDolTranscoderVideo', ''),
+('bx_albums_video_mp4_hd', 'bx_albums_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_albums_files";}', 'no', 0, 0, 0, 'BxDolTranscoderVideo', ''),
+('bx_albums_proxy_preview', 'bx_albums_photos_resized', 'Proxy', 'a:4:{s:6:"object";s:15:"bx_albums_files";s:5:"image";s:17:"bx_albums_preview";s:12:"video_poster";s:30:"bx_albums_video_poster_preview";s:5:"video";a:4:{i:0;s:19:"bx_albums_video_mp4";i:1;s:22:"bx_albums_video_mp4_hd";i:2;s:29:"bx_albums_video_poster_browse";i:3;s:26:"bx_albums_video_poster_big";}}', 'no', 0, 0, 0, 'BxDolTranscoderProxy', ''),
+('bx_albums_proxy_browse', 'bx_albums_photos_resized', 'Proxy', 'a:4:{s:6:"object";s:15:"bx_albums_files";s:5:"image";s:16:"bx_albums_browse";s:12:"video_poster";s:29:"bx_albums_video_poster_browse";s:5:"video";a:2:{i:0;s:19:"bx_albums_video_mp4";i:1;s:22:"bx_albums_video_mp4_hd";}}', 'no', 0, 0, 0, 'BxDolTranscoderProxy', ''),
+('bx_albums_proxy_cover', 'bx_albums_photos_resized', 'Proxy', 'a:4:{s:6:"object";s:15:"bx_albums_files";s:5:"image";s:13:"bx_albums_big";s:12:"video_poster";s:26:"bx_albums_video_poster_big";s:5:"video";a:2:{i:0;s:19:"bx_albums_video_mp4";i:1;s:22:"bx_albums_video_mp4_hd";}}', 'no', 0, 0, 0, 'BxDolTranscoderProxy', '');
+
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES 
+('bx_albums_preview', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"300";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_albums_browse', 'Resize', 'a:1:{s:1:"h";s:3:"180";}', '0'),
+('bx_albums_big', 'Resize', 'a:2:{s:1:"w";s:4:"1280";s:1:"h";s:4:"1280";}', '0'),
+('bx_albums_video_poster_browse', 'Poster', 'a:2:{s:1:"h";s:3:"180";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_albums_video_poster_preview', 'Poster', 'a:2:{s:1:"h";s:3:"480";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_albums_video_poster_preview', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"300";s:13:"square_resize";s:1:"1";}', 10),
+('bx_albums_video_poster_big', 'Poster', 'a:2:{s:1:"h";s:3:"480";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_albums_video_mp4', 'Mp4', 'a:2:{s:1:"h";s:3:"480";s:10:"force_type";s:3:"mp4";}', 0),
+('bx_albums_video_mp4_hd', 'Mp4', 'a:3:{s:1:"h";s:3:"720";s:13:"video_bitrate";s:4:"1536";s:10:"force_type";s:3:"mp4";}', 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_albums', 'bx_albums', '_bx_albums_form_entry', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_albums_albums', 'id', '', '', 'do_submit', '', 0, 1, 'BxAlbumsFormEntry', 'modules/boonex/albums/classes/BxAlbumsFormEntry.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_albums', 'bx_albums_entry_add', 'bx_albums', 0, '_bx_albums_form_entry_display_add'),
+('bx_albums', 'bx_albums_entry_edit', 'bx_albums', 0, '_bx_albums_form_entry_display_edit'),
+('bx_albums', 'bx_albums_entry_add_images', 'bx_albums', 0, '_bx_albums_form_entry_display_add_images'),
+('bx_albums', 'bx_albums_entry_delete', 'bx_albums', 0, '_bx_albums_form_entry_display_delete'),
+('bx_albums', 'bx_albums_entry_view', 'bx_albums', 1, '_bx_albums_form_entry_display_view');
+
+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_albums', 'bx_albums', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_albums_form_entry_input_sys_delete_confirm', '_bx_albums_form_entry_input_delete_confirm', '_bx_albums_form_entry_input_delete_confirm_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_albums_form_entry_input_delete_confirm_error', '', '', 1, 0),
+('bx_albums', 'bx_albums', 'do_submit', '_bx_albums_form_entry_input_do_submit', '', 0, 'submit', '_bx_albums_form_entry_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_albums', 'bx_albums', 'title', '', '', 0, 'text', '_bx_albums_form_entry_input_sys_title', '_bx_albums_form_entry_input_title', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_albums_form_entry_input_title_err', 'Xss', '', 1, 0),
+('bx_albums', 'bx_albums', 'text', '', '', 0, 'textarea', '_bx_albums_form_entry_input_sys_text', '_bx_albums_form_entry_input_text', '', 0, 0, 2, '', '', '', '', '', '', 'XssHtml', '', 1, 0),
+('bx_albums', 'bx_albums', 'pictures', 'a:2:{i:0;s:15:"bx_albums_html5";i:1;s:22:"bx_albums_record_video";}', 'a:3:{s:15:"bx_albums_html5";s:25:"_sys_uploader_html5_title";s:22:"bx_albums_record_video";s:32:"_sys_uploader_record_video_title";s:14:"bx_albums_crop";s:24:"_sys_uploader_crop_title";}', 0, 'files', '_bx_albums_form_entry_input_sys_pictures', '_bx_albums_form_entry_input_pictures', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_albums', 'bx_albums', '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_albums', 'bx_albums', 'allow_view_to', '', '', 0, 'custom', '_bx_albums_form_entry_input_sys_allow_view_to', '_bx_albums_form_entry_input_allow_view_to', '', 1, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_albums', 'bx_albums', 'location', '', '', 0, 'location', '_sys_form_input_sys_location', '_sys_form_input_location', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_albums', 'bx_albums', 'added', '', '', 0, 'datetime', '_bx_albums_form_entry_input_sys_date_added', '_bx_albums_form_entry_input_date_added', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_albums', 'bx_albums', 'changed', '', '', 0, 'datetime', '_bx_albums_form_entry_input_sys_date_changed', '_bx_albums_form_entry_input_date_changed', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_albums', 'bx_albums', 'labels', '', '', 0, 'custom', '_sys_form_input_sys_labels', '_sys_form_input_labels', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_albums_entry_add', 'delete_confirm', 2147483647, 0, 1),
+('bx_albums_entry_add', 'title', 2147483647, 1, 2),
+('bx_albums_entry_add', 'text', 2147483647, 1, 3),
+('bx_albums_entry_add', 'pictures', 2147483647, 1, 4),
+('bx_albums_entry_add', 'allow_view_to', 2147483647, 1, 5),
+('bx_albums_entry_add', 'cf', 2147483647, 1, 6),
+('bx_albums_entry_add', 'location', 2147483647, 1, 7),
+('bx_albums_entry_add', 'do_submit', 2147483647, 1, 8),
+
+('bx_albums_entry_edit', 'delete_confirm', 2147483647, 0, 1),
+('bx_albums_entry_edit', 'title', 2147483647, 1, 2),
+('bx_albums_entry_edit', 'text', 2147483647, 1, 3),
+('bx_albums_entry_edit', 'pictures', 2147483647, 1, 4),
+('bx_albums_entry_edit', 'allow_view_to', 2147483647, 1, 5),
+('bx_albums_entry_edit', 'cf', 2147483647, 1, 6),
+('bx_albums_entry_edit', 'location', 2147483647, 1, 7),
+('bx_albums_entry_edit', 'do_submit', 2147483647, 1, 8),
+
+('bx_albums_entry_add_images', 'delete_confirm', 2147483647, 0, 1),
+('bx_albums_entry_add_images', 'title', 2147483647, 0, 2),
+('bx_albums_entry_add_images', 'text', 2147483647, 0, 3),
+('bx_albums_entry_add_images', 'allow_view_to', 2147483647, 0, 4),
+('bx_albums_entry_add_images', 'location', 2147483647, 0, 5),
+('bx_albums_entry_add_images', 'pictures', 2147483647, 1, 6),
+('bx_albums_entry_add_images', 'do_submit', 2147483647, 1, 7),
+
+('bx_albums_entry_view', 'delete_confirm', 2147483647, 0, 0),
+('bx_albums_entry_view', 'allow_view_to', 2147483647, 0, 0),
+('bx_albums_entry_view', 'do_submit', 2147483647, 0, 0),
+('bx_albums_entry_view', 'text', 2147483647, 0, 0),
+('bx_albums_entry_view', 'title', 2147483647, 0, 0),
+('bx_albums_entry_view', 'pictures', 2147483647, 0, 0),
+('bx_albums_entry_view', 'added', 2147483647, 1, 1),
+('bx_albums_entry_view', 'changed', 2147483647, 1, 2),
+
+('bx_albums_entry_delete', 'delete_confirm', 2147483647, 1, 1),
+('bx_albums_entry_delete', 'do_submit', 2147483647, 1, 2),
+('bx_albums_entry_delete', 'allow_view_to', 2147483647, 0, 0),
+('bx_albums_entry_delete', 'pictures', 2147483647, 0, 0),
+('bx_albums_entry_delete', 'text', 2147483647, 0, 0),
+('bx_albums_entry_delete', 'title', 2147483647, 0, 0);
+
+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_albums_media', 'bx_albums', '_bx_albums_form_media', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_albums_files2albums', 'id', '', '', 'do_submit', '', 0, 1, 'BxAlbumsFormMedia', 'modules/boonex/albums/classes/BxAlbumsFormMedia.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_albums_media', 'bx_albums_media_edit', 'bx_albums', 0, '_bx_albums_form_media_display_edit'),
+('bx_albums_media', 'bx_albums_media_move', 'bx_albums', 0, '_bx_albums_form_media_display_move');
+
+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_albums_media', 'bx_albums', 'title', '', '', 0, 'text', '_bx_albums_form_media_input_sys_title', '_bx_albums_form_media_input_title', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_albums_media', 'bx_albums', 'content_id', '', '', 0, 'select', '_bx_albums_form_media_input_sys_content_id', '_bx_albums_form_media_input_content_id', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_albums_media', 'bx_albums', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_albums_media', 'bx_albums', 'do_submit', '_bx_albums_form_media_input_do_submit', '', 0, 'submit', '_bx_albums_form_media_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_albums_media', 'bx_albums', 'do_cancel', '_bx_albums_form_media_input_do_cancel', '', 0, 'button', '_bx_albums_form_media_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";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_albums_media_edit', 'title', 2147483647, 1, 1),
+('bx_albums_media_edit', 'controls', 2147483647, 1, 2),
+('bx_albums_media_edit', 'do_submit', 2147483647, 1, 3),
+('bx_albums_media_edit', 'do_cancel', 2147483647, 1, 4),
+
+('bx_albums_media_move', 'content_id', 2147483647, 1, 1),
+('bx_albums_media_move', 'controls', 2147483647, 1, 2),
+('bx_albums_media_move', 'do_submit', 2147483647, 1, 3),
+('bx_albums_media_move', 'do_cancel', 2147483647, 1, 4);
+
+
+-- 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_albums', 'bx_albums', 'bx_albums_cmts', 1, 5000, 1000, 3, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-album&id={object_id}', '', 'bx_albums_albums', 'id', 'author', 'title', 'comments', '', ''),
+('bx_albums_notes', 'bx_albums', 'bx_albums_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_albums_albums', 'id', 'author', 'title', '', 'BxTemplCmtsNotes', ''),
+('bx_albums_media', 'bx_albums', 'bx_albums_cmts_media', 1, 5000, 1000, 3, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-album-media&id={object_id}', '', 'bx_albums_files2albums', 'id', 'author', 'title', 'comments', 'BxAlbumsCmtsMedia', 'modules/boonex/albums/classes/BxAlbumsCmtsMedia.php');
+
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_albums', 'bx_albums_votes', 'bx_albums_votes_track', '604800', '1', '1', '0', '1', 'bx_albums_albums', 'id', 'author', 'rate', 'votes', '', ''),
+('bx_albums_media', 'bx_albums_votes_media', 'bx_albums_votes_media_track', '604800', '1', '1', '0', '1', 'bx_albums_files2albums', 'id', 'author', 'rate', 'votes', '', ''),
+
+('bx_albums_reactions', 'bx_albums_reactions', 'bx_albums_reactions_track', '604800', '1', '1', '1', '1', 'bx_albums_albums', 'id', 'author', 'rrate', 'rvotes', 'BxTemplVoteReactions', '');
+
+
+-- 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_albums', 'bx_albums', 'bx_albums_scores', 'bx_albums_scores_track', '604800', '0', 'bx_albums_albums', 'id', 'author', 'score', 'sc_up', 'sc_down', '', ''),
+('bx_albums_media', 'bx_albums', 'bx_albums_scores_media', 'bx_albums_scores_media_track', '604800', '0', 'bx_albums_files2albums', '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_albums', 'bx_albums', 'bx_albums_reports', 'bx_albums_reports_track', '1', 'page.php?i=view-album&id={object_id}', 'bx_albums_notes', 'bx_albums_albums', 'id', 'author', 'reports', '', ''),
+('bx_albums_media', 'bx_albums', 'bx_albums_reports_media', 'bx_albums_reports_media_track', '1', 'page.php?i=view-album-media&id={object_id}', '', 'bx_albums_files2albums', 'id', 'author', 'reports', '', '');
+
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_albums', 'bx_albums_views_track', '86400', '1', 'bx_albums_albums', 'id', '', 'views', '', ''),
+('bx_albums_media', 'bx_albums_views_media_track', '86400', '1', 'bx_albums_files2albums', 'id', 'author', 'views', '', '');
+
+
+-- FAFORITES
+INSERT INTO `sys_objects_favorite` (`name`, `table_track`, `table_lists`, `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_albums', 'bx_albums_favorites_track', 'bx_albums_favorites_lists', '1', '1', '1', 'page.php?i=view-album&id={object_id}', 'bx_albums_albums', 'id', 'author', 'favorites', '', ''),
+('bx_albums_media', 'bx_albums_favorites_media_track', '', '1', '1', '1', 'page.php?i=view-album-media&id={object_id}', 'bx_albums_files2albums', '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_albums', 'bx_albums', '1', '1', 'page.php?i=view-album&id={object_id}', 'bx_albums_albums', 'id', 'author', 'featured', '', ''),
+('bx_albums_media', 'bx_albums', '1', '1', 'page.php?i=view-album-media&id={object_id}', 'bx_albums_files2albums', 'id', '', '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_albums', '_bx_albums', 'bx_albums', 'added', 'edited', 'deleted', '', ''),
+('bx_albums_media', '_bx_albums_media', 'bx_albums', 'media_added', '', 'media_deleted', 'BxAlbumsContentInfoMedia', 'modules/boonex/albums/classes/BxAlbumsContentInfoMedia.php'),
+('bx_albums_cmts', '_bx_albums_cmts', 'bx_albums', 'commentPost', 'commentUpdated', 'commentRemoved', 'BxDolContentInfoCmts', ''),
+('bx_albums_media_cmts', '_bx_albums_media_cmts', 'bx_albums_media', 'commentPost', 'commentUpdated', 'commentRemoved', 'BxDolContentInfoCmts', '');
+
+INSERT INTO `sys_content_info_grids` (`object`, `grid_object`, `grid_field_id`, `condition`, `selection`) VALUES
+('bx_albums', 'bx_albums_administration', 'id', '', ''),
+('bx_albums', 'bx_albums_common', 'id', '', '');
+
+
+-- SEARCH EXTENDED
+INSERT INTO `sys_objects_search_extended` (`object`, `object_content_info`, `module`, `title`, `active`, `class_name`, `class_file`) VALUES
+('bx_albums', 'bx_albums', 'bx_albums', '_bx_albums_search_extended', 1, '', ''),
+('bx_albums_media', 'bx_albums_media', 'bx_albums', '_bx_albums_search_extended_media', 1, '', ''),
+('bx_albums_cmts', 'bx_albums_cmts', 'bx_albums', '_bx_albums_search_extended_cmts', 1, 'BxTemplSearchExtendedCmts', ''),
+('bx_albums_media_cmts', 'bx_albums_media_cmts', 'bx_albums', '_bx_albums_search_extended_media_cmts', 1, 'BxTemplSearchExtendedCmts', '');
+
+
+-- STUDIO: page & widget
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_albums', '_bx_albums', '_bx_albums', 'bx_albums@modules/boonex/albums/|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_albums', 'content', '{url_studio}module.php?name=bx_albums', '', 'bx_albums@modules/boonex/albums/|std-icon.svg', '_bx_albums', '', '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));
+

+ 23 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/template/form_ghost_template.html

@@ -0,0 +1,23 @@
+<div id="bx-uploader-file-{storage_object}-{file_id}" class="bx-uploader-ghost mt-2 flex items-start">
+    <div class="bx-uploader-ghost-cnt">
+        <a class="bx-anchor-invisible" name="album-media-{file_id}"></a>
+        <input type="hidden" name="__name__[]" value="{file_id}" />
+        <div class="bx-base-general-icon-wrapper">
+            <img src="{file_icon}" class="bx-def-round-corners bx-base-general-icon bx-base-general-icon-{file_id}" />
+        </div>
+        <span class="bx-base-general-uploader-ghost">
+            <a class="bx-btn bx-btn-small bx-def-margin-sec-right" href="javascript:void(0);" title="<bx_text:_sys_txt_form_entry_input_picture_delete />" onclick="bx_base_general_delete_ghost('{file_id}', '{file_url}', '{file_icon}', ['__editor_id__'], {js_instance_name});"><i class="sys-icon times"></i></a>
+            <a class="bx-btn bx-btn-small mr-2" href="javascript:void(0);" title="<bx_text:_sys_txt_form_entry_input_picture_copy />" onclick="bx_copy_to_clipboard('{file_url}');"><i class="sys-icon copy"></i></a>
+        </span>
+    </div>
+    <input placeholder="<bx_text:_bx_albums_form_entry_file_title />" class="bx-def-font-inputs bx-form-input-text block w-full py-2 px-3 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm bg-white dark:bg-gray-900 placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-2 focus:text-gray-900 dark:focus:text-gray-100 focus:ring-blue-500 focus:border-opacity-70 focus:ring-opacity-20 focus:border-blue-500 text-sm text-gray-700 dark:text-gray-300 appearance-none" type="text" value="{file_title_attr}" name="title-{file_id}" />
+    <bx_if:set_thumb>
+        <span class="bx-base-general-use-as-thumb">
+            <input type="checkbox" name="__name_thumb__[]" value="{file_id}" onclick="bx_base_general_select_thumb(this)" id="__name_thumb__-{file_id}" /> 
+            <label for="__name_thumb__-{file_id}"><bx_text:_sys_txt_form_entry_input_picture_use_as_thumb /></label>
+        </span>
+    </bx_if:set_thumb>
+</div>
+<script>
+    $('#bx-uploader-file-{storage_object}-{file_id} .bx-base-general-use-as-thumb input[value="__thumb_id__"]').attr('checked', true);
+</script>

+ 40 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/template/images/icons/std-icon.svg

@@ -0,0 +1,40 @@
+<svg width="320" height="320" viewBox="0 0 320 320" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_935_6804)">
+<path d="M160 0C281.326 0 320 38.6737 320 160C320 281.326 281.326 320 160 320C38.6736 320 0 281.326 0 160C0 38.6737 38.6736 0 160 0Z" fill="url(#paint0_linear_935_6804)"/>
+<path d="M160 2C220.573 2 259.85 11.6833 284.083 35.9168C308.317 60.1504 318 99.4272 318 160C318 220.573 308.317 259.85 284.083 284.083C259.85 308.317 220.573 318 160 318C99.4272 318 60.1504 308.317 35.9168 284.083C11.6833 259.85 2 220.573 2 160C2 99.4272 11.6833 60.1504 35.9168 35.9168C60.1504 11.6833 99.4272 2 160 2Z" stroke="#0F172A" stroke-opacity="0.2" stroke-width="4"/>
+<g clip-path="url(#clip1_935_6804)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M81.9394 81.0474C79.5575 84.9494 83.9695 89.1266 88.2974 87.6542C104.079 82.2851 124.353 80.0001 150 80.0001C233.412 80.0001 260 104.171 260 180V180C260 183.888 264.49 184.914 265.521 181.165C268.63 169.855 270 156.245 270 140C270 71.7539 245.829 50 170 50C122.941 50 95.7774 58.3782 81.9394 81.0474Z" fill="url(#paint1_linear_935_6804)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M50 180C50 111.754 74.1711 90 150 90C225.829 90 250 111.754 250 180C250 248.246 225.829 270 150 270C74.1711 270 50 248.246 50 180ZM147.679 150C155.377 136.667 174.623 136.667 182.321 150L216.962 210C224.66 223.333 215.037 240 199.641 240H130.359C114.963 240 105.34 223.333 113.038 210L147.679 150ZM105 170C118.807 170 130 158.807 130 145C130 131.193 118.807 120 105 120C91.1929 120 80 131.193 80 145C80 158.807 91.1929 170 105 170Z" fill="url(#paint2_linear_935_6804)"/>
+<path d="M156.34 155C160.189 148.333 169.811 148.333 173.66 155L208.301 215C212.15 221.667 207.339 230 199.641 230H130.359C122.661 230 117.85 221.667 121.699 215L156.34 155Z" fill="url(#paint3_linear_935_6804)"/>
+<circle cx="105" cy="145" r="15" fill="url(#paint4_linear_935_6804)"/>
+</g>
+</g>
+<defs>
+<linearGradient id="paint0_linear_935_6804" x1="160" y1="0" x2="160" y2="320" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F8FAFC"/>
+<stop offset="1" stop-color="#E2E8F0"/>
+</linearGradient>
+<linearGradient id="paint1_linear_935_6804" x1="175.635" y1="50" x2="175.635" y2="183.504" gradientUnits="userSpaceOnUse">
+<stop stop-color="#7DD3FC"/>
+<stop offset="1" stop-color="#0EA5E9"/>
+</linearGradient>
+<linearGradient id="paint2_linear_935_6804" x1="150" y1="90" x2="150" y2="270" gradientUnits="userSpaceOnUse">
+<stop stop-color="#60A5FA"/>
+<stop offset="1" stop-color="#2563EB"/>
+</linearGradient>
+<linearGradient id="paint3_linear_935_6804" x1="165" y1="140" x2="165" y2="260" gradientUnits="userSpaceOnUse">
+<stop stop-color="#34D399"/>
+<stop offset="1" stop-color="#059669"/>
+</linearGradient>
+<linearGradient id="paint4_linear_935_6804" x1="105" y1="130" x2="105" y2="160" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FB923C"/>
+<stop offset="1" stop-color="#EA580C"/>
+</linearGradient>
+<clipPath id="clip0_935_6804">
+<rect width="320" height="320" fill="white"/>
+</clipPath>
+<clipPath id="clip1_935_6804">
+<rect width="240" height="240" fill="white" transform="translate(40 40)"/>
+</clipPath>
+</defs>
+</svg>

+ 28 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/template/unit.html

@@ -0,0 +1,28 @@
+<div class="bx-base-text-unit bx-base-text-unit-ext bx-def-box bx-def-box-round-corners bx-def-color-bg-box mb-3 md:mb-4 lg:mb-6 text-left">
+    <div class="bx-albums-unit-text-cont px-4 pt-4 pb-2">
+        <div class="bx-base-text-unit-title">
+            <a href="__content_url__">__title__</a>
+        </div>
+        <bx_if:meta>
+            <div class="bx-base-text-unit-info mt-1 mb-2">
+                <div class="bx-base-general-unit-meta">__meta__</div>
+            </div>
+        </bx_if:meta>
+        <div class="bx-base-text-unit-summary bx-clearfix">__summary__</div> 
+    </div>
+    <div class="bx-albums-unit-images-cont px-1 pb-4">
+        <div class="bx-albums-unit-images">
+            <bx_repeat:browse>
+                <a class="bx-albums-unit-image" title="__title_attr__" href="__url__">
+                    <img alt="__title_attr__" src="__img_url__" />
+                    <bx_if:show_play>
+                        <div class="bx-albums-media-play rounded"><i class="sys-icon play"></i></div>
+                    </bx_if:show_play>
+                    <bx_if:show_duration>
+                        <div class="bx-albums-media-duration px-2 py-1 border rounded text-base">__duration__</div>
+                    </bx_if:show_duration>
+                </a>
+            </bx_repeat:browse>
+        </div> 
+    </div> 
+</div>

+ 17 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/template/unit_gallery.html

@@ -0,0 +1,17 @@
+<div class="bx-base-text-unit bx-base-text-unit-gallery bx-def-gal-unit-size p-2">
+    <div class="bx-base-text-unit-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box mb-3 md:mb-4 lg:mb-6 text-left">
+        <div class="bx-albums-unit-images-cont">
+            <div class="bx-albums-unit-images">
+                <bx_repeat:browse><a class="bx-albums-unit-image" title="__title_attr__" href="__url__"><img alt="__title_attr__" src="__img_url__" /></a></bx_repeat:browse>
+            </div> 
+        </div>
+        <div class="bx-albums-unit-text-cont px-4 py-2 text-center">
+            <div class="bx-base-text-unit-title">
+                <a href="__content_url__">__title__</a>
+            </div>
+            <div class="bx-base-text-unit-info">
+                <bx_if:meta><div class="bx-base-general-unit-meta">__meta__</div></bx_if:meta>
+            </div>
+        </div>
+    </div>
+</div>

+ 24 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/template/unit_media.html

@@ -0,0 +1,24 @@
+<div class="__class__ bx-albums-media-wrapper sm:w-full md:w-1/2 lg:w-1/3 p-2 box-border">
+    <div class="bx-albums-media-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box">
+        <div class="bx-albums-media-thumb bx-albums-unit-size h-48 rounded-tl-md rounded-tr-md overflow-hidden">
+            <bx_if:image>
+                <a href="__url__" title="__title_attr__">
+                    <img class="bx-albums-unit-size h-48" src="__url_img__" alt="__title_attr__" />
+                </a>
+            </bx_if:image>
+            <bx_if:video>
+                <a href="__url__" title="__title_attr__">
+                    <img class="bx-albums-unit-size h-48" src="__url_img__" alt="__title_attr__" />
+                    <div class="bx-albums-media-play rounded-md"><i class="sys-icon play"></i></div>
+                </a>
+                <bx_if:show_duration>
+                    <div class="bx-albums-media-duration px-2 py-1 border text-sm rounded-md">__duration__</div>
+                </bx_if:show_duration>
+            </bx_if:video>
+        </div>
+        <div class="bx-base-text-unit-title bx-albums-media-caption m-2">
+            <a href="__url__" title="__title_attr__">__title__</a>
+        </div>
+        <div class="bx-albums-media-actions mx-2 mb-2">__actions__</div>
+    </div>
+</div>

+ 23 - 0
modules/boonex/albums/updates/13.0.3_13.0.4/source/template/unit_media_gallery.html

@@ -0,0 +1,23 @@
+<div class="__class__ bx-albums-media-wrapper sm:w-full md:w-1/2 lg:w-1/3 p-2 box-border">
+    <div class="bx-albums-media-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box">
+        <div class="bx-albums-media-thumb bx-albums-unit-size h-48 rounded-tl-md rounded-tr-md overflow-hidden">
+            <bx_if:image>
+                <a href="__url__" title="__title_attr__">
+                    <img class="bx-albums-unit-size h-48" src="__url_img__" alt="__title_attr__" />
+                </a>
+            </bx_if:image>
+            <bx_if:video>
+                <a href="__url__" title="__title_attr__">
+                    <img class="bx-albums-unit-size h-48" src="__url_img__" alt="__title_attr__" />
+                    <div class="bx-albums-media-play rounded-md"><i class="sys-icon play"></i></div>
+                </a>
+                <bx_if:show_duration>
+                    <div class="bx-albums-media-duration px-2 py-1 border text-sm rounded-md">__duration__</div>
+                </bx_if:show_duration>
+            </bx_if:video>
+        </div>
+        <div class="bx-base-text-unit-title bx-albums-media-caption m-2">
+            <a href="__url__" title="__title_attr__">__title__</a>
+        </div>
+    </div>
+</div>

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

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Analytics',
+    'version_from' => '13.0.0',
+    'version_to' => '13.0.1',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.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/analytics/updates/update_13.0.0_13.0.1/',
+    'home_uri' => 'analytics_update_1300_1301',
+
+    'module_dir' => 'boonex/analytics/',
+    'module_uri' => 'analytics',
+
+    'db_prefix' => 'bx_analytics_',
+    'class_prefix' => 'BxAnalytics',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Analytics',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

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

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

+ 77 - 0
modules/boonex/analytics/updates/13.0.0_13.0.1/source/install/config.php

@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Analytics Analytics
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_analytics',
+    'title' => 'Analytics',
+    'note' => 'Analytics module.',
+    'version' => '13.0.1',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.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/analytics/',
+    'home_uri' => 'analytics',
+
+    'db_prefix' => 'bx_analytics_',
+    'class_prefix' => 'BxAnalytics',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Analytics',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 149 - 0
modules/boonex/analytics/updates/13.0.0_13.0.1/source/js/analytics.js

@@ -0,0 +1,149 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Analytics Analytics
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxAnalytics(oOptions) {
+    this._sContainerId = 'bx_analytics_container';
+    this._sModuleSelector = '#' + this._sContainerId + ' .bx_analytics_module_selector';
+    this._sReportSelector = '#' + this._sContainerId + " .bx_analytics_report_selector";
+    this._sContainerDataSelector = '#' + this._sContainerId + " .bx_analytics_data";
+    this._sCanvasSelector = '#' + this._sContainerId + " .bx_analytics_grath";
+    this._sDatePickerSelector = '#' + this._sContainerId + " .bx_analytics_date_picker";
+    this._sExportUrlSelector = '#' + this._sContainerId + " .bx_analytics_export_url";
+    this._sActionsUri = oOptions.sActionUri;
+    this._aStrings = oOptions.aStrings;
+    var $this = this;
+    $(document).ready(function () {
+        $this.init(); 
+    });
+}
+
+BxAnalytics.prototype.init = function () {
+    var $this = this;
+    $($this._sModuleSelector).change(function () {
+        $this.reloadReports();
+    });
+    $($this._sReportSelector).change(function () {
+        $this.reloadData();
+    });
+    $this.reloadReports();
+
+    $($this._sDatePickerSelector).daterangepicker({
+        opens: 'left',
+        locale: {
+            "format": "DD/MM/YYYY"
+        },
+    }, function (start, end, label) {
+        $this.reloadData();
+    });
+
+}
+
+BxAnalytics.prototype.reloadReports = function () {
+    var $this = this;
+    $.getJSON($this._sActionsUri + 'GetReports/' + $($this._sModuleSelector).val() + '/', function (aReports) {
+        $($this._sReportSelector).empty();
+        $.each(aReports, function (key, value) {
+            $($this._sReportSelector).append('<option value="' + key + '">' + value + '</option>');
+        });
+        $this.reloadData();
+    });
+};
+
+BxAnalytics.prototype.reloadData = function () {
+    var $this = this;
+    bx_loading($($this._sContainerDataSelector), true);
+    $sUrl = $this._sActionsUri + 'GetReportsData/' + $($this._sModuleSelector).val() + '/' + $($this._sReportSelector).val() + '/' + $($this._sDatePickerSelector).data('daterangepicker').startDate.format('YYYY-MM-DD') + '/' + $($this._sDatePickerSelector).data('daterangepicker').endDate.format('YYYY-MM-DD') + '/';
+    $($this._sExportUrlSelector).attr('href', $sUrl + 'csv/');
+    $.getJSON($sUrl, function (oData) {
+        Chart.defaults.global.layout = {
+            padding: {
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }
+        }
+		
+        Chart.defaults.scale.ticks.callback = function (label, index, labels) {
+            if (label.length > 10)
+                return label.slice(0, 10) + '...';
+            else
+                return label;
+        };
+
+        bx_loading($($this._sContainerDataSelector), false);
+        var oDataForChart = oData.data || false;
+        var oChartOptions = oData.options || oOptionsDefault;
+        if ($this._oChart)
+            $this._oChart.destroy();
+        $this._oChart = new Chart($($this._sCanvasSelector), {
+            type: oData.type != undefined ? oData.type : 'line',
+            data: oDataForChart,
+            options: $.extend({}, $this._oChartOptionsDefault, oChartOptions)
+        });
+        $this.dataToTable(oData);
+    });
+};
+
+BxAnalytics.prototype.dataToTable = function (oDataIn) {
+    var $this = this;
+    var oData = oDataIn.data;
+    var sHtml = '<table>';
+    var sCol1 = oDataIn.strings[0];
+
+    var iColumnCount = oData.datasets.length;
+    sHtml += '<thead><tr><th> ' + sCol1 + '</th>';
+    $.each(oData.datasets, function (iDx, oItem) {
+        var sText = oItem.label;
+        sHtml += '<th>' + (oItem.label != '' ? oItem.label : oDataIn.strings[1]) + '</th>';
+    });
+
+    sHtml += '</tr></thead>';
+    var iK = 0;
+    
+    oData.datasets[0].data.forEach(function (oItemData, iDx) {
+        var sTxt = "";
+        if (oDataIn.options.scales.xAxes[0].type == 'time')
+            sTxt = oData.datasets[0].data[iDx].x;
+        else{
+            sTxt = oData.labels[iDx];
+        }
+        if (oDataIn.links && oDataIn.links.length > 0) {
+            sTxt = "<a href='" + oDataIn.links[iDx] + "'>" + sTxt + "</a>"
+        }
+        sHtml += '<tr><td>&nbsp;'+  sTxt + '</td>';
+        for (i = 0; i < iColumnCount; i++) {
+            var sText = '';
+            if (typeof oData.datasets[i].data[iDx] === 'object') {
+                sText = oData.datasets[i].data[iDx].y;
+            }
+            else {
+                sText = oData.datasets[i].data[iDx];
+            }
+            sHtml += '<td>' + sText + '</td>';
+        }
+        sHtml += '</tr>';
+        iK++;
+    });
+
+    sHtml += '</tr><tbody></table>';
+    if ($this._oTable)
+        $this._oTable.destroy();
+    $('.bx_analytics_table').html(sHtml);
+
+    var $aOrder = [];
+    if (oDataIn.options.scales.xAxes[0].type == 'time') {
+        $aOrder = [[0, 'desc']];
+    }
+    $this._oTable = $('.bx_analytics_table').DataTable({ "stripeClasses": ['bx-def-color-bg-hl', ''], dom: '<"top"i>rt<"bottom"flp><"clear">', paging: true, searching: false, ordering: true, order: $aOrder });
+   
+};
+
+/** @} */

Diff do ficheiro suprimidas por serem muito extensas
+ 12 - 0
modules/boonex/analytics/updates/13.0.0_13.0.1/source/plugins/datatables/datatables.min.css


+ 40 - 0
modules/boonex/analytics/updates/13.0.0_13.0.1/source/template/canvas.html

@@ -0,0 +1,40 @@
+<div id="bx_analytics_container">
+    <div class="bx_analytics_filters">
+        <div class="bx-form-element">
+            <div class="bx-form-value bx-clearfix">
+                <div class="bx-form-input-wrapper bx-form-input-wrapper-select">
+                    <select class="bx-def-font-inputs bx-form-input-select bx_analytics_module_selector">
+                        <bx_repeat:items>
+                            <option value="__value__">__title__</option>
+                        </bx_repeat:items>
+                    </select>
+                </div>
+            </div>
+        </div>
+        <div class="bx-form-element">
+            <div class="bx-form-value bx-clearfix">
+                <div class="bx-form-input-wrapper bx-form-input-wrapper-select">
+                    <select class="bx-def-font-inputs bx-form-input-select bx_analytics_report_selector"></select>
+                </div>
+            </div>
+        </div>
+         <div class="bx-form-element">
+            <div class="bx-form-value bx-clearfix">
+                <div class="bx-form-input-wrapper bx-form-input-wrapper-select">
+                    <input type="text" class="bx-def-font-inputs bx-form-input-select bx_analytics_date_picker" value="__interval__" />
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="bx_analytics_data">
+        <div class="bx_analytics_grath_cnt bx-def-margin-top">
+            <canvas class="bx_analytics_grath bx-canvas"></canvas>
+        </div>
+        <div class="bx-def-margin-top bx-grid-table">
+            <table class="bx_analytics_table" width="100%"></table>
+        </div>
+    </div>
+    <div class="bx-def-margin-top">
+        <a href="javascript:" class="bx_analytics_export_url">__export_to_csv_title__</a>
+    </div>
+</div>

+ 88 - 0
modules/boonex/analytics/updates/13.0.0_13.0.1/source/template/css/main.css

@@ -0,0 +1,88 @@
+.bx_analytics_filters {
+    display: -webkit-flex;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-align-items: stretch;
+    -ms-flex-align: stretch;
+    align-items: stretch;
+    -webkit-flex-wrap: wrap;
+    -ms-flex-wrap: wrap;
+    flex-wrap: wrap;
+    -webkit-justify-content: space-between;
+    justify-content: space-between;
+}
+
+.bx_analytics_filters .bx-form-element {
+    width: 30%;
+}
+
+.bx_analytics_filters .bx-def-font-inputs{
+    position: relative;
+    display: inline-block;
+    overflow: hidden;
+}
+
+.bx_analytics_data .bx-def-font-inputs {
+    width: calc(100%);
+    max-width:200px;
+    float:left;
+}
+
+.bx_analytics_grath_cnt {
+    width:100%;
+}
+
+.bx_analytics_grath_cnt .bx_analytics_grath{
+    width:100%;
+    height:100%;
+}
+
+.bx_analytics_data .dataTables_info {
+    display:none;
+}
+
+.bx_analytics_data .bx-grid-table th, .bx-grid-table td {
+    text-align: left;
+}
+.bx_analytics_data .bx-grid-table .odd
+{
+    background-color: rgba(210, 230, 250, 0.3);
+}
+.bx_analytics_data .bottom {
+    display: flex;
+    justify-content: space-between;
+    margin-top: 1rem;
+}
+/* datatables fix*/
+table.dataTable thead .sorting:after { margin-left:10px; font-family: "sys-user", "sys-user-fal", sans-serif; content: "\f0dc"; display:inline-block }
+table.dataTable thead .sorting_asc:after{ margin-left:10px;font-family: "sys-user", "sys-user-fal", sans-serif; content: "\f0de"; display:inline-block}
+table.dataTable thead .sorting_desc:after{ margin-left:10px; font-family: "sys-user", "sys-user-fal", sans-serif; content: "\f0dd"; display:inline-block}
+table.dataTable.no-footer {border-bottom:none !important}
+table.dataTable thead th{border-bottom:none !important; padding: 10px 10px !important}
+table.dataTable thead .sorting {background-image: none !important}
+.bx-media-phone #bx_analytics_container .bx-grid-table 
+{
+	min-width: inherit !important;
+}
+.dataTables_wrapper .dataTables_length, .dataTables_wrapper .dataTables_filter, .dataTables_wrapper .dataTables_info, .dataTables_wrapper .dataTables_processing, .dataTables_wrapper .dataTables_paginate{
+    color:inherit !important;
+}
+.dataTables_wrapper .dataTables_paginate .paginate_button{
+    padding: 0em 0.25em !important;
+    background: none !important;
+    border: none !important;
+}
+.dataTables_wrapper .dataTables_paginate .paginate_button:hover,
+.dataTables_wrapper .dataTables_paginate .paginate_button:active{
+    cursor: pointer;
+    color: inherit !important;
+    border: none !important;
+}
+html.dark .bx-canvas {
+    filter: invert(1) hue-rotate(180deg);
+}
+html.dark .dataTables_wrapper select{
+    background-color: #11182780;
+    border:1px solid rgb(55 65 81);
+    margin: 0px 0.5rem;
+}    

+ 40 - 0
modules/boonex/analytics/updates/13.0.0_13.0.1/source/template/images/icons/std-icon.svg

@@ -0,0 +1,40 @@
+<svg width="320" height="320" viewBox="0 0 320 320" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_937_7190)">
+<path d="M160 0C281.326 0 320 38.6737 320 160C320 281.326 281.326 320 160 320C38.6736 320 0 281.326 0 160C0 38.6737 38.6736 0 160 0Z" fill="url(#paint0_linear_937_7190)"/>
+<path d="M160 2C220.573 2 259.85 11.6833 284.083 35.9168C308.317 60.1504 318 99.4272 318 160C318 220.573 308.317 259.85 284.083 284.083C259.85 308.317 220.573 318 160 318C99.4272 318 60.1504 308.317 35.9168 284.083C11.6833 259.85 2 220.573 2 160C2 99.4272 11.6833 60.1504 35.9168 35.9168C60.1504 11.6833 99.4272 2 160 2Z" stroke="#F8FAFC" stroke-opacity="0.2" stroke-width="4"/>
+<path d="M70 100C81.3743 100 85 114.503 85 160C85 205.497 81.3743 220 70 220C58.6257 220 55 205.497 55 160C55 114.503 58.6257 100 70 100Z" fill="url(#paint1_linear_937_7190)"/>
+<path d="M115 140C126.374 140 130 154.503 130 200C130 245.497 126.374 260 115 260C103.626 260 100 245.497 100 200C100 154.503 103.626 140 115 140Z" fill="url(#paint2_linear_937_7190)"/>
+<path d="M160 80C171.374 80 175 94.5026 175 140C175 185.497 171.374 200 160 200C148.626 200 145 185.497 145 140C145 94.5026 148.626 80 160 80Z" fill="url(#paint3_linear_937_7190)"/>
+<path d="M205 120C216.374 120 220 134.503 220 180C220 225.497 216.374 240 205 240C193.626 240 190 225.497 190 180C190 134.503 193.626 120 205 120Z" fill="url(#paint4_linear_937_7190)"/>
+<path d="M250 60C261.374 60 265 74.5026 265 120C265 165.497 261.374 180 250 180C238.626 180 235 165.497 235 120C235 74.5026 238.626 60 250 60Z" fill="url(#paint5_linear_937_7190)"/>
+</g>
+<defs>
+<linearGradient id="paint0_linear_937_7190" x1="160" y1="0" x2="160" y2="320" gradientUnits="userSpaceOnUse">
+<stop stop-color="#475569"/>
+<stop offset="1" stop-color="#1E293B"/>
+</linearGradient>
+<linearGradient id="paint1_linear_937_7190" x1="70" y1="100" x2="70" y2="220" gradientUnits="userSpaceOnUse">
+<stop stop-color="#34D399"/>
+<stop offset="1" stop-color="#059669"/>
+</linearGradient>
+<linearGradient id="paint2_linear_937_7190" x1="115" y1="140" x2="115" y2="260" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FB7185"/>
+<stop offset="1" stop-color="#E11D48"/>
+</linearGradient>
+<linearGradient id="paint3_linear_937_7190" x1="160" y1="80" x2="160" y2="200" gradientUnits="userSpaceOnUse">
+<stop stop-color="#34D399"/>
+<stop offset="1" stop-color="#059669"/>
+</linearGradient>
+<linearGradient id="paint4_linear_937_7190" x1="205" y1="120" x2="205" y2="240" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FB7185"/>
+<stop offset="1" stop-color="#E11D48"/>
+</linearGradient>
+<linearGradient id="paint5_linear_937_7190" x1="250" y1="60" x2="250" y2="180" gradientUnits="userSpaceOnUse">
+<stop stop-color="#34D399"/>
+<stop offset="1" stop-color="#059669"/>
+</linearGradient>
+<clipPath id="clip0_937_7190">
+<rect width="320" height="320" fill="white"/>
+</clipPath>
+</defs>
+</svg>

+ 51 - 0
modules/boonex/antispam/updates/13.0.1_13.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' => 'Antispam',
+    'version_from' => '13.0.1',
+    'version_to' => '13.0.2',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.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/antispam/updates/update_13.0.1_13.0.2/',
+    'home_uri' => 'antispam_update_1301_1302',
+
+    'module_dir' => 'boonex/antispam/',
+    'module_uri' => 'antispam',
+
+    'db_prefix' => 'bx_antispam_',
+    'class_prefix' => 'BxAntispam',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Antispam',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/antispam/updates/13.0.1_13.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 BxAntispamUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 6 - 0
modules/boonex/antispam/updates/13.0.1_13.0.2/install/sql/enable.sql

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

+ 5 - 0
modules/boonex/antispam/updates/13.0.1_13.0.2/install/sql/install.sql

@@ -0,0 +1,5 @@
+SET @sName = 'bx_antispam';
+
+
+-- TABLES
+UPDATE `bx_antispam_dnsbl_rules` SET `recheck`='https://surbl.org/surbl-analysis' WHERE `chain`='uridns' AND `zonedomain`='multi.surbl.org.';

+ 54 - 0
modules/boonex/antispam/updates/13.0.1_13.0.2/source/classes/BxAntispamAlertsResponse.php

@@ -0,0 +1,54 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Antispam Antispam
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * alerts handler
+ */
+class BxAntispamAlertsResponse extends BxDolAlertsResponse
+{
+    public function response($oAlert)
+    {
+        if ('account' == $oAlert->sUnit) {
+
+            switch ($oAlert->sAction) {
+                case 'check_login':
+                    $oAlert->aExtras['error_msg'] = BxDolService::call('bx_antispam', 'check_login');
+                    break;
+                case 'check_join';
+                    $oAlert->aExtras['error_msg'] = BxDolService::call('bx_antispam', 'check_join', array($oAlert->aExtras['email'], &$oAlert->aExtras['approve']));
+                    break;
+            }
+
+        } elseif ('system' == $oAlert->sUnit) {
+            
+            switch ($oAlert->sAction) {
+                case 'check_spam_url':
+                    $oAlert->aExtras['is_spam'] = BxDolService::call('bx_antispam', 'is_spam_url', array(&$oAlert->aExtras['content']));
+                    break;
+                case 'check_spam':
+                    $oAlert->aExtras['content'] = BxDolService::call('bx_antispam', 'filter_spam', array($oAlert->aExtras['content']));
+                    if ((!isset($oAlert->aExtras['type']) || 'textarea' == $oAlert->aExtras['type']) && is_string($oAlert->aExtras['content']))
+                        $oAlert->aExtras['is_spam'] = BxDolService::call('bx_antispam', 'is_spam', array(&$oAlert->aExtras['content']));
+                    break;
+                case 'form_check':
+                    BxDolService::call('bx_antispam', 'check_form_for_toxicity', array(&$oAlert->aExtras['object']));
+                    break;
+                case 'form_submitted':
+                    BxDolService::call('bx_antispam', 'on_form_submitted', array($oAlert->aExtras['module'], $oAlert->aExtras['entry_id']));
+                    break;
+            }
+        } elseif ('comment' == $oAlert->sUnit && BxDolService::call('bx_antispam', 'is_last_form_submitted_toxic', array())) {
+            BxDolService::call('bx_antispam', 'set_comment_as_pending', array($oAlert->iObject));
+        }
+    }
+}
+
+/** @} */

+ 554 - 0
modules/boonex/antispam/updates/13.0.1_13.0.2/source/classes/BxAntispamModule.php

@@ -0,0 +1,554 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Antispam Antispam
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxAntispamModule extends BxDolModule
+{
+    private $_bLastSubmittedFormWasToxic;
+
+    public function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+        $this->_bLastSubmittedFormWasToxic = false;
+    }
+
+    public function serviceUpdateDisposableDomainsLists ()
+    {
+        $o = bx_instance('BxAntispamDisposableEmailDomains', array(), 'bx_antispam');
+
+        $o->updateList('blacklist', 'https://raw.githubusercontent.com/martenson/disposable-email-domains/master/disposable_email_blocklist.conf');
+
+        // TODO: uncomment after adding interface for whitelisting
+        // $o->updateList('whitelist', 'https://raw.githubusercontent.com/martenson/disposable-email-domains/master/whitelist.conf');
+    }
+    
+    public function serviceIpTable ()
+    {
+        $o = bx_instance('BxAntispamIP', array(), $this->_aModule);
+        $s = _t('_bx_antispam_ip_table_status', mb_strtolower($o->getIpTableConfigTitle((int)getParam('bx_antispam_ip_list_type'))));
+        $s .= $this->_grid('bx_antispam_grid_ip_table');
+        return $s;
+    }
+
+    public function serviceDnsblList ()
+    {
+        $s = _t('_bx_antispam_dnsbl_status',
+             BxTemplFunctions::getInstance()->statusOnOff((bool)$this->_oConfig->getAntispamOption('dnsbl_enable'), true),
+             BxTemplFunctions::getInstance()->statusOnOff((bool)$this->_oConfig->getAntispamOption('uridnsbl_enable'), true),
+             mb_strtolower(_t('_bx_antispam_dnsbl_behaviour_login_' . $this->_oConfig->getAntispamOption('dnsbl_behaviour_login'))),
+             mb_strtolower(_t('_bx_antispam_dnsbl_behaviour_join_' . $this->_oConfig->getAntispamOption('dnsbl_behaviour_join')))
+        );
+        $s .= $this->_grid('bx_antispam_grid_dnsbl');
+        return $s;
+    }
+
+    public function serviceBlockLog ()
+    {
+        return $this->_grid('bx_antispam_grid_block_log');
+    }
+
+    /**
+     * Filter undesired words
+     *
+     * @param $sContent content to filter
+     * @param $sIp IP address of content poster
+     * @return modified or the same content.
+     */
+    public function serviceFilterSpam ($mContent, $sIp = '')
+    {      
+        if (defined('BX_DOL_CRON_EXECUTE') || isAdmin() || 'on' != $this->_oConfig->getAntispamOption('profanity_enable'))
+            return $mContent;
+        
+        $oProfanityFilter = bx_instance('BxAntispamProfanityFilter', array(), $this->_aModule);
+        return $oProfanityFilter->censor($mContent); 
+    }
+    
+    /**
+     * Check text for spam URL.
+     * It checks URLs found in text for DNSURI black lists (@see BxAntispamDNSURIBlacklists),
+     *
+     * @param $sContent content to check for spam
+     * @return true if spam detected, false if spam isn't detected, null if detection wasn't performed.
+     */
+    public function serviceIsSpamUrl ($sContent)
+    {
+        $bRet = null;
+        if ('on' == $this->_oConfig->getAntispamOption('uridnsbl_enable')) {
+            $oDNSURIBlacklists = bx_instance('BxAntispamDNSURIBlacklists', array(), $this->_aModule);
+            if ($oDNSURIBlacklists->isSpam($sContent)) {
+                $oDNSURIBlacklists->onPositiveDetection($sContent);
+                $bRet = true;
+            } 
+            else {
+                $bRet = false;
+            }
+        }
+        return $bRet;
+    }
+
+    /**
+     * Check text for spam.
+     * First it check if IP is whitelisted(or under cron execution or user is admin) - for whitelisted IPs check for spam isn't performed,
+     * then it checks URLs found in text for DNSURI black lists (@see BxAntispamDNSURIBlacklists),
+     * then it checks text in Akismet service (@see BxAntispamAkismet).
+     * It can send report if spam is found or tries to inform caller to block the content (depending on configuration).
+     *
+     * @param $sContent content to check for spam
+     * @param $sIp IP address of content poster
+     * @param $isStripSlashes slashes parameter:
+     *          BX_SLASHES_AUTO - automatically detect magic_quotes_gpc setting
+     *          BX_SLASHES_NO_ACTION - do not perform any action with slashes
+     * @return true if spam detected and content shouln't be recorded, false if content should be processed as usual.
+     */
+    public function serviceIsSpam ($sContent, $sIp = '', $isStripSlashes = BX_SLASHES_AUTO)
+    {      
+        if (defined('BX_DOL_CRON_EXECUTE') || isAdmin())
+            return false;
+
+        if ($this->serviceIsIpWhitelisted($sIp))
+            return false;
+
+        if (version_compare(phpversion(), '7.4.0', '<') && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc() && $isStripSlashes == BX_SLASHES_AUTO)
+            $sContent = stripslashes($sContent);
+        
+        $bRet = false;
+        if ('on' == $this->_oConfig->getAntispamOption('uridnsbl_enable')) {
+            $oDNSURIBlacklists = bx_instance('BxAntispamDNSURIBlacklists', array(), $this->_aModule);
+            if ($oDNSURIBlacklists->isSpam($sContent)) {
+                $oDNSURIBlacklists->onPositiveDetection($sContent);
+                $bRet = true;
+            }
+        }
+
+        if (!$bRet && 'on' == $this->_oConfig->getAntispamOption('akismet_enable')) {
+            $oAkismet = bx_instance('BxAntispamAkismet', array(), $this->_aModule);
+            if ($oAkismet->isSpam($sContent)) {
+                $oAkismet->onPositiveDetection($sContent);
+                $bRet = true;
+            }
+        }
+
+        if ($bRet && 'on' == $this->_oConfig->getAntispamOption('antispam_report')) {
+
+            $oProfile = BxDolProfile::getInstance();
+            $aPlus = array(
+                'SpammerUrl' => $oProfile->getUrl(),
+                'SpammerNickName' => $oProfile->getDisplayName(),
+                'Page' => htmlspecialchars_adv($_SERVER['PHP_SELF']),
+                'Get' => print_r($_GET, true),
+                'Post' => print_r($_POST, true),
+                'SpamContent' => htmlspecialchars_adv($sContent),
+            );
+
+            $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate('bx_antispam_spam_report', $aPlus);
+            if (!$aTemplate)
+                trigger_error('Email template or translation missing: bx_antispam_spam_report', E_USER_ERROR);
+
+            sendMail(getParam('site_email'), $aTemplate['Subject'], $aTemplate['Body']);
+        }
+
+        if ($bRet && 'on' == $this->_oConfig->getAntispamOption('antispam_block'))
+            return true;
+
+        return false;
+    }
+
+    /**
+     * Check text for toxicity.
+     * It can send report if toxic content is found or tries to inform caller to block the content (depending on configuration).
+     *
+     * @param $sContent content to check for spam
+     * @param $sIp IP address of content poster
+     * @param $isStripSlashes slashes parameter:
+     *          BX_SLASHES_AUTO - automatically detect magic_quotes_gpc setting
+     *          BX_SLASHES_NO_ACTION - do not perform any action with slashes
+     * @return true if toxic content detected and content shouln't be recorded, false if content should be processed as usual.
+     */
+    public function serviceIsToxic ($sContent, $sIp = '', $isStripSlashes = BX_SLASHES_AUTO, $bSupressNotification = false)
+    {
+        if (defined('BX_DOL_CRON_EXECUTE') || isAdmin())
+            return false;
+
+        static $aQuickCache;
+        $key = md5($sContent);
+        if (isset($aQuickCache[$key]))
+            return $aQuickCache[$key];
+
+        $aQuickCache[$key] = false;
+
+        if (!$this->serviceIsIpWhitelisted($sIp)) {
+            if (version_compare(phpversion(), '7.4.0', '<') && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc() && $isStripSlashes == BX_SLASHES_AUTO)
+                $sContent = stripslashes($sContent);
+
+            if ('on' == $this->_oConfig->getAntispamOption('toxicity_enable')) {
+                $oPerspectiveAPI = bx_instance('BxAntispamPerspectiveAPI', array(), $this->_aModule);
+                if ($oPerspectiveAPI->isToxic($sContent)) {
+                    $oPerspectiveAPI->onPositiveDetection($sContent);
+                    $aQuickCache[$key] = true;
+
+                    if (!$bSupressNotification) $this->serviceOnToxicContentFound($sContent);
+                }
+            }
+        }
+
+        return $aQuickCache[$key];
+    }
+
+    public function serviceCheckFormForToxicity(&$oForm) {
+        $this->_bLastSubmittedFormWasToxic = false;
+
+        if (!$oForm->isValid() || !$oForm->isSubmitted()) return false;
+
+        $sSubmitName = false;
+        $sFormText = '';
+        foreach ($oForm->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;
+
+            $a['name'] = str_replace('[]', '', $a['name']);
+
+            if ($a['type'] != 'textarea' && $a['type'] != 'text')
+                continue;
+
+            $val = BxDolForm::getSubmittedValue($a['name'], $oForm->aFormAttrs['method']);
+            if (!$val)
+                continue;
+
+            $sFormText .= " ".$val; // collect all text fields into a single text
+        }
+
+        if ($this->serviceIsToxic($sFormText, '', BX_SLASHES_AUTO, true)) {
+            $this->_bLastSubmittedFormWasToxic = true;
+
+            $sActionrequired = $this->_oConfig->getAntispamOption('toxicity_action');
+
+            if ($sActionrequired == 'block' || $sActionrequired == 'disapprove' && !$oForm->isStatusFieldSupported()) {
+                $oForm->setValid(false);
+                $this->serviceOnToxicContentFound($sFormText);
+
+                if ($sSubmitName)
+                    $oForm->aInputs[$sSubmitName]['error'] = _t('_bx_antispam_form_submission_error');
+            } elseif ($sActionrequired == 'disapprove' && $oForm->isStatusFieldSupported()) {
+                $oForm->setForceSetToPending(true);
+                return false;
+            }
+        }
+    }
+
+    public function serviceIsLastFormSubmittedToxic() {
+        return $this->_bLastSubmittedFormWasToxic;
+    }
+
+    public function serviceSetCommentAsPending($iCmtId) {
+        return $this->_oDb->setCommentStatus($iCmtId, BX_CMT_STATUS_PENDING);
+    }
+
+    public function serviceOnFormSubmitted($sModule, $iEntry) {
+        if ($this->_bLastSubmittedFormWasToxic) {
+            $this->serviceOnToxicContentPosted($sModule, $iEntry);
+        }
+    }
+
+    public function serviceOnToxicContentFound(&$sText) {
+        if ('on' == $this->_oConfig->getAntispamOption('toxicity_report')) {
+            $oProfile = BxDolProfile::getInstance();
+            if (!$oProfile) return;
+            $aPlus = array(
+                'AuthorUrl' => $oProfile->getUrl(),
+                'AuthorNickName' => $oProfile->getDisplayName(),
+                'Page' => htmlspecialchars_adv($_SERVER['PHP_SELF']),
+                'Content' => htmlspecialchars_adv(strip_tags($sText)),
+            );
+
+            $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate('bx_antispam_toxicity_blocked_report', $aPlus);
+            if (!$aTemplate)
+                trigger_error('Email template or translation missing: bx_antispam_toxicity_blocked_report', E_USER_ERROR);
+
+            sendMail(getParam('site_email'), $aTemplate['Subject'], $aTemplate['Body']);
+
+            bx_alert('bx_antispam', 'toxic_content_found', 0, bx_get_logged_profile_id(), array(
+                'text' => $sText,
+            ));
+        }
+    }
+
+    public function serviceOnToxicContentPosted($sModule, $iContentId) {
+        if ('on' == $this->_oConfig->getAntispamOption('toxicity_report') && $sModule) {
+            $oModule = BxDolModule::getInstance($sModule);
+            $CNF = &$oModule->_oConfig->CNF;
+            $sContentUrl = isset($CNF['URI_VIEW_ENTRY']) ? bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iContentId)) : false;
+            $sManageContentUrl = isset($CNF['URL_MANAGE_ADMINISTRATION']) ? bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URL_MANAGE_ADMINISTRATION'])) : false;
+
+            $oProfile = BxDolProfile::getInstance();
+            if (!$oProfile) return;
+
+            $aPlus = array(
+                'AuthorUrl' => $oProfile->getUrl(),
+                'AuthorNickName' => $oProfile->getDisplayName(),
+                'Page' => htmlspecialchars_adv($_SERVER['PHP_SELF']),
+                'bx_if:content_url' => [
+                    'condition' => boolval($sContentUrl),
+                    'content' => ['c_url' => $sContentUrl],
+                ],
+                'bx_if:manage_content_url' => [
+                    'condition' => boolval($sManageContentUrl),
+                    'content' => ['m_url' => $sManageContentUrl],
+                ],
+            );
+
+            $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate('bx_antispam_toxicity_posted_report', $aPlus);
+            if (!$aTemplate)
+                trigger_error('Email template or translation missing: bx_antispam_toxicity_posted_report', E_USER_ERROR);
+
+            sendMail(getParam('site_email'), $aTemplate['Subject'], $aTemplate['Body']);
+
+            bx_alert('bx_antispam', 'toxic_content_posted', $iContentId, bx_get_logged_profile_id(), array(
+                'module' => $sModule,
+                'entry_id' => $iContentId,
+                'entry_url' => $sContentUrl,
+            ));
+        }
+    }
+
+    /**
+     * Perform complex check if user is allowed to login.
+     * First it checks if IP is directly blocked (@see serviceIsIpBlocked),
+     * then it checks in DNS black lists (@see serviceIsIpDnsBlacklisted).
+     *
+     * @param $sIp IP to check, or empty for current IP
+     * @return empty string - if join should be allowed, error message - if join should be blocked
+     */
+    public function serviceCheckLogin ($sIp = '')
+    {
+        $bLoginBlock = ('block' == $this->_oConfig->getAntispamOption('dnsbl_behaviour_login'));
+        $sErrorMsg = '';
+        $sNote = $bLoginBlock ? 'login block' : 'login log';
+
+        if (!$sIp)
+            $sIp = getVisitorIP();
+
+        if (!$sErrorMsg && $this->serviceIsIpBlocked($sIp))
+            $sErrorMsg = $this->getErrorMessageIpBlocked();
+
+        if (!$sErrorMsg && 'on' == $this->_oConfig->getAntispamOption('dnsbl_enable') && $this->serviceIsIpDnsBlacklisted($sIp, $sNote) && $bLoginBlock)
+            $sErrorMsg = $this->getErrorMessageSpam();
+
+        return $sErrorMsg;
+    }
+
+    /**
+     * Perform complex check if user is allowed to join.
+     * First it checks if IP is directly blocked (@see serviceIsIpBlocked),
+     * then it checks in DNS black lists (@see serviceIsIpDnsBlacklisted),
+     * then it checks in StopForumSpam service (@see BxAntispamStopForumSpam).
+     *
+     * @param $sCurIP IP to check, or empty for current IP
+     * @return empty string - if join should be allowed, error message - if join should be blocked
+     */
+    public function serviceCheckJoin ($sEmail, &$bApproval, $sIp = '')
+    {
+        $bJoinBlock = ('block' == $this->_oConfig->getAntispamOption('dnsbl_behaviour_join'));
+        $bApproval = false;
+        $sErrorMsg = '';
+        $sNote = $bJoinBlock ? 'join block' : 'join approval';
+
+        if (!$sIp)
+            $sIp = getVisitorIP();
+
+        // check if IP is blocked
+        if (!$sErrorMsg && $this->serviceIsIpBlocked($sIp))
+            $sErrorMsg = $this->getErrorMessageIpBlocked();
+
+        // check in DNSBL lists
+        if (!$sErrorMsg && 'on' == $this->_oConfig->getAntispamOption('dnsbl_enable') && $this->serviceIsIpDnsBlacklisted($sIp, $sNote)) {
+            if ('approval' == $this->_oConfig->getAntispamOption('dnsbl_behaviour_join'))
+                $bApproval = true;
+            else
+                $sErrorMsg = $this->getErrorMessageSpam();
+        }
+
+        // check in StopForumSpam service
+        if (!$sErrorMsg) {
+            $oStopForumSpam = bx_instance('BxAntispamStopForumSpam', array(), $this->_aModule);
+            if ($oStopForumSpam->isSpammer(array('email' => $sEmail, 'ip' => $sIp), $sNote))
+                $sErrorMsg = $this->getErrorMessageSpam();
+        }
+
+        // check for disposable email domains
+        if (!$sErrorMsg && 'disable' != ($sMode = $this->_oConfig->getAntispamOption('disposable_email_domains_mode'))) {
+
+            $bDisposableEmailDomainsBehaviour = $this->_oConfig->getAntispamOption('disposable_email_domains_behaviour_join');
+            $oDisposableEmailDomains = bx_instance('BxAntispamDisposableEmailDomains', array(), 'bx_antispam');
+            
+            if ('blacklist' == $sMode && $oDisposableEmailDomains->isBlacklisted($sEmail)) {
+                if ('approval' == $bDisposableEmailDomainsBehaviour)
+                    $bApproval = true;
+                else
+                    $sErrorMsg = $oDisposableEmailDomains->getErrorMessageBlacklisted();
+            }
+            elseif ('whitelist' == $sMode && !$oDisposableEmailDomains->isWhitelisted($sEmail)) {
+                if ('approval' == $bDisposableEmailDomainsBehaviour)
+                    $bApproval = true;
+                else
+                    $sErrorMsg = $oDisposableEmailDomains->getErrorMessageNotWhitelisted();
+            }
+
+        }
+
+        return $sErrorMsg;
+    }
+
+    /**
+     * Check if IP is blacklisted in some DNS chain (@see BxAntispamDNSBlacklists).
+     *
+     * @param $sCurIP IP to check, or empty for current IP
+     * @param $sNote [optional] place where checking is performed, for example 'join', 'login'
+     * @return true if IP blacklisted and not whiteloisted, or false if under cron execution or if IP isn't blacklisted
+     */
+    public function serviceIsIpDnsBlacklisted($sCurIP = '', $sNote = '')
+    {
+        if (defined('BX_DOL_CRON_EXECUTE'))
+            return false;
+
+        if (!$sCurIP)
+            $sCurIP = getVisitorIP();
+
+        if ($this->serviceIsIpWhitelisted($sCurIP))
+            return false;
+
+        $o = bx_instance('BxAntispamDNSBlacklists', array(), $this->_aModule);
+
+        if (BX_DOL_DNSBL_POSITIVE == $o->dnsbl_lookup_ip(BX_DOL_DNSBL_CHAIN_SPAMMERS, $sCurIP) && BX_DOL_DNSBL_POSITIVE != $o->dnsbl_lookup_ip(BX_DOL_DNSBL_CHAIN_WHITELIST, $sCurIP)) {
+            $o->onPositiveDetection ($sCurIP, $sNote);
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @see BxAntispamIP::isIpWhitelisted
+     */
+    public function serviceIsIpWhitelisted($sIp = '')
+    {
+        $o = bx_instance('BxAntispamIP', array(), $this->_aModule);
+        return $o->isIpWhitelisted($sIp);
+    }
+
+    /**
+     * @see BxAntispamIP::isIpBlocked
+     */
+    public function serviceIsIpBlocked($sIp = '')
+    {
+        $o = bx_instance('BxAntispamIP', array(), $this->_aModule);
+        return $o->isIpBlocked($sIp);
+    }
+
+    /**
+     * @see BxAntispamIP::blockIp
+     */
+    public function serviceBlockIp($mixedIP, $iExpirationInSec = 86400, $sComment = '')
+    {
+        $o = bx_instance('BxAntispamIP', array(), $this->_aModule);
+        return $o->blockIp($mixedIP, $iExpirationInSec, $sComment);
+    }
+
+    /**
+     * @see BxAntispamIP::pruning
+     */
+    public function servicePruning()
+    {
+        $o = bx_instance('BxAntispamIP', array(), $this->_aModule);
+        return $o->pruning();
+    }
+
+    /**
+     * @see BxAntispamIP::pruning
+     */
+    public function serviceConfigValues($s)
+    {
+        switch ($s) {
+            case 'ip_table':
+                $o = bx_instance('BxAntispamIP', array(), $this->_aModule);
+                return $o->getIpTableConfigValues();
+            case 'dnsbl_login':
+                $o = bx_instance('BxAntispamDNSBlacklists', array(), $this->_aModule);
+                return $o->getDNSBLConfigValues();
+            case 'dnsbl_join';
+                $o = bx_instance('BxAntispamDNSURIBlacklists', array(), $this->_aModule);
+                return $o->getURIDNSBLConfigValues();
+            case 'disposable_email_domains_join';
+                $o = bx_instance('BxAntispamDisposableEmailDomains', array(), $this->_aModule);
+                return $o->getJoinBehaviourValues();                
+            case 'disposable_email_domains_mode';
+                $o = bx_instance('BxAntispamDisposableEmailDomains', array(), $this->_aModule);
+                return $o->getJoinBehaviourModes();                
+        }
+    }
+    
+    /**
+     * @return array with avaliable dictionaries languages
+     */
+    public function serviceGetProfanityFilterDicts ()
+    {
+        $oProfanityFilter = bx_instance('BxAntispamProfanityFilter', array(), $this->_aModule);
+        return $oProfanityFilter->getDicts(); 
+    }
+
+    /**
+     * @return array with avaliable toxicity filter actions
+     */
+    public function serviceGetToxicityFilterActions ()
+    {
+        return [
+            'none' => _t('_bx_antispam_option_toxicity_filter_action_none'),
+            'block' => _t('_bx_antispam_option_toxicity_filter_action_block'),
+            'disapprove' => _t('_bx_antispam_option_toxicity_filter_action_disapprove'),
+        ];
+    }
+
+    protected function getErrorMessageIpBlocked ()
+    {
+        bx_import('BxDolLanguages');
+        return _t('_bx_antispam_ip_blocked', $this->getErrorMessageSubmitFalsePositiveReport());
+    }
+
+    protected function getErrorMessageSpam ()
+    {
+        bx_import('BxDolLanguages');
+        return _t('_bx_antispam_spam_detected', $this->getErrorMessageSubmitFalsePositiveReport());
+    }
+
+    protected function getErrorMessageSubmitFalsePositiveReport ()
+    {
+        if (BxDolRequest::serviceExists('bx_contact', 'get_contact_page_url') && ($sUrl = BxDolService::call('bx_contact', 'get_contact_page_url')))
+            return _t('_bx_antispam_submit_false_positive_report', $sUrl);
+        return '';
+    }
+
+    protected function _grid ($sObjectGrid)
+    {
+        $oGrid = BxDolGrid::getObjectInstance($sObjectGrid);
+        return $oGrid ? $oGrid->getCode() : '';
+    }
+}
+
+/** @} */

+ 37 - 0
modules/boonex/antispam/updates/13.0.1_13.0.2/source/classes/BxAntispamStudioPage.php

@@ -0,0 +1,37 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Antispam Antispam
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxAntispamStudioPage extends BxTemplStudioModule
+{
+    protected $oModule;
+
+    function __construct($sModule, $mixedPageName, $sPage = "")
+    {
+        parent::__construct($sModule, $mixedPageName, $sPage);
+
+        $this->oModule = BxDolModule::getInstance('bx_antispam');
+
+        $this->aMenuItems = array(
+            'settings' => array('name' => 'settings', 'icon' => 'cogs', 'title' => '_adm_lmi_cpt_settings'),
+            'ip_table' => array('name' => 'ip_table', 'icon' => 'align-justify', 'title' => '_bx_antispam_ip_table', 'link' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=antispam-ip-table'))),
+            'dnsbl_list' => array('name' => 'dnsbl_list', 'icon' => 'align-justify', 'title' => '_bx_antispam_dnsbl_list', 'link' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=antispam-dnsbl-list'))),
+            'block_log' => array('name' => 'block_log', 'icon' => 'far clock', 'title' => '_bx_antispam_block_log', 'link' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=antispam-block-log'))),
+            'help' => array('name' => 'help', 'icon' => 'question', 'title' => '_bx_antispam_help'),
+        );
+    }
+
+    function getHelp ()
+    {
+        return _t('_bx_antispam_help_text');
+    }
+}
+
+/** @} */

+ 68 - 0
modules/boonex/antispam/updates/13.0.1_13.0.2/source/install/config.php

@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Antispam Antispam
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_antispam',
+    'title' => 'Antispam',
+    'note' => 'Antispam tools',
+    'version' => '13.0.2',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.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/antispam/',
+    'home_uri' => 'antispam',
+
+    'db_prefix' => 'bx_antispam_',
+    'class_prefix' => 'BxAntispam',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Antispam',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 245 - 0
modules/boonex/antispam/updates/13.0.1_13.0.2/source/install/sql/enable.sql

@@ -0,0 +1,245 @@
+
+-- 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_antispam', '_bx_antispam_adm_stg_cpt_type', 'bx_antispam@modules/boonex/antispam/|std-icon.svg', IF(NOT ISNULL(@iTypeOrder), @iTypeOrder + 1, 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order` )  
+VALUES (@iTypeId, 'bx_antispam_general', '_bx_antispam_adm_stg_cpt_category_general', 1);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, 'bx_antispam_block', '_bx_antispam_option_block', '', 'checkbox', '', '', '', 10),
+(@iCategoryId, 'bx_antispam_report', '_bx_antispam_option_report', 'on', 'checkbox', '', '', '', 20);
+
+
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order` )  
+VALUES (@iTypeId, 'bx_antispam_ip_table', '_bx_antispam_adm_stg_cpt_category_ip_table', 2);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, 'bx_antispam_ip_list_type', '_bx_antispam_option_ip_list_type', '0', 'select', 'a:3:{s:6:"module";s:11:"bx_antispam";s:6:"method";s:13:"config_values";s:6:"params";a:1:{i:0;s:8:"ip_table";}}', '', '', 10);
+
+
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order` )  
+VALUES (@iTypeId, 'bx_antispam_dnsbl', '_bx_antispam_adm_stg_cpt_category_dnsbl', 3);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, 'bx_antispam_dnsbl_enable', '_bx_antispam_option_dnsbl_enable', 'on', 'checkbox', '', '', '', 10),
+(@iCategoryId, 'bx_antispam_dnsbl_behaviour_login', '_bx_antispam_option_dnsbl_behaviour_login', 'block', 'select', 'a:3:{s:6:"module";s:11:"bx_antispam";s:6:"method";s:13:"config_values";s:6:"params";a:1:{i:0;s:11:"dnsbl_login";}}', '', '', 20),
+(@iCategoryId, 'bx_antispam_dnsbl_behaviour_join', '_bx_antispam_option_dnsbl_behaviour_join', 'approval', 'select', 'a:3:{s:6:"module";s:11:"bx_antispam";s:6:"method";s:13:"config_values";s:6:"params";a:1:{i:0;s:10:"dnsbl_join";}}', '', '', 30),
+(@iCategoryId, 'bx_antispam_uridnsbl_enable', '_bx_antispam_option_uridnsbl_enable', 'on', 'checkbox', '', '', '', 40);
+
+
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order` )  
+VALUES (@iTypeId, 'bx_antispam_akismet', '_bx_antispam_adm_stg_cpt_category_akismet', 4);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, 'bx_antispam_akismet_enable', '_bx_antispam_option_akismet_enable', '', 'checkbox', '', '', '', 10),
+(@iCategoryId, 'bx_antispam_akismet_api_key', '_bx_antispam_option_akismet_api_key', '', 'digit', '', '', '', 20);
+
+
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order` )  
+VALUES (@iTypeId, 'bx_antispam_stopforumspam', '_bx_antispam_adm_stg_cpt_category_stopforumspam', 5);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, 'bx_antispam_stopforumspam_enable', '_bx_antispam_option_stopforumspam_enable', 'on', 'checkbox', '', '', '', 10),
+(@iCategoryId, 'bx_antispam_stopforumspam_api_key', '_bx_antispam_option_stopforumspam_api_key', '', 'digit', '', '', '', 20);
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order` )  
+VALUES (@iTypeId, 'bx_antispam_disposable_email_domains', '_bx_antispam_adm_stg_cpt_category_disposable_email_domains', 6);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, 'bx_antispam_disposable_email_domains_mode', '_bx_antispam_option_disposable_email_domains_mode', 'blacklist', 'select', 'a:3:{s:6:"module";s:11:"bx_antispam";s:6:"method";s:13:"config_values";s:6:"params";a:1:{i:0;s:29:"disposable_email_domains_mode";}}', '', '', 10),
+(@iCategoryId, 'bx_antispam_disposable_email_domains_behaviour_join', '_bx_antispam_option_disposable_email_domains_behaviour_join', 'block', 'select', 'a:3:{s:6:"module";s:11:"bx_antispam";s:6:"method";s:13:"config_values";s:6:"params";a:1:{i:0;s:29:"disposable_email_domains_join";}}', '', '', 20);
+
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order` )  
+VALUES (@iTypeId, 'bx_antispam_profanity_filter', '_bx_antispam_adm_stg_cpt_category_profanity_filter', 7);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, 'bx_antispam_profanity_filter_enable', '_bx_antispam_option_profanity_filter_enable', '', 'checkbox', '', '', '', 10),
+(@iCategoryId, 'bx_antispam_profanity_filter_dicts', '_bx_antispam_option_profanity_filter_dicts', '', 'list', 'a:2:{s:6:"module";s:11:"bx_antispam";s:6:"method";s:26:"get_profanity_filter_dicts";}', '', '', 15),
+(@iCategoryId, 'bx_antispam_profanity_filter_bad_words_list', '_bx_antispam_option_profanity_filter_bad_words_list', '', 'text', '', '', '', 20),
+(@iCategoryId, 'bx_antispam_profanity_filter_char_replace', '_bx_antispam_option_profanity_filter_char_replace', '*', 'digit', '', '', '', 30),
+(@iCategoryId, 'bx_antispam_profanity_filter_white_words_list', '_bx_antispam_option_profanity_filter_white_words_list', '', 'text', '', '', '', 40),
+(@iCategoryId, 'bx_antispam_profanity_filter_full_words_only', '_bx_antispam_option_profanity_filter_full_words_only', 'on', 'checkbox', '', '', '', 50);
+
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order` )
+VALUES (@iTypeId, 'bx_antispam_toxicity_filter', '_bx_antispam_adm_stg_cpt_category_toxicity_filter', 8);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, 'bx_antispam_toxicity_filter_enable', '_bx_antispam_option_toxicity_filter_enable', '', 'checkbox', '', '', '', 10),
+(@iCategoryId, 'bx_antispam_toxicity_filter_api_key', '_bx_antispam_option_toxicity_filter_api_key', '', 'digit', '', '', '', 20),
+(@iCategoryId, 'bx_antispam_toxicity_filter_action', '_bx_antispam_option_toxicity_filter_action', 'none', 'select', 'a:2:{s:6:"module";s:11:"bx_antispam";s:6:"method";s:27:"get_toxicity_filter_actions";}', '', '', 30),
+(@iCategoryId, 'bx_antispam_toxicity_filter_report', '_bx_antispam_option_toxicity_report', '', 'checkbox', 'on', '', '', 40),
+(@iCategoryId, 'bx_antispam_toxicity_filter_threshold', '_bx_antispam_option_toxicity_filter_threshold', '60', 'digit', '', '', '', 50);
+
+-- page: DNSBL list
+
+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_antispam_dnsbl', 'antispam-dnsbl-list', '_bx_antispam_page_title_sys_dnsbl_list', '_bx_antispam_page_title_dnsbl_list', 'bx_antispam', 5, 128, 1, 'page.php?i=antispam-dnsbl-list', '', '', '', 0, 1, 0, 'BxAntispamPage', 'modules/boonex/antispam/classes/BxAntispamPage.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_antispam_dnsbl', 1, 'bx_antispam', '_bx_antispam_page_block_title_dnsbl_list', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_antispam\";s:6:\"method\";s:10:\"dnsbl_list\";}', 0, 1, 1, 1);
+
+-- page: ip table
+
+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_antispam_ip_table', 'antispam-ip-table', '_bx_antispam_page_title_sys_ip_table', '_bx_antispam_page_title_ip_table', 'bx_antispam', 5, 128, 1, 'page.php?i=antispam-ip-table', '', '', '', 0, 1, 0, 'BxAntispamPage', 'modules/boonex/antispam/classes/BxAntispamPage.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_antispam_ip_table', 1, 'bx_antispam', '_bx_antispam_page_block_title_ip_table', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_antispam\";s:6:\"method\";s:8:\"ip_table\";}', 0, 1, 1, 1);
+
+-- page: block log
+
+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_antispam_block_log', 'antispam-block-log', '_bx_antispam_page_title_sys_block_log', '_bx_antispam_page_title_block_log', 'bx_antispam', 5, 192, 1, 'page.php?i=antispam-block-log', '', '', '', 0, 1, 0, 'BxAntispamPage', 'modules/boonex/antispam/classes/BxAntispamPage.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_antispam_block_log', 1, 'bx_antispam', '_bx_antispam_page_block_title_block_log', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_antispam\";s:6:\"method\";s:9:\"block_log\";}', 0, 1, 1, 1);
+
+-- grid: DNSBL
+
+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_antispam_grid_dnsbl', 'Sql', 'SELECT `id`, `chain`, `zonedomain`, `postvresp`, `url`, `recheck`, `comment`, `added`, `active` FROM `bx_antispam_dnsbl_rules`', 'bx_antispam_dnsbl_rules', 'id', 'added', 'active', '', 16, NULL, 'start', '', 'chain,zonedomain,url,recheck', 'comment', 'auto', 'chain,zonedomain', 'comment', 128, 'BxAntispamGridDNSBL', 'modules/boonex/antispam/classes/BxAntispamGridDNSBL.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_antispam_grid_dnsbl', 'switcher', '_sys_active', '10%', 0, 0, '', 1),
+('bx_antispam_grid_dnsbl', 'chain', '_bx_antispam_field_chain', '15%', 0, 0, '', 2),
+('bx_antispam_grid_dnsbl', 'zonedomain', '_bx_antispam_field_zonedomain', '15%', 0, 0, '', 3),
+('bx_antispam_grid_dnsbl', 'comment', '_bx_antispam_field_note', '55%', 0, 0, '', 4),
+('bx_antispam_grid_dnsbl', 'actions', '_sys_actions', '5%', 0, 0, '', 5);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_antispam_grid_dnsbl', 'independent', 'log', '_bx_antispam_grid_action_log', '', 0, 1),
+('bx_antispam_grid_dnsbl', 'independent', 'recheck', '_bx_antispam_grid_action_recheck', '', 0, 2),
+('bx_antispam_grid_dnsbl', 'independent', 'add', '_bx_antispam_grid_action_add', '', 0, 3),
+('bx_antispam_grid_dnsbl', 'independent', 'help', '_bx_antispam_grid_action_help', '', 0, 4),
+('bx_antispam_grid_dnsbl', 'single', 'delete', '', 'remove',  1, 1);
+
+-- grid: ip table
+
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_mode`, `sorting_fields`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_antispam_grid_ip_table', 'Sql', 'SELECT `ID`, `From`, `To`, `Type`, `LastDT`, `Desc` FROM `bx_antispam_ip_table`', 'bx_antispam_ip_table', 'ID', '', '', 10, NULL, 'start', '', 'From,To,Desc', 'auto', 'From,To,Type,LastDT,Desc', 128, 'BxAntispamGridIpTable', 'modules/boonex/antispam/classes/BxAntispamGridIpTable.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `params`, `order`) VALUES
+('bx_antispam_grid_ip_table', 'checkbox', '_sys_select', '2%', '', 1),
+('bx_antispam_grid_ip_table', 'From', '_bx_antispam_field_ip_from', '15%', '', 2),
+('bx_antispam_grid_ip_table', 'To', '_bx_antispam_field_ip_to', '15%', '', 3),
+('bx_antispam_grid_ip_table', 'Type', '_bx_antispam_field_action', '15%', '', 4),
+('bx_antispam_grid_ip_table', 'LastDT', '_bx_antispam_field_expiration', '15%', '', 5),
+('bx_antispam_grid_ip_table', 'Desc', '_bx_antispam_field_note', '26%', '', 6),
+('bx_antispam_grid_ip_table', 'actions', '_sys_actions', '12%', '', 7);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_antispam_grid_ip_table', 'bulk', 'delete', '_bx_antispam_grid_action_delete', '', 1, 1),
+('bx_antispam_grid_ip_table', 'single', 'edit', '', 'pencil-alt', 0, 1),
+('bx_antispam_grid_ip_table', 'single', 'delete', '', 'remove',  1, 2),
+('bx_antispam_grid_ip_table', 'independent', 'add', '_bx_antispam_grid_action_add', '', 0, 1);
+
+-- grid: block log
+
+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_antispam_grid_block_log', 'Sql', 'SELECT `id`, `ip`, `profile_id`, `type`, `extra`, `added` FROM `bx_antispam_block_log`', 'bx_antispam_block_log', 'id', 'id', '', '', 8, NULL, 'start', '', 'type,extra', '', 'auto', 'ip,profile_id,type,extra,added', '', 192, 'BxAntispamGridBlockLog', 'modules/boonex/antispam/classes/BxAntispamGridBlockLog.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_antispam_grid_block_log', 'ip', '_bx_antispam_field_ip', '20%', 0, 0, '', 1),
+('bx_antispam_grid_block_log', 'profile_id', '_bx_antispam_field_profile_id', '20%', 0, 0, '', 2),
+('bx_antispam_grid_block_log', 'type', '_bx_antispam_field_type', '15%', 0, 0, '', 3),
+('bx_antispam_grid_block_log', 'extra', '_bx_antispam_field_note', '15%', 0, 8, '', 4),
+('bx_antispam_grid_block_log', 'added', '_bx_antispam_field_when', '30%', 0, 0, '', 5);
+
+-- data list: ip table actions
+
+INSERT INTO `sys_form_pre_lists`(`module`, `key`, `title`, `use_for_sets`) VALUES 
+('bx_antispam', 'bx_antispam_ip_table_actions', '_bx_antispam_data_list_ip_table_actions', 0);
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `LKey`, `LKey2`, `Order`) VALUES 
+('bx_antispam_ip_table_actions', 'allow', '_bx_antispam_ip_allow', '', 0),
+('bx_antispam_ip_table_actions', 'deny', '_bx_antispam_ip_deny', '', 0);
+
+-- form: IP table add/edit
+
+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_antispam_ip_table_form', 'bx_antispam', '_bx_antispam_form_ip_table', 'grid.php?o={grid_object}&a={grid_action}', '', 'bx_antispam_ip_table', 'ID', '', '', 'bx_antispam_ip_table_submit', '', 0, 1, '', '');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_antispam_ip_table_form', 'bx_antispam_ip_table_form_add', 'bx_antispam', 0, '_bx_antispam_form_ip_table_add'),
+('bx_antispam_ip_table_form', 'bx_antispam_ip_table_form_edit', 'bx_antispam', 0, '_bx_antispam_form_ip_table_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_antispam_ip_table_form', 'bx_antispam', 'ID', '', '', 0, 'hidden', '_bx_antispam_field_id', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_antispam_ip_table_form', 'bx_antispam', 'From', '', '', 0, 'text', '_bx_antispam_field_ip_from', '_bx_antispam_field_ip_from', '', 1, 0, 0, '', '', '', 'preg', 'a:1:{s:4:\"preg\";s:20:\"#\\d+\\.\\d+\\.\\d+\\.\\d+#\";}', '_bx_antispam_field_ip_err_msg', 'Xss', '', 1, 0),
+('bx_antispam_ip_table_form', 'bx_antispam', 'To', '', '', 0, 'text', '_bx_antispam_field_ip_to', '_bx_antispam_field_ip_to', '', 1, 0, 0, '', '', '', 'preg', 'a:1:{s:4:\"preg\";s:20:\"#\\d+\\.\\d+\\.\\d+\\.\\d+#\";}', '_bx_antispam_field_ip_err_msg', 'Xss', '', 1, 0),
+('bx_antispam_ip_table_form', 'bx_antispam', 'Type', 'allow', '#!bx_antispam_ip_table_actions', 0, 'select', '_bx_antispam_field_action', '_bx_antispam_field_action', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_antispam_ip_table_form', 'bx_antispam', 'LastDT', '', '', 0, 'datetime', '_bx_antispam_field_expiration', '_bx_antispam_field_expiration', '', 1, 0, 0, '', '', '', 'date_time', '', '_bx_antispam_field_expiration_err_msg', 'DateTimeTs', '', 1, 0),
+('bx_antispam_ip_table_form', 'bx_antispam', 'Desc', '', '', 0, 'text', '_bx_antispam_field_note', '_bx_antispam_field_note', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_antispam_ip_table_form', 'bx_antispam', 'bx_antispam_ip_table_submit', '_sys_submit', '', 0, 'submit', '_sys_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_antispam_ip_table_form', 'bx_antispam', 'close', '_sys_close', '', 0, 'reset', '_sys_close', '', '', 0, 0, 0, 'a:2:{s:7:\"onclick\";s:46:\"$(\'.bx-popup-applied:visible\').dolPopupHide();\";s:5:\"class\";s:22:\"bx-def-margin-sec-left\";}', '', '', '', '', '', '', '', 1, 0),
+('bx_antispam_ip_table_form', 'bx_antispam', 'buttons', '', 'bx_antispam_ip_table_submit,close', 0, 'input_set', '_bx_antispam_form_buttons', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0);
+
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_antispam_ip_table_form_add', 'ID', 2147483647, 0, 0),
+('bx_antispam_ip_table_form_add', 'From', 2147483647, 1, 1),
+('bx_antispam_ip_table_form_add', 'To', 2147483647, 1, 2),
+('bx_antispam_ip_table_form_add', 'Type', 2147483647, 1, 3),
+('bx_antispam_ip_table_form_add', 'LastDT', 2147483647, 1, 4),
+('bx_antispam_ip_table_form_add', 'Desc', 2147483647, 1, 5),
+('bx_antispam_ip_table_form_add', 'bx_antispam_ip_table_submit', 2147483647, 1, 6),
+('bx_antispam_ip_table_form_add', 'close', 2147483647, 1, 7),
+('bx_antispam_ip_table_form_add', 'buttons', 2147483647, 1, 8),
+('bx_antispam_ip_table_form_edit', 'ID', 2147483647, 1, 0),
+('bx_antispam_ip_table_form_edit', 'From', 2147483647, 1, 1),
+('bx_antispam_ip_table_form_edit', 'To', 2147483647, 1, 2),
+('bx_antispam_ip_table_form_edit', 'Type', 2147483647, 1, 3),
+('bx_antispam_ip_table_form_edit', 'LastDT', 2147483647, 1, 4),
+('bx_antispam_ip_table_form_edit', 'Desc', 2147483647, 1, 5),
+('bx_antispam_ip_table_form_edit', 'bx_antispam_ip_table_submit', 2147483647, 1, 6),
+('bx_antispam_ip_table_form_edit', 'close', 2147483647, 1, 7),
+('bx_antispam_ip_table_form_edit', 'buttons', 2147483647, 1, 8);
+
+-- alerts
+
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_antispam', 'BxAntispamAlertsResponse', 'modules/boonex/antispam/classes/BxAntispamAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('account', 'check_login', @iHandler),
+('account', 'check_join', @iHandler),
+('system', 'check_spam', @iHandler),
+('system', 'check_spam_url', @iHandler),
+('system', 'form_check', @iHandler),
+('system', 'form_submitted', @iHandler),
+('comment', 'added', @iHandler),
+('comment', 'edited', @iHandler);
+
+-- email templates
+
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES
+('bx_antispam', '_bx_antispam_spam_report_name', 'bx_antispam_spam_report', '_bx_antispam_spam_report_subject', '_bx_antispam_spam_report_body'),
+('bx_antispam', '_bx_antispam_toxicity_blocked_report_name', 'bx_antispam_toxicity_blocked_report', '_bx_antispam_toxicity_blocked_report_subject', '_bx_antispam_toxicity_blocked_report_body'),
+('bx_antispam', '_bx_antispam_toxicity_posted_report_name', 'bx_antispam_toxicity_posted_report', '_bx_antispam_toxicity_posted_report_subject', '_bx_antispam_toxicity_posted_report_body');
+
+-- cron
+
+INSERT INTO `sys_cron_jobs` (`name`, `time`, `class`, `file`, `service_call`) VALUES
+('bx_antispam_pruning', '0 0 * * *', 'BxAntispamCronPruning', 'modules/boonex/antispam/classes/BxAntispamCronPruning.php', ''),
+('bx_antispam_update_disposable_email_domains', '0 0 */14 * *', 'BxAntispamCronUpdateDisposableEmailDomains', 'modules/boonex/antispam/classes/BxAntispamCronUpdateDisposableEmailDomains.php', '');
+

+ 73 - 0
modules/boonex/antispam/updates/13.0.1_13.0.2/source/install/sql/install.sql

@@ -0,0 +1,73 @@
+
+CREATE TABLE `bx_antispam_ip_table` (
+  `ID` int(11) NOT NULL auto_increment,
+  `From` int(10) unsigned NOT NULL,
+  `To` int(10) unsigned NOT NULL,
+  `Type` enum('allow','deny') NOT NULL default 'deny',
+  `LastDT` int(11) unsigned NOT NULL,
+  `Desc` varchar(128) NOT NULL,
+  PRIMARY KEY  (`ID`),
+  KEY `From` (`From`),
+  KEY `To` (`To`)
+);
+
+
+CREATE TABLE `bx_antispam_dnsbl_rules` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `chain` enum('spammers','whitelist','uridns') NOT NULL,
+  `zonedomain` varchar(255) NOT NULL,
+  `postvresp` varchar(32) NOT NULL,
+  `url` varchar(255) NOT NULL,
+  `recheck` varchar(255) NOT NULL,
+  `comment` varchar(255) NOT NULL,
+  `added` int(11) NOT NULL,
+  `active` tinyint(4) NOT NULL,
+  PRIMARY KEY (`id`)
+);
+
+INSERT INTO `bx_antispam_dnsbl_rules` (`chain`, `zonedomain`, `postvresp`, `url`, `recheck`, `comment`, `added`, `active`) VALUES
+('spammers', 'sbl.spamhaus.org.', 'any', 'http://www.spamhaus.org/sbl/', 'http://www.spamhaus.org/query/bl?ip=%s', '_bx_antispam_rule_note_spamhaus_org', 0, 1),
+('spammers', 'dnsbl.tornevall.org.', '230', 'http://dnsbl.tornevall.org/', '', '_bx_antispam_rule_note_dnsbl_tornevall_org', 0, 0),
+('uridns', 'multi.surbl.org.', 'any', 'http://www.surbl.org/', 'https://surbl.org/surbl-analysis', '_bx_antispam_rule_note_surbl_org', 0, 1),
+('spammers', 'zomgbl.spameatingmonkey.net.', 'any', 'http://spameatingmonkey.com/index.html', '', '_bx_antispam_rule_note_zomgbl_spameatingmonkey_net', 0, 0);
+
+CREATE TABLE `bx_antispam_dnsbluri_zones` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `level` tinyint(4) NOT NULL,
+  `zone` varchar(64) NOT NULL,
+  PRIMARY KEY (`id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_antispam_disposable_email_domains` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `domain` varchar(255) NOT NULL,
+  `list` enum('blacklist','custom_blacklist','whitelist','custom_whitelist') NOT NULL DEFAULT 'custom_blacklist',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `domain` (`domain`(191))
+);
+
+CREATE TABLE `bx_antispam_block_log` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `ip` int(10) unsigned NOT NULL,
+  `profile_id` int(10) unsigned NOT NULL,
+  `type` varchar(32) NOT NULL,
+  `extra` text NOT NULL,
+  `added` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `ip` (`ip`),
+  KEY `profile_id` (`profile_id`)
+);
+
+-- Studio page and widget
+
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_antispam', '_bx_antispam', '_bx_antispam', 'bx_antispam@modules/boonex/antispam/|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_antispam', 'extensions', '{url_studio}module.php?name=bx_antispam', '', 'bx_antispam@modules/boonex/antispam/|std-icon.svg', '_bx_antispam', '', '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));
+

+ 30 - 0
modules/boonex/antispam/updates/13.0.1_13.0.2/source/template/images/icons/std-icon.svg

@@ -0,0 +1,30 @@
+<svg width="320" height="320" viewBox="0 0 320 320" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_937_6706)">
+<path d="M160 0C281.326 0 320 38.6737 320 160C320 281.326 281.326 320 160 320C38.6736 320 0 281.326 0 160C0 38.6737 38.6736 0 160 0Z" fill="url(#paint0_linear_937_6706)"/>
+<path d="M160 2C220.573 2 259.85 11.6833 284.083 35.9168C308.317 60.1504 318 99.4272 318 160C318 220.573 308.317 259.85 284.083 284.083C259.85 308.317 220.573 318 160 318C99.4272 318 60.1504 308.317 35.9168 284.083C11.6833 259.85 2 220.573 2 160C2 99.4272 11.6833 60.1504 35.9168 35.9168C60.1504 11.6833 99.4272 2 160 2Z" stroke="#0F172A" stroke-opacity="0.2" stroke-width="4"/>
+<g clip-path="url(#clip1_937_6706)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M254.789 79.537C253.232 74.8851 248.405 72.2435 243.58 73.1273C215.904 78.1963 189.647 80.0543 163.441 71.3624C161.182 70.6132 158.735 70.6152 156.477 71.3665C130.579 79.9825 104.614 78.134 77.2649 73.1271C72.4395 72.2437 67.613 74.8851 66.0559 79.5371C49.2065 129.877 51.6791 182.384 101.775 232.479C154.538 285.242 166.307 285.242 219.07 232.479C269.166 182.384 271.639 129.877 254.789 79.537ZM160.001 221C193.138 221 220.001 194.137 220.001 161C220.001 127.863 193.138 101 160.001 101C126.864 101 100.001 127.863 100.001 161C100.001 194.137 126.864 221 160.001 221Z" fill="url(#paint1_linear_937_6706)"/>
+<circle cx="160" cy="161" r="50" fill="url(#paint2_linear_937_6706)"/>
+</g>
+</g>
+<defs>
+<linearGradient id="paint0_linear_937_6706" x1="160" y1="0" x2="160" y2="320" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F8FAFC"/>
+<stop offset="1" stop-color="#E2E8F0"/>
+</linearGradient>
+<linearGradient id="paint1_linear_937_6706" x1="160.423" y1="70.8018" x2="160.423" y2="272.052" gradientUnits="userSpaceOnUse">
+<stop stop-color="#2DD4BF"/>
+<stop offset="1" stop-color="#0D9488"/>
+</linearGradient>
+<linearGradient id="paint2_linear_937_6706" x1="160" y1="111" x2="160" y2="211" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FB923C"/>
+<stop offset="1" stop-color="#EA580C"/>
+</linearGradient>
+<clipPath id="clip0_937_6706">
+<rect width="320" height="320" fill="white"/>
+</clipPath>
+<clipPath id="clip1_937_6706">
+<rect width="240" height="240" fill="white" transform="translate(40 40)"/>
+</clipPath>
+</defs>
+</svg>

+ 51 - 0
modules/boonex/api/updates/12.0.2_13.0.0/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' => 'API',
+    'version_from' => '12.0.2',
+    'version_to' => '13.0.0',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.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/api/updates/update_12.0.2_13.0.0/',
+    'home_uri' => 'api_update_1202_1300',
+
+    'module_dir' => 'boonex/api/',
+    'module_uri' => 'api',
+
+    'db_prefix' => 'bx_api_',
+    'class_prefix' => 'BxApi',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'API',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/api/updates/12.0.2_13.0.0/install/installer.php

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

+ 602 - 0
modules/boonex/api/updates/12.0.2_13.0.0/source/classes/BxApiModule.php

@@ -0,0 +1,602 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    API API to the UNA backend
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxApiModule extends BxDolModule
+{
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+
+    public function serviceGetSafeServices()
+    {
+        $a = parent::serviceGetSafeServices();
+        return array_merge($a, array (
+            'DeletePage' => '',
+            'ChangeAccountPassword' => '',
+            'SwitchProfile' => ''
+        ));
+    }
+
+    public function serviceGetPublicServices()
+    {
+        $a = parent::serviceGetPublicServices();
+        return array_merge($a, array (
+            'Test' => '',
+            'GetPage' => '',
+            'ResetPasswordSendRequest' => '',
+            'ResetPasswordCheckCode' => '',
+            'CreateAccount' => '',
+        ));
+    }
+
+    /**
+     * @page public_api API Public
+     * @section public_api_api_test /m/oauth2/com/test
+     * 
+     * Test method to check public API
+     * 
+     * **HTTP Method:** 
+     * `GET`
+     *
+     * **Request params:**
+     * n/a
+     *
+     * **Response (success):**
+     * @code
+     * {  
+     *    "result": "Test passed."
+     * }
+     * @endcode
+     */
+    public function serviceTest()
+    {
+        return array('result' => 'Test passed.');
+    }
+
+    /**
+     * @page public_api API Public
+     * @section public_api_api_get_page /m/oauth2/com/get_page
+     * 
+     * Get page with cells and blocks as array
+     * 
+     * **HTTP Method:** 
+     * `GET`
+     *
+     * **Request params:**
+     * - `uri` - page URI
+     *
+     * **Response (success):**
+     * @code
+     * {  
+     *     "id": "123", // page ID
+     *     "layout": "5", // page layout, 5 is simplest page with one cell
+     *     "module": "system", // module which this page 
+     *     "title": "Test page", // page title
+     *     "type": 1, // page type, 1 is for default page with header and footer
+     *     "uri": "test", // page URI, which is part of page URL
+     *     "elements": {
+     *         "cell_1": [
+     *             {
+     *                 "content": "test content", // block content, it can be array as well
+     *                 "designbox_id": "11", // block design, such as padding, border, title
+     *                 "hidden_on": "", // not empty block need to be hidden on mobile, or desktop
+     *                 "id": "321",
+     *                 "module": "system", // module name this block is related to
+     *                 "order": "1", // block order
+     *                 "title": "Test block", // block title
+     *                 "type": "raw" // block type
+     *             }
+     *      ]
+     * }
+     * @endcode
+     *
+     * **Response (error):**
+     * @code
+     * {  
+     *    "error":"short error description here",
+     *    "error_description":"long error description here"
+     * }
+     * @endcode
+     */
+    public function serviceGetPage()
+    {
+        $sUri = bx_get('uri');
+        $oPage = BxDolPage::getObjectInstanceByURI($sUri);
+        if (!$oPage) {
+            return array(
+                'code' => 404,
+                'error' => 'Not Found',
+                'desc' => 'This page doesn\'t exist',
+            );
+        }
+        if (!$oPage->isVisiblePage()) {
+            return array(
+                'code' => 403,
+                'error' => 'Forbidden',
+                'desc' => 'This page requires special right to be viewed',
+            );
+        }
+
+        return $oPage->getPage ();
+    }
+
+    /**
+     * @page private_api API Private
+     * @section private_api_api_delete_page /m/oauth2/com/delete_page
+     * 
+     * Delete page with all blocks
+     * 
+     * **Scopes:** 
+     * `api`
+     *
+     * **HTTP Method:** 
+     * `POST`
+     *
+     * **Request params:**
+     * - `uri` - page URI
+     *
+     * **Request header:**
+     * @code
+     * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
+     * @endcode
+     *
+     * **Response (success):**
+     * @code
+     * {  
+     *     "code": 200,
+     * }
+     * @endcode
+     *
+     * **Response (error):**
+     * @code
+     * {  
+     *    "error":"short error description here",
+     *    "error_description":"long error description here"
+     * }
+     * @endcode
+     */
+    public function serviceDeletePage()
+    {        
+        $sUri = bx_get('uri');
+        $oPage = BxDolPage::getObjectInstanceByURI($sUri);
+        if (!$oPage) {
+            return array(
+                'code' => 404,
+                'error' => 'No Content',
+                'desc' => 'Such page doesn\'t exist',
+            );
+        }
+
+        if (!$oPage->isDeleteAllowed()) {
+            return array(
+                'code' => 403,
+                'error' => 'Forbidden',
+                'desc' => 'Not enough rights to delete this page',
+            );
+        }
+
+        $oPageBuilder = new BxTemplStudioBuilderPage($oPage->getModule(), $oPage->getName());
+        $mixed = $oPageBuilder->processAction('page_delete');
+        if (is_array($mixed) && (isset($mixed['msg']) || isset($mixed['message']))) {
+            return array(
+                'code' => 500,
+                'error' => 'Internal Error',
+                'desc' => isset($mixed['msg']) ? $mixed['msg'] : $mixed['message'],
+            );
+        }
+
+        return array('code' => 200);
+    }
+    
+    /**
+     * @page private_api API Private
+     * @section private_api_api_change_account_password /m/oauth2/com/change_account_password
+     * 
+     * Change account password
+     * 
+     * **Scopes:** 
+     * `api`
+     *
+     * **HTTP Method:** 
+     * `POST`
+     *
+     * **Request params:**
+     * - `password` - new password
+     *
+     * **Request header:**
+     * @code
+     * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
+     * @endcode
+     *
+     * **Response (success):**
+     * @code
+     * {  
+     *     "code": 200,
+     * }
+     * @endcode
+     *
+     * **Response (error):**
+     * @code
+     * {  
+     *    "error":"short error description here",
+     *    "error_description":"long error description here"
+     * }
+     * @endcode
+     */
+    public function serviceChangeAccountPassword()
+    {        
+        $sPassword = bx_get('password');
+        
+        if ($sPassword == '') {
+            return array(
+                'code' => 404,
+                'error' => 'No Content',
+                'desc' => 'Password can\'t be empty',
+            );
+        }
+        
+        $oAccount = BxDolAccount::getInstance();
+        if (!$oAccount->updatePassword($sPassword)){
+            return array(
+                'code' => 500,
+                'error' => 'Internal Error',
+            );
+        }
+
+        return array('code' => 200);
+    }
+    
+    /**
+     * @page private_api API Private
+     * @section private_api_api_switch_profile /m/oauth2/com/switch_profile
+     * 
+     * Switch account active profile
+     * 
+     * **Scopes:** 
+     * `api`
+     *
+     * **HTTP Method:** 
+     * `POST`
+     *
+     * **Request params:**
+     * - `profile_id` - profile id
+     *
+     * **Request header:**
+     * @code
+     * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
+     * @endcode
+     *
+     * **Response (success):**
+     * @code
+     * {  
+     *     "code": 200,
+     * }
+     * @endcode
+     *
+     * **Response (error):**
+     * @code
+     * {  
+     *    "error":"short error description here",
+     *    "error_description":"long error description here"
+     * }
+     * @endcode
+     */
+    public function serviceSwitchProfile()
+    {
+        $mixedProfileIdToSwitch = bx_get('profile_id');
+        
+        if ($mixedProfileIdToSwitch == '') {
+            return array(
+                'code' => 404,
+                'error' => 'No Content',
+                'desc' => 'Profile_id can\'t be empty',
+            );
+        }
+        
+		if (bx_get_logged_profile_id() == (int)$mixedProfileIdToSwitch){
+            return array(
+                'code' => 404,
+                'error' => 'Not Allowed',
+                'desc' => 'Requested profile_id equal with current profile_id',
+            );
+		}
+        
+        $mixedRes = bx_srv('system', 'switch_profile', [$mixedProfileIdToSwitch], 'TemplServiceAccount');
+        
+        if (true === $mixedRes) {
+            return array('code' => 200);
+        } 
+        else {
+            return array(
+                'code' => 500,
+                'error' => 'Internal Error',
+                'desc' => $mixedRes,
+            );
+        }
+    }
+    
+    /**
+     * @page public_api API Public
+     * @section public_api_api_reset_password_send_request /m/oauth2/com/reset_password_send_request
+     * 
+     * Send email with reset password code
+     * 
+     * **Scopes:** 
+     * `api`
+     *
+     * **HTTP Method:** 
+     * `POST`
+     *
+     * **Request params:**
+     * - `email` - email address
+     *
+     * **Request header:**
+     * @code
+     * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
+     * @endcode
+     *
+     * **Response (success):**
+     * @code
+     * {  
+     *     "code": 200,
+     * }
+     * @endcode
+     *
+     * **Response (error):**
+     * @code
+     * {  
+     *    "error":"short error description here",
+     *    "error_description":"long error description here"
+     * }
+     * @endcode
+     */
+    public function serviceResetPasswordSendRequest(){
+		$sEmail = bx_get('email');
+        if ($sEmail == ''){
+			return array(
+                'code' => 404,
+                'error' => 'No Content',
+                'desc' => 'Email can\'t be empty',
+            );
+		}
+		
+		$oAccountQuery = BxDolAccountQuery::getInstance();
+		$iAccountId = $oAccountQuery->getIdByEmail($sEmail);
+		if (!$iAccountId){
+			return array(
+                'code' => 404,
+                'error' => 'No Content',
+                'desc' => 'Email is not valid',
+            );
+		}
+		
+		$oKey = BxDolKey::getInstance();
+		$aPlus['key'] = $oKey->getNewKey(array('email' => $sEmail));
+		$aPlus['forgot_password_url'] = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=forgot-password', array('key' => $aPlus['key'])));
+        $aTemplate = BxDolEmailTemplates::getInstance() -> parseTemplate('t_Forgot', $aPlus, $iAccountId);
+        if ($aTemplate && sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, $aPlus, BX_EMAIL_SYSTEM)){
+            return array('code' => 200);
+		}
+		
+		return array(
+            'code' => 500,
+            'error' => 'Internal Error'
+        );
+	}
+    
+    /**
+     * @page public_api API Public
+     * @section public_api_api_reset_password_check_code /m/oauth2/com/reset_password_check_code
+     * 
+     * Check validation code & set new password 
+     * 
+     * **Scopes:** 
+     * `api`
+     *
+     * **HTTP Method:** 
+     * `POST`
+     *
+     * **Request params:**
+     * - `code` - validation code
+     * - `email` - email address
+     *
+     * **Request header:**
+     * @code
+     * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
+     * @endcode
+     *
+     * **Response (success):**
+     * @code
+     * {  
+     *     "code": 200,
+     *     "password" : "[NEW PASSWORD]"
+     * }
+     * @endcode
+     *
+     * **Response (error):**
+     * @code
+     * {  
+     *    "error":"short error description here",
+     *    "error_description":"long error description here"
+     * }
+     * @endcode
+     */
+    public function serviceResetPasswordCheckCode() {
+        $sKey = bx_get('code');
+
+        if ($sKey == '') {
+            return array(
+                'code' => 404,
+                'error' => 'No Content',
+                'desc' => 'Validation code can\'t be empty',
+            );
+        }
+
+        $oKey = BxDolKey::getInstance();
+        if (!$oKey || !$oKey->isKeyExists($sKey)) {
+            return array(
+                'code' => 404,
+                'error' => 'Wrong code',
+                'desc' => 'Validation code is not exist or expired',
+            );
+        }
+
+        $aData = $oKey->getKeyData($sKey);
+        if (!isset($aData['email'])){
+            return array(
+                'code' => 404,
+                'error' => 'Wrong code',
+                'desc' => 'Validation code is not exist or expired',
+            );
+        }
+
+        $oAccountQuery = BxDolAccountQuery::getInstance();
+        $iAccountId = $oAccountQuery->getIdByEmail($aData['email']);
+        if (!$iAccountId) {
+            return array(
+                'code' => 404,
+                'error' => 'Wrong code',
+                'desc' => 'Validation code is not exist or expired',
+            );
+        }
+
+        $oBxTemplServiceAccount = new BxTemplServiceAccount();
+        $sPassword = $oBxTemplServiceAccount->generateUserNewPwd($iAccountId);
+
+        $oKey->removeKey($sKey);
+
+        $aPlus = array ('password' => $sPassword);
+        $aTemplate = BxDolEmailTemplates::getInstance() -> parseTemplate('bx_api_password_reset', $aPlus, $iAccountId);
+
+        $oAccountQuery->unlockAccount($iAccountId);
+
+        if ($aTemplate && sendMail($aData['email'], $aTemplate['Subject'], $aTemplate['Body'], 0, $aPlus, BX_EMAIL_SYSTEM)) {
+            return array(
+                'code' => 200,
+                'password' => $sPassword,
+            );
+        }
+    }
+    
+    /**
+     * @page public_api API Public
+     * @section public_api_api_create_account /m/oauth2/com/create_account
+     * 
+     * Create account
+     * 
+     * **Scopes:** 
+     * `api`
+     *
+     * **HTTP Method:** 
+     * `POST`
+     *
+     * **Request params:**
+     * - `name` - account name
+     * - `email` - email address
+     * - `password` - password
+     *
+     * **Request header:**
+     * @code
+     * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
+     * @endcode
+     *
+     * **Response (success):**
+     * @code
+     * {  
+     *     "code": 200,
+     *     "profile_id" : "[PROFILE ID]"
+     * }
+     * @endcode
+     *
+     * **Response (error):**
+     * @code
+     * {  
+     *    "error":"short error description here",
+     *    "error_description":"long error description here"
+     * }
+     * @endcode
+     */
+    public function serviceCreateAccount()
+	{
+		
+		$sAccountName = bx_get('name');
+		$sEmail = bx_get('email');
+		$sPassword = bx_get('password');
+		
+        if (!($sAccountName && $sEmail && $sPassword)){
+			return array(
+                'code' => 404,
+                'error' => 'No Content',
+                'desc' => 'Account name, email, password code can\'t be empty',
+            );
+		}
+		
+		$oAccQuery = BxDolAccountQuery::getInstance();;
+		$iId = $oAccQuery->getIdByEmail($sEmail);
+		if ($iId > 0){
+			return array(
+                'code' => 404,
+                'error' => 'Already exists',
+                'desc' => 'Account with requested email already exists',
+            );
+		}
+
+		$_POST['name'] = $sAccountName;
+		$_POST['email'] = $sEmail;
+		$_POST['password'] = $sPassword;
+		$_POST['email_confirmed'] = false;
+		$_POST['do_submit'] = 'Submit';
+
+		$oForm = BxDolForm::getObjectInstance('bx_accounts_account', 'bx_accounts_account_create');
+		$oForm->aParams['csrf']['disable'] = true;
+		$oForm->initChecker();
+		
+		if($oForm->isSubmittedAndValid()) {
+			$iAccountId = $oForm->insert();			
+			if (!$iAccountId) {
+				return $this->_error(_t('_sg_wtv_error_account_creation_failed'), 150);
+			}
+
+			$oBxTemplAccountForms = new BxTemplAccountForms();
+
+			$iProfileId = $oBxTemplAccountForms->onAccountCreated($iAccountId, $oForm->isSetPendingApproval(), BX_PROFILE_ACTION_MANUAL, false);
+
+			$sProfileModule = getParam('sys_account_default_profile_type');
+			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 ($a['code'] != 0)
+					return $this->_error($a['message']);
+				$iProfileId = $a['content']['profile_id'];
+			}
+            
+			return array(
+				'code' => 200,
+				'profile_id' => $iProfileId
+			);
+		}
+		else{
+			$s = $oForm->getFormErrors();
+			return array(
+                'code' => 500,
+                'error' => 'Internal Error',
+                'desc' => $s,
+            );
+		}
+	}
+}
+
+/** @} */

+ 70 - 0
modules/boonex/api/updates/12.0.2_13.0.0/source/install/config.php

@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    API API to the UNA backend
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_api',
+    'title' => 'API',
+    'note' => 'API for backend.',
+    'version' => '13.0.0',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.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/api/',
+    'home_uri' => 'api',
+
+    'db_prefix' => 'bx_api_',
+    'class_prefix' => 'BxApi',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'API',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(
+        'oauth2' => 'BoonEx OAuth2 Server Module'
+    ),
+);
+
+/** @} */

+ 65 - 0
modules/boonex/api/updates/12.0.2_13.0.0/source/template/images/icons/std-icon.svg

@@ -0,0 +1,65 @@
+<svg width="320" height="320" viewBox="0 0 320 320" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_740_4577)">
+<path d="M160 0C281.326 0 320 38.6737 320 160C320 281.326 281.326 320 160 320C38.6736 320 0 281.326 0 160C0 38.6737 38.6736 0 160 0Z" fill="url(#paint0_linear_740_4577)"/>
+<path d="M160 2C220.573 2 259.85 11.6833 284.083 35.9168C308.317 60.1504 318 99.4272 318 160C318 220.573 308.317 259.85 284.083 284.083C259.85 308.317 220.573 318 160 318C99.4272 318 60.1504 308.317 35.9168 284.083C11.6833 259.85 2 220.573 2 160C2 99.4272 11.6833 60.1504 35.9168 35.9168C60.1504 11.6833 99.4272 2 160 2Z" stroke="#F8FAFC" stroke-opacity="0.2" stroke-width="4"/>
+<g clip-path="url(#clip1_740_4577)">
+<path d="M89.0546 96.1256C88.1799 95.2508 88.3046 93.8024 89.2529 93.008C90.6124 91.8693 91.8694 90.6122 93.0082 89.2528C93.8025 88.3045 95.251 88.1798 96.1257 89.0545L107.251 100.18C108.106 101.034 108.01 102.443 107.096 103.234C105.715 104.429 104.429 105.714 103.234 107.096C102.443 108.009 101.035 108.105 100.18 107.251L89.0546 96.1256Z" fill="url(#paint1_linear_740_4577)"/>
+<path d="M213.59 220.661C212.715 219.786 212.84 218.338 213.788 217.543C215.148 216.405 216.405 215.148 217.543 213.788C218.338 212.84 219.786 212.715 220.661 213.59L231.786 224.715C232.641 225.57 232.545 226.978 231.631 227.769C230.25 228.964 228.964 230.25 227.769 231.631C226.978 232.545 225.57 232.641 224.715 231.786L213.59 220.661Z" fill="url(#paint2_linear_740_4577)"/>
+<path d="M220.661 106.785C219.786 107.66 218.338 107.535 217.543 106.587C216.405 105.228 215.148 103.97 213.788 102.832C212.84 102.037 212.715 100.589 213.59 99.7142L224.715 88.5888C225.57 87.7343 226.978 87.8303 227.769 88.7442C228.964 90.1253 230.25 91.4112 231.631 92.6061C232.545 93.3968 232.641 94.8053 231.786 95.6599L220.661 106.785Z" fill="url(#paint3_linear_740_4577)"/>
+<path d="M99.7142 213.59C100.589 212.715 102.037 212.84 102.832 213.788C103.97 215.148 105.228 216.405 106.587 217.543C107.535 218.338 107.66 219.786 106.785 220.661L95.6599 231.786C94.8053 232.641 93.3968 232.545 92.6061 231.631C91.4112 230.25 90.1253 228.964 88.7442 227.769C87.8303 226.978 87.7343 225.57 88.5888 224.715L99.7142 213.59Z" fill="url(#paint4_linear_740_4577)"/>
+<path d="M160 100C205.497 100 220 114.503 220 160C220 205.497 205.497 220 160 220C114.503 220 100 205.497 100 160C100 114.503 114.503 100 160 100Z" fill="url(#paint5_linear_740_4577)"/>
+<circle cx="70" cy="70" r="20" fill="url(#paint6_linear_740_4577)"/>
+<circle cx="70" cy="250" r="20" fill="url(#paint7_linear_740_4577)"/>
+<circle cx="250" cy="70" r="20" fill="url(#paint8_linear_740_4577)"/>
+<circle cx="250" cy="250" r="20" fill="url(#paint9_linear_740_4577)"/>
+</g>
+</g>
+<defs>
+<linearGradient id="paint0_linear_740_4577" x1="160" y1="0" x2="160" y2="320" gradientUnits="userSpaceOnUse">
+<stop stop-color="#475569"/>
+<stop offset="1" stop-color="#1E293B"/>
+</linearGradient>
+<linearGradient id="paint1_linear_740_4577" x1="160.188" y1="88" x2="160.188" y2="232.375" gradientUnits="userSpaceOnUse">
+<stop stop-color="#94A3B8"/>
+<stop offset="1" stop-color="#64748B"/>
+</linearGradient>
+<linearGradient id="paint2_linear_740_4577" x1="160.188" y1="88" x2="160.188" y2="232.375" gradientUnits="userSpaceOnUse">
+<stop stop-color="#94A3B8"/>
+<stop offset="1" stop-color="#64748B"/>
+</linearGradient>
+<linearGradient id="paint3_linear_740_4577" x1="160.188" y1="88" x2="160.188" y2="232.375" gradientUnits="userSpaceOnUse">
+<stop stop-color="#94A3B8"/>
+<stop offset="1" stop-color="#64748B"/>
+</linearGradient>
+<linearGradient id="paint4_linear_740_4577" x1="160.188" y1="88" x2="160.188" y2="232.375" gradientUnits="userSpaceOnUse">
+<stop stop-color="#94A3B8"/>
+<stop offset="1" stop-color="#64748B"/>
+</linearGradient>
+<linearGradient id="paint5_linear_740_4577" x1="160" y1="100" x2="160" y2="220" gradientUnits="userSpaceOnUse">
+<stop stop-color="#2DD4BF"/>
+<stop offset="1" stop-color="#0D9488"/>
+</linearGradient>
+<linearGradient id="paint6_linear_740_4577" x1="70" y1="50" x2="70" y2="90" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FB7185"/>
+<stop offset="1" stop-color="#E11D48"/>
+</linearGradient>
+<linearGradient id="paint7_linear_740_4577" x1="70" y1="230" x2="70" y2="270" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FB923C"/>
+<stop offset="1" stop-color="#EA580C"/>
+</linearGradient>
+<linearGradient id="paint8_linear_740_4577" x1="250" y1="50" x2="250" y2="90" gradientUnits="userSpaceOnUse">
+<stop stop-color="#34D399"/>
+<stop offset="1" stop-color="#059669"/>
+</linearGradient>
+<linearGradient id="paint9_linear_740_4577" x1="250" y1="230" x2="250" y2="270" gradientUnits="userSpaceOnUse">
+<stop stop-color="#60A5FA"/>
+<stop offset="1" stop-color="#2563EB"/>
+</linearGradient>
+<clipPath id="clip0_740_4577">
+<rect width="320" height="320" fill="white"/>
+</clipPath>
+<clipPath id="clip1_740_4577">
+<rect width="240" height="240" fill="white" transform="translate(40 40)"/>
+</clipPath>
+</defs>
+</svg>

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

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Attendant',
+    'version_from' => '13.0.3',
+    'version_to' => '13.0.4',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.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/attendant/updates/update_13.0.3_13.0.4/',
+    'home_uri' => 'attendant_update_1303_1304',
+
+    'module_dir' => 'boonex/attendant/',
+    'module_uri' => 'attendant',
+
+    'db_prefix' => 'bx_attendant_',
+    'class_prefix' => 'BxAttendant',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Attendant',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

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

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

+ 256 - 0
modules/boonex/attendant/updates/13.0.3_13.0.4/source/classes/BxAttendantModule.php

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

+ 77 - 0
modules/boonex/attendant/updates/13.0.3_13.0.4/source/install/config.php

@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Attendant Attendant
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_attendant',
+    'title' => 'Attendant',
+    'note' => 'Attendant module.',
+    'version' => '13.0.4',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '13.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/attendant/',
+    'home_uri' => 'attendant',
+
+    'db_prefix' => 'bx_attendant_',
+    'class_prefix' => 'BxAttendant',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Attendant',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 30 - 0
modules/boonex/attendant/updates/13.0.3_13.0.4/source/template/images/icons/std-icon.svg

@@ -0,0 +1,30 @@
+<svg width="320" height="320" viewBox="0 0 320 320" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_895_8037)">
+<path d="M160 0C281.326 0 320 38.6737 320 160C320 281.326 281.326 320 160 320C38.6736 320 0 281.326 0 160C0 38.6737 38.6736 0 160 0Z" fill="url(#paint0_linear_895_8037)"/>
+<path d="M160 2C220.573 2 259.85 11.6833 284.083 35.9168C308.317 60.1504 318 99.4272 318 160C318 220.573 308.317 259.85 284.083 284.083C259.85 308.317 220.573 318 160 318C99.4272 318 60.1504 308.317 35.9168 284.083C11.6833 259.85 2 220.573 2 160C2 99.4272 11.6833 60.1504 35.9168 35.9168C60.1504 11.6833 99.4272 2 160 2Z" stroke="#0F172A" stroke-opacity="0.2" stroke-width="4"/>
+<g clip-path="url(#clip1_895_8037)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M175 70C175 58.6257 171.374 55 160 55C148.626 55 145 58.6257 145 70C145 81.3743 148.626 85 160 85C171.374 85 175 81.3743 175 70ZM160 245C235.829 245 260 238.957 260 220C260 201.043 235.829 195 160 195C84.1711 195 60 201.043 60 220C60 238.957 84.1711 245 160 245Z" fill="url(#paint1_linear_895_8037)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M136.865 83.8923C135.827 81.0596 132.945 79.0843 130.099 80.0863C95.0915 92.4135 70 125.777 70 165C70 172.812 70.9953 180.391 72.8659 187.618C73.554 190.277 76.352 191.719 79.0158 191.052C96.292 186.723 122.361 185 160 185C197.639 185 223.708 186.723 240.984 191.052C243.648 191.719 246.446 190.277 247.134 187.618C249.005 180.391 250 172.812 250 165C250 125.777 224.909 92.4135 189.901 80.0863C187.055 79.0843 184.173 81.0596 183.135 83.8923C180.138 92.0706 173.199 95.0001 160 95.0001C146.801 95.0001 139.862 92.0706 136.865 83.8923Z" fill="url(#paint2_linear_895_8037)"/>
+</g>
+</g>
+<defs>
+<linearGradient id="paint0_linear_895_8037" x1="160" y1="0" x2="160" y2="320" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F8FAFC"/>
+<stop offset="1" stop-color="#E2E8F0"/>
+</linearGradient>
+<linearGradient id="paint1_linear_895_8037" x1="160" y1="55" x2="160" y2="245" gradientUnits="userSpaceOnUse">
+<stop stop-color="#2DD4BF"/>
+<stop offset="1" stop-color="#0D9488"/>
+</linearGradient>
+<linearGradient id="paint2_linear_895_8037" x1="160" y1="79.8223" x2="160" y2="191.214" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FB923C"/>
+<stop offset="1" stop-color="#EA580C"/>
+</linearGradient>
+<clipPath id="clip0_895_8037">
+<rect width="320" height="320" fill="white"/>
+</clipPath>
+<clipPath id="clip1_895_8037">
+<rect width="240" height="240" fill="white" transform="translate(40 40)"/>
+</clipPath>
+</defs>
+</svg>

+ 67 - 0
modules/boonex/channels/updates/13.0.3_13.0.4/install/config.php

@@ -0,0 +1,67 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Channels',
+    'version_from' => '13.0.3',
+    'version_to' => '13.0.4',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '13.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_13.0.3_13.0.4/',
+    'home_uri' => 'channels_update_1303_1304',
+
+    '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' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Channels',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(
+        'template/css/manage_tools.css',
+        'template/css/',
+        'template/account_link.html',
+        'template/breadcrumb.html',
+        'template/entry-all-actions.html',
+        'template/entry-share.html',
+        'template/entry-text.html',
+        'template/form_ghost_template.html',
+        'template/image_popup.html',
+        'template/menu_main_submenu.html',
+        'template/name_link.html',
+        'template/picture_preview.html',
+        'template/search_extended_results.html',
+        'template/set_acl_popup.html',
+        'template/uploader_form_crop_cover.html',
+    ),
+);

+ 23 - 0
modules/boonex/channels/updates/13.0.3_13.0.4/install/installer.php

@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxCnlUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+
+    public function actionExecuteSql($sOperation)
+    {
+        if($sOperation == 'install') {
+            if(!$this->oDb->isFieldExists('bx_cnl_data', 'cover_data'))
+                $this->oDb->query("ALTER TABLE `bx_cnl_data` ADD `cover_data` varchar(50) NOT NULL AFTER `cover`");
+        }
+
+        return parent::actionExecuteSql($sOperation);
+    }
+}

+ 11 - 0
modules/boonex/channels/updates/13.0.3_13.0.4/install/sql/enable.sql

@@ -0,0 +1,11 @@
+SET @sName = 'bx_channels';
+
+
+-- PAGES
+DELETE FROM `sys_objects_page` WHERE `object`='bx_channels_edit_profile_cover';
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_channels_edit_profile_cover';
+
+
+-- MENUS
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_channels_view_actions_more' AND `name`='edit-channel-cover';
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_channels_view_actions_all' AND `name`='edit-channel-cover';

+ 1 - 0
modules/boonex/channels/updates/13.0.3_13.0.4/install/sql/install.sql

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

+ 189 - 0
modules/boonex/channels/updates/13.0.3_13.0.4/source/classes/BxCnlConfig.php

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

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff