AntonLV 10 лет назад
Родитель
Сommit
751e0f80b9
100 измененных файлов с 10556 добавлено и 1 удалено
  1. 53 0
      modules/boonex/albums/updates/9.0.0_9.0.1/install/config.php
  2. 29 0
      modules/boonex/albums/updates/9.0.0_9.0.1/install/installer.php
  3. 10 0
      modules/boonex/albums/updates/9.0.0_9.0.1/install/langs/en.xml
  4. 17 0
      modules/boonex/albums/updates/9.0.0_9.0.1/install/sql/enable.sql
  5. 2 0
      modules/boonex/albums/updates/9.0.0_9.0.1/install/sql/install.sql
  6. 153 0
      modules/boonex/albums/updates/9.0.0_9.0.1/source/classes/BxAlbumsConfig.php
  7. 145 0
      modules/boonex/albums/updates/9.0.0_9.0.1/source/classes/BxAlbumsSearchResult.php
  8. 130 0
      modules/boonex/albums/updates/9.0.0_9.0.1/source/install/config.php
  9. 188 0
      modules/boonex/albums/updates/9.0.0_9.0.1/source/install/langs/en.xml
  10. 393 0
      modules/boonex/albums/updates/9.0.0_9.0.1/source/install/sql/enable.sql
  11. 356 0
      modules/boonex/albums/updates/9.0.0_9.0.1/source/install/sql/install.sql
  12. 51 0
      modules/boonex/convos/updates/9.0.0_9.0.1/install/config.php
  13. 13 0
      modules/boonex/convos/updates/9.0.0_9.0.1/install/installer.php
  14. 6 0
      modules/boonex/convos/updates/9.0.0_9.0.1/install/langs/en.xml
  15. 4 0
      modules/boonex/convos/updates/9.0.0_9.0.1/install/sql/enable.sql
  16. 97 0
      modules/boonex/convos/updates/9.0.0_9.0.1/source/classes/BxCnvConfig.php
  17. 131 0
      modules/boonex/convos/updates/9.0.0_9.0.1/source/classes/BxCnvFormEntry.php
  18. 273 0
      modules/boonex/convos/updates/9.0.0_9.0.1/source/classes/BxCnvTemplate.php
  19. 104 0
      modules/boonex/convos/updates/9.0.0_9.0.1/source/install/config.php
  20. 129 0
      modules/boonex/convos/updates/9.0.0_9.0.1/source/install/langs/en.xml
  21. 200 0
      modules/boonex/convos/updates/9.0.0_9.0.1/source/install/sql/enable.sql
  22. 1 0
      modules/boonex/convos/updates/9.0.0_9.0.1/source/template/breadcrumb.html
  23. 12 0
      modules/boonex/convos/updates/9.0.0_9.0.1/source/template/css/main-media-desktop.css
  24. 12 0
      modules/boonex/convos/updates/9.0.0_9.0.1/source/template/css/main-media-tablet.css
  25. 69 0
      modules/boonex/convos/updates/9.0.0_9.0.1/source/template/css/main.css
  26. 51 0
      modules/boonex/groups/updates/9.0.0_9.0.1/install/config.php
  27. 13 0
      modules/boonex/groups/updates/9.0.0_9.0.1/install/installer.php
  28. 4 0
      modules/boonex/groups/updates/9.0.0_9.0.1/install/langs/en.xml
  29. 10 0
      modules/boonex/groups/updates/9.0.0_9.0.1/install/sql/enable.sql
  30. 21 0
      modules/boonex/groups/updates/9.0.0_9.0.1/source/classes/BxGroupsPrivacyNotifications.php
  31. 186 0
      modules/boonex/groups/updates/9.0.0_9.0.1/source/classes/BxGroupsSearchResult.php
  32. 139 0
      modules/boonex/groups/updates/9.0.0_9.0.1/source/install/config.php
  33. 277 0
      modules/boonex/groups/updates/9.0.0_9.0.1/source/install/langs/en.xml
  34. 417 0
      modules/boonex/groups/updates/9.0.0_9.0.1/source/install/sql/enable.sql
  35. 51 0
      modules/boonex/invites/updates/9.0.0_9.0.1/install/config.php
  36. 39 0
      modules/boonex/invites/updates/9.0.0_9.0.1/install/installer.php
  37. 5 0
      modules/boonex/invites/updates/9.0.0_9.0.1/install/sql/install.sql
  38. 70 0
      modules/boonex/invites/updates/9.0.0_9.0.1/source/install/config.php
  39. 93 0
      modules/boonex/invites/updates/9.0.0_9.0.1/source/install/sql/install.sql
  40. 32 0
      modules/boonex/invites/updates/9.0.0_9.0.1/source/template/css/main.css
  41. 52 0
      modules/boonex/notifications/updates/9.0.0_9.0.1/install/config.php
  42. 50 0
      modules/boonex/notifications/updates/9.0.0_9.0.1/install/installer.php
  43. 82 0
      modules/boonex/notifications/updates/9.0.0_9.0.1/source/install/config.php
  44. 30 0
      modules/boonex/notifications/updates/9.0.0_9.0.1/source/install/sql/disable.sql
  45. 56 0
      modules/boonex/notifications/updates/9.0.0_9.0.1/source/install/sql/enable.sql
  46. 51 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/install/config.php
  47. 23 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/install/installer.php
  48. 5 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/install/langs/en.xml
  49. 8 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/install/sql/enable.sql
  50. 6 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/install/sql/install.sql
  51. 177 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/source/classes/BxOAuthAPI.php
  52. 102 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/source/classes/BxOAuthDb.php
  53. 100 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/source/classes/BxOAuthFormAdd.php
  54. 83 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/source/classes/BxOAuthGrid.php
  55. 171 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/source/classes/BxOAuthModule.php
  56. 47 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/source/classes/BxOAuthStudioPage.php
  57. 68 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/source/install/config.php
  58. 23 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/source/install/langs/en.xml
  59. 16 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/source/install/sql/disable.sql
  60. 39 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/source/install/sql/enable.sql
  61. 68 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/source/install/sql/install.sql
  62. 17 0
      modules/boonex/oauth2/updates/9.0.0_9.0.1/source/template/page_auth.html
  63. 51 0
      modules/boonex/payment/updates/9.0.0_9.0.1/install/config.php
  64. 27 0
      modules/boonex/payment/updates/9.0.0_9.0.1/install/installer.php
  65. 37 0
      modules/boonex/payment/updates/9.0.0_9.0.1/install/langs/en.xml
  66. 36 0
      modules/boonex/payment/updates/9.0.0_9.0.1/install/sql/install.sql
  67. 258 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentCart.php
  68. 198 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentConfig.php
  69. 368 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentDb.php
  70. 192 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentDetails.php
  71. 129 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentGridCart.php
  72. 549 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentModule.php
  73. 280 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentProviderChargebee.php
  74. 256 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentProviderPayPal.php
  75. 324 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentProviderRecurly.php
  76. 517 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentProviderStripe.php
  77. 318 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentTemplate.php
  78. 70 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/install/config.php
  79. 20 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/install/installer.php
  80. 364 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/install/langs/en.xml
  81. 331 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/install/sql/install.sql
  82. 91 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/js/cart.js
  83. 47 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/js/main.js
  84. 93 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/js/stripe.js
  85. 5 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/template/css/stripe.css
  86. 8 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/template/providers_select.html
  87. 1 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/template/providers_select_button.html
  88. 2 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/template/strp_button_recurring.html
  89. 4 0
      modules/boonex/payment/updates/9.0.0_9.0.1/source/template/strp_button_single.html
  90. 1 1
      modules/boonex/persons/updates/9.0.0_9.0.1/source/install/config.php
  91. 53 0
      modules/boonex/posts/updates/9.0.0_9.0.1/install/config.php
  92. 29 0
      modules/boonex/posts/updates/9.0.0_9.0.1/install/installer.php
  93. 4 0
      modules/boonex/posts/updates/9.0.0_9.0.1/install/langs/en.xml
  94. 14 0
      modules/boonex/posts/updates/9.0.0_9.0.1/install/sql/enable.sql
  95. 2 0
      modules/boonex/posts/updates/9.0.0_9.0.1/install/sql/install.sql
  96. 135 0
      modules/boonex/posts/updates/9.0.0_9.0.1/source/classes/BxPostsConfig.php
  97. 32 0
      modules/boonex/posts/updates/9.0.0_9.0.1/source/classes/BxPostsPageEntry.php
  98. 127 0
      modules/boonex/posts/updates/9.0.0_9.0.1/source/classes/BxPostsSearchResult.php
  99. 124 0
      modules/boonex/posts/updates/9.0.0_9.0.1/source/install/config.php
  100. 199 0
      modules/boonex/posts/updates/9.0.0_9.0.1/source/install/langs/en.xml

+ 53 - 0
modules/boonex/albums/updates/9.0.0_9.0.1/install/config.php

@@ -0,0 +1,53 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Albums',
+    'version_from' => '9.0.0',
+	'version_to' => '9.0.1',
+    'vendor' => 'BoonEx',
+
+	'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * '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_9.0.0_9.0.1/',
+	'home_uri' => 'albums_update_900_901',
+
+	'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' => 1,
+		'clear_db_cache' => 1,
+    ),
+
+	/**
+     * Category for language keys.
+     */
+    'language_category' => 'Albums',
+
+	/**
+     * Files Section
+     */
+    'delete_files' => array(
+		'template/form_field_location.html'
+	),
+);

+ 29 - 0
modules/boonex/albums/updates/9.0.0_9.0.1/install/installer.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+class BxAlbumsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+	{
+        parent::__construct($aConfig);
+    }
+
+	public function actionExecuteSql($sOperation)
+    {
+    	if($sOperation == 'install') {
+    		if(!$this->oDb->isFieldExists('bx_albums_albums', 'status_admin'))
+        		$this->oDb->query("ALTER TABLE `bx_albums_albums` ADD `status_admin` enum('active','hidden') NOT NULL DEFAULT 'active' AFTER `status`");
+
+			if(!$this->oDb->isFieldExists('bx_albums_meta_locations', 'street'))
+	        		$this->oDb->query("ALTER TABLE `bx_albums_meta_locations` ADD `street` varchar(255) NOT NULL AFTER `zip`");
+	
+			if(!$this->oDb->isFieldExists('bx_albums_meta_locations', 'street_number'))
+	        		$this->oDb->query("ALTER TABLE `bx_albums_meta_locations` ADD `street_number` varchar(255) NOT NULL AFTER `street`");
+		}
+
+    	return parent::actionExecuteSql($sOperation);
+    }
+}

+ 10 - 0
modules/boonex/albums/updates/9.0.0_9.0.1/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_albums_option_searchable_fields"><![CDATA[Searchable fields]]></string_add>
+
+	<string_upd name="_bx_albums_page_title_sys_add_images"><![CDATA[Add/Edit Pictures]]></string_upd>
+	<string_upd name="_bx_albums_page_title_add_images"><![CDATA[Add/Edit Pictures]]></string_upd>
+	<string_upd name="_bx_albums_page_block_title_add_images"><![CDATA[Add/Edit Pictures]]></string_upd>
+	<string_upd name="_bx_albums_menu_item_title_system_add_images"><![CDATA[Add/Edit Pictures]]></string_upd>
+	<string_upd name="_bx_albums_menu_item_title_add_images"><![CDATA[Add/Edit Pictures]]></string_upd>
+</resources>

+ 17 - 0
modules/boonex/albums/updates/9.0.0_9.0.1/install/sql/enable.sql

@@ -0,0 +1,17 @@
+-- SETTINGS
+SET @iCategoryId = (SELECT `id` FROM `sys_options_categories` WHERE `name`='bx_albums' LIMIT 1);
+DELETE FROM `sys_options` WHERE `name` IN ('bx_albums_searchable_fields');
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+('bx_albums_searchable_fields', 'title,text', @iCategoryId, '_bx_albums_option_searchable_fields', 'list', '', '', 'a:2:{s:6:"module";s:9:"bx_albums";s:6:"method";s:21:"get_searchable_fields";}', 30);
+
+
+-- GRIDS
+UPDATE `sys_objects_grid` SET `visible_for_levels`='192', `field_active`='status_admin' WHERE `object`='bx_albums_administration';
+UPDATE `sys_objects_grid` SET `visible_for_levels`='2147483647' WHERE `object`='bx_albums_common';
+
+
+-- ALERTS
+SET @iHandler = (SELECT `id` FROM `sys_alerts_handlers` WHERE `name`='bx_albums' LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `unit`='system' AND `action`='save_setting' AND `handler_id`=@iHandler;
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler);

+ 2 - 0
modules/boonex/albums/updates/9.0.0_9.0.1/install/sql/install.sql

@@ -0,0 +1,2 @@
+-- FORMS
+UPDATE `sys_form_inputs` SET `type`='location', `caption`='_sys_form_input_location' WHERE `object`='bx_albums' AND `name`='location';

+ 153 - 0
modules/boonex/albums/updates/9.0.0_9.0.1/source/classes/BxAlbumsConfig.php

@@ -0,0 +1,153 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Albums Albums
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxAlbumsConfig extends BxBaseModTextConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $aMenuItems2Methods = array (
+            'edit-album' => 'checkAllowedEdit',
+            'delete-album' => 'checkAllowedDelete',
+        );
+
+        $this->CNF = array (
+
+            // module icon
+            'ICON' => 'picture-o col-blue1',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'albums',
+        	'TABLE_ENTRIES_FULLTEXT' => 'title_text',
+            'TABLE_FILES2ENTRIES' => $aModule['db_prefix'] . 'files2albums',
+            'TABLE_FILES' => $aModule['db_prefix'] . 'files',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => 'author',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => 'changed',
+            'FIELD_TITLE' => 'title',
+            'FIELD_TEXT' => 'text',
+            'FIELD_TEXT_ID' => 'album-desc',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_PHOTO' => 'pictures',
+            'FIELD_THUMB' => 'thumb',
+            'FIELD_COMMENTS' => 'comments',
+        	'FIELD_STATUS' => 'status',
+        	'FIELD_STATUS_ADMIN' => 'status_admin',
+            'FIELD_LOCATION_PREFIX' => 'location',
+            'FIELDS_WITH_KEYWORDS' => 'auto', // can be 'auto', array of fields or comma separated string of field names, works only when OBJECT_METATAGS is specified
+
+            // page URIs
+            'URI_VIEW_ENTRY' => 'view-album',
+            'URI_VIEW_MEDIA' => 'view-album-media',
+            'URI_AUTHOR_ENTRIES' => 'albums-author',
+            'URI_ADD_ENTRY' => 'create-album',
+        	'URI_EDIT_ENTRY' => 'edit-album',
+        	'URI_MANAGE_COMMON' => 'albums-manage',
+
+            'URL_HOME' => 'page.php?i=albums-home',
+            'URL_POPULAR' => 'page.php?i=albums-popular',
+            'URL_UPDATED' => 'page.php?i=albums-updated',
+            'URL_POPULAR_MEDIA' => 'page.php?i=albums-popular-media',
+            'URL_RECENT_MEDIA' => 'page.php?i=albums-recent-media', // TODO: add page
+        	'URL_MANAGE_COMMON' => 'page.php?i=albums-manage',
+        	'URL_MANAGE_ADMINISTRATION' => 'page.php?i=albums-administration',
+
+            // some params
+            'PARAM_CHARS_SUMMARY' => 'bx_albums_summary_chars',
+            'PARAM_CHARS_SUMMARY_PLAIN' => 'bx_albums_plain_summary_chars',
+            'PARAM_NUM_RSS' => 'bx_albums_rss_num',
+        	'PARAM_SEARCHABLE_FIELDS' => 'bx_albums_searchable_fields',
+
+            // objects
+            'OBJECT_STORAGE' => 'bx_albums_files',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW' => 'bx_albums_proxy_preview',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => '',
+            'OBJECT_IMAGES_TRANSCODER_BIG' => 'bx_albums_big',
+            'OBJECT_VIDEOS_TRANSCODERS' => array('poster' => 'bx_albums_video_poster_big', 'poster_preview' => 'bx_albums_video_poster_preview', 'mp4' => 'bx_albums_video_mp4', 'webm' => 'bx_albums_video_webm'),
+            'OBJECT_VIDEO_TRANSCODER_HEIGHT' => '480px',
+            'OBJECT_TRANSCODER_BROWSE' => 'bx_albums_proxy_browse',
+            'OBJECT_TRANSCODER_COVER' => 'bx_albums_proxy_cover',
+        	'OBJECT_REPORTS' => 'bx_albums',
+            'OBJECT_VIEWS' => 'bx_albums',
+            'OBJECT_VIEWS_MEDIA' => 'bx_albums_media',
+            'OBJECT_VOTES' => 'bx_albums',
+            'OBJECT_VOTES_MEDIA' => 'bx_albums_media',
+            'OBJECT_METATAGS' => 'bx_albums',
+            'OBJECT_METATAGS_MEDIA' => 'bx_albums_media',
+            'OBJECT_METATAGS_MEDIA_CAMERA' => 'bx_albums_media_camera',
+            'OBJECT_COMMENTS' => 'bx_albums',
+            'OBJECT_COMMENTS_MEDIA' => 'bx_albums_media',
+            'OBJECT_PRIVACY_VIEW' => 'bx_albums_allow_view_to',
+            'OBJECT_FORM_ENTRY' => 'bx_albums',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => 'bx_albums_entry_view',
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_albums_entry_add',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => 'bx_albums_entry_edit',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_albums_entry_delete',
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_albums_view', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_VIEW_MEDIA' => 'bx_albums_view_media', // actions menu on view media page
+            'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_albums_my', // actions menu on my entries page
+            'OBJECT_MENU_SUBMENU' => 'bx_albums_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => 'bx_albums_view_submenu', // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'albums-home', // first item in view entry submenu from main module submenu
+            'OBJECT_MENU_MANAGE_TOOLS' => 'bx_albums_menu_manage_tools', //manage menu in content administration tools
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_albums_administration',
+        	'OBJECT_GRID_COMMON' => 'bx_albums_common',
+        	'OBJECT_UPLOADERS' => array('bx_albums_simple', 'bx_albums_html5', 'bx_albums_crop'),
+
+            // menu items which visibility depends on custom visibility checking
+            'MENU_ITEM_TO_METHOD' => array (
+                'bx_albums_my' => array (
+                    'create-album' => 'checkAllowedAdd',
+                ),
+                'bx_albums_view' => $aMenuItems2Methods,
+            ),
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_albums_txt_sample_single',
+            	'txt_sample_comment_single' => '_bx_albums_txt_sample_comment_single',
+            	'txt_sample_vote_single' => '_bx_albums_txt_sample_vote_single',
+                'txt_media_single' => '_bx_albums_txt_media_single',
+                'txt_media_comment_single' => '_bx_albums_txt_media_comment_single',
+            	'grid_action_err_delete' => '_bx_albums_grid_action_err_delete',
+            	'grid_txt_account_manager' => '_bx_albums_grid_txt_account_manager',
+				'filter_item_active' => '_bx_albums_grid_filter_item_title_adm_active',
+            	'filter_item_hidden' => '_bx_albums_grid_filter_item_title_adm_hidden',
+            	'filter_item_select_one_filter1' => '_bx_albums_grid_filter_item_title_adm_select_one_filter1',
+            	'menu_item_manage_my' => '_bx_albums_menu_item_title_manage_my',
+            	'menu_item_manage_all' => '_bx_albums_menu_item_title_manage_all',
+                'txt_all_entries_by' => '_bx_albums_txt_all_entries_by',
+            ),
+        );
+
+        $this->_aJsClasses = array(
+        	'main' => 'BxAlbumsMain',
+        	'manage_tools' => 'BxAlbumsManageTools'
+        );
+
+        $this->_aJsObjects = array(
+        	'main' => 'oBxAlbumsMain',
+        	'manage_tools' => 'oBxAlbumsManageTools'
+        );
+
+        $this->_aGridObjects = array(
+        	'common' => $this->CNF['OBJECT_GRID_COMMON'],
+        	'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION'],
+        	
+        );
+    }
+}
+
+/** @} */

+ 145 - 0
modules/boonex/albums/updates/9.0.0_9.0.1/source/classes/BxAlbumsSearchResult.php

@@ -0,0 +1,145 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Albums Albums
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxAlbumsSearchResult extends BxBaseModTextSearchResult
+{
+    function __construct($sMode = '', $aParams = array())
+    {
+        $this->aUnitViews = array('extended' => 'unit.html', 'gallery' => 'unit_gallery.html',);
+    
+        if (empty($aParams['unit_view']))
+            $aParams['unit_view'] = 'extended';
+
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent = array(
+            'name' => 'bx_albums',
+            'module_name' => 'bx_albums',
+            'object_metatags' => 'bx_albums',
+            'title' => _t('_bx_albums_page_title_browse'),
+            'table' => 'bx_albums_albums',
+            'ownFields' => array('id', 'title', 'text', 'thumb', 'author', 'added'),
+            'searchFields' => array(),
+            'restriction' => array(
+                'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
+        		'status' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
+            ),
+            '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' => 'text',
+                ),
+            ),
+            'ident' => 'id',
+        );
+
+        $this->sFilterName = 'bx_albums_filter';
+        $this->oModule = $this->getMain();
+        $this->aCurrent['searchFields'] = explode(',', getParam($this->oModule->_oConfig->CNF['PARAM_SEARCHABLE_FIELDS']));
+
+        $oProfileAuthor = null;
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        switch ($sMode) {
+
+            case 'author':
+                $oProfileAuthor = BxDolProfile::getInstance((int)$aParams['author']);
+                if (!$oProfileAuthor) {
+                    $this->isError = true;
+                    break;
+                }
+
+                $this->aCurrent['restriction']['author']['value'] = $oProfileAuthor->id();
+
+                $this->sBrowseUrl = 'page.php?i=' . $CNF['URI_AUTHOR_ENTRIES'] . '&profile_id={profile_id}';
+                $this->aCurrent['title'] = _t('_bx_albums_page_title_browse_by_author');
+                $this->aCurrent['rss']['link'] = 'modules/?r=albums/rss/' . $sMode . '/' . $oProfileAuthor->id();
+                break;
+
+            case 'public':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_albums_page_title_browse_recent');
+                $this->aCurrent['rss']['link'] = 'modules/?r=albums/rss/' . $sMode;
+                break;
+
+            case 'popular':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_POPULAR']);
+                $this->aCurrent['title'] = _t('_bx_albums_page_title_browse_popular');
+                $this->aCurrent['rss']['link'] = 'modules/?r=albums/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'popular';
+                break;
+
+            case 'updated':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_UPDATED']);
+                $this->aCurrent['title'] = _t('_bx_albums_page_title_browse_updated');
+                $this->aCurrent['rss']['link'] = 'modules/?r=albums/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'updated';
+                break;
+
+            case '': // search results
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_albums');
+                $this->aCurrent['paginate']['perPage'] = 3;
+                unset($this->aCurrent['rss']);
+                break;
+
+            default:
+                $sMode = '';
+                $this->isError = true;
+        }
+
+        $this->processReplaceableMarkers($oProfileAuthor);
+
+        $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+    }
+
+    function displayResultBlock ()
+    {
+        $s = parent::displayResultBlock ();
+        $s = '<div class="bx-albums-wrapper">' . $s . '</div>';
+        return $this->oModule->_oTemplate->getJsCode('main') . $s;
+    }
+
+    function getAlterOrder()
+    {
+        $aSql = array();
+        switch ($this->aCurrent['sorting']) {
+            case 'last':
+                $aSql['order'] = ' ORDER BY `bx_albums_albums`.`added` DESC';
+                break;
+            case 'updated':
+                $aSql['order'] = ' ORDER BY `bx_albums_albums`.`changed` DESC';
+                break;
+            case 'popular':
+                $aSql['order'] = ' ORDER BY `bx_albums_albums`.`views` DESC';
+                break;
+        }
+
+        return $aSql;
+    }
+
+    function getDesignBoxMenu ()
+    {
+        return BxBaseModGeneralSearchResult::getDesignBoxMenu ();
+    }
+}
+
+/** @} */

+ 130 - 0
modules/boonex/albums/updates/9.0.0_9.0.1/source/install/config.php

@@ -0,0 +1,130 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Albums Albums
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_albums',
+    'title' => 'Albums',
+    'note' => 'Photos & videos',
+    'version' => '9.0.1',
+    'vendor' => 'BoonEx',
+	'help_url' => 'http://feed.boonex.com/?section={module_name}',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * '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'
+    ),
+
+    /**
+     * Storages.
+     */
+    '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_webm',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_storages' => 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,
+    	'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'
+    ),
+
+);
+
+/** @} */

+ 188 - 0
modules/boonex/albums/updates/9.0.0_9.0.1/source/install/langs/en.xml

@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+	<string name="_bx_albums"><![CDATA[Albums]]></string>
+	<string name="_bx_albums_cmts"><![CDATA[Albums' Comments]]></string>
+	<string name="_bx_albums_media"><![CDATA[Images]]></string>
+	<string name="_bx_albums_media_cmts"><![CDATA[Images' Comments]]></string>
+
+	<string name="_bx_albums_option_summary_chars"><![CDATA[Number of characters in auto-cropped album summary]]></string>
+	<string name="_bx_albums_option_plain_summary_chars"><![CDATA[Number of characters in plain album description when album hasn't thumb]]></string>
+	<string name="_bx_albums_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+	<string name="_bx_albums_option_rss_num"><![CDATA[Number of items in RSS feed]]></string>
+	<string name="_bx_albums_option_searchable_fields"><![CDATA[Searchable fields]]></string>
+
+	<string name="_bx_albums_form_entry"><![CDATA[Albums]]></string>
+	<string name="_bx_albums_form_entry_display_add"><![CDATA[Add Album]]></string>
+    <string name="_bx_albums_form_entry_display_edit"><![CDATA[Edit Album]]></string>
+	<string name="_bx_albums_form_entry_display_add_images"><![CDATA[Add Images To Album]]></string>
+	<string name="_bx_albums_form_entry_display_delete"><![CDATA[Delete Album]]></string>
+	<string name="_bx_albums_form_entry_display_view"><![CDATA[View Album]]></string>
+	<string name="_bx_albums_form_entry_input_sys_do_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_albums_form_entry_input_do_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_albums_form_entry_input_sys_title"><![CDATA[Caption]]></string>
+	<string name="_bx_albums_form_entry_input_title"><![CDATA[Caption]]></string>
+	<string name="_bx_albums_form_entry_input_title_err"><![CDATA[Caption is essential. Please, fill in this field]]></string>
+	<string name="_bx_albums_form_entry_input_sys_text"><![CDATA[Album Description]]></string>
+	<string name="_bx_albums_form_entry_input_text"><![CDATA[Album Description]]></string>
+	<string name="_bx_albums_form_entry_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+	<string name="_bx_albums_form_entry_input_delete_confirm"><![CDATA[I am sure I want to delete this album]]></string>
+	<string name="_bx_albums_form_entry_input_delete_confirm_info"><![CDATA[This action can not be undone]]></string>
+	<string name="_bx_albums_form_entry_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete the album]]></string>
+	<string name="_bx_albums_form_entry_input_sys_pictures"><![CDATA[Pictures]]></string>
+	<string name="_bx_albums_form_entry_input_pictures"><![CDATA[Pictures]]></string>
+    <string name="_bx_albums_form_entry_input_sys_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_albums_form_entry_input_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_albums_form_entry_file_title"><![CDATA[Caption]]></string>
+	<string name="_bx_albums_form_entry_input_sys_date_added"><![CDATA[Created]]></string>
+	<string name="_bx_albums_form_entry_input_date_added"><![CDATA[Created]]></string>
+	<string name="_bx_albums_form_entry_input_sys_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_albums_form_entry_input_date_changed"><![CDATA[Updated]]></string>
+    
+	<string name="_bx_albums_acl_action_create_entry"><![CDATA[Create Album]]></string>
+	<string name="_bx_albums_acl_action_delete_entry"><![CDATA[Delete Album]]></string>
+	<string name="_bx_albums_acl_action_view_entry"><![CDATA[View Album]]></string>
+	<string name="_bx_albums_acl_action_set_thumb"><![CDATA[Set Album Cover]]></string>
+	<string name="_bx_albums_acl_action_edit_any_entry"><![CDATA[Edit Any Album]]></string>
+
+	<string name="_bx_albums_page_title_sys_create_entry"><![CDATA[New Album]]></string>
+	<string name="_bx_albums_page_title_create_entry"><![CDATA[New Album]]></string>
+	<string name="_bx_albums_page_block_title_create_entry"><![CDATA[New Album]]></string>
+	<string name="_bx_albums_page_title_sys_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_albums_page_title_edit_entry"><![CDATA[Edit]]></string>
+	<string name="_bx_albums_page_title_sys_add_images"><![CDATA[Add/Edit Pictures]]></string>
+	<string name="_bx_albums_page_title_add_images"><![CDATA[Add/Edit Pictures]]></string>
+    <string name="_bx_albums_page_block_title_edit_entry"><![CDATA[Edit]]></string>
+	<string name="_bx_albums_page_block_title_add_images"><![CDATA[Add/Edit Pictures]]></string>
+    <string name="_bx_albums_page_title_sys_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_albums_page_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_albums_page_block_title_delete_entry"><![CDATA[Delete]]></string>
+	<string name="_bx_albums_page_title_sys_view_entry"><![CDATA[View Album]]></string>
+	<string name="_bx_albums_page_title_view_entry"><![CDATA[{title}]]></string>
+	<string name="_bx_albums_page_title_sys_view_media"><![CDATA[View Image]]></string>
+	<string name="_bx_albums_page_title_view_media"><![CDATA[{title}]]></string>
+	<string name="_bx_albums_page_block_title_entry_view_media"><![CDATA[View Image]]></string>
+	<string name="_bx_albums_page_block_title_entry_view_media_exif"><![CDATA[EXIF]]></string>
+	<string name="_bx_albums_page_block_title_entry_attachments"><![CDATA[Attachments]]></string>
+	<string name="_bx_albums_page_block_title_entry_text"><![CDATA[Album Description]]></string>
+	<string name="_bx_albums_page_title_browse"><![CDATA[Albums]]></string>
+	<string name="_bx_albums_page_title_search_results"><![CDATA[Albums matching "{0}"]]></string>
+	<string name="_bx_albums_page_title_browse_by_author"><![CDATA[{display_name}'s Albums]]></string>
+    <string name="_bx_albums_page_title_browse_recent"><![CDATA[Latest Albums]]></string>
+    <string name="_bx_albums_page_title_browse_popular"><![CDATA[Popular Albums]]></string>
+    <string name="_bx_albums_page_title_browse_popular_media"><![CDATA[Top Images]]></string>
+    <string name="_bx_albums_page_title_browse_recent_media"><![CDATA[Recent Images]]></string>
+    <string name="_bx_albums_page_title_browse_media_in_album"><![CDATA[Images]]></string>
+    <string name="_bx_albums_page_title_browse_updated"><![CDATA[Updated Albums]]></string>
+    <string name="_bx_albums_page_title_sys_home"><![CDATA[Albums Home]]></string>
+    <string name="_bx_albums_page_title_home"><![CDATA[Albums]]></string>
+    <string name="_bx_albums_page_block_title_recent_entries"><![CDATA[Latest Albums]]></string>
+    <string name="_bx_albums_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+    <string name="_bx_albums_page_block_title_entry_author"><![CDATA[Author]]></string>
+    <string name="_bx_albums_page_block_title_entry_info"><![CDATA[Info]]></string>
+    <string name="_bx_albums_page_block_title_entry_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_albums_page_block_title_entry_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_albums_page_block_title_entry_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_albums_page_block_title_entry_location"><![CDATA[Location]]></string>
+    <string name="_bx_albums_page_title_sys_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_albums_page_title_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_albums_page_title_sys_entries_popular_media"><![CDATA[Top Images]]></string>
+    <string name="_bx_albums_page_title_entries_popular_media"><![CDATA[Top Images]]></string>
+    <string name="_bx_albums_page_block_title_popular_entries"><![CDATA[Popular]]></string>
+    <string name="_bx_albums_page_block_title_popular_media"><![CDATA[Top Images]]></string>
+    <string name="_bx_albums_page_block_title_recent_media"><![CDATA[Recent Images]]></string>
+    <string name="_bx_albums_page_block_title_updated_entries"><![CDATA[Updated Albums]]></string>
+    <string name="_bx_albums_page_title_sys_view_entry_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_albums_page_title_view_entry_comments"><![CDATA[Comments to {title}]]></string>
+    <string name="_bx_albums_page_title_sys_entries_of_author"><![CDATA[Albums of author]]></string>
+    <string name="_bx_albums_page_title_entries_of_author"><![CDATA[{display_name}'s albums]]></string>
+    <string name="_bx_albums_page_block_title_entries_of_author"><![CDATA[Albums by <a href="{profile_link}">{display_name}</a>]]></string>   
+    <string name="_bx_albums_page_block_title_sys_entries_of_author"><![CDATA[Albums of author]]></string>   
+    <string name="_bx_albums_page_block_title_entries_actions"><![CDATA[Albums actions]]></string>
+    <string name="_bx_albums_page_block_title_browse_cmts"><![CDATA[Albums' Comments]]></string>
+    <string name="_bx_albums_page_block_title_browse_cmts_media"><![CDATA[Images Comments]]></string>
+	<string name="_bx_albums_page_title_sys_manage"><![CDATA[Manage Own Albums]]></string>
+	<string name="_bx_albums_page_title_sys_manage_administration"><![CDATA[Manage All Albums]]></string>
+	<string name="_bx_albums_page_title_manage"><![CDATA[Manage]]></string>
+	<string name="_bx_albums_page_block_title_system_manage"><![CDATA[Manage Own Albums]]></string>
+	<string name="_bx_albums_page_block_title_system_manage_administration"><![CDATA[Manage All Albums]]></string>
+	<string name="_bx_albums_page_block_title_manage"><![CDATA[Manage]]></string>
+	<string name="_bx_albums_page_block_title_popular_keywords_albums"><![CDATA[Popular Albums Hashtags]]></string>
+	<string name="_bx_albums_page_block_title_popular_keywords_media"><![CDATA[Popular Media Hashtags]]></string>
+	<string name="_bx_albums_page_block_title_popular_keywords_media_camera"><![CDATA[Popular Cameras]]></string>
+	<string name="_bx_albums_page_block_title_my_entries"><![CDATA[My Albums]]></string>
+
+    <string name="_bx_albums_menu_set_title_view_entry"><![CDATA[Album Actions]]></string>
+    <string name="_bx_albums_menu_title_view_entry"><![CDATA[Album Actions]]></string>
+    <string name="_bx_albums_menu_set_title_view_media"><![CDATA[Media Actions]]></string>
+    <string name="_bx_albums_menu_title_view_media"><![CDATA[Media Actions]]></string>
+    <string name="_bx_albums_menu_title_submenu"><![CDATA[Albums Submenu]]></string>
+    <string name="_bx_albums_menu_set_title_submenu"><![CDATA[Albums Submenu]]></string>
+    <string name="_bx_albums_menu_item_title_system_create_entry"><![CDATA[New Album]]></string>
+    <string name="_bx_albums_menu_item_title_create_entry"><![CDATA[New Album]]></string>
+    <string name="_bx_albums_menu_item_title_system_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_albums_menu_item_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_albums_menu_item_title_system_edit_album"><![CDATA[Edit Album]]></string>
+    <string name="_bx_albums_menu_item_title_edit_album"><![CDATA[Edit Album]]></string>
+    <string name="_bx_albums_menu_item_title_system_add_images"><![CDATA[Add/Edit Pictures]]></string>
+    <string name="_bx_albums_menu_item_title_add_images"><![CDATA[Add/Edit Pictures]]></string>
+    <string name="_bx_albums_menu_item_title_system_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_albums_menu_item_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_albums_menu_item_title_system_view_entry"><![CDATA[View Album]]></string>
+    <string name="_bx_albums_menu_item_title_system_entries_home"><![CDATA[Albums]]></string>
+    <string name="_bx_albums_menu_item_title_entries_home"><![CDATA[Albums]]></string>
+    <string name="_bx_albums_menu_item_title_system_entries_recent"><![CDATA[Latest]]></string>
+    <string name="_bx_albums_menu_item_title_entries_recent"><![CDATA[Latest]]></string>
+    <string name="_bx_albums_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_albums_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_albums_menu_item_title_system_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_albums_menu_item_title_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_albums_menu_item_title_system_entries_popular_media"><![CDATA[Top Images]]></string>
+    <string name="_bx_albums_menu_item_title_entries_popular_media"><![CDATA[Top Images]]></string>
+    <string name="_bx_albums_menu_title_view_entry_submenu"><![CDATA[View Album Submenu]]></string>
+    <string name="_bx_albums_menu_set_title_view_entry_submenu"><![CDATA[View Album Submenu]]></string>
+    <string name="_bx_albums_menu_item_title_view_entry_submenu_entry"><![CDATA[Album]]></string>
+    <string name="_bx_albums_menu_item_title_view_entry_submenu_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_albums_menu_item_title_system_view_entry_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_albums_menu_item_title_system_view_entries_author"><![CDATA[Albums]]></string>
+    <string name="_bx_albums_menu_item_title_view_entries_author"><![CDATA[Albums]]></string>
+    <string name="_bx_albums_menu_title_entries_my"><![CDATA[My Albums Action Menu]]></string>
+    <string name="_bx_albums_menu_set_title_entries_my"><![CDATA[My Albums Menu]]></string>
+	<string name="_bx_albums_menu_item_title_system_manage_my_albums"><![CDATA[My albums]]></string>
+    <string name="_bx_albums_menu_item_title_manage_my_albums"><![CDATA[{addon} albums]]></string>
+    <string name="_bx_albums_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_albums_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+	<string name="_bx_albums_menu_item_title_system_admt_albums"><![CDATA[Albums]]></string>
+	<string name="_bx_albums_menu_item_title_admt_albums"><![CDATA[Albums - {addon} hidden]]></string>
+	<string name="_bx_albums_menu_item_title_manage_my"><![CDATA[My Albums]]></string>
+	<string name="_bx_albums_menu_item_title_manage_all"><![CDATA[All Albums]]></string>
+
+	<string name="_bx_albums_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+	<string name="_bx_albums_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+	<string name="_bx_albums_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+	<string name="_bx_albums_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_albums_grid_column_title_adm_title"><![CDATA[Caption]]></string>
+    <string name="_bx_albums_grid_column_title_adm_added"><![CDATA[Added]]></string>
+    <string name="_bx_albums_grid_column_title_adm_author"><![CDATA[Author]]></string>
+    <string name="_bx_albums_grid_action_title_adm_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_albums_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_albums_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_albums_grid_action_err_delete"><![CDATA[Cannot delete the selected album(s).]]></string>
+    <string name="_bx_albums_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_albums_txt_all_entries_by"><![CDATA[<a href="{0}">All Albums by {1} ({2})</a>]]></string>
+    <string name="_bx_albums_txt_sample_single"><![CDATA[album]]></string>
+    <string name="_bx_albums_txt_sample_comment_single"><![CDATA[album's comment]]></string>
+    <string name="_bx_albums_txt_sample_vote_single"><![CDATA[album's vote]]></string>
+    <string name="_bx_albums_txt_media_single"><![CDATA[image]]></string>
+    <string name="_bx_albums_txt_media_comment_single"><![CDATA[image's comment]]></string>
+	<string name="_bx_albums_txt_media_title_alt"><![CDATA[{0}'s media]]></string>
+	<string name="_bx_albums_txt_media_album_link"><![CDATA[<a href="{0}">{1}</a> album by <a href="{2}">{3}</a>]]></string>
+	<string name="_bx_albums_txt_media_album_camera"><![CDATA[Camera]]></string>
+	<string name="_bx_albums_txt_media_album_focal_length"><![CDATA[Focal length]]></string>
+	<string name="_bx_albums_txt_media_album_focal_length_value"><![CDATA[{0}mm]]></string>
+	<string name="_bx_albums_txt_media_album_aperture"><![CDATA[Aperture]]></string>
+	<string name="_bx_albums_txt_media_album_shutter_speed"><![CDATA[Exposure time]]></string>
+	<string name="_bx_albums_txt_media_album_shutter_speed_value"><![CDATA[{0}s]]></string>
+	<string name="_bx_albums_txt_media_album_iso"><![CDATA[ISO]]></string>
+</resources>

+ 393 - 0
modules/boonex/albums/updates/9.0.0_9.0.1/source/install/sql/enable.sql

@@ -0,0 +1,393 @@
+
+-- 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-mi.png', 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_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_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', 10, 2147483647, 1, 'view-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`, `active`, `order`) VALUES 
+('bx_albums_view_entry', 4, '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, 0),
+('bx_albums_view_entry', 4, 'bx_albums', '_bx_albums_page_block_title_entry_attachments', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:18:\"entity_attachments\";}', 0, 0, 1, 1),
+('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, 1, 2),
+('bx_albums_view_entry', 4, '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, 3),
+('bx_albums_view_entry', 4, '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', 2, '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, 0),
+
+('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, 0);
+
+
+-- PAGE: view media
+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_view_media', 'view-album-media', '_bx_albums_page_title_sys_view_media', '_bx_albums_page_title_view_media', 'bx_albums', 10, 2147483647, 1, '', '', '', '', 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', 1, '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, 0),
+('bx_albums_view_media', 2, '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, 0),
+('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, 1, 0),
+('bx_albums_view_media', 4, '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, 0),
+('bx_albums_view_media', 4, '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, 1);
+
+
+-- PAGE: view entry comments
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_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: 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, 0),
+('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, 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_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, 1),
+('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: 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:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:13:\"browse_public\";}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1),
+('sys_home', 1, 'bx_albums', '_bx_albums_page_block_title_updated_entries', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_albums\";s:6:\"method\";s:14:\"browse_updated\";}', 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`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_albums', '_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:1:{i:0;s:12:"{profile_id}";}}', 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: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: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);
+
+
+-- MENU: add to site menu
+
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' 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_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', '', '', 'picture-o 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', '', '', 'picture-o 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', '', '', 'picture-o 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', '', 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);
+
+-- 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', '', 2147483647, 1, 0, 20);
+
+-- 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-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, 3),
+('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, 4);
+
+-- 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: 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-manage-albums', '_bx_albums_menu_item_title_system_manage_my_albums', '_bx_albums_menu_item_title_manage_my_albums', 'page.php?i=albums-manage', '', '_self', 'picture-o 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', 'trash-o', '', 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', '', '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}', '', '', 'picture-o 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', '', '');
+
+
+-- 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();
+
+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);
+
+
+-- 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`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_albums', 'bx_albums_meta_keywords', 'bx_albums_meta_locations', '', '', ''),
+('bx_albums_media', 'bx_albums_meta_keywords_media', '', '', '', ''),
+('bx_albums_media_camera', 'bx_albums_meta_keywords_media_camera', '', '', '', '');
+
+-- 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', '', '', 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', 'title', '_bx_albums_grid_column_title_adm_title', '25%', 0, '', '', 3),
+('bx_albums_administration', 'added', '_bx_albums_grid_column_title_adm_added', '20%', 1, '25', '', 4),
+('bx_albums_administration', 'author', '_bx_albums_grid_column_title_adm_author', '25%', 0, '25', '', 5),
+('bx_albums_administration', 'actions', '', '20%', 0, '', '', 6),
+('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', '30%', 1, '25', '', 4),
+('bx_albums_common', 'actions', '', '20%', 0, '', '', 5);
+
+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', 'single', 'edit', '_bx_albums_grid_action_title_adm_edit', 'pencil', 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_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', 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_simple', 1, 'BxAlbumsUploaderSimple', 'modules/boonex/albums/classes/BxAlbumsUploaderSimple.php'),
+('bx_albums_html5', 1, 'BxAlbumsUploaderHTML5', 'modules/boonex/albums/classes/BxAlbumsUploaderHTML5.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),
+('bx_albums_files', 'file_deleted', @iHandler),
+('profile', 'delete', @iHandler);

+ 356 - 0
modules/boonex/albums/updates/9.0.0_9.0.1/source/install/sql/install.sql

@@ -0,0 +1,356 @@
+
+-- 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,
+  `views` int(11) NOT NULL default '0',
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `comments` int(11) NOT NULL default '0',
+  `reports` int(11) NOT NULL default '0',
+  `allow_view_to` int(11) NOT NULL DEFAULT '3',
+  `status` enum('active','hidden') NOT NULL DEFAULT 'active',
+  `status_admin` enum('active','hidden') 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(255) 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` 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(255) 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` 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_files2albums` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `content_id` int(10) unsigned NOT NULL,
+  `file_id` int(11) NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `views` int(11) NOT NULL,
+  `rate` float NOT NULL,
+  `votes` int(11) NOT NULL,
+  `comments` int(11) NOT NULL,
+  `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`)
+);
+
+-- 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(10) unsigned 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',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`)
+);
+
+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(10) unsigned 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',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`)
+);
+
+-- TABLE: votes
+
+CREATE TABLE IF NOT EXISTS `bx_albums_votes` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  UNIQUE KEY `object_id` (`object_id`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+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`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_albums_votes_media` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  UNIQUE KEY `object_id` (`object_id`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+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`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+-- TABLE: views
+
+CREATE TABLE `bx_albums_views_track` (
+  `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',
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE `bx_albums_views_media_track` (
+  `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',
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- TABLE: metas
+
+CREATE TABLE `bx_albums_meta_keywords` (
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE `bx_albums_meta_keywords_media` (
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE `bx_albums_meta_keywords_media_camera` (
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+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))
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- TABLE: reports
+
+CREATE TABLE IF NOT EXISTS `bx_albums_reports` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  UNIQUE KEY `object_id` (`object_id`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+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',
+  PRIMARY KEY (`id`),
+  KEY `report` (`object_id`, `author_nip`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+-- STORAGES & TRANSCODERS
+
+INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `cache_control`, `levels`, `table_files`, `ext_mode`, `ext_allow`, `ext_deny`, `quota_size`, `current_size`, `quota_number`, `current_number`, `max_file_size`, `ts`) VALUES
+('bx_albums_files', 'Local', '', 360, 2592000, 3, 'bx_albums_files', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
+('bx_albums_photos_resized', 'Local', '', 360, 2592000, 3, 'bx_albums_photos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 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_webm', '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:20:"bx_albums_video_webm";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:20:"bx_albums_video_webm";}}', '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:20:"bx_albums_video_webm";}}', '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_webm', 'Webm', 'a:2:{s:1:"h";s:3:"480";s:10:"force_type";s:4:"webm";}', 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:14:"bx_albums_crop";}', 'a:3:{s:16:"bx_albums_simple";s:26:"_sys_uploader_simple_title";s:15:"bx_albums_html5";s:25:"_sys_uploader_html5_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', '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, '', '', '', '', '', '', '', '', 0, 0),
+('bx_albums', 'bx_albums', 'location', '', '', 0, 'location', '_sys_form_input_sys_location', '_sys_form_input_location', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 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);
+
+
+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', 'location', 2147483647, 1, 6),
+('bx_albums_entry_add', 'do_submit', 2147483647, 1, 7),
+
+('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, 0, 4),
+('bx_albums_entry_edit', 'allow_view_to', 2147483647, 1, 5),
+('bx_albums_entry_edit', 'location', 2147483647, 1, 6),
+('bx_albums_entry_edit', 'do_submit', 2147483647, 1, 7),
+
+('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);
+
+-- COMMENTS
+
+INSERT INTO `sys_objects_cmts` (`Name`, `Table`, `CharsPostMin`, `CharsPostMax`, `CharsDisplayMax`, `Nl2br`, `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_cmts', 1, 5000, 1000, 1, 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_media', 'bx_albums_cmts_media', 1, 5000, 1000, 1, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-album-media&id={object_id}', '', 'bx_albums_files2albums', 'id', '', 'title', 'comments', '', '');
+
+-- 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', '', 'rate', 'votes', '', '');
+
+-- REPORTS
+
+INSERT INTO `sys_objects_report` (`name`, `table_main`, `table_track`, `is_on`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_albums', 'bx_albums_reports', 'bx_albums_reports_track', '1', 'page.php?i=view-album&id={object_id}', 'bx_albums_albums', 'id', 'author', 'reports', '', '');
+
+-- VIEWS
+
+INSERT INTO `sys_objects_view` (`name`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `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', 'views', '', '');
+
+-- 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-pi.png');
+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`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, 'bx_albums', '{url_studio}module.php?name=bx_albums', '', 'bx_albums@modules/boonex/albums/|std-wi.png', '_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));
+

+ 51 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Conversations',
+    'version_from' => '9.0.0',
+	'version_to' => '9.0.1',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/convos/updates/update_9.0.0_9.0.1/',
+	'home_uri' => 'convos_update_900_901',
+
+	'module_dir' => 'boonex/convos/',
+	'module_uri' => 'convos',
+
+    'db_prefix' => 'bx_convos_',
+    'class_prefix' => 'BxCnv',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+		'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+		'clear_db_cache' => 1,
+    ),
+
+	/**
+     * Category for language keys.
+     */
+    'language_category' => 'Conversations',
+
+	/**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+class BxCnvUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+	{
+        parent::__construct($aConfig);
+    }
+}

+ 6 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/install/langs/en.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_cnv_page_block_title_entry_breadcrumb"><![CDATA[Breadcrumb]]></string_add>
+
+	<string_upd name="_bx_cnv_page_title_sys_view_entry"><![CDATA[View conversation]]></string_upd>
+</resources>

+ 4 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/install/sql/enable.sql

@@ -0,0 +1,4 @@
+-- PAGES
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_convos_view_entry' AND `title`='_bx_cnv_page_block_title_entry_breadcrumb';
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('bx_convos_view_entry', 1, 'bx_convos', '_bx_cnv_page_block_title_entry_breadcrumb', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_convos";s:6:"method";s:17:"entity_breadcrumb";}', 0, 0, 1, 0);

+ 97 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/source/classes/BxCnvConfig.php

@@ -0,0 +1,97 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Convos Convos
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxCnvConfig extends BxBaseModTextConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $aMenuItems2Methods = array (
+            'delete-convos' => 'checkAllowedDelete',
+            'mark-unread-convo' => 'checkAllowedView',
+        );
+
+        $this->CNF = array (
+
+            // module icon
+            'ICON' => 'comments col-red1',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'conversations',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => 'author',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => 'changed',
+            'FIELD_TITLE' => '',
+            'FIELD_TEXT' => 'text',
+            'FIELD_TEXT_ID' => 'convo-text',
+            'FIELD_ALLOW_VIEW_TO' => '',
+            'FIELD_PHOTO' => 'attachments',
+            'FIELD_THUMB' => '',
+            'FIELD_COMMENTS' => 'comments',
+
+            // page URIs
+            'URI_VIEW_ENTRY' => 'view-convo',
+            'URI_AUTHOR_ENTRIES' => 'convos',
+            'URI_ADD_ENTRY' => 'start-convo',
+
+            'URL_HOME' => 'modules/?r=convos/folder/1',
+        	'URL_FOLDER' => 'modules/?r=convos/folder/',
+
+            // some params
+            'PARAM_CHARS_SUMMARY' => '',
+            'PARAM_CHARS_SUMMARY_PLAIN' => '',
+            'PARAM_NUM_RSS' => '',
+
+            // objects
+            'OBJECT_GRID' => 'bx_convos',
+            'OBJECT_STORAGE' => 'bx_convos_files',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW' => 'bx_convos_preview',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => '',
+            'OBJECT_VIDEOS_TRANSCODERS' => array(),
+            'OBJECT_VIEWS' => 'bx_convos',
+            'OBJECT_VOTES' => '',
+            'OBJECT_COMMENTS' => 'bx_convos',
+            'OBJECT_PRIVACY_VIEW' => '',
+            'OBJECT_FORM_ENTRY' => 'bx_convos',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => 'bx_convos_entry_view',
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_convos_entry_add',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => '',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_convos_entry_delete',
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_convos_view', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_convos_my', // actions menu on my entries page
+            'OBJECT_MENU_SUBMENU' => 'bx_convos_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => '', // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'convos', // first item in view entry submenu from main module submenu
+            'OBJECT_UPLOADERS' => array('sys_simple', 'sys_html5'),
+
+            // menu items which visibility depends on custom visibility checking
+            'MENU_ITEM_TO_METHOD' => array (
+                'bx_convos_view' => $aMenuItems2Methods,
+            ),
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_cnv_txt_sample_single',
+            	'txt_folder_' . BX_CNV_FOLDER_INBOX => '_bx_cnv_folder_inbox',
+	            'txt_folder_' . BX_CNV_FOLDER_DRAFTS => '_bx_cnv_folder_drafts',
+	            'txt_folder_' . BX_CNV_FOLDER_SPAM => '_bx_cnv_folder_spam',
+	            'txt_folder_' . BX_CNV_FOLDER_TRASH => '_bx_cnv_folder_trash',
+            ),
+        );
+
+    }
+}
+
+/** @} */

+ 131 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/source/classes/BxCnvFormEntry.php

@@ -0,0 +1,131 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Convos Convos
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/**
+ * Create/Edit entry form
+ */
+class BxCnvFormEntry extends BxBaseModTextFormEntry
+{
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_convos';
+        parent::__construct($aInfo, $oTemplate);
+
+        $oTemplate = BxDolTemplate::getInstance();
+        $oTemplate->addJsTranslation(array(
+            '_bx_cnv_draft_saving_error',
+            '_bx_cnv_draft_saved_success',
+        ));
+    }
+
+    public function insert ($aValsToAdd = array(), $isIgnore = false)
+    {
+        $aValsToAdd['last_reply_timestamp'] = time();
+        $aValsToAdd['last_reply_profile_id'] = bx_get_logged_profile_id();
+
+        $bSaveToDrafts = bx_get('draft_save');
+        $iContentId = bx_get('draft_id');
+        $bDraft = $iContentId ? BX_CNV_FOLDER_DRAFTS == $this->_oModule->_oDb->getConversationFolder($iContentId, bx_get_logged_profile_id()) : false;
+
+        if ($iContentId) {
+
+            if (!$bDraft)
+                return 0;
+
+            if (!parent::update ($iContentId, $aValsToAdd, $isIgnore))
+                return 0;
+
+        } else {
+            $iContentId = parent::insert ($aValsToAdd, $isIgnore);
+            if (!$iContentId)
+                return 0;
+        }
+
+        if ($bSaveToDrafts) {
+
+            if (!$bDraft)
+                $this->_oModule->_oDb->conversationToFolder($iContentId, BX_CNV_FOLDER_DRAFTS, bx_get_logged_profile_id(), 0);
+
+            // draft is saved via ajax call only, upon successfull draft saving content id is returned
+            echo $iContentId;
+            exit;
+
+        } else {
+
+            // check for spam
+            $bSpam = false;
+            bx_alert('system', 'check_spam', 0, getLoggedId(), array('is_spam' => &$bSpam, 'content' => $this->getCleanValue('text'), 'where' => $this->MODULE));
+            $iFolder = $bSpam ? BX_CNV_FOLDER_SPAM : BX_CNV_FOLDER_INBOX;
+
+            // place conversation to "inbox" (or "spam" - in case of spam) folder
+            $aRecipients = array_unique(array_merge($this->getCleanValue('recipients'), array(bx_get_logged_profile_id())), SORT_NUMERIC);
+            foreach ($aRecipients as $iProfile) {
+                $oProfile = BxDolProfile::getInstance($iProfile);
+                if (!$oProfile)
+                    continue;
+
+                if ($bDraft && $oProfile->id() == bx_get_logged_profile_id())
+                    $this->_oModule->_oDb->moveConvo($iContentId, $oProfile->id(), $iFolder);
+                else
+                    $this->_oModule->_oDb->conversationToFolder($iContentId, $iFolder, $oProfile->id(), $oProfile->id() == bx_get_logged_profile_id() ? 0 : -1);
+            }
+        }
+
+        return $iContentId;
+    }
+
+    protected function genCustomInputRecipients ($aInput)
+    {
+        $aInput['ajax_get_suggestions'] = BX_DOL_URL_ROOT . "modules/?r=convos/ajax_get_recipients";
+        return $this->genCustomInputUsernamesSuggestions($aInput);
+    }
+
+    protected function genCustomInputSubmitText ($aInput)
+    {
+        $aVars = array();
+        return $this->_oModule->_oTemplate->parseHtmlByName('form_submit_text.html', $aVars);
+    }
+
+    function initChecker ($aValues = array (), $aSpecificValues = array())
+    {
+        if ($iContentId = bx_get('draft_id')) { // if adding from draft, fill in existing fields info
+            $aContentInfo = $this->_oModule->_oDb->getContentInfoById($iContentId);
+            if ($aContentInfo)
+                $aValues = array_merge($aContentInfo, $aValues);
+        }
+
+        if ($sProfilesIds = bx_get('profiles')) { // if writing directly to some recipients, pre-fill them
+            $a = explode(',', $sProfilesIds);
+            $a = array_unique(BxDolFormCheckerHelper::passInt($a));
+            if ($a)
+                $aValues['recipients'] = array_merge(empty($aValues['recipients']) ? array() : $aValues['recipients'], $a);
+            
+        }
+        return parent::initChecker ($aValues, $aSpecificValues);
+    }
+
+    function isValid ()
+    {
+        if (bx_get('draft_save')) // form is always valid when saving to drafts
+            return true;
+        return parent::isValid ();
+    }
+
+    public function processFiles ($sFieldFile, $iContentId = 0, $isAssociateWithContent = false)
+    {
+        if (!$isAssociateWithContent && bx_get('draft_id')) // when draft is already saved then db update is called but we still need to do association since it's draft
+            $isAssociateWithContent = true; // TODO: if edit mode will be added, then this functionality maybe reconsidered
+         
+        return parent::processFiles ($sFieldFile, $iContentId, $isAssociateWithContent);
+    }
+}
+
+/** @} */

+ 273 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/source/classes/BxCnvTemplate.php

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

+ 104 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/source/install/config.php

@@ -0,0 +1,104 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Convos Convos
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_convos',
+    'title' => 'Conversations',
+    'note' => 'Conversations module.',
+    'version' => '9.0.1',
+    'vendor' => 'BoonEx',
+	'help_url' => 'http://feed.boonex.com/?section={module_name}',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/convos/',
+    'home_uri' => 'convos',
+
+    'db_prefix' => 'bx_convos_',
+    'class_prefix' => 'BxCnv',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Conversations',
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+        'trigger_profile_view_actions',
+        'trigger_group_view_actions',
+    ),
+
+    /**
+     * Storages.
+     */
+    'storages' => array(
+    	'bx_convos_files'
+    ),
+
+	/**
+     * Transcoders.
+     */
+    'transcoders' => array(
+		'bx_convos_preview'
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_storages' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+	'enable_success' => array(
+    	'process_menu_triggers' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'unregister_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 129 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/source/install/langs/en.xml

@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+	<string name="_bx_cnv"><![CDATA[Conversations]]></string>
+
+	<string name="_bx_cnv_option_preview_messages_num"><![CDATA[Number of preview messages]]></string>
+
+	<string name="_bx_cnv_form_entry"><![CDATA[Conversations]]></string>
+	<string name="_bx_cnv_form_entry_display_add"><![CDATA[New conversation]]></string>
+	<string name="_bx_cnv_form_entry_display_delete"><![CDATA[Delete conversation]]></string>
+	<string name="_bx_cnv_form_entry_display_view"><![CDATA[View conversation]]></string>
+	<string name="_bx_cnv_form_entry_input_sys_do_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_cnv_form_entry_input_do_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_cnv_form_entry_input_sys_text"><![CDATA[Text]]></string>
+	<string name="_bx_cnv_form_entry_input_text"><![CDATA[Text]]></string>
+	<string name="_bx_cnv_form_entry_input_text_err"><![CDATA[Text field can't be empty]]></string>
+	<string name="_bx_cnv_form_entry_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+	<string name="_bx_cnv_form_entry_input_delete_confirm"><![CDATA[I am sure I want to delete this conversation]]></string>
+	<string name="_bx_cnv_form_entry_input_delete_confirm_info"><![CDATA[This action can not be undone]]></string>
+	<string name="_bx_cnv_form_entry_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete the conversation]]></string>
+	<string name="_bx_cnv_form_entry_input_sys_attachments"><![CDATA[Attachments]]></string>
+	<string name="_bx_cnv_form_entry_input_attachments"><![CDATA[Attachments]]></string>
+    <string name="_bx_cnv_form_entry_input_recipients"><![CDATA[Recipients]]></string>
+    <string name="_bx_cnv_form_entry_input_sys_recipients"><![CDATA[Recipients]]></string>
+    <string name="_bx_cnv_form_entry_input_recipients_err"><![CDATA[Recipients is mandatory]]></string>
+    <string name="_bx_cnv_form_entry_input_sys_submit_text"><![CDATA[Draft status]]></string>
+    <string name="_bx_cnv_form_entry_input_sys_submit_block"><![CDATA[Submit block]]></string>
+
+	<string name="_bx_cnv_acl_action_create_entry"><![CDATA[New conversation]]></string>
+	<string name="_bx_cnv_acl_action_delete_entry"><![CDATA[Delete conversation]]></string>
+	<string name="_bx_cnv_acl_action_view_entry"><![CDATA[View conversation]]></string>
+
+	<string name="_bx_cnv_page_title_sys_create_entry"><![CDATA[New conversation]]></string>
+	<string name="_bx_cnv_page_title_create_entry"><![CDATA[New conversation]]></string>
+	<string name="_bx_cnv_page_block_title_create_entry"><![CDATA[New conversation]]></string>
+	<string name="_bx_cnv_page_title_sys_view_entry"><![CDATA[View conversation]]></string>
+	<string name="_bx_cnv_page_title_view_entry"><![CDATA[{title}]]></string>
+	<string name="_bx_cnv_page_block_title_entry_attachments"><![CDATA[Attachments]]></string>
+	<string name="_bx_cnv_page_block_title_entry_text"><![CDATA[Text]]></string>
+    <string name="_bx_cnv_page_block_title_entry_author"><![CDATA[Author]]></string>
+    <string name="_bx_cnv_page_block_title_entry_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_cnv_page_block_title_entry_breadcrumb"><![CDATA[Breadcrumb]]></string>
+    <string name="_bx_cnv_page_block_title_entry_comments"><![CDATA[Replies ({0})]]></string>
+    <string name="_bx_cnv_page_block_title_entry_collaborators"><![CDATA[Participants]]></string>
+    <string name="_bx_cnv_page_title_sys_folder"><![CDATA[Conversations in folder]]></string>
+    <string name="_bx_cnv_page_title_folder"><![CDATA[Folder: {folder}]]></string>
+    <string name="_bx_cnv_page_block_title_folder"><![CDATA[Folder: {folder}]]></string>
+    <string name="_bx_cnv_page_block_title_convos"><![CDATA[Conversations]]></string>
+
+    <string name="_bx_cnv_menu_set_title_view_entry"><![CDATA[Conversation Actions]]></string>
+    <string name="_bx_cnv_menu_title_view_entry"><![CDATA[Conversation Actions]]></string>
+    <string name="_bx_cnv_menu_title_submenu"><![CDATA[Conversations Submenu]]></string>
+    <string name="_bx_cnv_menu_set_title_submenu"><![CDATA[Conversations Submenu]]></string>
+    <string name="_bx_cnv_menu_title_folders_more"><![CDATA[Conversations folders]]></string>
+    <string name="_bx_cnv_menu_set_title_submenu"><![CDATA[Conversations folders]]></string>
+    <string name="_bx_cnv_menu_set_title_folders_more"><![CDATA[More folders]]></string>
+    <string name="_bx_cnv_menu_item_title_system_message"><![CDATA[Message]]></string>
+    <string name="_bx_cnv_menu_item_title_message"><![CDATA[Message]]></string>
+    <string name="_bx_cnv_menu_item_title_system_message_group"><![CDATA[Group Message]]></string>
+    <string name="_bx_cnv_menu_item_title_message_group"><![CDATA[Group Message]]></string>
+    <string name="_bx_cnv_menu_item_title_system_mark_unread_entry"><![CDATA[Mark as unread]]></string>
+    <string name="_bx_cnv_menu_item_title_mark_unread_entry"><![CDATA[Mark as unread]]></string>
+
+
+    <string name="_bx_cnv_menu_item_title_system_delete_entry"><![CDATA[Delete conversation]]></string>
+    <string name="_bx_cnv_menu_item_title_delete_entry"><![CDATA[Delete conversation]]></string>
+    <string name="_bx_cnv_menu_item_title_system_folder_inbox"><![CDATA[Inbox]]></string>
+    <string name="_bx_cnv_menu_item_title_folder_inbox"><![CDATA[Inbox]]></string>
+    <string name="_bx_cnv_menu_item_title_system_folder_drafts"><![CDATA[Drafts]]></string>
+    <string name="_bx_cnv_menu_item_title_folder_drafts"><![CDATA[Drafts]]></string>
+    <string name="_bx_cnv_menu_item_title_system_folder_spam"><![CDATA[Spam]]></string>
+    <string name="_bx_cnv_menu_item_title_folder_spam"><![CDATA[Spam]]></string>
+    <string name="_bx_cnv_menu_item_title_system_folder_trash"><![CDATA[Trash]]></string>
+    <string name="_bx_cnv_menu_item_title_folder_trash"><![CDATA[Trash]]></string>
+    <string name="_bx_cnv_menu_item_title_system_folder_more"><![CDATA[More]]></string>
+    <string name="_bx_cnv_menu_item_title_folder_more"><![CDATA[More]]></string>
+    <string name="_bx_cnv_menu_item_title_system_convos"><![CDATA[Conversations]]></string>
+    <string name="_bx_cnv_menu_item_title_convos"><![CDATA[Conversations]]></string>
+    <string name="_bx_cnv_menu_item_title_system_unread_messages"><![CDATA[Unread messages number]]></string>
+    <string name="_bx_cnv_menu_item_title_unread_messages"><![CDATA[{addon} unread messages]]></string>
+
+    <string name="_bx_cnv_txt_sample_single"><![CDATA[conversation]]></string>
+
+    <string name="_bx_cnv_folder_inbox"><![CDATA[Inbox]]></string>
+    <string name="_bx_cnv_folder_drafts"><![CDATA[Drafts]]></string>
+    <string name="_bx_cnv_folder_spam"><![CDATA[Spam]]></string>
+    <string name="_bx_cnv_folder_trash"><![CDATA[Trash]]></string>
+
+    <string name="_bx_cnv_field_comments"><![CDATA[#]]></string>
+    <string name="_bx_cnv_field_preview"><![CDATA[Preview]]></string>
+    <string name="_bx_cnv_field_collaborators"><![CDATA[Participants]]></string>
+
+    <string name="_bx_cnv_grid_action_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_cnv_grid_action_compose"><![CDATA[New conversation]]></string>
+
+    <string name="_bx_cnv_collaborator_info"><![CDATA[{0} ({1})]]></string>
+    <string name="_bx_cnv_collaborator_author"><![CDATA[author]]></string>
+    <string name="_bx_cnv_collaborator_last_replier"><![CDATA[last replier]]></string>
+    <string name="_bx_cnv_more"><![CDATA[{0} more]]></string>
+
+    <string name="_bx_cnv_author_desc"><![CDATA[{0} (updated {1})]]></string>
+    <string name="_bx_cnv_x_date_by_x_replier"><![CDATA[{0} by {1}]]></string>
+
+    <string name="_bx_cnv_read_by_all"><![CDATA[Read by all]]></string>
+    <string name="_bx_cnv_see_all"><![CDATA[See all conversations...]]></string>
+    <string name="_bx_cnv_you_are_last_replier"><![CDATA[You are last replier]]></string>
+
+    <string name="_bx_cnv_draft_saving_error"><![CDATA[Draft saving error!]]></string>
+    <string name="_bx_cnv_draft_saved_success"><![CDATA[Draft saved.]]></string>
+
+    <string name="_bx_cnv_email_new_message"><![CDATA[New message]]></string>
+    <string name="_bx_cnv_email_new_message_subject"><![CDATA[New message from {SenderDisplayName}]]></string>
+    <string name="_bx_cnv_email_new_message_body"><![CDATA[
+<bx_include_auto:_email_header.html />
+<p>New message from <a href="{SenderUrl}">{SenderDisplayName}</a>:</p>
+<hr />
+<p>{Message}</p>
+<bx_include_auto:_email_footer.html />]]></string>
+
+    <string name="_bx_cnv_email_new_reply"><![CDATA[New reply]]></string>
+    <string name="_bx_cnv_email_new_reply_subject"><![CDATA[New reply from {SenderDisplayName}]]></string>
+    <string name="_bx_cnv_email_new_reply_body"><![CDATA[
+<bx_include_auto:_email_header.html />
+<p>New reply from <a href="{SenderUrl}">{SenderDisplayName}</a>:</p>
+<hr />
+<p>{Message}</p>
+<bx_include_auto:_email_footer.html />]]></string>
+
+</resources>

+ 200 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/source/install/sql/enable.sql

@@ -0,0 +1,200 @@
+
+-- 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_convos', '_bx_cnv', 'bx_convos@modules/boonex/convos/|std-mi.png', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_convos', '_bx_cnv', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_convos_preview_messages_num', '3', @iCategId, '_bx_cnv_option_preview_messages_num', 'digit', '', '', '', 1);
+
+-- PAGE: dash
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('sys_dashboard', 3, 'bx_convos', '_bx_cnv_page_block_title_convos', 11, 2147483646, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_convos\";s:6:\"method\";s:17:\"messages_previews\";}', 0, 1, 1, 0);
+
+
+-- 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_convos_create_entry', '_bx_cnv_page_title_sys_create_entry', '_bx_cnv_page_title_create_entry', 'bx_convos', 5, 2147483647, 1, 'start-convo', 'page.php?i=start-convo', '', '', '', 0, 1, 0, 'BxCnvPageBrowse', 'modules/boonex/convos/classes/BxCnvPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_convos_create_entry', 1, 'bx_convos', '_bx_cnv_page_block_title_create_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_convos";s:6:"method";s:13:"entity_create";}', 0, 1, 1);
+
+
+-- PAGE: view entry
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_convos_view_entry', 'view-convo', '_bx_cnv_page_title_sys_view_entry', '_bx_cnv_page_title_view_entry', 'bx_convos', 10, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxCnvPageEntry', 'modules/boonex/convos/classes/BxCnvPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('bx_convos_view_entry', 1, 'bx_convos', '_bx_cnv_page_block_title_entry_breadcrumb', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_convos";s:6:"method";s:17:"entity_breadcrumb";}', 0, 0, 1, 0),
+('bx_convos_view_entry', 4, 'bx_convos', '_bx_cnv_page_block_title_entry_text', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_convos\";s:6:\"method\";s:17:\"entity_text_block\";}', 0, 0, 1, 0),
+('bx_convos_view_entry', 3, 'bx_convos', '_bx_cnv_page_block_title_entry_collaborators', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_convos\";s:6:\"method\";s:20:\"entity_collaborators\";}', 0, 0, 1, 0),
+('bx_convos_view_entry', 2, 'bx_convos', '_bx_cnv_page_block_title_entry_author', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_convos\";s:6:\"method\";s:13:\"entity_author\";}', 0, 0, 1, 0),
+('bx_convos_view_entry', 4, 'bx_convos', '_bx_cnv_page_block_title_entry_attachments', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_convos\";s:6:\"method\";s:18:\"entity_attachments\";}', 0, 0, 1, 1),
+('bx_convos_view_entry', 4, 'bx_convos', '_bx_cnv_page_block_title_entry_comments', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_convos\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 1, 2);
+
+
+-- PAGE: module home
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_convos_home', '_bx_cnv_page_title_sys_folder', '_bx_cnv_page_title_folder', 'bx_convos', 5, 2147483647, 1, 'convos-folder', 'modules/?r=convos/folder/1', '', '', '', 0, 1, 0, 'BxCnvPageBrowse', 'modules/boonex/convos/classes/BxCnvPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_convos_home', 1, 'bx_convos', '_bx_cnv_page_block_title_folder', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_convos";s:6:"method";s:23:"conversations_in_folder";s:6:"params";a:1:{i:0;s:11:"{folder_id}";}}', 0, 1, 0);
+
+
+-- 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_convos_view', '_bx_cnv_menu_title_view_entry', 'bx_convos_view', 'bx_convos', 9, 0, 1, 'BxCnvMenuView', 'modules/boonex/convos/classes/BxCnvMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_convos_view', 'bx_convos', '_bx_cnv_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_convos_view', 'bx_convos', 'delete-convo', '_bx_cnv_menu_item_title_system_delete_entry', '_bx_cnv_menu_item_title_delete_entry', 'javascript:void(0);', 'bx_cnv_delete(this, \'{content_id}\')', '', 'remove', '', 2147483647, 1, 0, 1),
+('bx_convos_view', 'bx_convos', 'mark-unread-convo', '_bx_cnv_menu_item_title_system_mark_unread_entry', '_bx_cnv_menu_item_title_mark_unread_entry', 'javascript:void(0);', 'bx_cnv_mark_unread(this, \'{content_id}\')', '', 'check', '', 2147483647, 1, 0, 2);
+
+
+-- 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_convos_submenu', '_bx_cnv_menu_title_submenu', 'bx_convos_submenu', 'bx_convos', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_convos_submenu', 'bx_convos', '_bx_cnv_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_convos_submenu', 'bx_convos', 'convos-folder-inbox', '_bx_cnv_menu_item_title_system_folder_inbox', '_bx_cnv_menu_item_title_folder_inbox', 'modules/?r=convos/folder/1', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_convos_submenu', 'bx_convos', 'convos-drafts', '_bx_cnv_menu_item_title_system_folder_drafts', '_bx_cnv_menu_item_title_folder_drafts', 'modules/?r=convos/folder/2', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_convos_submenu', 'bx_convos', 'convos-spam', '_bx_cnv_menu_item_title_system_folder_spam', '_bx_cnv_menu_item_title_folder_spam', 'modules/?r=convos/folder/3', '', '', '', '', 2147483647, 1, 1, 3),
+('bx_convos_submenu', 'bx_convos', 'convos-trash', '_bx_cnv_menu_item_title_system_folder_trash', '_bx_cnv_menu_item_title_folder_trash', 'modules/?r=convos/folder/4', '', '', '', '', 2147483647, 1, 1, 4);
+-- ('bx_convos_submenu', 'bx_convos', 'convos-folder-more', '_bx_cnv_menu_item_title_system_folder_more', '_bx_cnv_menu_item_title_folder_more', 'javascript:void(0);', 'bx_menu_popup(''bx_convos_menu_folders_more'', this);', '', '', '', 2147483647, 1, 1, 5)
+
+-- TODO: Remove it completely if 'more' menu item isn't needed.
+-- MENU: more folders
+-- INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+-- ('bx_convos_menu_folders_more', '_bx_cnv_menu_title_folders_more', 'bx_convos_menu_folders_more', 'bx_convos', 4, 0, 1, '', '');
+
+-- INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+-- ('bx_convos_menu_folders_more', 'bx_convos', '_bx_cnv_menu_set_title_folders_more', 0);
+
+-- INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+-- ('bx_convos_menu_folders_more', 'bx_convos', 'convos-drafts', '_bx_cnv_menu_item_title_system_folder_drafts', '_bx_cnv_menu_item_title_folder_drafts', 'modules/?r=convos/folder/2', '', '', '', '', 2147483647, 1, 1, 1);
+
+
+-- MENU: notifications
+SET @iMIOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name` = 'sys_account_notifications');
+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_notifications', 'bx_convos', 'notifications-convos', '_bx_cnv_menu_item_title_system_convos', '_bx_cnv_menu_item_title_convos', 'modules/?r=convos/folder/1', '', '', 'comments col-red1', 'a:2:{s:6:"module";s:9:"bx_convos";s:6:"method";s:23:"get_unread_messages_num";}', '', 2147483646, 1, 0, @iMIOrder + 1);
+
+
+-- MENU: profile stats
+
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES
+('sys_profile_stats', 'bx_convos', 'profile-stats-unread-messages', '_bx_cnv_menu_item_title_system_unread_messages', '_bx_cnv_menu_item_title_unread_messages', 'modules/?r=convos/folder/1', '', '', 'comments col-red1', 'a:2:{s:6:"module";s:9:"bx_convos";s:6:"method";s:23:"get_unread_messages_num";}', '', 2147483646, 1, 0, 2);
+
+-- MENU: add menu item to profiles modules actions menu (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_actions', 'bx_convos', 'convos-compose', '_bx_cnv_menu_item_title_system_message', '_bx_cnv_menu_item_title_message', 'page.php?i=start-convo&profiles={profile_id}', '', '', 'envelope', '', 2147483646, 1, 0, 0),
+('trigger_group_view_actions', 'bx_convos', 'convos-compose', '_bx_cnv_menu_item_title_system_message_group', '_bx_cnv_menu_item_title_message_group', 'page.php?i=start-convo&profiles={recipients}', '', '', 'envelope', '', 2147483646, 1, 0, 0);
+
+-- GRID
+
+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_convos', 'Sql', 'SELECT `c`.`id`, `c`.`author`, `c`.`text`, `c`.`added`, `c`.`comments`, `f`.`read_comments`, `last_reply_timestamp`, `last_reply_profile_id`, `cmt`.`cmt_text` FROM `bx_convos_conversations` AS `c` INNER JOIN `bx_convos_conv2folder` AS `f` ON (`c`.`id` = `f`.`conv_id` AND `f`.`folder_id` = {folder_id} AND `f`.`collaborator` = {profile_id}) LEFT JOIN `bx_convos_cmts` AS `cmt` ON (`cmt`.`cmt_id` = `c`.`last_reply_comment_id`)', 'bx_convos_conversations', 'id', 'last_reply_timestamp', '', 10, NULL, 'start', '', 'text', 'auto', 'comments,last_reply_timestamp', 2147483646, 'BxCnvGrid', 'modules/boonex/convos/classes/BxCnvGrid.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `params`, `order`) VALUES
+('bx_convos', 'checkbox', '_sys_select', '2%', '', 1),
+('bx_convos', 'collaborators', '_bx_cnv_field_collaborators', '25%', '', 2),
+('bx_convos', 'last_reply_timestamp', '_bx_cnv_field_preview', '68%', '', 3),
+('bx_convos', 'comments', '_bx_cnv_field_comments', '5%', '', 4);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_convos', 'bulk', 'delete', '_bx_cnv_grid_action_delete', '', 1, 1),
+('bx_convos', 'independent', 'add', '_bx_cnv_grid_action_compose', '', 0, 1);
+
+
+-- ACL
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_convos', 'create entry', NULL, '_bx_cnv_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_convos', 'delete entry', NULL, '_bx_cnv_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_convos', 'view entry', NULL, '_bx_cnv_acl_action_view_entry', '', 1, 0);
+SET @iIdActionEntryView = 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);
+
+
+-- COMMENTS
+INSERT INTO `sys_objects_cmts` (`Name`, `Table`, `CharsPostMin`, `CharsPostMax`, `CharsDisplayMax`, `Nl2br`, `PerView`, `PerViewReplies`, `BrowseType`, `IsBrowseSwitch`, `PostFormPosition`, `NumberOfLevels`, `IsDisplaySwitch`, `IsRatable`, `ViewingThreshold`, `IsOn`, `RootStylePrefix`, `BaseUrl`, `ObjectVote`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES
+('bx_convos', 'bx_convos_cmts', 1, 5000, 1000, 1, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-convo&id={object_id}', '', 'bx_convos_conversations', 'id', 'author', '', 'comments', 'BxCnvCmts', 'modules/boonex/convos/classes/BxCnvCmts.php');
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_convos', 'bx_convos_views_track', '86400', '1', 'bx_convos_conversations', 'id', 'views', '', '');
+
+-- ALERTS
+
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_convos', 'BxCnvAlertsResponse', 'modules/boonex/convos/classes/BxCnvAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('bx_convos', 'commentPost', @iHandler),
+('bx_convos', 'commentRemoved', @iHandler),
+('profile', 'delete', @iHandler);
+
+-- EMAIL TEMPLATES
+
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES
+('bx_convos', '_bx_cnv_email_new_message', 'bx_cnv_new_message', '_bx_cnv_email_new_message_subject', '_bx_cnv_email_new_message_body'),
+('bx_convos', '_bx_cnv_email_new_reply', 'bx_cnv_new_reply', '_bx_cnv_email_new_reply_subject', '_bx_cnv_email_new_reply_body');
+

+ 1 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/source/template/breadcrumb.html

@@ -0,0 +1 @@
+<bx_include_base:../modules/base/text/template/breadcrumb.html />

+ 12 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/source/template/css/main-media-desktop.css

@@ -0,0 +1,12 @@
+@media (min-width:1024px) {
+
+.bx-grid-table .bx-cnv-collaborator {
+    display:inline;
+    display:inline-block;
+}
+
+.bx-grid-table .bx-grid-header-collaborators span {
+    display:inline;
+}
+
+} /* @media end */

+ 12 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/source/template/css/main-media-tablet.css

@@ -0,0 +1,12 @@
+@media (min-width:720px) and (max-width:1024px) {
+
+.bx-grid-table .bx-cnv-collaborator {
+    display:inline;
+    display:inline-block;
+}
+
+.bx-grid-table .bx-grid-header-collaborators span {
+    display:inline;
+}
+
+} /* @media end */

+ 69 - 0
modules/boonex/convos/updates/9.0.0_9.0.1/source/template/css/main.css

@@ -0,0 +1,69 @@
+
+@import url(../../../../base/text/template/css/main.css);
+
+.bx-cnv-collaborators {
+    white-space:nowrap;
+}
+.bx-popup-content .bx-cnv-collaborators {
+    margin-right:0px;
+}
+.bx-cnv-collaborator {
+	display:inline;
+    display:inline-block;
+}
+
+.bx-grid-table .bx-cnv-collaborator,
+.bx-grid-table .bx-grid-header-collaborators span {
+    display:none;
+}
+
+.bx-grid-table .bx-cnv-collaborator-author {
+    display:inline;
+    display:inline-block;
+}
+
+.bx-cnv-preview {
+    position:relative;
+}
+
+.bx-cnv-title {    
+    padding-right:2em;
+    white-space:nowrap;    
+    text-overflow:ellipsis;
+    overflow:hidden;
+}
+
+.bx-cnv-grid-field-label {
+    display:inline-block;
+}
+
+.bx-cnv-preview .bx-cnv-grid-field-label {
+    position: absolute;
+    right: 0;
+    top: 0;
+}
+
+.bx-cnv-grid-field-messages .bx-def-unit-alert-middle {
+    position:static;
+    display:inline-block;
+    vertical-align:middle;
+}
+
+.bx-cnv-grid-field-messages > span {
+    vertical-align:middle;
+}
+
+.bx-cnv-grid-field-messages {
+    white-space:nowrap;
+}
+
+.bx-cnv-preview .bx-def-unit-info {
+    line-height:1.15em;
+}
+
+.bx-cnv-grid-preview div {
+    white-space:nowrap;
+    text-overflow:ellipsis;
+    overflow:hidden;
+    line-height:1.4em;
+}

+ 51 - 0
modules/boonex/groups/updates/9.0.0_9.0.1/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Groups',
+    'version_from' => '9.0.0',
+	'version_to' => '9.0.1',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/groups/updates/update_9.0.0_9.0.1/',
+	'home_uri' => 'groups_update_900_901',
+
+	'module_dir' => 'boonex/groups/',
+	'module_uri' => 'groups',
+
+    'db_prefix' => 'bx_groups_',
+    'class_prefix' => 'BxGroups',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+		'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+		'clear_db_cache' => 1,
+    ),
+
+	/**
+     * Category for language keys.
+     */
+    'language_category' => 'Groups',
+
+	/**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/groups/updates/9.0.0_9.0.1/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+class BxGroupsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+	{
+        parent::__construct($aConfig);
+    }
+}

+ 4 - 0
modules/boonex/groups/updates/9.0.0_9.0.1/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_groups_option_per_page_browse"><![CDATA[Number of items per page]]></string_add>
+</resources>

+ 10 - 0
modules/boonex/groups/updates/9.0.0_9.0.1/install/sql/enable.sql

@@ -0,0 +1,10 @@
+-- SETTINGS
+SET @iCategoryId = (SELECT `id` FROM `sys_options_categories` WHERE `name`='bx_groups' LIMIT 1);
+DELETE FROM `sys_options` WHERE `name` IN ('bx_groups_per_page_browse');
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+('bx_groups_per_page_browse', '20', @iCategoryId, '_bx_groups_option_per_page_browse', 'digit', '', '', '', 11);
+
+
+-- GRIDS
+UPDATE `sys_objects_grid` SET `visible_for_levels`='192' WHERE `object`='bx_groups_administration';
+UPDATE `sys_objects_grid` SET `visible_for_levels`='2147483647' WHERE `object`='bx_groups_common';

+ 21 - 0
modules/boonex/groups/updates/9.0.0_9.0.1/source/classes/BxGroupsPrivacyNotifications.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Groups Groups
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxGroupsPrivacyNotifications extends BxBaseModGroupsPrivacyNotifications
+{
+    function __construct($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_groups';
+        parent::__construct($aOptions, $oTemplate);
+    }
+}
+
+/** @} */

+ 186 - 0
modules/boonex/groups/updates/9.0.0_9.0.1/source/classes/BxGroupsSearchResult.php

@@ -0,0 +1,186 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Groups Groups
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxGroupsSearchResult extends BxBaseModProfileSearchResult
+{
+    function __construct($sMode = '', $aParams = false)
+    {
+        parent::__construct($sMode, $aParams); 
+
+        $this->aCurrent =  array(
+            'name' => 'bx_groups',
+            'module_name' => 'bx_groups',
+            'object_metatags' => 'bx_groups',
+            'title' => _t('_bx_groups_page_title_browse'),
+            'table' => 'sys_profiles',
+            'tableSearch' => 'bx_groups_data',
+            'ownFields' => array(),
+            'searchFields' => array('group_name', 'group_desc'),
+            'restriction' => array(
+        		'account_id' => array('value' => '', 'field' => 'account_id', 'operator' => '='),
+                'perofileStatus' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
+                'perofileType' => array('value' => 'bx_groups', 'field' => 'type', 'operator' => '='),
+                'owner' => array('value' => '', 'field' => 'author', 'operator' => '=', 'table' => 'bx_groups_data'),
+            ),
+            'join' => array (
+                'profile' => array(
+                    'type' => 'INNER',
+                    'table' => 'bx_groups_data',
+                    'mainField' => 'content_id',
+                    'onField' => 'id',
+                    'joinFields' => array('id', 'group_name', 'picture', 'cover', 'added', 'author', 'allow_view_to'),
+                ),
+                'account' => array(
+                    'type' => 'INNER',
+                    'table' => 'sys_accounts',
+                    'mainField' => 'account_id',
+                    'onField' => 'id',
+                    'joinFields' => array(),
+                ),
+            ),
+            'paginate' => array('perPage' => getParam('bx_groups_per_page_browse'), 'start' => 0),
+            'sorting' => 'none',
+            'rss' => array(
+                'title' => '',
+                'link' => '',
+                'image' => '',
+                'profile' => 0,
+                'fields' => array (
+                    'Guid' => 'link',
+                    'Link' => 'link',
+                    'Title' => 'group_name',
+                    'DateTimeUTS' => 'added',
+                    'Desc' => 'group_name',
+                    'Picture' => 'picture',
+                ),
+            ),
+            'ident' => 'id'
+        );
+
+        $this->sFilterName = 'bx_groups_data_filter';
+        $this->oModule = $this->getMain();
+
+        $oJoinedProfile = null;
+        $bProcessConditionsForPrivateContent = true;
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        switch ($sMode) {
+
+            case 'joined_entries':
+                $oJoinedProfile = BxDolProfile::getInstance((int)$aParams['joined_profile']);
+                if (!$oJoinedProfile) {
+                    $this->isError = true;
+                    break;
+                }
+
+                $bProcessConditionsForPrivateContent = false;
+
+                $this->aCurrent['join']['fans'] = array(
+                    'type' => 'INNER',
+                    'table' => 'bx_groups_fans',
+                    'mainField' => 'id',
+                    'onField' => 'content',
+                    'joinFields' => array('initiator'),
+                );
+
+                $this->aCurrent['restriction']['fans'] = array('value' => $oJoinedProfile->id(), 'field' => 'initiator', 'operator' => '=', 'table' => 'bx_groups_fans');
+
+                $this->sBrowseUrl = 'page.php?i=' . $CNF['URI_JOINED_ENTRIES'] . '&profile_id={profile_id}';
+                $this->aCurrent['title'] = _t('_bx_groups_page_title_joined_entries');
+                $this->aCurrent['rss']['link'] = 'modules/?r=groups/rss/' . $sMode . '/' . $oJoinedProfile->id();
+                break;
+
+            case 'connections':
+                if ($this->_setConnectionsConditions($aParams)) {
+                    $bProcessConditionsForPrivateContent = false;
+                    $oProfile = BxDolProfile::getInstance($aParams['profile']);
+                    $oProfile2 = isset($aParams['profile2']) ? BxDolProfile::getInstance($aParams['profile2']) : null;
+
+                    if (isset($aParams['type']) && $aParams['type'] == 'common' && $oProfile && $oProfile2)
+                        $this->aCurrent['title'] = _t('_bx_groups_page_title_browse_connections_mutual', $oProfile->getDisplayName(), $oProfile2->getDisplayName());
+                    elseif ((!isset($aParams['type']) || $aParams['type'] != 'common') && $oProfile)
+                        $this->aCurrent['title'] = _t('_bx_groups_page_title_browse_connections', $oProfile->getDisplayName());
+
+                    $this->aCurrent['rss']['link'] = 'modules/?r=groups/rss/' . $sMode . '/' . $aParams['object'] . '/' . $aParams['type'] . '/' . (int)$aParams['profile'] . '/' . (int)$aParams['profile2'] . '/' . (int)$aParams['mutual'];
+                }
+                break;
+
+            case 'recent':
+                $this->aCurrent['rss']['link'] = 'modules/?r=groups/rss/' . $sMode;
+                $this->aCurrent['title'] = _t('_bx_groups_page_title_browse_recent');
+                $this->aCurrent['sorting'] = 'last';
+                $this->sBrowseUrl = 'page.php?i=groups-home';
+                break;
+
+            case 'top':
+                $this->aCurrent['rss']['link'] = 'modules/?r=groups/rss/' . $sMode;
+                $this->aCurrent['title'] = _t('_bx_groups_page_title_browse_top');
+                $this->aCurrent['sorting'] = 'top';
+                $this->sBrowseUrl = 'page.php?i=groups-top';
+                break;
+
+            case '': // search results
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_groups');
+                $this->aCurrent['paginate']['perPage'] = 5;
+                unset($this->aCurrent['rss']);
+                break;
+
+            default:
+                $this->isError = true;
+        }
+
+        if ($bProcessConditionsForPrivateContent)
+            $this->addConditionsForPrivateContent($CNF, $oJoinedProfile);
+
+        $this->sCenterContentUnitSelector = false;
+    }
+
+    protected function addConditionsForPrivateContent($CNF, $oJoinedProfile) 
+    {
+        // add conditions for private content
+        $oPrivacy = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_VIEW']);
+        $a = $oPrivacy ? $oPrivacy->getContentPublicAsCondition($oJoinedProfile ? $oJoinedProfile->id() : 0, $oPrivacy->getPartiallyVisiblePrivacyGroups()) : array();
+        if (isset($a['restriction']))
+            $this->aCurrent['restriction'] = array_merge($this->aCurrent['restriction'], $a['restriction']);
+        if (isset($a['join']))
+            $this->aCurrent['join'] = array_merge($this->aCurrent['join'], $a['join']);
+
+        $this->setProcessPrivateContent(false);
+    }
+
+    function getAlterOrder()
+    {
+        switch ($this->aCurrent['sorting']) {
+        case 'none':
+            return array('order' => ' ORDER BY `sys_accounts`.`logged` DESC ');
+        case 'top':
+            return array('order' => ' ORDER BY `bx_groups_data`.`views` DESC ');
+        case 'last':
+        default:                        
+            return array('order' => ' ORDER BY `bx_groups_data`.`added` DESC ');
+        }
+    }
+
+    function _getPseud ()
+    {
+        return array(
+            'id' => 'id',
+            'group_name' => 'group_name',
+            'added' => 'added',
+            'author' => 'author',
+            'picture' => 'picture',
+        );
+    }
+}
+
+/** @} */

+ 139 - 0
modules/boonex/groups/updates/9.0.0_9.0.1/source/install/config.php

@@ -0,0 +1,139 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Groups Groups
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_groups',
+    'title' => 'Groups',
+    'note' => 'Basic group profiles functionality.',
+    'version' => '9.0.1',
+    'vendor' => 'BoonEx',
+	'help_url' => 'http://feed.boonex.com/?section={module_name}',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/groups/',
+    'home_uri' => 'groups',
+
+    'db_prefix' => 'bx_groups_',
+    'class_prefix' => 'BxGroups',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Groups',
+
+    /**
+     * Connections.
+     */
+    'connections' => array(
+    	'sys_profiles_friends' => array ('type' => 'profiles'),
+		'sys_profiles_subscriptions' => array ('type' => 'profiles'),
+    ),
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+    	'trigger_profile_view_submenu',
+    	'trigger_group_view_submenu',
+        'trigger_group_view_actions',
+    ),
+
+    /**
+     * Page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_group_view_entry', 
+    ),
+
+    /**
+     * Storages.
+     */
+    'storages' => array(
+    	'bx_groups_pics'
+    ),
+
+	/**
+     * Transcoders.
+     */
+    'transcoders' => array(
+    	'bx_groups_icon', 
+    	'bx_groups_thumb', 
+    	'bx_groups_avatar', 
+    	'bx_groups_picture', 
+    	'bx_groups_cover', 
+    	'bx_groups_cover_thumb'
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_storages' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'process_connections' => 1,
+        'process_deleted_profiles' => 1,
+    	'update_relations' => 1,        
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+    	'process_menu_triggers' => 1,
+    	'process_page_triggers' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'unregister_transcoders' => 1,
+        'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Connections Section
+     */
+    'relations' => array(
+        'bx_timeline',
+        'bx_notifications',
+    ),
+);
+
+/** @} */

+ 277 - 0
modules/boonex/groups/updates/9.0.0_9.0.1/source/install/langs/en.xml

@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+	<string name="_bx_groups"><![CDATA[Groups]]></string>
+
+	<string name="_bx_groups_option_num_connections_quick"><![CDATA[Number of items in friends block]]></string>
+	<string name="_bx_groups_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+	<string name="_bx_groups_option_num_rss"><![CDATA[Number of items in RSS feed]]></string>
+
+	<string name="_bx_groups_form_profile"><![CDATA[Groups]]></string>
+	<string name="_bx_groups_form_profile_display_add"><![CDATA[Add Group]]></string>
+	<string name="_bx_groups_form_profile_display_edit"><![CDATA[Edit Group]]></string>
+	<string name="_bx_groups_form_profile_display_edit_cover"><![CDATA[Edit Cover]]></string>
+	<string name="_bx_groups_form_profile_display_delete"><![CDATA[Delete Group]]></string>
+	<string name="_bx_groups_form_profile_display_view"><![CDATA[View Group]]></string>
+	<string name="_bx_groups_form_profile_display_view_full"><![CDATA[Full View Group]]></string>
+	<string name="_bx_groups_form_profile_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_groups_form_profile_input_sys_join_confirm"><![CDATA[Join confirmation]]></string>
+    <string name="_bx_groups_form_profile_input_join_confirm"><![CDATA[Join confirmation]]></string>
+    <string name="_bx_groups_form_profile_input_sys_allow_view_to"><![CDATA[Privacy]]></string>
+    <string name="_bx_groups_form_profile_input_allow_view_to"><![CDATA[Privacy]]></string>
+    <string name="_bx_groups_form_profile_input_allow_view_to_desc"><![CDATA[Closed - anyone can find the group and see who's in it, only members can see posts. Secret - only members can find the group and see posts.]]></string>
+    <string name="_bx_groups_form_profile_input_sys_initial_members"><![CDATA[Invite Members]]></string>
+    <string name="_bx_groups_form_profile_input_initial_members"><![CDATA[Invite Members]]></string>
+    <string name="_bx_groups_form_profile_input_sys_group_name"><![CDATA[Group Name]]></string>
+    <string name="_bx_groups_form_profile_input_group_name"><![CDATA[Group Name]]></string>
+    <string name="_bx_groups_form_profile_input_group_name_err"><![CDATA[This information is essential. Please, fill in this field.]]></string>
+    <string name="_bx_groups_form_profile_input_sys_group_desc"><![CDATA[Description]]></string>
+    <string name="_bx_groups_form_profile_input_group_desc"><![CDATA[Description]]></string>
+    <string name="_bx_groups_form_profile_input_sys_group_cat"><![CDATA[Category]]></string>
+	<string name="_bx_groups_form_profile_input_group_cat"><![CDATA[Category]]></string>
+    <string name="_bx_groups_form_profile_input_group_cat_err"><![CDATA[Category field is mandatory]]></string>
+	<string name="_bx_groups_form_profile_input_sys_picture"><![CDATA[Group Picture]]></string>
+	<string name="_bx_groups_form_profile_input_picture"><![CDATA[Upload New Group Picture]]></string>
+	<string name="_bx_groups_form_profile_input_picture_err"><![CDATA[Group picture is mandatory.]]></string>
+	<string name="_bx_groups_form_profile_input_sys_cover"><![CDATA[Cover Picture]]></string>
+	<string name="_bx_groups_form_profile_input_cover"><![CDATA[Upload New Cover Picture]]></string>
+	<string name="_bx_groups_form_profile_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+	<string name="_bx_groups_form_profile_input_delete_confirm"><![CDATA[I am sure I want to delete this group]]></string>
+	<string name="_bx_groups_form_profile_input_delete_confirm_info"><![CDATA[This action can not be undone.]]></string>
+	<string name="_bx_groups_form_profile_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete group.]]></string>
+
+	<string name="_bx_groups_acl_action_create_profile"><![CDATA[Create Group]]></string>
+	<string name="_bx_groups_acl_action_delete_profile"><![CDATA[Delete Group]]></string>
+	<string name="_bx_groups_acl_action_view_profile"><![CDATA[View Group]]></string>
+	<string name="_bx_groups_acl_action_edit_any_profile"><![CDATA[Edit Any Group]]></string>
+
+	<string name="_bx_groups_page_title_sys_joined_entries"><![CDATA[Joined Groups]]></string>
+	<string name="_bx_groups_page_title_joined_entries"><![CDATA[Joined Groups]]></string>
+	<string name="_bx_groups_page_title_sys_create_profile"><![CDATA[Create Group]]></string>
+	<string name="_bx_groups_page_title_create_profile"><![CDATA[Create Group]]></string>
+	<string name="_bx_groups_page_title_sys_edit_profile"><![CDATA[Edit Group]]></string>
+	<string name="_bx_groups_page_title_edit_profile"><![CDATA[Edit Group]]></string>
+	<string name="_bx_groups_page_title_sys_edit_profile_cover"><![CDATA[Edit Group Cover]]></string>
+	<string name="_bx_groups_page_title_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+	<string name="_bx_groups_page_title_sys_delete_profile"><![CDATA[Delete Group]]></string>
+	<string name="_bx_groups_page_title_delete_profile"><![CDATA[Delete Group]]></string>
+	<string name="_bx_groups_page_title_sys_view_profile_closed"><![CDATA[View Closed Group]]></string>
+	<string name="_bx_groups_page_title_sys_view_profile"><![CDATA[View Group]]></string>
+	<string name="_bx_groups_page_title_view_profile"><![CDATA[{display_name}]]></string>
+	<string name="_bx_groups_page_title_browse"><![CDATA[Groups]]></string>
+	<string name="_bx_groups_page_title_browse_top"><![CDATA[Top Groups]]></string>
+	<string name="_bx_groups_page_title_browse_recent"><![CDATA[New Groups]]></string>
+	<string name="_bx_groups_page_title_browse_connections"><![CDATA[{0} connections]]></string>
+	<string name="_bx_groups_page_title_browse_connections_mutual"><![CDATA[{0} and {1} mutual connections]]></string>
+	<string name="_bx_groups_page_title_sys_profile_friends"><![CDATA[Friends]]></string>
+	<string name="_bx_groups_page_title_profile_friends"><![CDATA[Friends]]></string>
+	<string name="_bx_groups_page_title_sys_group_fans"><![CDATA[Members]]></string>
+	<string name="_bx_groups_page_title_group_fans"><![CDATA[Members]]></string>
+	<string name="_bx_groups_page_title_sys_profile_info"><![CDATA[Group Info]]></string>
+	<string name="_bx_groups_page_title_profile_info"><![CDATA[Info about {display_name}]]></string>
+	<string name="_bx_groups_page_title_sys_recent"><![CDATA[New Groups]]></string>
+	<string name="_bx_groups_page_title_recent"><![CDATA[New Groups]]></string>
+	<string name="_bx_groups_page_title_sys_manage"><![CDATA[Manage Own Groups]]></string>
+	<string name="_bx_groups_page_title_sys_manage_administration"><![CDATA[Manage All Groups]]></string>
+	<string name="_bx_groups_page_title_manage"><![CDATA[Manage Groups]]></string>
+	<string name="_bx_groups_page_title_sys_top"><![CDATA[Top Groups]]></string>
+	<string name="_bx_groups_page_title_top"><![CDATA[Top Groups]]></string>
+
+	<string name="_bx_groups_page_block_title_sys_joined_entries"><![CDATA[Joined Groups]]></string>
+	<string name="_bx_groups_page_block_title_joined_entries"><![CDATA[Joined Groups]]></string>
+	<string name="_bx_groups_page_block_title_create_profile"><![CDATA[Create Group]]></string>
+	<string name="_bx_groups_page_block_title_edit_profile"><![CDATA[Edit Group]]></string>
+	<string name="_bx_groups_page_block_title_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+	<string name="_bx_groups_page_block_title_delete_profile"><![CDATA[Delete Group]]></string>
+	<string name="_bx_groups_page_block_title_profile_info_link"><![CDATA[About <a href="{profile_link}">{display_name}</a>]]></string>
+	<string name="_bx_groups_page_block_title_profile_info"><![CDATA[Info]]></string>
+	<string name="_bx_groups_page_block_title_system_profile_info"><![CDATA[Info]]></string>
+	<string name="_bx_groups_page_block_title_profile_description"><![CDATA[Description]]></string>
+	<string name="_bx_groups_page_block_title_profile_friends_link"><![CDATA[Friends of <a href="{profile_link}">{display_name}</a>]]></string>
+	<string name="_bx_groups_page_block_title_profile_friends"><![CDATA[Friends]]></string>
+	<string name="_bx_groups_page_block_title_system_profile_friends"><![CDATA[Friends]]></string>
+	<string name="_bx_groups_page_block_title_fans_link"><![CDATA[Members of <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_groups_page_block_title_fans"><![CDATA[Members]]></string>
+	<string name="_bx_groups_page_block_title_system_fans"><![CDATA[Members]]></string>
+	<string name="_bx_groups_page_block_title_profile_actions"><![CDATA[Actions]]></string>
+	<string name="_bx_groups_page_block_title_latest_profiles"><![CDATA[New Groups]]></string>
+	<string name="_bx_groups_page_block_title_system_manage"><![CDATA[Manage Own Groups]]></string>
+	<string name="_bx_groups_page_block_title_system_manage_administration"><![CDATA[Manage All Groups]]></string>
+	<string name="_bx_groups_page_block_title_manage"><![CDATA[Manage Groups]]></string>
+    <string name="_bx_groups_page_block_title_top_profiles"><![CDATA[Top Groups]]></string>
+    <string name="_bx_groups_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+
+    <string name="_bx_groups_page_block_title_categories"><![CDATA[Group categories]]></string>
+
+    <string name="_bx_groups_menu_title_submenu"><![CDATA[Groups Submenu]]></string>
+    <string name="_bx_groups_menu_set_title_submenu"><![CDATA[Groups Submenu]]></string>
+    <string name="_bx_groups_menu_set_title_view_profile_actions"><![CDATA[Group Actions]]></string>
+    <string name="_bx_groups_menu_title_view_profile_actions"><![CDATA[Group Actions]]></string>
+    <string name="_bx_groups_menu_set_title_view_profile_actions_more"><![CDATA[Group More Actions]]></string>
+    <string name="_bx_groups_menu_title_view_profile_actions_more"><![CDATA[Group More Actions]]></string>
+    <string name="_bx_groups_menu_set_title_view_profile_submenu"><![CDATA[View Group Submenu]]></string>
+    <string name="_bx_groups_menu_title_view_profile_submenu"><![CDATA[View Group Submenu]]></string>
+    <string name="_bx_groups_menu_title_view_profile_submenu_cover"><![CDATA[Group Cover Submenu]]></string>
+	<string name="_bx_groups_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_groups_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_groups_menu_item_title_system_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_groups_menu_item_title_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_groups_menu_item_title_system_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_groups_menu_item_title_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_groups_menu_item_title_system_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_groups_menu_item_title_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_groups_menu_item_title_system_edit_profile"><![CDATA[Edit Group]]></string>
+    <string name="_bx_groups_menu_item_title_edit_profile"><![CDATA[Edit Group]]></string>
+    <string name="_bx_groups_menu_item_title_system_delete_profile"><![CDATA[Delete Group]]></string>
+    <string name="_bx_groups_menu_item_title_delete_profile"><![CDATA[Delete Group]]></string>
+    <string name="_bx_groups_menu_item_title_system_delete_account"><![CDATA[Delete Account]]></string>
+    <string name="_bx_groups_menu_item_title_delete_account"><![CDATA[Delete Account]]></string>
+    <string name="_bx_groups_menu_item_title_system_profile_type"><![CDATA[Group]]></string>
+    <string name="_bx_groups_menu_item_title_profile_type"><![CDATA[Group]]></string>
+    <string name="_bx_groups_menu_item_title_system_create_profile"><![CDATA[New Group]]></string>
+    <string name="_bx_groups_menu_item_title_create_profile"><![CDATA[New Group]]></string>
+    <string name="_bx_groups_menu_item_title_system_view_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_groups_menu_item_title_view_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_groups_menu_item_title_system_view_joined_groups"><![CDATA[Groups]]></string>
+    <string name="_bx_groups_menu_item_title_view_joined_groups"><![CDATA[Groups]]></string>
+    <string name="_bx_groups_menu_item_title_system_view_fans"><![CDATA[Members]]></string>
+    <string name="_bx_groups_menu_item_title_view_fans"><![CDATA[Members]]></string>
+    <string name="_bx_groups_menu_item_title_system_view_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_groups_menu_item_title_view_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_groups_menu_item_title_system_view_profile_view"><![CDATA[Group]]></string>
+    <string name="_bx_groups_menu_item_title_view_profile_view"><![CDATA[Group]]></string>
+
+    <string name="_bx_groups_menu_item_title_system_befriend"><![CDATA[Add friend]]></string>
+    <string name="_bx_groups_menu_item_title_befriend"><![CDATA[Add friend]]></string>
+    <string name="_bx_groups_menu_item_title_befriend_sent"><![CDATA[Add friend (requested)]]></string>
+    <string name="_bx_groups_menu_item_title_befriend_confirm"><![CDATA[Accept friend request]]></string>
+    <string name="_bx_groups_menu_item_title_system_unfriend"><![CDATA[Unfriend]]></string>
+    <string name="_bx_groups_menu_item_title_unfriend"><![CDATA[Unfriend]]></string>
+    <string name="_bx_groups_menu_item_title_unfriend_cancel_request"><![CDATA[Cancel friend request]]></string>
+    <string name="_bx_groups_menu_item_title_unfriend_reject_request"><![CDATA[Reject friend request]]></string>
+
+    <string name="_bx_groups_menu_item_title_system_become_fan"><![CDATA[Join Group]]></string>
+    <string name="_bx_groups_menu_item_title_become_fan"><![CDATA[Join Group]]></string>
+    <string name="_bx_groups_menu_item_title_become_fan_sent"><![CDATA[Join Group (requested)]]></string>
+    <string name="_bx_groups_menu_item_title_become_fan_confirm"><![CDATA[Accept Request]]></string>
+    <string name="_bx_groups_menu_item_title_system_leave_group"><![CDATA[Leave Group]]></string>
+    <string name="_bx_groups_menu_item_title_leave_group"><![CDATA[Leave Group]]></string>
+    <string name="_bx_groups_menu_item_title_leave_group_cancel_request"><![CDATA[Cancel Request]]></string>
+    <string name="_bx_groups_menu_item_title_leave_group_reject_request"><![CDATA[Reject Request]]></string>
+
+    <string name="_bx_groups_menu_item_title_system_subscribe"><![CDATA[Subscribe]]></string>
+    <string name="_bx_groups_menu_item_title_subscribe"><![CDATA[Subscribe]]></string>
+    <string name="_bx_groups_menu_item_title_system_unsubscribe"><![CDATA[Unsubscribe]]></string>
+    <string name="_bx_groups_menu_item_title_unsubscribe"><![CDATA[Unsubscribe]]></string>
+    <string name="_bx_groups_menu_item_title_system_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_groups_menu_item_title_more_actions"><![CDATA[]]></string>
+    <string name="_bx_groups_menu_item_title_system_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_groups_menu_item_title_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_groups_menu_item_title_system_friend_requests"><![CDATA[Friend requests number]]></string>
+    <string name="_bx_groups_menu_item_title_friend_requests"><![CDATA[{addon} friend requests]]></string>
+    <string name="_bx_groups_menu_item_title_system_manage_my_groups"><![CDATA[My groups]]></string>
+    <string name="_bx_groups_menu_item_title_manage_my_groups"><![CDATA[{addon} groups]]></string>
+    <string name="_bx_groups_menu_item_title_system_entries_recent"><![CDATA[New]]></string>
+    <string name="_bx_groups_menu_item_title_entries_recent"><![CDATA[New]]></string>
+    <string name="_bx_groups_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_groups_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_groups_menu_item_title_system_entries_home"><![CDATA[Groups]]></string>
+    <string name="_bx_groups_menu_item_title_entries_home"><![CDATA[Groups]]></string>
+    <string name="_bx_groups_menu_item_title_system_admt_groups"><![CDATA[Groups]]></string>
+	<string name="_bx_groups_menu_item_title_admt_groups"><![CDATA[Groups - {addon} unapproved]]></string>
+	<string name="_bx_groups_menu_item_title_manage_my"><![CDATA[My Groups]]></string>
+	<string name="_bx_groups_menu_item_title_manage_all"><![CDATA[All Groups]]></string>
+	<string name="_bx_groups_menu_item_title_system_entries_top"><![CDATA[Top]]></string>
+	<string name="_bx_groups_menu_item_title_entries_top"><![CDATA[Top]]></string>
+
+	<string name="_bx_groups_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+	<string name="_bx_groups_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+	<string name="_bx_groups_grid_filter_item_title_adm_pending"><![CDATA[Pending]]></string>
+	<string name="_bx_groups_grid_filter_item_title_adm_suspended"><![CDATA[Suspended]]></string>
+	<string name="_bx_groups_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_groups_grid_column_title_adm_group_name"><![CDATA[Name]]></string>
+    <string name="_bx_groups_grid_column_title_adm_added"><![CDATA[Created]]></string>
+    <string name="_bx_groups_grid_column_title_adm_account"><![CDATA[Account]]></string>
+    <string name="_bx_groups_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_groups_grid_action_title_adm_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_groups_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+	<string name="_bx_groups_grid_action_err_delete"><![CDATA[Cannot delete the selected group(s).]]></string>
+	<string name="_bx_groups_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_groups_txt_account_pending"><![CDATA[This group is pending approval, please wait until it is activated.]]></string>
+    <string name="_bx_groups_txt_account_suspended"><![CDATA[This group is suspended.]]></string>
+    <string name="_bx_groups_txt_N_fans"><![CDATA[{0} members]]></string>
+    <string name="_bx_groups_txt_sample_single"><![CDATA[group]]></string>
+    <string name="_bx_groups_txt_sample_vote_single"><![CDATA[group's vote]]></string>
+    <string name="_bx_groups_txt_to_admins"><![CDATA[To Admins]]></string>
+    <string name="_bx_groups_txt_from_admins"><![CDATA[From Admins]]></string>
+    <string name="_bx_groups_txt_private_group"><![CDATA[Private group]]></string>
+
+    <string name="_bx_groups_txt_ntfs_fan_added"><![CDATA[<a class="bx-ntfs-content-profile" href="{owner_link}">{owner_name}</a> group has got new member - <a href="{subentry_url}">{subentry_sample}</a>]]></string>
+    <string name="_bx_groups_txt_ntfs_join_request"><![CDATA[<a class="bx-ntfs-content-profile" href="{owner_link}">{owner_name}</a> group has new request from <a href="{subentry_url}">{subentry_sample}</a>]]></string>
+    <string name="_bx_groups_txt_ntfs_timeline_post_common"><![CDATA[New post in <a class="bx-ntfs-content-profile" href="{owner_link}">{owner_name}</a> group timeline  from <a href="{subentry_url}">{subentry_sample}</a>]]></string>
+
+    <string name="_bx_groups_privacy_group_closed"><![CDATA[Closed]]></string>
+    <string name="_bx_groups_privacy_group_secret"><![CDATA[Secret]]></string>
+
+    <string name="_bx_groups_pre_lists_cats"><![CDATA[Group categories]]></string>
+    <string name="_bx_groups_cat_General"><![CDATA[General]]></string>
+    <string name="_bx_groups_cat_Business"><![CDATA[Business]]></string>
+    <string name="_bx_groups_cat_Interests"><![CDATA[Interests]]></string>
+    <string name="_bx_groups_cat_Causes"><![CDATA[Causes]]></string>
+    <string name="_bx_groups_cat_Fun"><![CDATA[Fun]]></string>
+    <string name="_bx_groups_cat_Uncategorised"><![CDATA[Uncategorised]]></string>
+
+    <string name="_bx_groups_email_join_request"><![CDATA[Group join request]]></string>
+    <string name="_bx_groups_email_join_request_subject"><![CDATA[Request to join your group]]></string>
+    <string name="_bx_groups_email_join_request_body"><![CDATA[
+<bx_include_auto:_email_header.html />
+<p>New request to join <a href="{EntryUrl}">{EntryTitle}</a> group from <a href="{NewMemberUrl}">{NewMemberDisplayName}</a></p>
+<bx_include_auto:_email_footer.html />]]></string>
+
+    <string name="_bx_groups_email_join_reject"><![CDATA[Group join request was rejected]]></string>
+    <string name="_bx_groups_email_join_reject_subject"><![CDATA[Request to join a group was rejected]]></string>
+    <string name="_bx_groups_email_join_reject_body"><![CDATA[
+<bx_include_auto:_email_header.html />
+<p>Your request to join <a href="{EntryUrl}">{EntryTitle}</a> group was rejected by group admin.</p>
+<bx_include_auto:_email_footer.html />]]></string>
+
+    <string name="_bx_groups_email_join_confirm"><![CDATA[Group join request was confirmed]]></string>
+    <string name="_bx_groups_email_join_confirm_subject"><![CDATA[Your request to join a group was confirmed]]></string>
+    <string name="_bx_groups_email_join_confirm_body"><![CDATA[
+<bx_include_auto:_email_header.html />
+<p>Your request to join <a href="{EntryUrl}">{EntryTitle}</a> group was confirmed by the group admin.</p>
+<bx_include_auto:_email_footer.html />]]></string>
+
+    <string name="_bx_groups_email_fan_remove"><![CDATA[Profile was removed from group fans]]></string>
+    <string name="_bx_groups_email_fan_remove_subject"><![CDATA[Your profile was removed from the group]]></string>
+    <string name="_bx_groups_email_fan_remove_body"><![CDATA[
+<bx_include_auto:_email_header.html />
+<p>Your profile was removed from <a href="{EntryUrl}">{EntryTitle}</a> group by the group admin.</p>
+<bx_include_auto:_email_footer.html />]]></string>
+
+    <string name="_bx_groups_email_fan_become_admin"><![CDATA[Group admin status was granted]]></string>
+    <string name="_bx_groups_email_fan_become_admin_subject"><![CDATA[You are a group admin now]]></string>
+    <string name="_bx_groups_email_fan_become_admin_body"><![CDATA[
+<bx_include_auto:_email_header.html />
+<p>You are an admin of <a href="{EntryUrl}">{EntryTitle}</a> group now.</p>
+<bx_include_auto:_email_footer.html />]]></string>
+
+    <string name="_bx_groups_email_admin_become_fan"><![CDATA[Group admin status was revoked]]></string>
+    <string name="_bx_groups_email_admin_become_fan_subject"><![CDATA[Your group admin status was revoked]]></string>
+    <string name="_bx_groups_email_admin_become_fan_body"><![CDATA[
+<bx_include_auto:_email_header.html />
+<p>Your admin status was revoked from <a href="{EntryUrl}">{EntryTitle}</a> group.</p>
+<bx_include_auto:_email_footer.html />]]></string>
+
+    <string name="_bx_groups_email_invitation"><![CDATA[Invitation to group]]></string>
+    <string name="_bx_groups_email_invitation_subject"><![CDATA[Invitation to "{EntryTitle}" group]]></string>
+    <string name="_bx_groups_email_invitation_body"><![CDATA[
+<bx_include_auto:_email_header.html />
+<p><a href="{InviterUrl}">{InviterDisplayName}</a> invited you to <a href="{EntryUrl}">{EntryTitle} group</a>.</p>
+<bx_include_auto:_email_footer.html />]]></string>
+
+    <string name="_bx_ntfs_alert_action_fan_added"><![CDATA[member joined]]></string>
+    <string name="_bx_ntfs_alert_action_join_request"><![CDATA[join request]]></string>
+    <string name="_bx_ntfs_alert_action_timeline_post_common"><![CDATA[post to timeline]]></string>
+</resources>

+ 417 - 0
modules/boonex/groups/updates/9.0.0_9.0.1/source/install/sql/enable.sql

@@ -0,0 +1,417 @@
+
+-- 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_groups', '_bx_groups', 'bx_groups@modules/boonex/groups/|std-mi.png', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_groups', '_bx_groups', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+('bx_groups_num_connections_quick', '4', @iCategId, '_bx_groups_option_num_connections_quick', 'digit', '', '', '', 10),
+('bx_groups_per_page_browse', '20', @iCategId, '_bx_groups_option_per_page_browse', 'digit', '', '', '', 11),
+('bx_groups_num_rss', '10', @iCategId, '_bx_groups_option_num_rss', 'digit', '', '', '', 12);
+
+-- PAGES
+
+-- PAGE: create profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_create_profile', 'create-group-profile', '_bx_groups_page_title_sys_create_profile', '_bx_groups_page_title_create_profile', 'bx_groups', 5, 2147483647, 1, 'page.php?i=create-group-profile', '', '', '', 0, 1, 0, '', '');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_groups_create_profile', 1, 'bx_groups', '_bx_groups_page_block_title_create_profile', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:13:\"entity_create\";}', 0, 1, 1);
+
+-- PAGE: view profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_view_profile', 'view-group-profile', '_bx_groups_page_title_sys_view_profile', '_bx_groups_page_title_view_profile', 'bx_groups', 10, 2147483647, 1, 'page.php?i=view-group-profile', '', '', '', 0, 1, 0, 'BxGroupsPageEntry', 'modules/boonex/groups/classes/BxGroupsPageEntry.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_groups_view_profile', 1, 'bx_groups', '', '_bx_groups_page_block_title_entry_social_sharing', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:21:\"entity_social_sharing\";}', 0, 0, 1, 0),
+('bx_groups_view_profile', 2, 'bx_groups', '', '_bx_groups_page_block_title_profile_info', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:11:\"entity_info\";}', 0, 0, 1, 0),
+('bx_groups_view_profile', 3, 'bx_groups', '', '_bx_groups_page_block_title_fans', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:4:\"fans\";}', 0, 0, 1, 0),
+('bx_groups_view_profile', 4, 'bx_groups', '', '_bx_groups_page_block_title_profile_description', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:17:\"entity_text_block\";}', 0, 0, 1, 0);
+
+-- PAGE: view closed profile 
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_view_profile_closed', 'view-group-profile-closed', '_bx_groups_page_title_sys_view_profile_closed', '_bx_groups_page_title_view_profile', 'bx_groups', 10, 2147483647, 1, 'page.php?i=view-group-profile', '', '', '', 0, 1, 0, 'BxGroupsPageEntry', 'modules/boonex/groups/classes/BxGroupsPageEntry.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_groups_view_profile_closed', 2, 'bx_groups', '', '_bx_groups_page_block_title_profile_info', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:11:\"entity_info\";}', 0, 0, 1, 0),
+('bx_groups_view_profile_closed', 3, 'bx_groups', '', '_bx_groups_page_block_title_fans', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:4:\"fans\";}', 0, 0, 1, 0);
+
+-- PAGE: edit profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_edit_profile', 'edit-group-profile', '_bx_groups_page_title_sys_edit_profile', '_bx_groups_page_title_edit_profile', 'bx_groups', 5, 2147483647, 1, 'page.php?i=edit-group-profile', '', '', '', 0, 1, 0, 'BxGroupsPageEntry', 'modules/boonex/groups/classes/BxGroupsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_groups_edit_profile', 1, 'bx_groups', '_bx_groups_page_block_title_edit_profile', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:11:\"entity_edit\";}', 0, 0, 0);
+
+-- PAGE: edit profile cover
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_edit_profile_cover', 'edit-group-cover', '_bx_groups_page_title_sys_edit_profile_cover', '_bx_groups_page_title_edit_profile_cover', 'bx_groups', 5, 2147483647, 1, 'page.php?i=edit-group-cover', '', '', '', 0, 1, 0, 'BxGroupsPageEntry', 'modules/boonex/groups/classes/BxGroupsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_groups_edit_profile_cover', 1, 'bx_groups', '_bx_groups_page_block_title_edit_profile_cover', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:17:\"entity_edit_cover\";}', 0, 0, 0);
+
+-- PAGE: delete profile
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_delete_profile', 'delete-group-profile', '_bx_groups_page_title_sys_delete_profile', '_bx_groups_page_title_delete_profile', 'bx_groups', 5, 2147483647, 1, 'page.php?i=delete-group-profile', '', '', '', 0, 1, 0, 'BxGroupsPageEntry', 'modules/boonex/groups/classes/BxGroupsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_groups_delete_profile', 1, 'bx_groups', '_bx_groups_page_block_title_delete_profile', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:13:\"entity_delete\";}', 0, 0, 0);
+
+-- PAGE: profile info
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_profile_info', 'group-profile-info', '_bx_groups_page_title_sys_profile_info', '_bx_groups_page_title_profile_info', 'bx_groups', 5, 2147483647, 1, 'page.php?i=group-profile-info', '', '', '', 0, 1, 0, 'BxGroupsPageEntry', 'modules/boonex/groups/classes/BxGroupsPageEntry.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_groups_profile_info', 1, 'bx_groups', '_bx_groups_page_block_title_system_profile_info', '_bx_groups_page_block_title_profile_info_link', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:16:\"entity_info_full\";}', 0, 0, 1, 1),
+('bx_groups_profile_info', 1, 'bx_groups', '', '_bx_groups_page_block_title_profile_description', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:17:\"entity_text_block\";}', 0, 0, 1, 2);
+
+-- PAGE: group fans
+
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_fans', 'group-fans', '_bx_groups_page_title_sys_group_fans', '_bx_groups_page_title_group_fans', 'bx_groups', 5, 2147483647, 1, 'page.php?i=group-fans', '', '', '', 0, 1, 0, 'BxGroupsPageEntry', 'modules/boonex/groups/classes/BxGroupsPageEntry.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_groups_fans', 1, 'bx_groups', '_bx_groups_page_block_title_system_fans', '_bx_groups_page_block_title_fans_link', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_groups";s:6:"method";s:10:"fans_table";}', 0, 0, 1, 1);
+
+-- PAGE: module home
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_home', '_bx_groups_page_title_sys_recent', '_bx_groups_page_title_recent', 'bx_groups', 5, 2147483647, 1, 'groups-home', 'page.php?i=groups-home', '', '', '', 0, 1, 0, 'BxGroupsPageBrowse', 'modules/boonex/groups/classes/BxGroupsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_groups_home', 1, 'bx_groups', '_bx_groups_page_block_title_latest_profiles', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:22:\"browse_recent_profiles\";s:6:"params";a:1:{i:0;b:1;}}', 0, 1, 0);
+
+-- PAGE: top profiles
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_top', '_bx_groups_page_title_sys_top', '_bx_groups_page_title_top', 'bx_groups', 5, 2147483647, 1, 'groups-top', 'page.php?i=groups-top', '', '', '', 0, 1, 0, 'BxGroupsPageBrowse', 'modules/boonex/groups/classes/BxGroupsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_groups_top', 1, 'bx_groups', '_bx_groups_page_block_title_top_profiles', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:19:\"browse_top_profiles\";s:6:"params";a:1:{i:0;b:1;}}', 0, 1, 0);
+
+-- PAGE: module manage own
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_manage', '_bx_groups_page_title_sys_manage', '_bx_groups_page_title_manage', 'bx_groups', 5, 2147483647, 1, 'groups-manage', 'page.php?i=groups-manage', '', '', '', 0, 1, 0, 'BxGroupsPageBrowse', 'modules/boonex/groups/classes/BxGroupsPageBrowse.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_groups_manage', 1, 'bx_groups', '_bx_groups_page_block_title_system_manage', '_bx_groups_page_block_title_manage', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_groups\";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_groups_administration', '_bx_groups_page_title_sys_manage_administration', '_bx_groups_page_title_manage', 'bx_groups', 5, 192, 1, 'groups-administration', 'page.php?i=groups-administration', '', '', '', 0, 1, 0, 'BxGroupsPageBrowse', 'modules/boonex/groups/classes/BxGroupsPageBrowse.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_groups_administration', 1, 'bx_groups', '_bx_groups_page_block_title_system_manage_administration', '_bx_groups_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_groups\";s:6:\"method\";s:12:\"manage_tools\";s:6:\"params\";a:1:{i:0;s:14:\"administration\";}}', 0, 1, 0);
+
+-- PAGE: user's groups
+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_groups_joined', 'joined-groups', '_bx_groups_page_title_sys_joined_entries', '_bx_groups_page_title_joined_entries', 'bx_groups', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxGroupsPageJoinedEntries', 'modules/boonex/groups/classes/BxGroupsPageJoinedEntries.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_groups_joined', 1, 'bx_groups', '_bx_groups_page_block_title_sys_joined_entries', '_bx_groups_page_block_title_joined_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_groups";s:6:"method";s:21:"browse_joined_entries";s:6:"params";a:2:{i:0;i:0;i:1;b:1;}}', 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_groups', '_bx_groups_page_block_title_latest_profiles', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_groups";s:6:"method";s:22:"browse_recent_profiles";}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1);
+
+-- 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_groups', '', '_bx_groups_page_block_title_categories', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:15:"categories_list";s:6:"params";a:2:{i:0;s:14:"bx_groups_cats";i:1;a:2:{s:10:\"show_empty\";b:1;s:21:\"show_empty_categories\";b:1;}}s:5:"class";s:20:"TemplServiceCategory";}', 1, 1, 1, IFNULL(@iBlockOrder, 0) + 1);
+
+
+-- MENU
+
+-- MENU: add to site menu
+
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' 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_site', 'bx_groups', 'groups-home', '_bx_groups_menu_item_title_system_entries_home', '_bx_groups_menu_item_title_entries_home', 'page.php?i=groups-home', '', '', 'group col-red2', 'bx_groups_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_groups', 'groups-home', '_bx_groups_menu_item_title_system_entries_home', '_bx_groups_menu_item_title_entries_home', 'page.php?i=groups-home', '', '', 'group col-red2', 'bx_groups_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_groups', 'create-group-profile', '_bx_groups_menu_item_title_system_create_profile', '_bx_groups_menu_item_title_create_profile', 'page.php?i=create-group-profile', '', '', 'group col-red2', '', 2147483647, 1, 1, IFNULL(@iAddMenuOrder, 0) + 1);
+
+-- MENU: view actions
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_view_actions', '_bx_groups_menu_title_view_profile_actions', 'bx_groups_view_actions', 'bx_groups', 9, 0, 1, 'BxGroupsMenuView', 'modules/boonex/groups/classes/BxGroupsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_groups_view_actions', 'bx_groups', '_bx_groups_menu_set_title_view_profile_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_groups_view_actions', 'bx_groups', 'profile-fan-add', '_bx_groups_menu_item_title_system_become_fan', '{title_add_fan}', 'javascript:void(0)', 'bx_conn_action(this, \'bx_groups_fans\', \'add\', \'{profile_id}\')', '', 'user-plus', '', 0, 2147483647, 1, 0, 5),
+('bx_groups_view_actions', 'bx_groups', 'profile-subscribe-add', '_bx_groups_menu_item_title_system_subscribe', '_bx_groups_menu_item_title_subscribe', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_subscriptions\', \'add\', \'{profile_id}\')', '', 'check', '', 0, 2147483647, 1, 0, 20),
+('bx_groups_view_actions', 'bx_groups', 'profile-actions-more', '_bx_groups_menu_item_title_system_more_actions', '_bx_groups_menu_item_title_more_actions', 'javascript:void(0)', 'bx_menu_popup(''bx_groups_view_actions_more'', this, {}, {profile_id:{profile_id}});', '', 'cog', 'bx_groups_view_actions_more', 1, 2147483647, 1, 0, 9999);
+
+-- MENU: view actions more
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_view_actions_more', '_bx_groups_menu_title_view_profile_actions_more', 'bx_groups_view_actions_more', 'bx_groups', 6, 0, 1, 'BxGroupsMenuView', 'modules/boonex/groups/classes/BxGroupsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_groups_view_actions_more', 'bx_groups', '_bx_groups_menu_set_title_view_profile_actions_more', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_groups_view_actions_more', 'bx_groups', 'profile-fan-remove', '_bx_groups_menu_item_title_system_leave_group', '{title_remove_fan}', 'javascript:void(0)', 'bx_conn_action(this, \'bx_groups_fans\', \'remove\', \'{profile_id}\')', '', 'user-times', '', 2147483647, 1, 0, 10),
+('bx_groups_view_actions_more', 'bx_groups', 'profile-subscribe-remove', '_bx_groups_menu_item_title_system_unsubscribe', '_bx_groups_menu_item_title_unsubscribe', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_subscriptions\', \'remove\', \'{profile_id}\')', '', 'check', '', 2147483647, 1, 0, 20),
+('bx_groups_view_actions_more', 'bx_groups', 'edit-group-cover', '_bx_groups_menu_item_title_system_edit_cover', '_bx_groups_menu_item_title_edit_cover', 'page.php?i=edit-group-cover&id={content_id}', '', '', 'pencil', '', 2147483647, 1, 0, 30),
+('bx_groups_view_actions_more', 'bx_groups', 'edit-group-profile', '_bx_groups_menu_item_title_system_edit_profile', '_bx_groups_menu_item_title_edit_profile', 'page.php?i=edit-group-profile&id={content_id}', '', '', 'pencil', '', 2147483647, 1, 0, 40),
+('bx_groups_view_actions_more', 'bx_groups', 'delete-group-profile', '_bx_groups_menu_item_title_system_delete_profile', '_bx_groups_menu_item_title_delete_profile', 'page.php?i=delete-group-profile&id={content_id}', '', '', 'remove', '', 2147483647, 1, 0, 50);
+
+-- 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_groups_submenu', '_bx_groups_menu_title_submenu', 'bx_groups_submenu', 'bx_groups', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_groups_submenu', 'bx_groups', '_bx_groups_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_groups_submenu', 'bx_groups', 'groups-home', '_bx_groups_menu_item_title_system_entries_recent', '_bx_groups_menu_item_title_entries_recent', 'page.php?i=groups-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_groups_submenu', 'bx_groups', 'groups-top', '_bx_groups_menu_item_title_system_entries_top', '_bx_groups_menu_item_title_entries_top', 'page.php?i=groups-top', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_groups_submenu', 'bx_groups', 'groups-manage', '_bx_groups_menu_item_title_system_entries_manage', '_bx_groups_menu_item_title_entries_manage', 'page.php?i=groups-manage', '', '', '', '', 2147483646, 1, 1, 3);
+
+-- MENU: view submenu
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_groups_view_submenu', '_bx_groups_menu_title_view_profile_submenu', 'bx_groups_view_submenu', 'bx_groups', 8, 0, 1, 'BxGroupsMenuView', 'modules/boonex/groups/classes/BxGroupsMenuView.php'),
+('bx_groups_view_submenu_cover', '_bx_groups_menu_title_view_profile_submenu_cover', 'bx_groups_view_submenu', 'bx_groups', 7, 0, 1, 'BxGroupsMenuView', 'modules/boonex/groups/classes/BxGroupsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_groups_view_submenu', 'bx_groups', '_bx_groups_menu_set_title_view_profile_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_groups_view_submenu', 'bx_groups', 'view-group-profile', '_bx_groups_menu_item_title_system_view_profile_view', '_bx_groups_menu_item_title_view_profile_view', 'page.php?i=view-group-profile&id={content_id}', '', '', 'group col-red2', '', 2147483647, 1, 0, 1),
+('bx_groups_view_submenu', 'bx_groups', 'group-profile-info', '_bx_groups_menu_item_title_system_view_profile_info', '_bx_groups_menu_item_title_view_profile_info', 'page.php?i=group-profile-info&id={content_id}', '', '', 'info-circle col-gray', '', 2147483647, 1, 0, 2),
+('bx_groups_view_submenu', 'bx_groups', 'group-fans', '_bx_groups_menu_item_title_system_view_fans', '_bx_groups_menu_item_title_view_fans', 'page.php?i=group-fans&profile_id={profile_id}', '', '', 'group col-blue3', '', 2147483647, 1, 0, 3);
+
+-- 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_groups', 'profile-stats-manage-groups', '_bx_groups_menu_item_title_system_manage_my_groups', '_bx_groups_menu_item_title_manage_my_groups', 'page.php?i=groups-manage', '', '_self', 'group col-red2', 'a:2:{s:6:"module";s:9:"bx_groups";s:6:"method";s:41:"get_menu_addon_manage_tools_profile_stats";}', '', 2147483646, 1, 0, @iNotifMenuOrder + 2);
+
+-- 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_groups_menu_manage_tools', '_bx_groups_menu_title_manage_tools', 'bx_groups_menu_manage_tools', 'bx_groups', 6, 0, 1, 'BxGroupsMenuManageTools', 'modules/boonex/groups/classes/BxGroupsMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_groups_menu_manage_tools', 'bx_groups', '_bx_groups_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_groups_menu_manage_tools', 'bx_groups', 'delete', '_bx_groups_menu_item_title_system_delete', '_bx_groups_menu_item_title_delete', 'javascript:void(0)', 'javascript:{js_object}.onClickDelete({content_id});', '_self', 'trash-o', '', 2147483647, 1, 0, 1),
+('bx_groups_menu_manage_tools', 'bx_groups', 'delete-with-content', '_bx_groups_menu_item_title_system_delete_with_content', '_bx_groups_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'trash-o', '', 2147483647, 1, 0, 2);
+
+-- MENU: dashboard manage tools
+SET @iManageMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard_manage_tools' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_account_dashboard_manage_tools', 'bx_groups', 'groups-administration', '_bx_groups_menu_item_title_system_admt_groups', '_bx_groups_menu_item_title_admt_groups', 'page.php?i=groups-administration', '', '_self', '', 'a:2:{s:6:"module";s:9:"bx_groups";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_groups', 'joined-groups', '_bx_groups_menu_item_title_system_view_joined_groups', '_bx_groups_menu_item_title_view_joined_groups', 'page.php?i=joined-groups&profile_id={profile_id}', '', '', 'group col-red2', '', 2147483647, 1, 0, 0);
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_groups', 'create entry', NULL, '_bx_groups_acl_action_create_profile', '', 1, 1);
+SET @iIdActionProfileCreate = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_groups', 'delete entry', NULL, '_bx_groups_acl_action_delete_profile', '', 1, 1);
+SET @iIdActionProfileDelete = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_groups', 'view entry', NULL, '_bx_groups_acl_action_view_profile', '', 1, 0);
+SET @iIdActionProfileView = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_groups', 'edit any entry', NULL, '_bx_groups_acl_action_edit_any_profile', '', 1, 3);
+SET @iIdActionProfileEditAny = LAST_INSERT_ID();
+
+SET @iUnauthenticated = 1;
+SET @iAccount = 2;
+SET @iStandard = 3;
+SET @iUnconfirmed = 4;
+SET @iPending = 5;
+SET @iSuspended = 6;
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+
+-- profile create
+(@iAccount, @iIdActionProfileCreate),
+(@iStandard, @iIdActionProfileCreate),
+(@iUnconfirmed, @iIdActionProfileCreate),
+(@iPending, @iIdActionProfileCreate),
+(@iModerator, @iIdActionProfileCreate),
+(@iAdministrator, @iIdActionProfileCreate),
+(@iPremium, @iIdActionProfileCreate),
+
+-- profile delete
+(@iAccount, @iIdActionProfileDelete),
+(@iStandard, @iIdActionProfileDelete),
+(@iUnconfirmed, @iIdActionProfileDelete),
+(@iPending, @iIdActionProfileDelete),
+(@iModerator, @iIdActionProfileDelete),
+(@iAdministrator, @iIdActionProfileDelete),
+(@iPremium, @iIdActionProfileDelete),
+
+-- profile view
+(@iUnauthenticated, @iIdActionProfileView),
+(@iAccount, @iIdActionProfileView),
+(@iStandard, @iIdActionProfileView),
+(@iUnconfirmed, @iIdActionProfileView),
+(@iPending, @iIdActionProfileView),
+(@iModerator, @iIdActionProfileView),
+(@iAdministrator, @iIdActionProfileView),
+(@iPremium, @iIdActionProfileView),
+
+-- any profile edit
+(@iModerator, @iIdActionProfileEditAny),
+(@iAdministrator, @iIdActionProfileEditAny);
+
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_groups', 'bx_groups_views_track', '86400', '1', 'bx_groups_data', 'id', 'views', '', '');
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_groups', 'bx_groups_votes', 'bx_groups_votes_track', '604800', '1', '1', '0', '1', 'bx_groups_data', 'id', 'author', 'rate', 'votes', '', '');
+
+-- REPORTS
+INSERT INTO `sys_objects_report` (`name`, `table_main`, `table_track`, `is_on`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_groups', 'bx_groups_reports', 'bx_groups_reports_track', '1', 'page.php?i=view-group-profile&id={object_id}', 'bx_groups_data', 'id', 'author', 'reports', '', '');
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_groups', 'bx_groups_meta_keywords', '', '', '', '');
+
+-- CATEGORY
+INSERT INTO `sys_objects_category` (`object`, `search_object`, `form_object`, `list_name`, `table`, `field`, `join`, `where`, `override_class_name`, `override_class_file`) VALUES
+('bx_groups_cats', 'bx_groups', 'bx_group', 'bx_groups_cats', 'bx_groups_data', 'group_cat', 'INNER JOIN `sys_profiles` ON (`sys_profiles`.`content_id` = `bx_groups_data`.`id` AND `sys_profiles`.`type` = ''bx_groups'')', 'AND `sys_profiles`.`status` = ''active''', '', '');
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+('bx_groups', '_bx_groups', @iSearchOrder + 1, 'BxGroupsSearchResult', 'modules/boonex/groups/classes/BxGroupsSearchResult.php');
+
+-- CONNECTIONS
+INSERT INTO `sys_objects_connection` (`object`, `table`, `type`, `override_class_name`, `override_class_file`) VALUES
+('bx_groups_fans', 'bx_groups_fans', 'mutual', '', '');
+
+-- GRID: connections
+
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_groups_fans', 'Sql', 'SELECT `p`.`id`, `c`.`added`, `c`.`mutual` FROM `sys_profiles` AS `p` INNER JOIN `sys_accounts` AS `a` ON (`a`.`id` = `p`.`account_id`) {join_connections}', 'sys_profiles', 'id', 'c`.`added', '', '', 10, NULL, 'start', '', 'name,email', '', 'auto', '', '', 2147483647, 'BxGroupsGridConnections', 'modules/boonex/groups/classes/BxGroupsGridConnections.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `params`, `order`) VALUES
+('bx_groups_fans', 'name', '_sys_name', '50%', '', 10),
+('bx_groups_fans', 'actions', '', '50%', '', 20);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_groups_fans', 'single', 'accept', '_sys_accept', '', 0, 10),
+('bx_groups_fans', 'single', 'to_admins', '_bx_groups_txt_to_admins', '', 0, 20),
+('bx_groups_fans', 'single', 'from_admins', '_bx_groups_txt_from_admins', '', 0, 30),
+('bx_groups_fans', 'single', 'delete', '', 'remove', 1, 40);
+
+-- GRIDS: administration
+
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_groups_administration', 'Sql', 'SELECT `td`.*, `ta`.`email` AS `account`, `td`.`added` AS `added_ts`, `tp`.`status` AS `status` FROM `bx_groups_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id`=`tp`.`content_id` AND `tp`.`type`=''bx_groups'' LEFT JOIN `sys_accounts` AS `ta` ON `tp`.`account_id`=`ta`.`id` WHERE 1 ', 'bx_groups_data', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'group_name', '', 'like', '', '', 192, 'BxGroupsGridAdministration', 'modules/boonex/groups/classes/BxGroupsGridAdministration.php'),
+('bx_groups_common', 'Sql', 'SELECT `td`.*, `ta`.`email` AS `account`, `ta`.`added` AS `added_ts`, `tp`.`status` AS `status` FROM `bx_groups_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id`=`tp`.`content_id` AND `tp`.`type`=''bx_groups'' LEFT JOIN `sys_accounts` AS `ta` ON `tp`.`account_id`=`ta`.`id` WHERE 1 ', 'bx_groups_data', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'group_name', '', 'like', '', '', 2147483647, 'BxGroupsGridCommon', 'modules/boonex/groups/classes/BxGroupsGridCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_groups_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_groups_administration', 'switcher', '_bx_groups_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_groups_administration', 'group_name', '_bx_groups_grid_column_title_adm_group_name', '25%', 0, '', '', 3),
+('bx_groups_administration', 'added_ts', '_bx_groups_grid_column_title_adm_added', '20%', 1, '25', '', 4),
+('bx_groups_administration', 'account', '_bx_groups_grid_column_title_adm_account', '25%', 0, '25', '', 5),
+('bx_groups_administration', 'actions', '', '20%', 0, '', '', 6),
+('bx_groups_common', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_groups_common', 'group_name', '_bx_groups_grid_column_title_adm_group_name', '48%', 0, '', '', 2),
+('bx_groups_common', 'added_ts', '_bx_groups_grid_column_title_adm_added', '30%', 1, '25', '', 3),
+('bx_groups_common', 'actions', '', '20%', 0, '', '', 4);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_groups_administration', 'bulk', 'delete', '_bx_groups_grid_action_title_adm_delete', '', 0, 1, 2),
+('bx_groups_administration', 'bulk', 'delete_with_content', '_bx_groups_grid_action_title_adm_delete_with_content', '', 0, 1, 3),
+('bx_groups_administration', 'single', 'settings', '_bx_groups_grid_action_title_adm_more_actions', 'cog', 1, 0, 2),
+('bx_groups_common', 'bulk', 'delete', '_bx_groups_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_groups_common', 'bulk', 'delete_with_content', '_bx_groups_grid_action_title_adm_delete_with_content', '', 0, 1, 2),
+('bx_groups_common', 'single', 'settings', '_bx_groups_grid_action_title_adm_more_actions', 'cog', 1, 0, 1);
+
+
+-- ALERTS
+
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_groups', 'BxGroupsAlertsResponse', 'modules/boonex/groups/classes/BxGroupsAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('bx_timeline', 'post_common', @iHandler),
+('bx_groups_pics', 'file_deleted', @iHandler),
+('bx_groups_fans', 'connection_added', @iHandler),
+('bx_groups_fans', 'connection_removed', @iHandler),
+('profile', 'delete', @iHandler),
+('bx_groups', 'fan_added', @iHandler),
+('bx_groups', 'join_invitation', @iHandler),
+('bx_groups', 'join_request', @iHandler),
+('bx_groups', 'join_request_accepted', @iHandler),
+('bx_groups', 'timeline_view', @iHandler),
+('bx_groups', 'timeline_post', @iHandler),
+('bx_groups', 'timeline_delete', @iHandler),
+('bx_groups', 'timeline_comment', @iHandler),
+('bx_groups', 'timeline_vote', @iHandler),
+('bx_groups', 'timeline_report', @iHandler),
+('bx_groups', 'timeline_share', @iHandler);
+
+-- 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_groups_allow_view_to', 'bx_groups', 'view', '_bx_groups_form_profile_input_allow_view_to', '3', 'bx_groups_data', 'id', 'author', 'BxGroupsPrivacy', 'modules/boonex/groups/classes/BxGroupsPrivacy.php'),
+('bx_groups_allow_view_notification_to', 'bx_groups', 'view_event', '_bx_groups_form_profile_input_allow_view_notification_to', '3', 'bx_notifications_events', 'id', 'object_owner_id', 'BxGroupsPrivacyNotifications', 'modules/boonex/groups/classes/BxGroupsPrivacyNotifications.php');
+
+-- EMAIL TEMPLATES
+
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES
+('bx_groups', '_bx_groups_email_join_request', 'bx_groups_join_request', '_bx_groups_email_join_request_subject', '_bx_groups_email_join_request_body'),
+('bx_groups', '_bx_groups_email_join_reject', 'bx_groups_join_reject', '_bx_groups_email_join_reject_subject', '_bx_groups_email_join_reject_body'),
+('bx_groups', '_bx_groups_email_join_confirm', 'bx_groups_join_confirm', '_bx_groups_email_join_confirm_subject', '_bx_groups_email_join_confirm_body'),
+('bx_groups', '_bx_groups_email_fan_remove', 'bx_groups_fan_remove', '_bx_groups_email_fan_remove_subject', '_bx_groups_email_fan_remove_body'),
+('bx_groups', '_bx_groups_email_fan_become_admin', 'bx_groups_fan_become_admin', '_bx_groups_email_fan_become_admin_subject', '_bx_groups_email_fan_become_admin_body'),
+('bx_groups', '_bx_groups_email_admin_become_fan', 'bx_groups_admin_become_fan', '_bx_groups_email_admin_become_fan_subject', '_bx_groups_email_admin_become_fan_body'),
+('bx_groups', '_bx_groups_email_invitation', 'bx_groups_invitation', '_bx_groups_email_invitation_subject', '_bx_groups_email_invitation_body');
+
+-- UPLOADERS
+
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_groups_cover_crop', 1, 'BxGroupsUploaderCoverCrop', 'modules/boonex/groups/classes/BxGroupsUploaderCoverCrop.php'),
+('bx_groups_picture_crop', 1, 'BxGroupsUploaderPictureCrop', 'modules/boonex/groups/classes/BxGroupsUploaderPictureCrop.php');
+

+ 51 - 0
modules/boonex/invites/updates/9.0.0_9.0.1/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Invitations',
+    'version_from' => '9.0.0',
+	'version_to' => '9.0.1',
+    'vendor' => 'BoonEx',
+
+	'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/invites/updates/update_9.0.0_9.0.1/',
+	'home_uri' => 'invites_update_900_901',
+
+	'module_dir' => 'boonex/invites/',
+	'module_uri' => 'invites',
+
+    'db_prefix' => 'bx_inv_',
+    'class_prefix' => 'BxInv',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+		'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 0,
+		'clear_db_cache' => 1,
+    ),
+
+	/**
+     * Category for language keys.
+     */
+    'language_category' => 'Invitations',
+
+	/**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 39 - 0
modules/boonex/invites/updates/9.0.0_9.0.1/install/installer.php

@@ -0,0 +1,39 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+class BxInvUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+	{
+        parent::__construct($aConfig);
+    }
+
+	public function actionExecuteSql($sOperation)
+    {
+    	if($sOperation == 'install') {
+    		if(!$this->oDb->isFieldExists('bx_inv_invites', 'key'))
+        		$this->oDb->query("ALTER TABLE `bx_inv_invites` ADD `key` varchar(128) collate utf8_unicode_ci NOT NULL AFTER `profile_id`");
+
+			$sFile = BX_DIRECTORY_PATH_TMP . $this->_aConfig['home_uri'] . '_processed.txt';
+			if(!file_exists($sFile)) {
+				$aEntries = $this->oDb->getAll('SELECT * FROM `bx_inv_requests`');
+				foreach($aEntries as $aEntry)
+					$this->oDb->query('UPDATE `bx_inv_requests` SET `text`=:text WHERE `id`=:id', array(
+						'text' => nl2br(htmlspecialchars_adv($aEntry['text'])), 
+						'id' => $aEntry['id']
+					));
+
+				$oHandler = fopen($sFile, 'w');
+				if($oHandler) {
+					fwrite($oHandler, 'processed');
+					fclose($oHandler);
+				}
+			}
+		}
+
+    	return parent::actionExecuteSql($sOperation);
+    }
+}

+ 5 - 0
modules/boonex/invites/updates/9.0.0_9.0.1/install/sql/install.sql

@@ -0,0 +1,5 @@
+SET @sName = 'bx_invites';
+
+
+-- GRIDS
+UPDATE `sys_objects_grid` SET `visible_for_levels`='192' WHERE `object`='bx_invites_requests';

+ 70 - 0
modules/boonex/invites/updates/9.0.0_9.0.1/source/install/config.php

@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Invites Invites
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_invites',
+    'title' => 'Invitations',
+    'note' => 'Invitations module.',
+    'version' => '9.0.1',
+    'vendor' => 'BoonEx',
+	'help_url' => 'http://feed.boonex.com/?section={module_name}',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/invites/',
+    'home_uri' => 'invites',
+
+    'db_prefix' => 'bx_inv_',
+    'class_prefix' => 'BxInv',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Invitations',
+
+    /**
+     * 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(),
+);
+
+/** @} */

+ 93 - 0
modules/boonex/invites/updates/9.0.0_9.0.1/source/install/sql/install.sql

@@ -0,0 +1,93 @@
+SET @sName = 'bx_invites';
+
+
+-- TABLES
+CREATE TABLE IF NOT EXISTS `bx_inv_invites` (
+  `id` int(11) NOT NULL auto_increment,
+  `account_id` int(11) collate utf8_unicode_ci NOT NULL,
+  `profile_id` int(11) collate utf8_unicode_ci NOT NULL,
+  `key` varchar(128) collate utf8_unicode_ci NOT NULL,
+  `email` varchar(128) collate utf8_unicode_ci NOT NULL,
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY  (`id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_inv_requests` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(255) collate utf8_unicode_ci NOT NULL,
+  `email` varchar(128) collate utf8_unicode_ci NOT NULL,
+  `text` text collate utf8_unicode_ci NOT NULL,
+  `nip` int(11) unsigned NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY  (`id`)
+);
+
+
+-- 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_invites_invite', @sName, '_bx_invites_form_invite', '', '', 'do_submit', 'bx_inv_invites', 'id', '', '', 'a:1:{s:14:"checker_helper";s:22:"BxInvFormCheckerHelper";}', 0, 1, '', '');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_invites_invite_send', @sName, 'bx_invites_invite', '_bx_invites_form_invite_display_send', 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_invites_invite', @sName, 'emails', '', '', 0, 'textarea', '_bx_invites_form_invite_input_sys_emails', '_bx_invites_form_invite_input_emails', '_bx_invites_form_invite_input_emails_inf', 1, 0, 0, '', '', '', 'Emails', '', '_bx_invites_form_invite_input_emails_err', '', '', 0, 0),
+('bx_invites_invite', @sName, 'text', '', '', 0, 'textarea', '_bx_invites_form_invite_input_sys_text', '_bx_invites_form_invite_input_text', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:10;s:3:"max";i:5000;}', '_bx_invites_form_invite_input_text_err', '', '', 0, 0),
+('bx_invites_invite', @sName, 'do_submit', '_bx_invites_form_invite_input_do_submit', '', 0, 'submit', '_bx_invites_form_invite_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_invites_invite_send', 'emails', 2147483647, 1, 1),
+('bx_invites_invite_send', 'text', 2147483647, 1, 2),
+('bx_invites_invite_send', 'do_submit', 2147483647, 1, 3);
+
+
+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_invites_request', @sName, '_bx_invites_form_request', '', '', 'do_submit', 'bx_inv_requests', 'id', '', '', '', 0, 1, '', '');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_invites_request_send', @sName, 'bx_invites_request', '_bx_invites_form_request_display_send', 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_invites_request', @sName, 'name', '', '', 0, 'text', '_bx_invites_form_request_input_sys_name', '_bx_invites_form_request_input_name', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:1;s:3:"max";i:150;}', '_bx_invites_form_request_input_name_err', 'Xss', '', 0, 0),
+('bx_invites_request', @sName, 'email', '', '', 0, 'text', '_bx_invites_form_request_input_sys_email', '_bx_invites_form_request_input_email', '', 1, 0, 0, '', '', '', 'Email', '', '_bx_invites_form_request_input_email_err', 'Xss', '', 0, 0),
+('bx_invites_request', @sName, 'text', '', '', 0, 'textarea', '_bx_invites_form_request_input_sys_text', '_bx_invites_form_request_input_text', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:10;s:3:"max";i:5000;}', '_bx_invites_form_request_input_text_err', 'Xss', '', 0, 0),
+('bx_invites_request', @sName, 'do_submit', '_bx_invites_form_request_input_do_submit', '', 0, 'submit', '_bx_invites_form_request_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_invites_request_send', 'name', 2147483647, 1, 1),
+('bx_invites_request_send', 'email', 2147483647, 1, 2),
+('bx_invites_request_send', 'text', 2147483647, 1, 3),
+('bx_invites_request_send', 'do_submit', 2147483647, 1, 4);
+
+
+-- 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_invites_requests', 'Sql', 'SELECT * FROM `bx_inv_requests` WHERE 1 ', 'bx_inv_requests', 'id', '', '', '', 20, NULL, 'start', '', 'name,email', '', 'like', '', '', 192, 'BxInvGridRequests', 'modules/boonex/invites/classes/BxInvGridRequests.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_invites_requests', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_invites_requests', 'name', '_bx_invites_grid_column_title_name', '20%', 0, '', '', 2),
+('bx_invites_requests', 'email', '_bx_invites_grid_column_title_email', '20%', 1, '25', '', 3),
+('bx_invites_requests', 'nip', '_bx_invites_grid_column_title_nip', '15%', 0, '15', '', 4),
+('bx_invites_requests', 'date', '_bx_invites_grid_column_title_date', '20%', 0, '20', '', 5),
+('bx_invites_requests', 'actions', '', '23%', 0, '', '', 6);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_invites_requests', 'bulk', 'invite', '_bx_invites_grid_action_title_adm_invite', '', 0, 0, 1),
+('bx_invites_requests', 'bulk', 'delete', '_bx_invites_grid_action_title_adm_delete', '', 0, 1, 2),
+('bx_invites_requests', 'single', 'info', '_bx_invites_grid_action_title_adm_info', 'exclamation-circle', 1, 0, 1),
+('bx_invites_requests', 'single', 'invite', '_bx_invites_grid_action_title_adm_invite', 'envelope', 1, 0, 2),
+('bx_invites_requests', 'single', 'delete', '_bx_invites_grid_action_title_adm_delete', 'remove', 1, 1, 3);
+
+
+-- STUDIO PAGE & WIDGET
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, @sName, '_bx_invites', '_bx_invites', 'bx_invites@modules/boonex/invites/|std-pi.png');
+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`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, @sName, '{url_studio}module.php?name=bx_invites', '', 'bx_invites@modules/boonex/invites/|std-wi.png', '_bx_invites', '', '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));

+ 32 - 0
modules/boonex/invites/updates/9.0.0_9.0.1/source/template/css/main.css

@@ -0,0 +1,32 @@
+/*--- Invite block ---*/
+div.bx-inv-invite-btn  {
+	text-align: center;
+}
+div.bx-inv-invite-btn .bx-btn {
+	float: none;
+	display: inline-block;
+}
+
+
+/*--- Invitation Link popup ---*/
+div.bx-inv-link-actions {
+	text-align: center;
+}
+div.bx-inv-link-actions .bx-btn {
+	float: none;
+	display: inline-block;
+}
+
+
+/*--- Request Invite block ---*/
+div.bx-inv-request-btn  .bx-btn {
+	float: none;
+	display: inline-block;
+}
+
+
+/*--- Manage Requests page ---*/
+div.bx-inv-request-text {
+	max-width: 400px;
+	max-width: 25rem;
+}

+ 52 - 0
modules/boonex/notifications/updates/9.0.0_9.0.1/install/config.php

@@ -0,0 +1,52 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Notifications',
+    'version_from' => '9.0.0',
+	'version_to' => '9.0.1',
+    'vendor' => 'BoonEx',
+
+	'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/notifications/updates/update_9.0.0_9.0.1/',
+	'home_uri' => 'notifications_update_900_901',
+
+	'module_dir' => 'boonex/notifications/',
+	'module_uri' => 'notifications',
+
+    'db_prefix' => 'bx_notifications_',
+    'class_prefix' => 'BxNtfs',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+		'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+		'update_relations_for_all' => 1,
+		'clear_db_cache' => 1,
+    ),
+
+	/**
+     * Category for language keys.
+     */
+    'language_category' => 'Notifications',
+
+	/**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 50 - 0
modules/boonex/notifications/updates/9.0.0_9.0.1/install/installer.php

@@ -0,0 +1,50 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+class BxNtfsUpdater extends BxDolStudioUpdater
+{
+	protected $_aModule;
+
+    function __construct($aConfig)
+	{
+        parent::__construct($aConfig);
+
+        $this->_aModule = $this->oDb->getModuleByUri($this->_aConfig['module_uri']);
+    }
+
+	public function actionExecuteSql($sOperation)
+    {
+    	if($sOperation == 'install') {
+    		if(!$this->oDb->isFieldExists('bx_notifications_events', 'object_owner_id'))
+        		$this->oDb->query("ALTER TABLE `bx_notifications_events` ADD `object_owner_id` int(11) unsigned NOT NULL default '0' AFTER `object_id`");
+
+			if(!$this->oDb->isFieldExists('bx_notifications_events', 'allow_view_event_to'))
+        		$this->oDb->query("ALTER TABLE `bx_notifications_events` ADD `allow_view_event_to` varchar(32) NOT NULL default '3' AFTER `content`");
+
+			if(!$this->oDb->isFieldExists('bx_notifications_handlers', 'privacy'))
+        		$this->oDb->query("ALTER TABLE `bx_notifications_handlers` ADD `privacy` varchar(64) NOT NULL default '' AFTER `content`");
+		}
+
+    	return parent::actionExecuteSql($sOperation);
+    }
+
+	protected function actionClearDbCache($sOperation)
+    {
+    	if($sOperation == 'install') {
+	    	$aModules = $this->oDb->getModulesBy(array('type' => 'all', 'active' => 1));
+		    foreach($aModules as $aModule) {
+		    	$aConfig = self::getModuleConfig($aModule);
+				if(empty($aConfig['relations']) || !is_array($aConfig['relations']) || !in_array($this->_aModule['name'], $aConfig['relations'])) 
+					continue;	
+
+				BxDolService::call($this->_aModule['name'], 'delete_handlers', array($aModule['uri']));
+				BxDolService::call($this->_aModule['name'], 'add_handlers', array($aModule['uri']));
+			}
+    	}
+
+    	return parent::actionClearDbCache($sOperation);
+    }
+}

+ 82 - 0
modules/boonex/notifications/updates/9.0.0_9.0.1/source/install/config.php

@@ -0,0 +1,82 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Notifications Notifications
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_notifications',
+    'title' => 'Notifications',
+    'note' => 'Notifications module.',
+    'version' => '9.0.1',
+    'vendor' => 'BoonEx',
+	'help_url' => 'http://feed.boonex.com/?section={module_name}',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/notifications/',
+    'home_uri' => 'notifications',
+
+    'db_prefix' => 'bx_notifications_',
+    'class_prefix' => 'BxNtfs',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Notifications',
+
+    /**
+     * 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,
+    	'update_relations_for_all' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'update_relations_for_all' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Relations Section
+     */
+    'relation_handlers' => array(
+    	'on_install' => '',
+    	'on_uninstall' => 'delete_module_events',
+	    'on_enable' => 'add_handlers',
+	    'on_disable' => 'delete_handlers',
+    ),
+);
+
+/** @} */

+ 30 - 0
modules/boonex/notifications/updates/9.0.0_9.0.1/source/install/sql/disable.sql

@@ -0,0 +1,30 @@
+SET @sName = 'bx_notifications';
+
+
+-- PAGES & BLOCKS
+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;
+
+
+-- 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;
+
+
+-- PRIVACY 
+DELETE FROM `sys_objects_privacy` 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;

+ 56 - 0
modules/boonex/notifications/updates/9.0.0_9.0.1/source/install/sql/enable.sql

@@ -0,0 +1,56 @@
+SET @sName = 'bx_notifications';
+
+
+-- PAGES & BLOCKS
+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_notifications_view', '_bx_ntfs_page_title_system_view', '_bx_ntfs_page_title_view', @sName, 5, 2147483647, 1, 'notifications-view', 'page.php?i=notifications-view', '', '', '', 0, 1, 0, 'BxNtfsPageView', 'modules/boonex/notifications/classes/BxNtfsPageView.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_notifications_view', 1, @sName, '_bx_ntfs_page_block_title_view', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:14:"get_block_view";}', 0, 1, 1);
+
+
+-- MENU: module sub-menu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_notifications_submenu', '_bx_ntfs_menu_title_submenu', 'bx_notifications_submenu', @sName, 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_notifications_submenu', @sName, '_bx_ntfs_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_notifications_submenu', @sName, 'notifications-all', '_bx_ntfs_menu_item_title_system_notifications_all', '_bx_ntfs_menu_item_title_notifications_all', 'page.php?i=notifications-view', '', '', '', '', 2147483647, 1, 0, 1);
+
+-- MENU: Notifications
+SET @iMIOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name` = 'sys_account_notifications');
+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_notifications', @sName, 'notifications-notifications', '_bx_ntfs_menu_item_title_system_notifications', '_bx_ntfs_menu_item_title_notifications', 'page.php?i=notifications-view', '', '', 'bell col-green3', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:28:"get_unread_notifications_num";}', '', 2147483646, 1, 0, @iMIOrder + 1);
+
+
+-- SETTINGS
+SET @iTypeOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_options_types` WHERE `group` = 'modules');
+INSERT INTO `sys_options_types`(`group`, `name`, `caption`, `icon`, `order`) VALUES 
+('modules', @sName, '_bx_ntfs', 'bx_notifications@modules/boonex/notifications/|std-mi.png', @iTypeOrder + 1);
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, @sName, '_bx_ntfs', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_notifications_events_per_page', '10', @iCategId, '_bx_ntfs_option_events_per_page', 'digit', '', '', '', '', 1),
+('bx_notifications_events_hide', '', @iCategId, '_bx_ntfs_option_events_hide', 'rlist', '', '', '', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:21:"get_actions_checklist";}', 2);
+
+
+-- 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_notifications_privacy_view', @sName, 'view', '_bx_notifications_privacy_view', '3', 'bx_notifications_events', 'id', 'owner_id', 'BxNtfsPrivacy', 'modules/boonex/notifications/classes/BxNtfsPrivacy.php');
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers`(`name`, `class`, `file`, `service_call`) VALUES 
+(@sName, 'BxNtfsResponse', 'modules/boonex/notifications/classes/BxNtfsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('profile', 'delete', @iHandler),
+('sys_profiles_subscriptions', 'connection_added', @iHandler),
+('sys_profiles_subscriptions', 'connection_removed', @iHandler);

+ 51 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'OAuth2 Server',
+    'version_from' => '9.0.0',
+	'version_to' => '9.0.1',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/oauth2/updates/update_9.0.0_9.0.1/',
+	'home_uri' => 'oauth2_update_900_901',
+
+	'module_dir' => 'boonex/oauth2/',
+	'module_uri' => 'oauth2',
+
+    'db_prefix' => 'bx_oauth_',
+    'class_prefix' => 'BxOAuth',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+		'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+		'clear_db_cache' => 1,
+    ),
+
+	/**
+     * Category for language keys.
+     */
+    'language_category' => 'OAuth2 Server',
+
+	/**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 23 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/install/installer.php

@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+class BxOAuthUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+	{
+        parent::__construct($aConfig);
+    }
+
+	public function actionExecuteSql($sOperation)
+    {
+    	if($sOperation == 'install') {
+    		if(!$this->oDb->isFieldExists('bx_oauth_clients', 'parent_id'))
+        		$this->oDb->query("ALTER TABLE `bx_oauth_clients` ADD `parent_id` int(10) unsigned DEFAULT 0 AFTER `scope`");
+    	}
+
+    	return parent::actionExecuteSql($sOperation);
+    }
+}

+ 5 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/install/langs/en.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_oauth_form_valid_url"><![CDATA[Valid URL is required]]></string_add>
+    <string_add name="_bx_oauth_url"><![CDATA[URL]]></string_add>
+</resources>

+ 8 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/install/sql/enable.sql

@@ -0,0 +1,8 @@
+-- GRIDS
+UPDATE `sys_grid_fields` SET `width`='20%' WHERE `object`='bx_oauth' AND `name`='title';
+UPDATE `sys_grid_fields` SET `width`='15%' WHERE `object`='bx_oauth' AND `name`='client_id';
+UPDATE `sys_grid_fields` SET `width`='30%' WHERE `object`='bx_oauth' AND `name`='client_secret';
+
+DELETE FROM `sys_grid_fields` WHERE `object`='bx_oauth' AND `name`='redirect_uri';
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `params`, `order`) VALUES
+('bx_oauth', 'redirect_uri', '_bx_oauth_url', '33%', '', 50);

+ 6 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/install/sql/install.sql

@@ -0,0 +1,6 @@
+-- TABLES
+ALTER TABLE `bx_oauth_clients` CHANGE `user_id` `user_id` INT( 10 ) UNSIGNED NULL DEFAULT '0';
+
+
+DELETE FROM `bx_oauth_scopes` WHERE `scope` = 'market';
+INSERT INTO `bx_oauth_scopes` (`scope`, `is_default`) VALUES ('market', 0);

+ 177 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/source/classes/BxOAuthAPI.php

@@ -0,0 +1,177 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    OAuth2 OAuth2 server
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+use OAuth2\Response;
+
+class BxOAuthAPI extends BxDol
+{
+    protected $_oModule;
+    protected $_oDb;
+    public $aAction2Scope = array (
+        'me' => 'basic,market',
+        'user' => 'basic',
+        'friends' => 'basic',
+        'service' => 'service',
+        'market' => 'market',
+    );
+
+    function __construct($oModule)
+    {
+        $this->_oModule = $oModule;
+        $this->_oDb = $oModule->_oDb;
+    }
+    
+    function me($aToken)
+    {        
+        if (!($oProfile = BxDolProfile::getInstance($aToken['user_id']))) {
+            $this->errorOutput('404', 'not_found', 'Profile was not found');
+            return;
+        }
+    
+        $this->output($this->_prepareProfileArray($oProfile, false));
+    }
+
+    function user($aToken)
+    {
+        $iProfileId = (int)bx_get('id');
+
+        if ($iProfileId == $aToken['user_id']) {
+            $this->me($aToken);
+            return;
+        }
+
+        if (!($oProfile = $this->_getProfileWithAccessChecking($iProfileId)))
+            return;
+        
+        $this->output($this->_prepareProfileArray($oProfile, !isAdmin($aToken['user_id'])));
+    }
+
+    function friends($aToken)
+    {
+        $iProfileId = (int)bx_get('id');
+
+        if (!($oProfile = $this->_getProfileWithAccessChecking($iProfileId)))
+            return;
+
+        $this->output(array(
+            'user_id' => $iProfileId,
+            'friends' => getMyFriendsEx($iProfileId),
+        ));
+    }
+
+    function market($aToken) 
+    {
+    	$_GET['key'] = $_POST['key'] = $aToken['client_id'];
+        $_GET['module'] = $_POST['module'] = 'bx_market_api';
+        $this->service($aToken);
+    }
+
+    /**
+     * Service call should look like this
+     * http://example.com/m/oauth2/api/service?module=bx_market&method=test&params[]=1&params[]=abc&class=custom_class_name_or_remove_it_if_module_class
+     * or
+     * http://example.com/m/oauth2/api/service?module=bx_market&method=test&params=serialized_string_of_params
+     */ 
+    function service($aToken) 
+    {
+        bx_login($aToken['user_id'], false, false);
+
+        $sModule = bx_get('module');
+        $sMethod = bx_get('method');
+
+        if (!($aParams = bx_get('params')))
+            $aParams = array();
+        elseif (is_string($aParams) && preg_match('/^a:[\d+]:\{/', $aParams))
+            $aParams = @unserialize($aParams);
+        if (!is_array($aParams))
+            $aParams = array($aParams);
+
+        if (!($sClass = bx_get('class')))
+            $sClass = 'Module';
+
+        if (!BxDolRequest::serviceExists($sModule, $sMethod, $sClass)) {
+            $this->errorOutput(404, 'not_found', 'Service was not found');
+            return false;
+        }
+
+        $mixedRet = BxDolService::call($sModule, $sMethod, $aParams, $sClass);
+
+        $this->output(array(
+            'module' => $sModule,
+            'method' => $sMethod,
+            'data' => $mixedRet,
+        ));
+    }
+
+    function errorOutput($iHttpCode, $sError, $sErrorDesc)
+    {
+        $oReponse = new Response();
+        $oReponse->setError($iHttpCode, $sError, $sErrorDesc);
+        $oReponse->send();
+    }
+
+    function output($a)
+    {
+        $oReponse = new Response();
+        $oReponse->setParameters($a);
+        $oReponse->send();
+    }
+
+    protected function _getProfileWithAccessChecking ($iProfileId) 
+    {
+        if (!$oProfile = BxDolProfile::getInstance($iProfileId)) {
+            $this->errorOutput('404', 'not_found', 'Profile was not found');
+            return false;
+        }
+/*        
+        // TODO: check visibility
+        if (!bx_check_profile_visibility($iProfileId, $aToken['user_id'], true)) {
+            $this->errorOutput(403, 'access_denied', 'You have no rights to view this user info');
+            return false;
+        }
+*/
+        return $oProfile;
+    }
+
+    protected function _prepareProfileArray ($oProfile, $bPublicFieldsOnly = true) 
+    {
+        $oAccount = $oProfile->getAccountObject();
+        $aProfileInfo = $oProfile->getInfo();
+        $aAccountInfo = $oAccount->getInfo();
+
+        if ($bPublicFieldsOnly) {
+            $aProfileInfo = array(
+                'id' => $aProfileInfo['id'],
+            );
+        } 
+        else {
+            unset($aProfileInfo['account_id']);
+            unset($aProfileInfo['content_id']);
+            unset($aProfileInfo['status']);
+
+            $aProfileInfo['email'] = $oAccount->getEmail();
+
+            // TODO: fetch extended info from profile module
+        }
+
+
+        $aProfileInfo['role'] = $aAccountInfo['role'];
+        $aProfileInfo['name'] = $oAccount->getDisplayName();
+        $aProfileInfo['profile_display_name'] = $oProfile->getDisplayName();
+        $aProfileInfo['profile_link'] = $oProfile->getUrl();
+        $aProfileInfo['picture'] = $oProfile->getPicture();
+
+        return $aProfileInfo;
+    }
+
+}
+
+/** @} */

+ 102 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/source/classes/BxOAuthDb.php

@@ -0,0 +1,102 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    OAuth2 OAuth2 server
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxOAuthDb extends BxDolModuleDb
+{
+    function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+    }
+
+	function getClientsBy($aParams = array())
+    {
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        switch($aParams['type']) {
+            case 'client_id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                	'client_id' => $aParams['client_id']
+                );
+
+                $sWhereClause .= "AND `tc`.`client_id`=:client_id";
+                $sLimitClause .= "LIMIT 1";
+                break;
+
+			case 'parent_id':
+                $aMethod['params'][1] = array(
+                	'parent_id' => $aParams['parent_id']
+                );
+
+                $sWhereClause .= "AND `tc`.`parent_id`=:parent_id";
+                break;
+
+            case 'user_id':
+                $aMethod['params'][1] = array(
+                	'user_id' => $aParams['user_id']
+                );
+
+                $sWhereClause .= "AND `tc`.`user_id`=:user_id";
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT * " . $sSelectClause . "
+            FROM `bx_oauth_clients` AS `tc` " . $sJoinClause . "
+            WHERE 1 " . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    function getClientTitle($sClientId)
+    {
+        $sQuery = $this->prepare("SELECT `title` FROM `bx_oauth_clients` WHERE `client_id` = ?", $sClientId);
+        return $this->getOne($sQuery);
+    }
+
+	function addClient($aClient)
+    {
+        $mixedResult = $this->query("INSERT INTO `bx_oauth_clients` SET " . $this->arrayToSQL($aClient));
+        return (int)$mixedResult > 0 ? $this->lastId() : false;
+    }
+
+	function updateClientsBy($aPrmSet, $aPrmWhere)
+    {
+    	if(empty($aPrmSet) || !is_array($aPrmSet) || empty($aPrmWhere) || !is_array($aPrmWhere))
+    		return false;
+
+        return (int)$this->query("UPDATE `bx_oauth_clients` SET " . $this->arrayToSQL($aPrmSet) . " WHERE " . $this->arrayToSQL($aPrmWhere, ' AND ')) > 0;
+    }
+
+    function deleteClients($aClients)
+    {        
+        foreach ($aClients as $sClientId) {
+            $sQuery = $this->prepare("DELETE FROM `bx_oauth_clients` WHERE `client_id` = ?", $sClientId);
+            $this->query($sQuery);
+        }
+    }
+
+	function deleteClientsBy($aParams)
+    {
+    	if(empty($aParams) || !is_array($aParams))
+    		return false;
+
+        return $this->query("DELETE FROM `bx_oauth_clients` WHERE " . $this->arrayToSQL($aParams, ' AND '));
+    }
+
+    function getSavedProfile($aProfiles)
+    {
+        $aIds = array_keys($aProfiles);
+        return $this->getOne("SELECT `user_id` FROM `bx_oauth_refresh_tokens` WHERE `user_id` IN (" . $this->implode_escape($aIds) . ") LIMIT 1");
+    }
+
+}
+
+/** @} */

+ 100 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/source/classes/BxOAuthFormAdd.php

@@ -0,0 +1,100 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    OAuth2 OAuth2 server
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxOAuthFormAdd extends BxTemplFormView
+{
+     protected static $LENGTH_ID = 10;
+     protected static $LENGTH_SECRET = 32;
+
+    function __construct ($oModule)
+    {
+        $aCustomForm = array(
+
+            'form_attrs' => array(
+                'id' => 'bx-oauth-add',
+                'name' => 'bx-oauth-add',
+                'action' => BX_DOL_URL_ROOT . 'grid.php?' . bx_encode_url_params($_GET, array('ids', '_r')),
+                'method' => 'post',
+            ),
+
+            'params' => array (
+                'db' => array(
+                    'table' => 'bx_oauth_clients',
+                    'key' => 'id',
+                    'submit_name' => 'client_add',
+                ),
+            ),
+
+            'inputs' => array(
+
+                'title' => array(
+                    'type' => 'text',
+                    'name' => 'title',
+                    'caption' => _t('_Title'),
+                    'required' => true,
+                    'checker' => array (
+                        'func' => 'avail',
+                        'error' => _t ('_sys_form_account_input_name_error'),
+                    ),
+                    'db' => array (
+                        'pass' => 'Xss',
+                    ),
+                ),
+
+                'redirect_uri' => array(
+                    'type' => 'text',
+                    'name' => 'redirect_uri',
+                    'caption' => _t('_bx_oauth_client_url'),
+                    'required' => true,
+                    'checker' => array (
+                        'func' => 'preg',
+                        'params' => array('/^https?:\/\//'),
+                        'error' => _t ('_bx_oauth_form_valid_url'),
+                    ),
+                    'db' => array (
+                        'pass' => 'Xss',
+                    ),
+                ),
+
+                'Submit' => array (
+                    'type' => 'input_set',
+                    0 => array (
+                        'type' => 'submit',
+                        'name' => 'client_add',
+                        'value' => _t('_Submit'),
+                    ),
+                    1 => array (
+                        'type' => 'reset',
+                        'name' => 'close',
+                        'value' => _t('Close'),
+                        'attrs' => array(
+                            'onclick' => "$('.bx-popup-active').dolPopupHide()",
+                            'class' => 'bx-def-margin-sec-left',
+                        ),
+                    ),
+                ),
+            ),
+        );
+
+        parent::__construct ($aCustomForm);
+    }
+
+    function insert ($aValsToAdd = array(), $isIgnore = false)
+    {
+        $aValsToAdd['client_id'] = strtolower(genRndPwd(self::$LENGTH_ID, false));
+        $aValsToAdd['client_secret'] = strtolower(genRndPwd(self::$LENGTH_SECRET, false));
+        $aValsToAdd['scope'] = 'basic';
+        $aValsToAdd['user_id'] = bx_get_logged_profile_id();
+        return parent::insert($aValsToAdd, $isIgnore);
+    }
+}
+
+/** @} */

+ 83 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/source/classes/BxOAuthGrid.php

@@ -0,0 +1,83 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    OAuth2 OAuth2 server
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxOAuthGrid extends BxTemplGrid
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+    }
+
+    /**
+     * add js file for AJAX form submission
+     */
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+        $this->_oTemplate->addJs('jquery.form.min.js');
+
+        $oForm = new BxTemplFormView(array());
+        $oForm->addCssJs();
+    }
+
+	protected function _isVisibleGrid ($a)
+    {
+        return isAdmin();
+    }
+
+    /**
+     * 'add' action handler
+     */
+    public function performActionAdd()
+    {
+        $oModule = BxDolModule::getInstance('bx_oauth');
+
+        bx_import('FormAdd', $oModule->_aModule);
+        $oForm = new BxOAuthFormAdd($oModule);
+        $oForm->initChecker();
+
+        if ($oForm->isSubmittedAndValid()) { // if form is submitted and all fields are valid
+
+            $iNewId = $oForm->insert (array(), true); // insert record to database
+            if ($iNewId)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iNewId); // if record is successfully added, reload grid and highlight added row
+            else
+                $aRes = array('msg' => _t('_error occured')); // if record adding failed, display error message
+
+            echoJson($aRes);
+
+        } else { // if form is not submitted or some fields are invalid, display popup with form
+
+            // we need to use 'transBox' function to properly display 'popup'
+            $s = BxTemplFunctions::getInstance()->transBox('', '
+                <div class="bx-def-padding bx-def-color-bg-block">' . $oForm->getCode() . '</div>
+                <script>
+                    $(document).ready(function () {
+                        $("#bx-oauth-add").ajaxForm({
+                            dataType: "json",
+                            beforeSubmit: function (formData, jqForm, options) {
+                                bx_loading($("#' . $oForm->aFormAttrs['id'] . '"), true);
+                            },
+                            success: function (data) {
+                                $(".bx-popup-active").dolPopupHide();
+                                glGrids.' . $this->_sObject . '.processJson(data, "add");
+                            }
+                        });
+                    });
+                </script>');
+
+            echoJson(array('popup' => array('html' => $s, 'options' => array('closeOnOuterClick' => false))));
+
+        }
+    }
+}
+
+/** @} */

+ 171 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/source/classes/BxOAuthModule.php

@@ -0,0 +1,171 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    OAuth2 OAuth2 server
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+require_once (BX_DIRECTORY_PATH_PLUGINS . 'OAuth2/Autoloader.php');
+OAuth2\Autoloader::register();
+
+class BxOAuthModule extends BxDolModule
+{
+    protected $_oStorage;
+    protected $_oServer;
+    protected $_oAPI;
+
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+
+        $aConfig = array (
+            'client_table' => 'bx_oauth_clients',
+            'access_token_table' => 'bx_oauth_access_tokens',
+            'refresh_token_table' => 'bx_oauth_refresh_tokens',
+            'code_table' => 'bx_oauth_authorization_codes',
+            'user_table' => 'Profiles',
+            'jwt_table'  => '',
+            'jti_table'  => '',
+            'scope_table'  => 'bx_oauth_scopes',
+            'public_key_table'  => '',
+        );
+
+        $this->_oStorage = new OAuth2\Storage\Pdo(BxDolDb::getLink(), $aConfig);
+
+        $this->_oServer = new OAuth2\Server($this->_oStorage, array(
+            'require_exact_redirect_uri' => false,
+            'refresh_token_lifetime' => 7776000, // set lifetime to 90 days
+        ));
+
+        // Add the "Client Credentials" grant type (it is the simplest of the grant types)
+        $this->_oServer->addGrantType(new OAuth2\GrantType\ClientCredentials($this->_oStorage));
+
+        // Add the "Authorization Code" grant type (this is where the oauth magic happens)
+        $this->_oServer->addGrantType(new OAuth2\GrantType\AuthorizationCode($this->_oStorage));
+    }
+
+    function actionToken ()
+    {
+        // Handle a request for an OAuth2.0 Access Token and send the response to the client
+        $this->_oServer->handleTokenRequest(OAuth2\Request::createFromGlobals())->send();
+    }
+
+    function actionApi ($sAction)
+    {
+        // Handle a request to a resource and authenticate the access token
+        if (!$this->_oServer->verifyResourceRequest(OAuth2\Request::createFromGlobals())) {
+            $this->_oServer->getResponse()->send();
+            return;
+        }
+
+        $aToken = $this->_oServer->getAccessTokenData(OAuth2\Request::createFromGlobals());
+
+        if (!$this->_oAPI) {
+            bx_import('API', $this->_aModule);
+            $this->_oAPI = new BxOAuthAPI($this);
+        }
+
+        if (!$sAction || !method_exists($this->_oAPI, $sAction) || 0 == strcasecmp('errorOutput', $sAction) || 0 == strcasecmp('output', $sAction)) {
+            $this->_oAPI->errorOutput(404, 'not_found', 'No such API endpoint available');
+            return;
+        }
+
+        $sScope = $this->_oAPI->aAction2Scope[$sAction];
+        if (false === strpos($sScope, $aToken['scope'])) {
+            $this->_oAPI->errorOutput(403, 'insufficient_scope', 'The request requires higher privileges than provided by the access token');
+            return;
+        }
+
+        $this->_oAPI->$sAction($aToken);
+    }
+
+    function actionAuth ()
+    {
+        $oRequest = OAuth2\Request::createFromGlobals();
+        $oResponse = new OAuth2\Response();
+
+        // validate the authorize request
+        if (!$this->_oServer->validateAuthorizeRequest($oRequest, $oResponse)) {
+            require_once(BX_DIRECTORY_PATH_INC . 'design.inc.php');
+            $o = json_decode($oResponse->getResponseBody());
+            $this->_oTemplate->getPage(false, MsgBox($o->error_description));
+        }
+
+        if (!isLogged()) {
+            require_once(BX_DIRECTORY_PATH_INC . 'design.inc.php');
+            $sForceRelocate = BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'auth/?client_id=' . bx_get('client_id') . '&response_type=' . bx_get('response_type') . '&scope=' . bx_get('scope') . '&state=' . bx_get('state') . '&redirect_uri=' . bx_get('redirect_uri');
+            bx_login_form(false, false, $sForceRelocate);
+            return;
+        }
+
+        $aProfiles = BxDolAccount::getInstance()->getProfiles();
+        if (!($iProfileId = $this->_oDb->getSavedProfile($aProfiles)) && empty($_POST)) {
+            $oPage = BxDolPage::getObjectInstanceByURI('oauth-authorization');
+            $this->_oTemplate->getPage(false, $oPage->getCode());
+            return;
+        } 
+
+        if (!$iProfileId)
+            $iProfileId = bx_get('profile_id');
+
+        $this->_oServer->handleAuthorizeRequest($oRequest, $oResponse, (bool)$iProfileId, $iProfileId);
+
+        $oResponse->send();
+    }
+
+    function serviceAuthorization ()
+    {
+        $sTitle = $this->_oDb->getClientTitle(bx_get('client_id'));
+        $this->_oTemplate->addCss('main.css');
+        return $this->_oTemplate->parseHtmlByName('page_auth.html', array(
+            'text' => _t('_bx_oauth_authorize_app', htmlspecialchars_adv($sTitle)),
+            'url' => BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'auth',
+            'client_id' => bx_get('client_id'),
+            'response_type' => bx_get('response_type'),
+            'redirect_uri' => bx_get('redirect_uri'),
+        	'scope' => bx_get('scope'),
+            'state' => bx_get('state'),
+            'profiles' => BxDolService::call('system', 'account_profile_switcher', array(getLoggedId(), false, "javascript: $('#bx-auth-profile-id').val('{profile_id}'); $('#bx-auth-form form').submit(); void(0);"), 'TemplServiceProfiles')['content'],
+        ));
+    }
+
+    function serviceGetClientsBy ($aParams = array())
+    {
+    	return $this->_oDb->getClientsBy($aParams);
+    }
+
+    function serviceAddClient ($aClient)
+    {
+    	return $this->_oDb->addClient($aClient);
+    }
+
+	function serviceUpdateClientsBy ($aParamsSet, $aParamsWhere)
+    {
+    	return $this->_oDb->updateClientsBy($aParamsSet, $aParamsWhere);
+    }
+
+	function serviceDeleteClientsBy ($aParams)
+    {
+    	return $this->_oDb->deleteClientsBy($aParams);
+    }
+
+    function studioSettings ()
+    {
+        if (!isAdmin()) {
+            $this->_oTemplate->displayAccessDenied ();
+            return;
+        }
+
+        $oGrid = BxDolGrid::getObjectInstance('bx_oauth', BxDolStudioTemplate::getInstance());
+        if ($oGrid)
+            return $oGrid->getCode();
+
+        return '';
+    }
+}
+
+/** @} */

+ 47 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/source/classes/BxOAuthStudioPage.php

@@ -0,0 +1,47 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    OAuth2 OAuth2 server
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxOAuthStudioPage extends BxTemplStudioModule
+{
+    protected $oModule;
+
+    function __construct($sModule = "", $sPage = "")
+    {
+        parent::__construct($sModule, $sPage);
+
+        $this->oModule = BxDolModule::getInstance('bx_oauth');
+
+        $this->aMenuItems = array(
+            array('name' => 'settings', 'icon' => 'cogs', 'title' => '_adm_lmi_cpt_settings'),
+        );
+    }
+
+    function getSettings ()
+    {
+    	$this->oModule->_oTemplate->addStudioJs(array('BxDolGrid.js'));
+    	$this->oModule->_oTemplate->addStudioCss(array('grid.css'));
+        return $this->oModule->studioSettings();
+    }
+
+    function getHelp ()
+    {
+        return _t('_bx_oauth_help_text', BX_DOL_URL_ROOT);
+    }
+
+    protected function getPageCaptionHelp()
+    {
+        $oTemplate = BxDolStudioTemplate::getInstance();
+        $sContent = '<a href="' . BX_DOL_URL_STUDIO . 'module.php?name=bx_oauth&page=help">' . _t('_bx_oauth_help') . "</a>";
+        return $oTemplate->parseHtmlByName('page_caption_help.html', array('content' => $sContent));
+    }
+}
+
+/** @} */

+ 68 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/source/install/config.php

@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    OAuth2 OAuth2 server
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_oauth',
+    'title' => 'OAuth2 Server',
+    'note' => 'Allow to use site user credentials and basic API',
+    'version' => '9.0.1',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.boonex.com/?section={module_name}',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/oauth2/',
+    'home_uri' => 'oauth2',
+
+    'db_prefix' => 'bx_oauth_',
+    'class_prefix' => 'BxOAuth',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'OAuth2 Server',
+
+    /**
+     * 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(),
+);
+
+/** @} */

+ 23 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/source/install/langs/en.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string name="_sys_module_oauth2"><![CDATA[OAuth2 Server]]></string>
+	<string name="_bx_oauth_administration"><![CDATA[OAuth2 Server]]></string>
+	<string name="_bx_oauth"><![CDATA[OAuth2 Server]]></string>
+	<string name="_bx_oauth_help"><![CDATA[Information]]></string>
+	<string name="_bx_oauth_help_text"><![CDATA[Add clients to allow them to use profile information from this site on client's sites. <br />
+Client's sites must have "Dolphin Connect" module installed. <br />
+Specify the following "Dolphin Connect URL" on the client sites:<br />
+<strong>{0}</strong>]]></string>
+    <string name="_bx_oauth_client_url"><![CDATA[Client Site URL]]></string>
+	<string name="_bx_oauth_client_id"><![CDATA[Client Key]]></string>
+	<string name="_bx_oauth_client_secret"><![CDATA[Client Secret]]></string>
+	<string name="_bx_oauth_add"><![CDATA[Add new client]]></string>
+	<string name="_bx_oauth_clients"><![CDATA[OAuth2 clients]]></string>
+	<string name="_bx_oauth_authorization"><![CDATA[Authorization]]></string>
+    <string name="_bx_oauth_authorize_app"><![CDATA[Choose profile to use on "{0}" site:]]></string>
+    <string name="_bx_oauth_form_valid_url"><![CDATA[Valid URL is required]]></string>
+    <string name="_bx_oauth_url"><![CDATA[URL]]></string>
+
+	<string name="_bx_oauth_adm_stg_cpt_type"><![CDATA[OAuth2 Server]]></string>
+	<string name="_bx_oauth_adm_stg_cpt_category_general"><![CDATA[General]]></string>
+</resources>

+ 16 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/source/install/sql/disable.sql

@@ -0,0 +1,16 @@
+
+-- GRID
+
+DELETE FROM `sys_objects_grid` WHERE `object` = 'bx_oauth';
+DELETE FROM `sys_grid_fields` WHERE `object` = 'bx_oauth';
+DELETE FROM `sys_grid_actions` WHERE `object` = 'bx_oauth';
+
+-- SETTINGS
+
+DELETE FROM `top`, `toc`, `to` USING `sys_options_types` AS `top` LEFT JOIN `sys_options_categories` AS `toc` ON `top`.`id`=`toc`.`type_id` LEFT JOIN `sys_options` AS `to` ON `toc`.`id`=`to`.`category_id` WHERE `top`.`name` = 'bx_oauth';
+
+-- PAGES
+
+DELETE FROM `sys_objects_page` WHERE `module` = 'bx_oauth';
+DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_oauth' OR `object` IN ('bx_oauth_authorization');
+

+ 39 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/source/install/sql/enable.sql

@@ -0,0 +1,39 @@
+
+-- GRID
+
+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_oauth', 'Sql', 'SELECT * FROM `bx_oauth_clients`', 'bx_oauth_clients', 'id', '', '', 10, NULL, 'start', '', 'title,client_id,client_secret,redirect_uri', 'auto', 'title,client_id,client_secret,redirect_uri', 128, 'BxOAuthGrid', 'modules/boonex/oauth2/classes/BxOAuthGrid.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `params`, `order`) VALUES
+('bx_oauth', 'checkbox', 'Select', '2%', '', 10),
+('bx_oauth', 'title', '_Title', '20%', '', 20),
+('bx_oauth', 'client_id', '_bx_oauth_client_id', '15%', '', 30),
+('bx_oauth', 'client_secret', '_bx_oauth_client_secret', '30%', '', 40),
+('bx_oauth', 'redirect_uri', '_bx_oauth_url', '33%', '', 50);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `confirm`, `order`) VALUES
+('bx_oauth', 'bulk', 'delete', '_Delete', 1, 1),
+('bx_oauth', 'independent', 'add', '_bx_oauth_add', 0, 1);
+
+-- 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_oauth', '_bx_oauth_adm_stg_cpt_type', 'bx_oauth@modules/boonex/oauth2/|std-mi.png', 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_oauth_general', '_bx_oauth_adm_stg_cpt_category_general', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+-- INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `order`, `extra`) VALUES
+-- ('bx_oauth2_on', '', @iCategId, 'Enable OAuth2 Server', 'checkbox', '', '', '10', '');
+
+-- Pages
+
+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_oauth_authorization', 'oauth-authorization', '_bx_oauth_authorization', '_bx_oauth_authorization', 'bx_oauth', 5, 2147483647, 0, '', '', '', '', 0, 1, 0, 'BxOAuthPage', 'modules/boonex/oauth2/classes/BxOAuthPage.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_oauth_authorization', 1, 'bx_oauth', '_bx_oauth_authorization', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_oauth\";s:6:\"method\";s:13:\"authorization\";}', 0, 0, 1, 1);
+

+ 68 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/source/install/sql/install.sql

@@ -0,0 +1,68 @@
+
+CREATE TABLE IF NOT EXISTS `bx_oauth_access_tokens` (
+  `access_token` varchar(40) NOT NULL,
+  `client_id` varchar(80) NOT NULL,
+  `user_id` int(10) unsigned DEFAULT NULL,
+  `expires` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `scope` varchar(255) DEFAULT NULL,
+  PRIMARY KEY (`access_token`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_oauth_authorization_codes` (
+  `authorization_code` varchar(40) NOT NULL,
+  `client_id` varchar(80) NOT NULL,
+  `user_id` int(10) unsigned DEFAULT NULL,
+  `redirect_uri` varchar(255) DEFAULT NULL,
+  `expires` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `scope` varchar(255) DEFAULT NULL,
+  PRIMARY KEY (`authorization_code`),
+  KEY `user_id` (`user_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_oauth_clients` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `title` varchar(255) NOT NULL,
+  `client_id` varchar(80) NOT NULL,
+  `client_secret` varchar(80) DEFAULT NULL,
+  `redirect_uri` varchar(255) NOT NULL,
+  `grant_types` varchar(80) DEFAULT NULL,
+  `scope` varchar(255) DEFAULT NULL,
+  `parent_id` int(10) unsigned DEFAULT 0,
+  `user_id` int(10) unsigned DEFAULT 0,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `client_id` (`client_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_oauth_refresh_tokens` (
+  `refresh_token` varchar(40) NOT NULL,
+  `client_id` varchar(80) NOT NULL,
+  `user_id` int(10) unsigned DEFAULT NULL,
+  `expires` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `scope` varchar(255) DEFAULT NULL,
+  PRIMARY KEY (`refresh_token`),
+  KEY `user_id` (`user_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_oauth_scopes` (
+  `scope` varchar(255)  DEFAULT NULL,
+  `is_default` tinyint(1) DEFAULT NULL
+);
+
+INSERT INTO `bx_oauth_scopes` (`scope`, `is_default`) VALUES
+('basic', 1),
+('service', 0),
+('market', 0);
+
+-- Studio page and widget
+
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_oauth', '_bx_oauth', '_bx_oauth', 'bx_oauth@modules/boonex/oauth2/|std-pi.png');
+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`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, 'bx_oauth', '{url_studio}module.php?name=bx_oauth&page=settings', '', 'bx_oauth@modules/boonex/oauth2/|std-wi.png', '_bx_oauth', '', '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));
+

+ 17 - 0
modules/boonex/oauth2/updates/9.0.0_9.0.1/source/template/page_auth.html

@@ -0,0 +1,17 @@
+<div id="bx-auth-form" class="controlsDiv">
+    <h3>__text__</h3>
+    <form method="post" action="__url__">
+        <input type="hidden" name="profile_id" id="bx-auth-profile-id" value="0" />
+        <input type="hidden" name="client_id" value="__client_id__" />
+        <input type="hidden" name="response_type" value="__response_type__" />
+        <input type="hidden" name="redirect_uri" value="__redirect_uri__" />
+        <input type="hidden" name="scope" value="__scope__" />
+        <input type="hidden" name="state" value="__state__" />
+        <div class="bx-auth-form-profiles">
+            __profiles__
+        </div>
+        <div class="bx-auth-form-buttons bx-def-margin-top">
+            <button class="bx-btn" onclick="$('#bx-auth-profile-id').val(0); $('#bx-auth-form form').submit(); return false;"><bx_text:_Cancel /></button>
+        </div>
+    </form>
+</div>

+ 51 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Payment',
+    'version_from' => '9.0.0',
+	'version_to' => '9.0.1',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/payment/updates/update_9.0.0_9.0.1/',
+	'home_uri' => 'payment_update_900_901',
+
+	'module_dir' => 'boonex/payment/',
+	'module_uri' => 'payment',
+
+    'db_prefix' => 'bx_payment_',
+    'class_prefix' => 'BxPayment',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+		'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+		'clear_db_cache' => 1,
+    ),
+
+	/**
+     * Category for language keys.
+     */
+    'language_category' => 'Payment',
+
+	/**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 27 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/install/installer.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+class BxPaymentUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+	{
+        parent::__construct($aConfig);
+    }
+
+	public function actionExecuteSql($sOperation)
+    {
+    	if($sOperation == 'install') {
+			if(!$this->oDb->isFieldExists('bx_payment_providers', 'for_single'))
+				$this->oDb->query("ALTER TABLE `bx_payment_providers` ADD `for_single` tinyint(4) NOT NULL default '0' AFTER `for_visitor`");
+
+			if(!$this->oDb->isFieldExists('bx_payment_providers', 'for_subscription'))
+        		$this->oDb->query("ALTER TABLE `bx_payment_providers` CHANGE `for_subscription` `for_recurring` tinyint(4) NOT NULL default '0'");
+
+		}
+
+    	return parent::actionExecuteSql($sOperation);
+    }
+}

+ 37 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/install/langs/en.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_payment_err_already_processed"><![CDATA[This payment has already processed.]]></string_add>
+	<string_add name="_bx_payment_txt_payment_to_for"><![CDATA[Payment to {0} for:]]></string_add>
+	<string_add name="_bx_payment_txt_buyer_name_mask"><![CDATA[{0} {1}]]></string_add>
+	<string_add name="_bx_payment_strp_cpt"><![CDATA[Stripe]]></string_add>
+	<string_add name="_bx_payment_strp_dsc"><![CDATA[Stripe payment provider]]></string_add>
+	<string_add name="_bx_payment_strp_active_cpt"><![CDATA[Active]]></string_add>
+	<string_add name="_bx_payment_strp_active_dsc"><![CDATA[Activate(Deactivate) provider. Note. It's recommended to use SSL for better payment processing.]]></string_add>
+	<string_add name="_bx_payment_strp_mode_cpt"><![CDATA[Mode]]></string_add>
+	<string_add name="_bx_payment_strp_mode_dsc"><![CDATA[Mode to process payments]]></string_add>
+	<string_add name="_bx_payment_strp_mode_live"><![CDATA[live]]></string_add>
+	<string_add name="_bx_payment_strp_mode_test"><![CDATA[test]]></string_add>
+	<string_add name="_bx_payment_strp_live_pub_key_cpt"><![CDATA[Public Key (live)]]></string_add>
+	<string_add name="_bx_payment_strp_live_pub_key_dsc"><![CDATA[Your Public Key generated in Stripe for 'live' mode]]></string_add>
+	<string_add name="_bx_payment_strp_live_sec_key_cpt"><![CDATA[Secret Key (live)]]></string_add>
+	<string_add name="_bx_payment_strp_live_sec_key_dsc"><![CDATA[Your Stripe Secret Key for 'live' mode]]></string_add>
+	<string_add name="_bx_payment_strp_test_pub_key_cpt"><![CDATA[Public Key (test)]]></string_add>
+	<string_add name="_bx_payment_strp_test_pub_key_dsc"><![CDATA[Your Public Key generated in Stripe for 'test' mode]]></string_add>
+	<string_add name="_bx_payment_strp_test_sec_key_cpt"><![CDATA[Secret Key (test)]]></string_add>
+	<string_add name="_bx_payment_strp_test_sec_key_dsc"><![CDATA[Your Stripe Secret Key for 'test' mode]]></string_add>
+	<string_add name="_bx_payment_strp_check_amount_cpt"><![CDATA[Enable amount checking]]></string_add>
+	<string_add name="_bx_payment_strp_check_amount_dsc"><![CDATA[Enable amount checking for Stripe Webhooks (recomended). However checking should be disabled when discounts and coupons are used.]]></string_add>
+	<string_add name="_bx_payment_strp_ssl_cpt"><![CDATA[Enable SSL]]></string_add>
+	<string_add name="_bx_payment_strp_ssl_dsc"><![CDATA[Enable SSL connection to communicate with Stripe. Note. URLs below will be updated after saving.]]></string_add>
+	<string_add name="_bx_payment_strp_notify_url_cpt"><![CDATA[Webhooks URL]]></string_add>
+	<string_add name="_bx_payment_strp_msg_charged"><![CDATA[Payment was successfully accepted.]]></string_add>
+	<string_add name="_bx_payment_strp_msg_subscribed"><![CDATA[Subscription was successfully created.]]></string_add>
+	<string_add name="_bx_payment_strp_txt_checkout_with_single"><![CDATA[{0}]]></string_add>
+	<string_add name="_bx_payment_strp_txt_checkout_with_recurring"><![CDATA[Checkout with {0}]]></string_add>
+	<string_add name="_bx_payment_txt_cart_stripe"><![CDATA[Stripe]]></string_add>
+
+	<string_upd name="_bx_payment_txt_payment_to"><![CDATA[Payment to {0}]]></string_upd>
+
+	<string_del name="_bx_payment_pp_err_no_vendor_given"><![CDATA[Unknown vendor.]]></string_del>
+	<string_del name="_bx_payment_pp_err_already_processed"><![CDATA[This payment has already processed.]]></string_del>
+</resources>

+ 36 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/install/sql/install.sql

@@ -0,0 +1,36 @@
+SET @sName = 'bx_payment';
+
+
+-- TABLES
+ALTER TABLE `bx_payment_providers` CHANGE `description` `description` varchar(128) NOT NULL default '';
+
+UPDATE `bx_payment_providers` SET `for_single`='1', `for_recurring`='0' WHERE `name`='paypal';
+UPDATE `bx_payment_providers` SET `for_single`='1', `for_recurring`='0' WHERE `name`='2checkout';
+UPDATE `bx_payment_providers` SET `for_single`='1', `for_recurring`='0' WHERE `name`='bitpay';
+UPDATE `bx_payment_providers` SET `for_single`='0', `for_recurring`='1' WHERE `name`='chargebee';
+UPDATE `bx_payment_providers` SET `for_single`='0', `for_recurring`='1' WHERE `name`='recurly';
+
+DELETE FROM `bx_payment_providers` WHERE `name`='stripe';
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `class_name`) VALUES
+('stripe', '_bx_payment_strp_cpt', '_bx_payment_strp_dsc', 'strp_', 1, 1, 1, 'BxPaymentProviderStripe');
+SET @iProviderId = LAST_INSERT_ID();
+
+DELETE FROM `bx_payment_providers_options` WHERE `name` LIKE 'strp_%';
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'strp_active', 'checkbox', '_bx_payment_strp_active_cpt', '_bx_payment_strp_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'strp_mode', 'select', '_bx_payment_strp_mode_cpt', '_bx_payment_strp_mode_dsc', '1|_bx_payment_strp_mode_live,2|_bx_payment_strp_mode_test', '', '', '', 2),
+(@iProviderId, 'strp_live_pub_key', 'text', '_bx_payment_strp_live_pub_key_cpt', '_bx_payment_strp_live_pub_key_dsc', '', '', '', '', 3),
+(@iProviderId, 'strp_live_sec_key', 'text', '_bx_payment_strp_live_sec_key_cpt', '_bx_payment_strp_live_sec_key_dsc', '', '', '', '', 4),
+(@iProviderId, 'strp_test_pub_key', 'text', '_bx_payment_strp_test_pub_key_cpt', '_bx_payment_strp_test_pub_key_dsc', '', '', '', '', 5),
+(@iProviderId, 'strp_test_sec_key', 'text', '_bx_payment_strp_test_sec_key_cpt', '_bx_payment_strp_test_sec_key_dsc', '', '', '', '', 6),
+(@iProviderId, 'strp_check_amount', 'checkbox', '_bx_payment_strp_check_amount_cpt', '_bx_payment_strp_check_amount_dsc', '', '', '', '', 7),
+(@iProviderId, 'strp_ssl', 'checkbox', '_bx_payment_strp_ssl_cpt', '_bx_payment_strp_ssl_dsc', '', '', '', '', 8),
+(@iProviderId, 'strp_notify_url', 'value', '_bx_payment_strp_notify_url_cpt', '', '', '', '', '', 9);
+
+
+-- GRIDS
+UPDATE `sys_objects_grid` SET `visible_for_levels`='2147483647' WHERE `object`='bx_payment_grid_carts';
+UPDATE `sys_objects_grid` SET `visible_for_levels`='2147483647' WHERE `object`='bx_payment_grid_cart';
+UPDATE `sys_objects_grid` SET `visible_for_levels`='2147483647' WHERE `object`='bx_payment_grid_orders_history';
+UPDATE `sys_objects_grid` SET `visible_for_levels`='2147483647' WHERE `object`='bx_payment_grid_orders_processed';
+UPDATE `sys_objects_grid` SET `visible_for_levels`='2147483647' WHERE `object`='bx_payment_grid_orders_pending';

+ 258 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentCart.php

@@ -0,0 +1,258 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentCart extends BxBaseModPaymentCart
+{
+    function __construct()
+    {
+    	$this->MODULE = 'bx_payment';
+
+    	parent::__construct();
+    }
+
+    /*
+     * Service methods
+     */
+	public function serviceGetBlockCarts()
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	if(bx_get('seller_id') !== false)
+    		return '';
+
+    	$iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return MsgBox(_t($CNF['T']['ERR_REQUIRED_LOGIN']));
+
+        return array(
+        	'content' => $this->_oModule->_oTemplate->displayBlockCarts($iUserId),
+        	'menu' => $this->_oModule->_oConfig->getObject('menu_cart_submenu')
+        );
+    }
+
+	public function serviceGetBlockCart()
+    {
+    	// Don't show the block at all if 'seller_id' not exists.
+    	if(bx_get('seller_id') === false)
+    		return '';
+
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	$iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return MsgBox(_t($CNF['T']['ERR_REQUIRED_LOGIN']));
+
+    	$iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+    	if(empty($iSellerId))
+    		return MsgBox(_t($CNF['T']['ERR_UNKNOWN_VENDOR']));
+
+		$aSeller = $this->_oModule->getProfileInfo();
+        return array(
+        	'title' => _t($CNF['T']['BLOCK_TITLE_CART'], $aSeller['name']),
+        	'content' => $this->_oModule->_oTemplate->displayBlockCart($iUserId, $iSellerId),
+        	'menu' => $this->_oModule->_oConfig->getObject('menu_cart_submenu')
+        );
+    }
+
+    public function serviceGetBlockCartHistory()
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+		$iSellerId = bx_get('vendor') !== false ? (int)bx_get('vendor') : 0;
+
+    	$iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return MsgBox(_t($CNF['T']['ERR_REQUIRED_LOGIN']));
+
+        return array(
+        	'content' => $this->_oModule->_oTemplate->displayBlockHistory($iUserId, $iSellerId),
+        	'menu' => $this->_oModule->_oConfig->getObject('menu_cart_submenu')
+		);
+    }
+
+    public function serviceAddToCart($iSellerId, $mixedModuleId, $iItemId, $iItemCount)
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	$iModuleId = $this->_oModule->_oConfig->getModuleId($mixedModuleId);
+    	$iClientId = $this->_oModule->getProfileId();
+
+    	$mixedResult = $this->_checkData($iClientId, $iSellerId, $iModuleId, $iItemId, $iItemCount);
+    	if($mixedResult !== true)
+    		return $mixedResult;
+
+        $aSellerProviders = $this->_oModule->_oDb->getVendorInfoProvidersSingle($iSellerId);
+        if(empty($aSellerProviders))
+            return array('code' => 5, 'message' => _t($CNF['T']['ERR_NOT_ACCEPT_PAYMENTS']));
+
+        $sCartItem = $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $iItemId, $iItemCount));
+        $sCartItems = $this->_oModule->_oDb->getCartItems($iClientId);
+
+        if(strpos($sCartItems, $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $iItemId))) !== false)
+            $sCartItems = preg_replace_callback(
+            	"/" . $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $iItemId, '([0-9])+')) . "/", 
+            	create_function('$aMatches', 'return ' . $this->_oModule->_oConfig->descriptorA2S(array("'" . $iSellerId, $iModuleId, $iItemId, "' . (\$aMatches[1] + " . $iItemCount . ")")) . ';'),
+            	$sCartItems
+			);
+        else
+            $sCartItems = empty($sCartItems) ? $sCartItem : $sCartItems . $this->_oModule->_oConfig->getDivider('DIVIDER_DESCRIPTORS') . $sCartItem;
+
+        $this->_oModule->_oDb->setCartItems($iClientId, $sCartItems);
+
+        $aInfo = $this->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId);
+        $iTotalQuantity = 0;
+        foreach($aInfo as $aCart)
+           $iTotalQuantity += $aCart['items_count'];
+
+        return array(
+        	'code' => 0, 
+        	'message' => _t($CNF['T']['MSG_ITEM_ADDED']), 
+        	'total_quantity' => $iTotalQuantity,
+	        //TODO: Update account submenu if it's needed.  
+        	'content' => '' //$this->_oModule->_oTemplate->displayToolbarSubmenu($aInfo)
+        );
+    }
+
+    public function serviceDeleteFromCart($iSellerId, $iModuleId = 0, $iItemId = 0)
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+        if($iSellerId == BX_PAYMENT_EMPTY_ID)
+            return array('code' => 1, 'message' => _t($CNF['T']['ERR_WRONG_DATA']));
+
+		$iClientId = $this->_oModule->getProfileId();
+        if(empty($iClientId))
+            return array('code' => 2, 'message' => _t($CNF['T']['ERR_REQUIRED_LOGIN']));
+
+        if(!empty($iModuleId) && !empty($iItemId))
+            $sPattern = "'" . $iSellerId . "_" . $iModuleId . "_" . $iItemId . "_[0-9]+:?'";
+        else
+            $sPattern = "'" . $iSellerId . "_[0-9]+_[0-9]+_[0-9]+:?'";
+
+        $sCartItems = $this->_oModule->_oDb->getCartItems($iClientId);
+        $sCartItems = trim(preg_replace($sPattern, "", $sCartItems), ":");
+        $this->_oModule->_oDb->setCartItems($iClientId, $sCartItems);
+
+        return array('code' => 0, 'message' => _t($CNF['T']['MSG_ITEM_DELETED']));
+    }
+
+	public function serviceSubscribe($iSellerId, $sSellerProvider, $iModuleId, $iItemId, $iItemCount)
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	$iClientId = $this->_oModule->getProfileId();
+
+    	$mixedResult = $this->_checkData($iClientId, $iSellerId, $iModuleId, $iItemId, $iItemCount);
+    	if($mixedResult !== true)
+    		return $mixedResult;
+
+        $aSellerProviders = $this->_oModule->_oDb->getVendorInfoProvidersRecurring($iSellerId);
+        if(empty($aSellerProviders))
+            return array('code' => 5, 'message' => _t($CNF['T']['ERR_NOT_ACCEPT_PAYMENTS']));
+
+        $aCartItem = array($iSellerId, $iModuleId, $iItemId, $iItemCount);
+        $sCartItem = $this->_oModule->_oConfig->descriptorA2S($aCartItem);
+
+		if(empty($sSellerProvider)) {
+			$sId = $this->_oModule->_oConfig->getHtmlIds('cart', 'providers_select') . BX_PAYMENT_TYPE_RECURRING;
+			$sTitle = _t($CNF['T']['POPUP_PROVIDERS_SELECT']);
+			return array('popup' => BxTemplStudioFunctions::getInstance()->popupBox($sId, $sTitle, $this->_oModule->_oTemplate->displayProvidersSelector($aCartItem, $aSellerProviders)));
+		}
+
+		$aProvider = $aSellerProviders[$sSellerProvider];
+        $mixedResult = $this->_oModule->serviceInitializeCheckout(BX_PAYMENT_TYPE_RECURRING, $iSellerId, $aProvider['name'], array($sCartItem));
+        if(is_string($mixedResult))
+        	return array('code' => 6, 'message' => _t($mixedResult));
+
+		return $mixedResult;
+    }
+
+    public function getInfo($sType, $iUserId, $iSellerId = BX_PAYMENT_EMPTY_ID, $aItems = array())
+    {
+        if($iSellerId != BX_PAYMENT_EMPTY_ID && !empty($aItems))
+            return $this->_getInfo($sType, $iUserId, $iSellerId, $this->_oModule->_oConfig->descriptorsM2A($aItems));
+
+        $aContent = $this->_parseByVendor($iUserId);
+
+        if($iSellerId != BX_PAYMENT_EMPTY_ID)
+            return isset($aContent[$iSellerId]) ? $this->_getInfo($sType, $iUserId, $iSellerId, $aContent[$iSellerId]) : array();
+
+        $aResult = array();
+        foreach($aContent as $iSellerId => $aSellerItems)
+            $aResult[$iSellerId] = $this->_getInfo($sType, $iUserId, $iSellerId, $aSellerItems);
+
+        return $aResult;
+    }
+
+    /**
+     * Enter description here...
+     *
+     * @param  integer $iClientId client's ID
+     * @param  integer $iSellerId vendor's ID
+     * @param  array   $aItems    item descriptors(quaternions) from shopping cart.
+     * @return array   with full info about vendor and items.
+     */
+    protected function _getInfo($sType, $iClientId, $iSellerId, $aItems)
+    {
+        $iItemsCount = 0;
+        $fItemsPrice = 0;
+        $aItemsInfo = array();
+        foreach($aItems as $aItem) {
+            $aItemInfo = $this->_oModule->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id']));
+            $aItemInfo['module_id'] = (int)$aItem['module_id'];
+            $aItemInfo['quantity'] = (int)$aItem['item_count'];
+
+            $iItemsCount += $aItem['item_count'];
+            $fItemsPrice += $aItem['item_count'] * $this->_oModule->_oConfig->getPrice($sType, $aItemInfo);
+            $aItemsInfo[] = $aItemInfo;
+        }
+
+        $aSeller = $this->_oModule->getVendorInfo((int)$iSellerId);
+        return array(
+        	'client_id' => $iClientId,
+            'vendor_id' => $aSeller['id'],
+            'vendor_name' => $aSeller['name'],
+        	'vendor_link' => $aSeller['link'],
+            'vendor_icon' => $aSeller['icon'],
+        	'vendor_unit' => $aSeller['unit'],
+            'vendor_currency_code' => $aSeller['currency_code'],
+            'vendor_currency_sign' => $aSeller['currency_sign'],
+            'items_count' => $iItemsCount,
+            'items_price' => $fItemsPrice,
+            'items' => $aItemsInfo
+        );
+    }
+
+	protected function _checkData($iClientId, $iSellerId, $iModuleId, $iItemId, $iItemCount)
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+		if($iSellerId == BX_PAYMENT_EMPTY_ID || empty($iModuleId) || empty($iItemId) || empty($iItemCount))
+            return array('code' => 1, 'message' => _t($CNF['T']['ERR_WRONG_DATA']));
+
+		$iClientId = $this->_oModule->getProfileId();
+        if(empty($iClientId)) {
+        	$sLoginUrl = BxDolPermalinks::getInstance()->permalink('page.php?i=login');
+            return array('code' => 2, 'eval' => 'window.open("' . $sLoginUrl . '", "_self");');
+        }
+
+        if($iClientId == $iSellerId)
+            return array('code' => 3, 'message' => _t($CNF['T']['ERR_SELF_PURCHASE']));
+
+        $aSeller = $this->_oModule->getVendorInfo($iSellerId);
+        if(!$aSeller['active'])
+            return array('code' => 4, 'message' => _t($CNF['T']['ERR_INACTIVE_VENDOR']));
+
+		return true;
+    }
+}
+
+/** @} */

+ 198 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentConfig.php

@@ -0,0 +1,198 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentConfig extends BxBaseModPaymentConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $sBaseUrl = BX_DOL_URL_ROOT . $this->getBaseUri();
+
+        $this->CNF = array_merge($this->CNF, array(
+        	'URL_JOIN' => 'page.php?i=payment-join',
+        	'URL_CARTS' => 'page.php?i=payment-carts',
+        	'URL_CART' => 'page.php?i=payment-cart',
+        	'URL_CART_CHECKOUT' => $sBaseUrl . 'initialize_checkout/' . BX_PAYMENT_TYPE_SINGLE . '/',
+        	'URL_SUBSCRIBE' => $sBaseUrl . 'subscribe/',
+        	'URL_HISTORY' => 'page.php?i=payment-history',
+        	'URL_ORDERS' => 'page.php?i=payment-orders',
+        	'URL_DETAILS' => 'page.php?i=payment-details',
+        	'URL_RETURN' => 'page.php?i=payment-cart',
+        	'URL_RETURN_DATA' => $sBaseUrl . 'finalize_checkout/',
+        	'URL_NOTIFY' => $sBaseUrl . 'notify/',
+
+        	'KEY_ARRAY_PRICE_SINGLE' => 'price_single',
+        	'KEY_ARRAY_PRICE_RECURRING' => 'price_recurring',
+        
+	        // some language keys
+        	'T' => array(
+        		'MSG_ITEM_ADDED' => '_bx_payment_msg_item_added',
+        		'MSG_ITEM_DELETED' => '_bx_payment_msg_item_deleted',
+        		'ERR_WRONG_DATA' => '_bx_payment_err_wrong_data',
+        		'ERR_REQUIRED_LOGIN' => '_bx_payment_err_required_login',
+        		'ERR_NOT_ACCEPT_PAYMENTS' => '_bx_payment_err_not_accept_payments',
+        		'ERR_SELF_PURCHASE' => '_bx_payment_err_self_purchase',
+        		'ERR_INACTIVE_VENDOR' => '_bx_payment_err_inactive_vendor',
+        		'ERR_UNKNOWN_VENDOR' => '_bx_payment_err_unknown_vendor',
+
+				'BLOCK_TITLE_CART' => '_bx_payment_page_block_title_cart',
+
+        		'POPUP_PROVIDERS_SELECT' => '_bx_payment_popup_title_crd_providers_select', 
+
+        		'TXT_CART_PROVIDER' => '_bx_payment_txt_cart_'
+        	)
+        ));
+
+        $this->_aHtmlIds = array(
+        	'cart' => array(
+        		'providers_select' => $this->_sName . '-cart-providers-select-',
+        	),
+        	'history' => array(
+        		'order_history_view' => $this->_sName . '-order-view-history',
+        	),
+        	'pending' => array(
+        		'order_pending_view' => $this->_sName . '-order-view-pending',
+        		'order_pending_process' => $this->_sName . '-order-process',
+        	),
+        	'processed' => array(
+        		'order_processed_view' => $this->_sName . '-order-view-processed',
+        		'order_processed_add' => $this->_sName . '-order-add',
+        		'order_processed_client_id' => $this->_sName . '-oa-client-id',
+        		'order_processed_client' => $this->_sName . '-oa-client',
+        		'order_processed_items' => $this->_sName . '-oa-items',	
+        	),
+        );
+
+        $this->_aPerPage = array(
+        	'orders' => 10,
+        	'history' => 10
+        );
+        $this->_aHandlers = array();
+
+        $this->_aJsClasses = array(
+        	'cart' => 'BxPaymentCart',
+        	'history' => 'BxPaymentOrders',
+        	'pending' => 'BxPaymentOrders',
+        	'processed' => 'BxPaymentOrders',
+        	'stripe' => 'BxPaymentProviderStripe'
+        );
+
+        $this->_aJsObjects = array(
+        	'cart' => 'oPaymentCart',
+        	'history' => 'oPaymentOrders',
+        	'pending' => 'oPaymentOrders',
+        	'processed' => 'oPaymentOrders',
+        	'stripe' => 'oPaymentProviderStripe'
+        );
+    }
+
+	public function getLicense()
+    {
+        list($fMilliSec, $iSec) = explode(' ', microtime());
+        $fSeed = (float)$iSec + ((float)$fMilliSec * 100000);
+        srand($fSeed);
+
+        $sResult = '';
+        for($i=0; $i < 16; ++$i) {
+            switch(rand(1,2)) {
+                case 1:
+                    $c = chr(rand(ord('A'),ord('Z')));
+                    break;
+                case 2:
+                    $c = chr(rand(ord('0'),ord('9')));
+                    break;
+            }
+            $sResult .= $c;
+        }
+
+        return $sResult;
+    }
+
+    public function getPrice($sType, $aItem)
+    {
+    	$fPrice = 0;
+
+		switch($sType) {
+			case BX_PAYMENT_TYPE_SINGLE:
+				$fPrice = $aItem[$this->getKey('KEY_ARRAY_PRICE_SINGLE')];
+				break;
+
+			case BX_PAYMENT_TYPE_RECURRING:
+				$fPrice = $aItem[$this->getKey('KEY_ARRAY_PRICE_RECURRING')];
+				break;
+		}
+
+		return (float)$fPrice;
+    }
+
+    public function getModuleId($mixedId)
+    {
+    	if(is_numeric($mixedId))
+    		return (int)$mixedId;
+
+		if(is_string($mixedId)) {
+            $aInfo = $this->_oDb->getModuleByName($mixedId);
+            if(!is_array($aInfo) || empty($aInfo['id']))
+            	$aInfo = $this->_oDb->getModuleByUri($mixedId);
+
+            if(is_array($aInfo) && !empty($aInfo['id']))
+            	return (int)$aInfo['id'];
+        } 
+
+        return 0;
+    }
+
+    public function descriptorA2S($a) 
+    {
+    	return implode($this->getDivider('DIVIDER_DESCRIPTOR'), $a);
+    }
+
+	public function descriptorS2A($s) 
+    {
+    	return explode($this->getDivider('DIVIDER_DESCRIPTOR'), $s);
+    }
+
+	/**
+     * Conver items to array with necessary structure.
+     *
+     * @param  string/array $mixed - string with cart items divided with (:) or an array of cart items.
+     * @return array        with items.
+     */
+    public function descriptorsM2A($mixed)
+    {
+        $aResult = array();
+
+        if(is_string($mixed))
+           $aItems = explode($this->getDivider('DIVIDER_DESCRIPTORS'), $mixed);
+        else if(is_array($mixed))
+           $aItems = $mixed;
+        else
+            $aItems = array();
+
+        foreach($aItems as $sItem) {
+            $aItem = $this->descriptorS2A($sItem);
+            $aResult[] = array('vendor_id' => $aItem[0], 'module_id' => $aItem[1], 'item_id' => $aItem[2], 'item_count' => $aItem[3]);
+        }
+
+        return $aResult;
+    }
+
+	public function http2https($s)
+    {
+    	if(strncmp($s, 'https://', 8) == 0)
+    		return $s;
+
+        return 'https://' . bx_ltrim_str($s, 'http://');
+    }
+}
+
+/** @} */

+ 368 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentDb.php

@@ -0,0 +1,368 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentDb extends BxBaseModPaymentDb
+{
+    function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+    }
+
+    /**
+     * Payment details methods
+     */
+    public function getForm()
+    {
+        $sQuery = "SELECT
+                `tp`.`id` AS `provider_id`,
+                `tp`.`name` AS `provider_name`,
+                `tp`.`caption` AS `provider_caption`,
+                `tp`.`description` AS `provider_description`,
+                `tp`.`option_prefix` AS `provider_option_prefix`,
+                `tpo`.`id` AS `id`,
+                `tpo`.`name` AS `name`,
+                `tpo`.`type` AS `type`,
+                `tpo`.`caption` AS `caption`,
+                `tpo`.`description` AS `description`,
+                `tpo`.`extra` AS `extra`,
+                `tpo`.`check_type` AS `check_type`,
+                `tpo`.`check_params` AS `check_params`,
+                `tpo`.`check_error` AS `check_error`
+            FROM `" . $this->_sPrefix . "providers` AS `tp`
+            LEFT JOIN `" . $this->_sPrefix . "providers_options` AS `tpo` ON `tp`.`id`=`tpo`.`provider_id`
+            ORDER BY `tp`.`id` ASC, `tpo`.`order` ASC";
+
+        return $this->getAll($sQuery);
+    }
+
+	public function getProviders($aParams = array())
+    {
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sWhereClause = "";
+        if(!empty($aParams['type']))
+	        switch($aParams['type']) {
+	        	case 'by_name':
+	        		$aMethod['name'] = 'getRow';
+	        		$aMethod['params'][1] = array(
+	                	'name' => $aParams['name']
+	                );
+	
+	        		$sWhereClause = " AND `tp`.`name`=:name";
+	        		break;
+	
+				case 'for_single':
+					$aMethod['name'] = 'getAllWithKey';
+					$aMethod['params'][1] = 'name';
+	
+					$sWhereClause = " AND `tp`.`for_single`='1'";
+	        		break;
+	
+				case 'for_recurring':
+					$aMethod['name'] = 'getAllWithKey';
+					$aMethod['params'][1] = 'name';
+	
+					$sWhereClause = " AND `tp`.`for_recurring`='1'";
+	        		break;
+
+	        	case 'all':
+					$aMethod['name'] = 'getAllWithKey';
+					$aMethod['params'][1] = 'name';
+	        		break;
+	        }          
+
+        $aMethod['params'][0] = "SELECT
+                `tp`.`id` AS `id`,
+                `tp`.`name` AS `name`,
+                `tp`.`caption` AS `caption`,
+                `tp`.`description` AS `description`,
+                `tp`.`option_prefix` AS `option_prefix`,
+                `tp`.`for_visitor` AS `for_visitor`,
+                `tp`.`for_single` AS `for_single`,
+                `tp`.`for_recurring` AS `for_recurring`,
+                `tp`.`class_name` AS `class_name`,
+                `tp`.`class_file` AS `class_file`
+            FROM `" . $this->_sPrefix . "providers` AS `tp`
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function getOptions($iUserId = BX_PAYMENT_EMPTY_ID, $iProviderId = 0)
+    {
+    	$aBinding = array(
+    		'user_id' => $iUserId
+    	);
+
+        if($iUserId == BX_PAYMENT_EMPTY_ID && empty($iProviderId))
+           return $this->getAll("SELECT `id`, `name`, `type` FROM `" . $this->_sPrefix . "providers_options`");
+
+        $sWhereAddon = "";
+        if(!empty($iProviderId)) {
+        	$aBinding['provider_id'] = $iProviderId;
+
+            $sWhereAddon = " AND `tpo`.`provider_id`=:provider_id";
+        }
+
+        $sQuery = "SELECT
+               `tpo`.`name` AS `name`,
+               `tuv`.`value` AS `value`
+            FROM `" . $this->_sPrefix . "providers_options` AS `tpo`
+            LEFT JOIN `" . $this->_sPrefix . "user_values` AS `tuv` ON `tpo`.`id`=`tuv`.`option_id`
+            WHERE 1" . $sWhereAddon . " AND `tuv`.`user_id`=:user_id";
+
+        return $this->getAllWithKey($sQuery, 'name', $aBinding);
+    }
+
+    public function updateOption($iUserId, $iOptionId, $sValue)
+    {
+        $sQuery = $this->prepare("REPLACE INTO `" . $this->_sPrefix . "user_values` SET `user_id`=?, `option_id`=?, `value`=?", $iUserId, $iOptionId, $sValue);
+        return $this->query($sQuery);
+    }
+
+
+    /**
+     * Shopping cart methods.
+     */
+    public function getCartItems($iId)
+    {
+    	$sQuery = $this->prepare("SELECT `items` FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=? LIMIT 1", $iId);
+        return $this->getOne($sQuery);
+    }
+    public function setCartItems($iId, $sItems)
+    {
+        $sItems = trim($sItems, ":");
+        if(empty($sItems))
+            $sQuery = $this->prepare("DELETE FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=? LIMIT 1", $iId);
+        else
+            $sQuery = $this->prepare("REPLACE INTO `" . $this->_sPrefix . "cart` SET `client_id`=?, `items`=?", $iId, $sItems);
+
+        return $this->query($sQuery);
+    }
+
+	public function getVendorInfoProvidersSingle($iVendorId)
+    {
+    	return $this->getVendorInfoProviders($iVendorId, array('type' => 'for_single'));
+    }
+
+	public function getVendorInfoProvidersRecurring($iVendorId)
+    {
+    	return $this->getVendorInfoProviders($iVendorId, array('type' => 'for_recurring'));
+    }
+
+    public function getVendorInfoProviders($iVendorId, $aParams = array())
+    {
+    	if(empty($aParams))
+    		$aParams = array('type' => 'all');
+
+		$aProviders = $this->getProviders($aParams);
+		$aOptions = $this->getOptions($iVendorId);
+
+		$aResult = array();
+		foreach($aProviders as $sProvider => $aProvider)
+			if(isset($aOptions[$aProvider['option_prefix'] . 'active']) && $aOptions[$aProvider['option_prefix'] . 'active']['value'] == 'on') {
+				foreach($aOptions as $sName => $aOption)
+					if(strpos($sName, $aProvider['option_prefix']) !== false)
+						$aProvider['options'][$sName] = $aOption;
+				$aResult[$sProvider] = $aProvider;
+			}
+
+		return $aResult;
+	}
+
+    public function getFirstAdminId()
+    {
+    	$sQuery = $this->prepare("SELECT `profile_id` FROM `sys_accounts` WHERE `role`&" . BX_DOL_ROLE_ADMIN . " ORDER BY `profile_id` ASC LIMIT 1");
+        return (int)$this->getOne($sQuery);
+    }
+
+    public function getAdminsIds()
+    {
+    	$sQuery = $this->prepare("SELECT `profile_id` FROM `sys_accounts` WHERE `role`&" . BX_DOL_ROLE_ADMIN . " ORDER BY `profile_id` ASC");
+        return $this->getColumn($sQuery);
+    }
+
+
+	/*
+     * Pending Orders methods
+     */
+    public function getOrderPending($aParams)
+    {
+    	$aMethod = array('name' => 'getRow', 'params' => array(0 => 'query'));
+
+    	$sWhereClause = $sLimitClause = '';
+        switch($aParams['type']) {
+            case 'id':
+            	$aMethod['params'][1] = array(
+                	'id' => $aParams['id']
+                );
+
+                $sWhereClause = " AND `id`=:id";
+                $sLimitClause = " LIMIT 1";
+                break;
+
+            case 'order':
+            	$aMethod['params'][1] = array(
+                	'order' => $aParams['order']
+                );
+
+            	$sWhereClause = " AND `order`=:order";
+                $sLimitClause = " LIMIT 1";
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT * FROM `" . $this->_sPrefix . "transactions_pending` WHERE 1 " . $sWhereClause . $sLimitClause;
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function insertOrderPending($iClientId, $sType, $sProvider, $aCartInfo)
+    {
+        $sItems = "";
+        foreach($aCartInfo['items'] as $aItem)
+            $sItems .= $aCartInfo['vendor_id'] . '_' . $aItem['module_id'] . '_' . $aItem['id'] . '_' . $aItem['quantity'] . ':';
+
+        $sQuery = $this->prepare("INSERT INTO `" . $this->_sPrefix . "transactions_pending` SET
+                    `client_id`=?,
+                    `seller_id`=?,
+                    `type`=?,
+                    `provider`=?,
+                    `items`=?,
+                    `amount`=?,
+                    `date`=UNIX_TIMESTAMP()", $iClientId, $aCartInfo['vendor_id'], $sType, $sProvider, trim($sItems, ':'), $aCartInfo['items_price']);
+
+        return (int)$this->query($sQuery) > 0 ? $this->lastId() : 0;
+    }
+
+    public function updateOrderPending($iId, $aValues)
+    {
+        $sQuery = $this->prepare("UPDATE `" . $this->_sPrefix . "transactions_pending` SET " . $this->arrayToSQL($aValues) . " WHERE `id`=?", $iId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function deleteOrderPending($mixedId)
+    {
+    	if(!is_array($mixedId))
+    		$mixedId = array($mixedId);
+
+        return (int)$this->query("DELETE FROM `" . $this->_sPrefix . "transactions_pending` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+
+    /*
+     * Processed Orders
+     */
+    public function getOrderProcessed($aParams)
+    {
+    	$aMethod = array('name' => 'getRow', 'params' => array(0 => 'query'));
+
+        $sWhereClause = "";
+        switch($aParams['type']) {
+            case 'id':
+            	$aMethod['params'][1] = array(
+                	'id' => $aParams['id']
+                );
+
+                $sWhereClause = " AND `tt`.`id`=:id";
+                break;
+
+			case 'pending_id':
+                if(empty($aParams['with_key'])) {
+                	$aMethod['name'] = 'getAll';
+                	$aMethod['params'][1] = array(
+						'pending_id' => $aParams['pending_id']
+					);
+                }
+                else {
+                	$aMethod['name'] = 'getAllWithKey';
+					$aMethod['params'][1] = $aParams['with_key'];
+					$aMethod['params'][2] = array(
+						'pending_id' => $aParams['pending_id']
+					);
+                }
+
+                $sWhereClause = " AND `tt`.`pending_id`=:pending_id";
+                break;
+
+            case 'license':
+                $aMethod['name'] = 'getAll';
+                $aMethod['params'][1] = array(
+                	'license' => $aParams['license']
+                );
+
+                $sWhereClause = " AND `tt`.`license`=:license";
+                break;
+
+            case 'mixed':
+                $aMethod['name'] = 'getAll';
+                $aMethod['params'][1] = $aParams['conditions'];
+
+                foreach($aParams['conditions'] as $sKey => $sValue)
+                    $sWhereClause .= " AND `tt`.`" . $sKey . "`=:" . $sKey;
+                break;
+
+        }
+
+        $aMethod['params'][0] = "SELECT
+        		`tt`.`id`,
+                `tt`.`license`,
+                `ttp`.`type`,
+                `tt`.`client_id`,
+                `tt`.`seller_id`,
+                `tt`.`module_id`,
+                `tt`.`item_id`,
+                `tt`.`item_count`,
+                `tt`.`amount`,
+                `tt`.`date`,
+                `ttp`.`order`,
+                `ttp`.`error_msg`,
+                `ttp`.`provider`
+            FROM `" . $this->_sPrefix . "transactions` AS `tt`
+            LEFT JOIN `" . $this->_sPrefix . "transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id`
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function insertOrderProcessed($aValues)
+    {
+        return $this->query("INSERT INTO `" . $this->_sPrefix . "transactions` SET " . $this->arrayToSQL($aValues) . ", `date`=UNIX_TIMESTAMP()");
+    }
+
+	public function updateOrderProcessed($iId, $aValues)
+    {
+        $sQuery = $this->prepare("UPDATE `" . $this->_sPrefix . "transactions` SET " . $this->arrayToSQL($aValues) . " WHERE `id`=?", $iId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function deleteOrderProcessed($mixedId)
+    {
+    	if(!is_array($mixedId))
+    		$mixedId = array($mixedId);
+
+        return (int)$this->query("DELETE FROM `" . $this->_sPrefix . "transactions` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+
+    public function getOrderHistory($aParams)
+    {
+        return $this->getOrderProcessed($aParams);
+    }
+
+    //--- Order Administration ---//
+    public function onProfileDelete($iId)
+    {
+    	$sQuery = $this->prepare("DELETE FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=?", $iId);
+    	$this->query($sQuery);
+
+    	$sQuery = $this->prepare("DELETE FROM `" . $this->_sPrefix . "user_values` WHERE `user_id`=?", $iId);
+    	$this->query($sQuery);
+    }
+}
+
+/** @} */

+ 192 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentDetails.php

@@ -0,0 +1,192 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+bx_import('BxDolForm');
+
+class BxPaymentDetailsFormCheckerHelper extends BxDolFormCheckerHelper
+{
+	function checkHttps ($s)
+    {
+        return empty($s) || substr(BX_DOL_URL_ROOT, 0, 5) == 'https';
+    }
+}
+
+class BxPaymentDetails extends BxBaseModPaymentDetails
+{
+	protected $_sLangsPrefix;
+    protected $_bCollapseFirst;
+
+    function __construct()
+    {
+    	$this->MODULE = 'bx_payment';
+
+    	parent::__construct();
+
+    	$this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+        $this->_bCollapseFirst = true;
+    }
+
+    public function serviceGetBlockDetails($iUserId = BX_PAYMENT_EMPTY_ID)
+    {
+        if(!$this->_oModule->isLogged())
+			return MsgBox(_t($this->_sLangsPrefix . 'err_required_login'));
+
+        $iUserId = $iUserId != BX_PAYMENT_EMPTY_ID ? $iUserId : $this->_oModule->getProfileId();
+
+		$sContent = $this->getForm($iUserId);
+		if(empty($sContent))
+			$sContent = MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        return array(
+        	'content' => $sContent,
+        	'menu' => $this->_oModule->_oConfig->getObject('menu_orders_submenu')
+        );
+    }
+
+    public function getForm($iUserId)
+    {
+        $aInputs = $this->_oModule->_oDb->getForm();
+        if(empty($aInputs))
+            return '';
+
+		$aForm = array(
+            'form_attrs' => array(
+                'id' => 'pmt_details',
+                'name' => 'pmt_details',
+                'action' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=payment-details'),
+                'method' => 'post',
+                'enctype' => 'multipart/form-data'
+            ),
+            'params' => array(
+                'db' => array(
+                    'table' => '',
+                    'key' => 'id',
+                    'uri' => '',
+                    'uri_title' => '',
+                    'submit_name' => 'submit'
+                ),
+                'checker_helper' => 'BxPaymentDetailsFormCheckerHelper'
+            ),
+            'inputs' => array (
+            )
+        );
+
+        $bCollapsed = $this->_bCollapseFirst;
+        $iProvider = 0;
+        $sProvider = "";
+        $oProvider = null;
+        foreach($aInputs as $aInput) {
+            if($iProvider != $aInput['provider_id']) {
+                if(!empty($iProvider))
+                    $aForm['inputs']['provider_' . $iProvider . '_end'] = array(
+                        'type' => 'block_end'
+                    );
+
+                $aForm['inputs']['provider_' . $aInput['provider_id'] . '_begin'] = array(
+                    'type' => 'block_header',
+                    'caption' => _t($aInput['provider_caption']),
+                    'collapsable' => true,
+                    'collapsed' => $bCollapsed
+                );
+
+                $iProvider = $aInput['provider_id'];
+                $sProvider = $aInput['provider_name'];
+                $oProvider = $this->_oModule->getObjectProvider($sProvider, $iUserId);
+                $bCollapsed = true;
+            }
+
+            $aForm['inputs'][$aInput['name']] = array(
+				'type' => $aInput['type'],
+                'name' => $aInput['name'],
+                'caption' => _t($aInput['caption']),
+                'value' => $oProvider->getOption($aInput['name']),
+                'info' => _t($aInput['description']),
+            	'attrs' => array(
+            		'bx-data-provider' => $iProvider
+            	),
+                'checker' => array (
+                    'func' => $aInput['check_type'],
+                    'params' => $aInput['check_params'],
+                    'error' => _t($aInput['check_error']),
+                )
+            );
+
+            //--- Make some field dependent actions ---//
+            switch($aInput['type']) {
+                case 'select':
+                    if(empty($aInput['extra']))
+                       break;
+
+                    $aAddon = array('values' => array());
+
+                    $aPairs = explode(',', $aInput['extra']);
+                    foreach($aPairs as $sPair) {
+                        $aPair = explode('|', $sPair);
+                        $aAddon['values'][] = array('key' => $aPair[0], 'value' => _t($aPair[1]));
+                    }
+                    break;
+
+                case 'checkbox':
+                    $aForm['inputs'][$aInput['name']]['value'] = 'on';
+                    $aAddon = array('checked' => $oProvider->getOption($aInput['name']) == 'on');
+                    break;
+
+				 case 'value':
+				 	$sName = str_replace($aInput['provider_option_prefix'], '', $aInput['name']);
+				 	if(!in_array($sName, array('return_data_url', 'notify_url')))
+				 		break;
+
+				 	$sMethod = 'get' . bx_gen_method_name($sName);
+				 	if(method_exists($oProvider, $sMethod))
+						$aForm['inputs'][$aInput['name']]['value'] = $oProvider->$sMethod($iUserId);
+				 	break;
+            }
+
+            if(!empty($aAddon) && is_array($aAddon))
+                $aForm['inputs'][$aInput['name']] = array_merge($aForm['inputs'][$aInput['name']], $aAddon);
+        }
+
+        $aForm['inputs']['provider_' . $iProvider . '_end'] = array(
+            'type' => 'block_end'
+        );
+        $aForm['inputs']['submit'] = array(
+            'type' => 'submit',
+            'name' => 'submit',
+            'value' => _t($this->_sLangsPrefix . 'form_details_input_do_submit'),
+        );
+
+        bx_import('BxTemplFormView');
+        $oForm = new BxTemplFormView($aForm);
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+            $aOptions = $this->_oModule->_oDb->getOptions();
+            foreach($aOptions as $aOption) {
+            	$sValue = bx_get($aOption['name']) !== false ? bx_get($aOption['name']) : '';
+                $this->_oModule->_oDb->updateOption($iUserId, $aOption['id'], bx_process_input($sValue));
+            }
+
+            header('Location: ' . $oForm->aFormAttrs['action']);
+        }
+        else {
+        	foreach($oForm->aInputs as $aInput)
+        		if(!empty($aInput['error']) && !empty($aInput['attrs']['bx-data-provider'])) {
+        			$sProviderBlock = 'provider_' . (int)$aInput['attrs']['bx-data-provider'] . '_begin';
+        			if(!empty($oForm->aInputs[$sProviderBlock]))
+        				$oForm->aInputs[$sProviderBlock]['collapsed'] = false;
+        		}
+
+			return $oForm->getCode();
+        }
+    }
+}
+
+/** @} */

+ 129 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentGridCart.php

@@ -0,0 +1,129 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ * 
+ * @{
+ */
+
+
+class BxPaymentGridCart extends BxBaseModPaymentGridCarts
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_bSelectAll = true;
+    }
+
+    public function performActionCheckout()
+    {
+    	$aParams = array(
+			'seller_id' => bx_process_input(bx_get('seller_id'), BX_DATA_INT), 
+			'provider' => bx_process_input(bx_get('provider')), 
+			'items' => bx_process_input(bx_get('ids'))    		
+    	);
+    	if(empty($aParams['seller_id']) || empty($aParams['provider']))
+    		return echoJson(array());
+
+        if(empty($aParams['items']) || !is_array($aParams['items'])) 
+        	return echoJson(array('msg' => _t('_bx_payment_err_nothing_selected')));
+
+		$oProvider = $this->_oModule->getObjectProvider($aParams['provider'], $aParams['seller_id']);
+		if($oProvider !== false && method_exists($oProvider, 'getCheckoutParamsSingle'))
+			$aParams = $oProvider->getCheckoutParamsSingle($aParams, $this);
+
+		$sLink = $this->_oModule->_oConfig->getUrl('URL_CART_CHECKOUT');
+		$sLink = $sLink . (strpos($sLink, '?') === false ? '?' : '&') . http_build_query($aParams);
+
+		echoJson(array(
+			'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onCartCheckout(oData);', 
+			'link' => $sLink
+		));
+    }
+
+    protected function _getCellTitle($mixedValue, $sKey, $aField, $aRow)
+    {
+    	return parent::_getCellDefault($this->_oModule->_oTemplate->displayLink('link', array(
+    		'href' => $aRow['url'],
+    		'title' => $aRow['title'],
+    		'content' => $aRow['title']
+    	)), $sKey, $aField, $aRow);
+    }
+
+	protected function _getCellPriceSingle($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_sCurrencySign . $mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getActions ($sType, $sActionData = false, $isSmall = false, $isDisabled = false, $isPermanentState = false, $aRow = array())
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+    	
+    	$sActions = '';
+    	if($sType == 'bulk' && !empty($this->_aQueryAppend['seller_id'])) {
+    		$sActionName = 'checkout';
+
+    		$aProviders = $this->_oModule->_oDb->getVendorInfoProvidersSingle($this->_aQueryAppend['seller_id']);
+    		foreach($aProviders as $aProvider) {
+				$sAction = $this->_getActionDefault($sType, $sActionName, array(
+					'title'=> _t($CNF['T']['TXT_CART_PROVIDER'] . $aProvider['name']),
+	    			'icon' => '',
+					'icon_only' => 0,
+	    			'confirm' => 0,
+					'attr' => array(
+						'bx_grid_action_' . $sType => $sActionName,
+						'bx_grid_action_append' => json_encode(array('provider' => $aProvider['name'])),
+						'bx_grid_action_confirm' => 0,
+						'bx_grid_action_reset_paginate' => 0,
+					)
+				), $isSmall, $isDisabled, $aRow);
+
+    			$oProvider = $this->_oModule->getObjectProvider($aProvider['name'], $this->_aQueryAppend['seller_id']);
+    			if($oProvider !== false && method_exists($oProvider, 'getButtonSingle'))
+    				$sAction = $oProvider->getButtonSingle($this->_aQueryAppend['client_id'], $this->_aQueryAppend['seller_id'], array(
+    					'sObjNameGrid' => $this->getObject()
+    				));
+
+    			$sActions .= $sAction;
+    		}
+    	}
+
+    	return $sActions . parent::_getActions ($sType, $sActionData, $isSmall, $isDisabled, $isPermanentState, $aRow);
+    }
+
+	protected function _getDataArray($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+		if(empty($this->_aQueryAppend['client_id']) || empty($this->_aQueryAppend['seller_id']))
+			return array();
+
+		$aCart = $this->_oCart->getInfo(BX_PAYMENT_TYPE_SINGLE, $this->_aQueryAppend['client_id'], $this->_aQueryAppend['seller_id']);
+		if(empty($aCart) || empty($aCart['items']) || !is_array($aCart['items']))
+			return array();
+
+		foreach($aCart['items'] as $aCartItem) {
+			$aCartItem['descriptor'] = $this->_oModule->_oConfig->descriptorA2S(array($aCart['vendor_id'], $aCartItem['module_id'], $aCartItem['id'], $aCartItem['quantity']));
+			$aCartItem['description'] = strip_tags($aCartItem['description']);
+
+			$this->_aOptions['source'][] = $aCartItem;
+		}
+
+        return parent::_getDataArray($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+
+    protected function _delete($mixedId)
+    {
+    	list($iVendorId, $iModuleId, $iItemId) = $this->_oModule->_oConfig->descriptorS2A($mixedId);
+    	if((int)$iVendorId != (int)$this->_aQueryAppend['seller_id'])
+    		return false;
+
+    	return $this->_oCart->serviceDeleteFromCart($iVendorId, $iModuleId, $iItemId);
+    }
+}
+
+/** @} */

+ 549 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentModule.php

@@ -0,0 +1,549 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+define('BX_PAYMENT_ORDERS_TYPE_PENDING', 'pending');
+define('BX_PAYMENT_ORDERS_TYPE_PROCESSED', 'processed');
+define('BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION', 'subscription');
+define('BX_PAYMENT_ORDERS_TYPE_HISTORY', 'history');
+
+define('BX_PAYMENT_EMPTY_ID', 0);
+
+define('BX_PAYMENT_RESULT_SUCCESS', 0);
+
+/**
+ * Payment module by BoonEx
+ *
+ * This module is needed to work with payment providers and organize the process
+ * of some item purchasing. Shopping Cart and Orders Manager are included.
+ *
+ * Integration notes:
+ * To integrate your module with this one, you need:
+ * 1. Get 'Add To Cart' button using serviceGetAddToCartLink service.
+ * 2. Add info about your module in the 'bx_pmt_modules' table.
+ * 3. Realize the following service methods in your Module class.
+ *   a. serviceGetItems($iSellerId) - Is used in Orders Administration to get all products of the requested seller(vendor).
+ *   b. serviceGetCartItem($iClientId, $iItemId) - Is used in Shopping Cart to get one product by specified id.
+ *   c. serviceRegisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrderId) - Register purchased product.
+ *   d. serviceUnregisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrderId) - Unregister the product purchased earlier.
+ * @see You may see an example of integration in Membership module.
+ *
+ *
+ * Profile's Wall:
+ * no spy events
+ *
+ *
+ *
+ * Spy:
+ * no spy events
+ *
+ *
+ *
+ * Memberships/ACL:
+ * Doesn't depend on user's membership.
+ *
+ *
+ *
+ * Service methods:
+ *
+ * Is used to get "Add to cart" link for some item(s) in your module.
+ * @see BxPmtModule::serviceGetAddToCartLink
+ * BxDolService::call('payment', 'get_add_to_cart_link', array($iSellerId, $mixedModuleId, $iItemId, $iItemCount));
+ *
+ * Check transaction(s) in database which satisty all conditions.
+ * @see BxPmtModule::serviceGetTransactionsInfo
+ * BxDolService::call('payment', 'get_transactions_info', array($aConditions));
+ *
+ * Get total count of items in Shopping Cart.
+ * @see BxPmtModule::serviceGetCartItemsCount
+ * BxDolService::call('payment', 'get_cart_items_count', array($iUserId, $iOldCount));
+ * @note is needed for internal usage(integration with member tool bar).
+ *
+ * Get Shopping cart content.
+ * @see BxPmtModule::serviceGetCartItems
+ * BxDolService::call('payment', 'get_cart_items');
+ * @note is needed for internal usage(integration with member tool bar).
+ *
+ *
+ * Alerts:
+ * no alerts available
+ *
+ */
+class BxPaymentModule extends BxBaseModPaymentModule
+{
+    protected $_iUserId;
+
+    protected $_aOrderTypes;
+
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_iUserId = $this->getProfileId();
+
+        $this->_aOrderTypes = array(
+        	BX_PAYMENT_ORDERS_TYPE_PENDING, 
+        	BX_PAYMENT_ORDERS_TYPE_PROCESSED, 
+        	BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION, 
+        	BX_PAYMENT_ORDERS_TYPE_HISTORY
+        );
+    }
+
+    /**
+     * Manage Orders Methods
+     */
+	public function actionGetClients()
+    {
+        $sTerm = bx_get('term');
+
+        $aResult = BxDolService::call('system', 'profiles_search', array($sTerm), 'TemplServiceProfiles');
+
+        echoJson($aResult);
+    }
+
+    public function actionGetItems($sType, $iModuleId)
+    {
+    	$iSellerId = $this->getProfileId();
+        $aItems = $this->callGetCartItems((int)$iModuleId, array($iSellerId));
+
+        $aResult = array('code' => 0);
+        if(is_array($aItems) && !empty($aItems))
+            $aResult['data'] = $this->_oTemplate->displayItems($sType, $aItems);
+
+		echoJson($aResult);
+    }
+
+
+    /**
+     * Payment Details Methods
+     */
+    public function serviceIsAcceptingPayments($iVendorId, $sPaymentType = '')
+    {
+    	$bResult = false;
+
+    	switch($sPaymentType) {
+    		case BX_PAYMENT_TYPE_SINGLE:
+    			$aProvidersCart = $this->_oDb->getVendorInfoProvidersSingle($iVendorId);
+    			$bResult = !empty($aProvidersCart);
+    			break;
+
+    		case BX_PAYMENT_TYPE_RECURRING:
+    			$aProvidersSubscription = $this->_oDb->getVendorInfoProvidersRecurring($iVendorId);
+    			$bResult = !empty($aProvidersSubscription);
+    			break;
+
+    		default:
+    			$aProviders = $this->_oDb->getVendorInfoProviders($iVendorId);
+    			$bResult = !empty($aProviders);
+    	}
+
+		return $bResult;
+    }
+
+    public function serviceIsPaymentProvider($iVendorId, $sVendorProvider, $sPaymentType = '')
+    {
+    	$aProvider = $this->serviceGetPaymentProvider($iVendorId, $sVendorProvider, $sPaymentType);
+    	return $aProvider !== false;
+    }
+
+    public function serviceGetPaymentProvider($iVendorId, $sVendorProvider, $sPaymentType = '')
+    {
+    	$aProviders = array();
+    	switch($sPaymentType) {
+    		case BX_PAYMENT_TYPE_SINGLE:
+    			$aProviders = $this->_oDb->getVendorInfoProvidersSingle($iVendorId);
+    			break;
+
+    		case BX_PAYMENT_TYPE_RECURRING:
+    			$aProviders = $this->_oDb->getVendorInfoProvidersRecurring($iVendorId);
+    			break;
+
+    		default:
+    			$aProviders = $this->_oDb->getVendorInfoProviders($iVendorId);
+    	}
+
+    	return !empty($aProviders) && !empty($aProviders[$sVendorProvider]) && is_array(($aProviders[$sVendorProvider])) ? $aProviders[$sVendorProvider] : false;
+    }
+
+    public function serviceGetOptionsSiteAdmin()
+    {
+        $aResult = array(
+            array('key' => '', 'value' => _t('_Select_one'))
+        );
+
+        $aIds = $this->_oDb->getAdminsIds();
+        foreach($aIds as $iId) {
+        	$aUser = $this->getProfileInfo($iId);
+
+            $aResult[] = array(
+                'key' => $iId,
+                'value' => $aUser['name']
+            );
+        }
+
+        return $aResult;
+    }
+
+    /**
+     * Check transaction(s) in database which satisty all conditions.
+     *
+     * @param array $aConditions an array of pears('key' => 'value'). Available keys are the following:
+     * a. license - internal license (string)
+     * b. client_id - client's ID (integer)
+     * c. seller_id - seller's ID (integer)
+     * d. module_id - modules's where the purchased product is located. (integer)
+     * e. item_id - item id in the database. (integer)
+     * f. date - the date when the payment was processed(UNIXTIME STAMP)
+     *
+     * @return array of transactions. Each transaction has full info(client ID, seller ID, external transaction ID, date and so on)
+     */
+    public function serviceGetTransactionsInfo($aConditions)
+    {
+        return $this->_oDb->getOrderProcessed(array('type' => 'mixed', 'conditions' => $aConditions));
+    }
+
+
+    /**
+     * Cart Processing Methods
+     */
+    public function actionAddToCart($iSellerId, $iModuleId, $iItemId, $iItemCount)
+    {
+        $aResult = $this->getObjectCart()->serviceAddToCart($iSellerId, $iModuleId, $iItemId, $iItemCount);
+		echoJson($aResult);
+    }
+
+    /**
+     * Isn't used yet.
+     */
+    public function actionDeleteFromCart($iSellerId, $iModuleId, $iItemId)
+    {
+        $aResult = $this->getObjectCart()->serviceDeleteFromCart($iSellerId, $iModuleId, $iItemId);
+        echoJson($aResult);
+    }
+
+    /**
+     * Isn't used yet.
+     */
+    public function actionEmptyCart($iSellerId)
+    {
+        $aResult = $this->getObjectCart()->serviceDeleteFromCart($iSellerId);
+		echoJson($aResult);
+    }
+
+	public function actionSubscribe()
+    {
+    	$iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+    	$sSellerProvider = bx_process_input(bx_get('seller_provider'));
+    	$iModuleId = bx_process_input(bx_get('module_id'), BX_DATA_INT);
+    	$iItemId = bx_process_input(bx_get('item_id'), BX_DATA_INT);
+    	$iItemCount = bx_process_input(bx_get('item_count'), BX_DATA_INT);
+    	if(empty($iItemCount))
+    		$iItemCount = 1;
+
+        $aResult = $this->getObjectCart()->serviceSubscribe($iSellerId, $sSellerProvider, $iModuleId, $iItemId, $iItemCount);
+
+		if($aResult['code'] != 0)
+			return $this->_oTemplate->displayPageCodeError($aResult['message']);
+
+		if(empty($aResult['redirect']) && !empty($aResult['message']))
+			return $this->_oTemplate->displayPageCodeResponse($aResult['message']);
+
+		header('Location: ' . $aResult['redirect']);
+        exit;
+    }
+
+    public function actionSubscribeJson()
+    {
+    	$iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+    	$sSellerProvider = bx_process_input(bx_get('seller_provider'));
+    	$iModuleId = bx_process_input(bx_get('module_id'), BX_DATA_INT);
+    	$iItemId = bx_process_input(bx_get('item_id'), BX_DATA_INT);
+    	$iItemCount = bx_process_input(bx_get('item_count'), BX_DATA_INT);
+    	if(empty($iItemCount))
+    		$iItemCount = 1;
+
+        $aResult = $this->getObjectCart()->serviceSubscribe($iSellerId, $sSellerProvider, $iModuleId, $iItemId, $iItemCount);
+		echoJson($aResult);
+    }
+
+
+    /**
+     * Payment Processing Methods
+     */
+	public function actionInitializeCheckout($sType)
+    {
+    	if(!$this->isLogged())
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_required_login');
+
+		if(bx_get('seller_id') !== false && bx_get('provider') !== false && bx_get('items') !== false) {
+			$iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+			$sProvider = bx_process_input(bx_get('provider'));
+			$aItems = bx_process_input(bx_get('items'));
+
+			$mixedResult = $this->serviceInitializeCheckout(BX_PAYMENT_TYPE_SINGLE, $iSellerId, $sProvider, $aItems);
+			if($mixedResult !== true)
+	    		return $this->_oTemplate->displayPageCodeError($mixedResult);
+		}
+
+        header('Location: ' . $this->_oConfig->getUrl('URL_CART'));
+        exit;
+    }
+
+	public function serviceInitializeCheckout($sType, $iSellerId, $sProvider, $aItems = array())
+	{
+		if(!is_array($aItems))
+			$aItems = array($aItems);
+
+		$iSellerId = (int)$iSellerId;
+        if($iSellerId == BX_PAYMENT_EMPTY_ID)
+            return $this->_sLangsPrefix . 'err_unknown_vendor';
+
+		$oProvider = $this->getObjectProvider($sProvider, $iSellerId);
+        if($oProvider === false || !$oProvider->isActive())
+        	return $this->_sLangsPrefix . 'err_incorrect_provider';
+
+        $aInfo = $this->getObjectCart()->getInfo($sType, $this->_iUserId, $iSellerId, $aItems);
+        if(empty($aInfo) || $aInfo['vendor_id'] == BX_PAYMENT_EMPTY_ID || empty($aInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_order';
+
+		/*
+		 * Process FREE (price = 0) items for LOGGED IN members
+		 * WITHOUT processing via payment provider.
+		 */
+		$bProcessedFree = false;
+		$sKeyPriceSingle = $this->_oConfig->getKey('KEY_ARRAY_PRICE_SINGLE');
+		$sKeyPriceRecurring = $this->_oConfig->getKey('KEY_ARRAY_PRICE_RECURRING');
+		foreach($aInfo['items'] as $iIndex => $aItem)
+			if((int)$aInfo['client_id'] != 0 && (float)$aItem[$sKeyPriceSingle] == 0 && (float)$aItem[$sKeyPriceRecurring] == 0) {
+				$aItemInfo = $this->callRegisterCartItem((int)$aItem['module_id'], array($aInfo['client_id'], $aInfo['vendor_id'], $aItem['id'], $aItem['quantity'], $this->_oConfig->getLicense()));
+	            if(is_array($aItemInfo) && !empty($aItemInfo))
+	            	$bProcessedFree = true;
+
+	            $aInfo['items_count'] -= 1;
+	            unset($aInfo['items'][$iIndex]);
+
+	            $sCartItems = $this->_oDb->getCartItems($aInfo['client_id']);
+	            $sCartItems = trim(preg_replace("'" . $this->_oConfig->descriptorA2S(array($aInfo['vendor_id'], $aItem['module_id'], $aItem['id'], $aItem['quantity'])) . ":?'", "", $sCartItems), ":");
+	            $this->_oDb->setCartItems($aInfo['client_id'], $sCartItems);
+			}
+
+		if(empty($aInfo['items']))
+            return $this->_sLangsPrefix . ($bProcessedFree ? 'msg_successfully_processed_free' : 'err_empty_order');
+
+        $iPendingId = $this->_oDb->insertOrderPending($this->_iUserId, $sType, $sProvider, $aInfo);
+        if(empty($iPendingId))
+            return $this->_sLangsPrefix . 'err_access_db';
+
+		/*
+		 * Perform Join WITHOUT processing via payment provider
+		 * if a client ISN'T logged in and has only ONE FREE item in the card.
+		 */
+		if((int)$aInfo['client_id'] == 0 && (int)$aInfo['items_count'] == 1) {
+			reset($aInfo['items']);
+			$aItem = current($aInfo['items']);
+
+			if(!empty($aItem) && $this->_oConfig->getPrice($sType, $aItem)) {
+				$this->_oDb->updateOrderPending($iPendingId, array(
+		            'order' => $this->_oConfig->getLicense(),
+		            'error_code' => '1',
+		            'error_msg' => ''
+		        ));
+
+				$this->getObjectJoin()->performJoin($iPendingId);
+			}
+		}
+
+		return $oProvider->initializeCheckout($iPendingId, $aInfo);
+	}
+
+    public function actionFinalizeCheckout($sProvider, $mixedVendorId = "")
+    {
+        $aData = &$_REQUEST;
+
+        $oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false || !$oProvider->isActive())
+        	return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_incorrect_provider');
+
+        $aResult = $oProvider->finalizeCheckout($aData);
+        if((int)$aResult['code'] != BX_PAYMENT_RESULT_SUCCESS) 
+        	return $this->_oTemplate->displayPageCodeError($aResult['message']);
+
+		$aPending = $this->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$aResult['pending_id']));
+
+		//--- 'System' -> 'Before Register Payment' for Alerts Engine ---//
+		bx_import('BxDolAlerts');
+        $oZ = new BxDolAlerts('system', 'before_register_payment', 0, $aPending['client_id'], array('pending' => $aPending));
+        $oZ->alert();
+		//--- 'System' -> 'Before Register Payment' for Alerts Engine ---//
+
+		//--- Check "Pay Before Join" situation
+		if((int)$aPending['client_id'] == 0)
+			$this->getObjectJoin()->performJoin((int)$aPending['id'], isset($aResult['client_name']) ? $aResult['client_name'] : '', isset($aResult['client_email']) ? $aResult['client_email'] : '');
+
+		//--- Register payment for purchased items in associated modules 
+		if(!empty($aResult['paid']))
+			$this->registerPayment($aPending);
+
+		if($oProvider->needRedirect()) {
+			header('Location: ' . $oProvider->getReturnUrl());
+			exit;
+		}
+
+		$this->_oTemplate->displayPageCodeResponse($aResult['message']);
+    }
+
+    public function actionFinalizedCheckout($sProvider, $mixedVendorId = "")
+    {
+        $oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false || !$oProvider->isActive())
+        	return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_incorrect_provider');
+
+        $aResult = $oProvider->finalizedCheckout();
+        $this->_oTemplate->displayPageCodeResponse($aResult['message']);
+    }
+
+    public function actionNotify($sProvider, $mixedVendorId = "")
+    {
+    	$oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false || !$oProvider->isActive())
+        	return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_incorrect_provider');
+
+		$oProvider->notify();
+    }
+
+    public function onProfileJoin($iProfileId)
+    {
+    	$this->getObjectJoin()->onProfileJoin($iProfileId);
+    }
+
+    public function onProfileDelete($iProfileId)
+    {
+		$this->_oDb->onProfileDelete($iProfileId);
+    }
+
+    public function isAllowedSell($aItem, $bPerform = false)
+    {
+		$iUserId = (int)$this->getProfileId();
+        if(!$iUserId)
+        	return false;
+
+		$aItemInfo = $this->callGetCartItem($aItem['module_id'], array($aItem['item_id']));
+		if(empty($aItemInfo))
+			return false;
+
+        if(isAdmin())
+            return true;
+
+        $aCheckResult = checkActionModule($iUserId, 'sell', $this->getName(), $bPerform);
+        if((int)$aItemInfo['author_id'] == $iUserId && $aCheckResult[CHECK_ACTION_RESULT] == CHECK_ACTION_RESULT_ALLOWED)
+			return true;
+
+        return $aCheckResult[CHECK_ACTION_MESSAGE];
+    }
+
+	public function registerPayment($mixedPending)
+    {
+    	$aPending = is_array($mixedPending) ? $mixedPending : $this->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
+    	if(empty($aPending) || !is_array($aPending))
+    		return false;
+
+		$sType = $aPending['type'];
+		$bTypeSingle = $sType == BX_PAYMENT_TYPE_SINGLE;
+
+		if($bTypeSingle && (int)$aPending['processed'] == 1)
+			return true;
+
+		$iClientId = (int)$aPending['client_id'];
+		$sLicense = $this->_oConfig->getLicense();
+
+		$sCartItems = '';
+		if($bTypeSingle)
+			$sCartItems = $this->_oDb->getCartItems($iClientId);
+
+		$bResult = false;
+        $aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+        foreach($aItems as $aItem) {
+        	$sMethod = $bTypeSingle ? 'callRegisterCartItem' : 'callRegisterSubscriptionItem';
+        	$aItemInfo = $this->$sMethod((int)$aItem['module_id'], array($aPending['client_id'], $aPending['seller_id'], $aItem['item_id'], $aItem['item_count'], $aPending['order'], $sLicense));
+            if(empty($aItemInfo) || !is_array($aItemInfo))
+                continue;
+
+            $this->_oDb->insertOrderProcessed(array(
+                'pending_id' => $aPending['id'],
+                'client_id' => $aPending['client_id'],
+                'seller_id' => $aPending['seller_id'],
+                'module_id' => $aItem['module_id'],
+                'item_id' => $aItem['item_id'],
+                'item_count' => $aItem['item_count'],
+                'amount' => $aItem['item_count'] * $this->_oConfig->getPrice($sType, $aItemInfo),
+            	'license' => $sLicense,
+            ));
+
+            if($bTypeSingle)
+            	$sCartItems = trim(preg_replace("'" . $this->_oConfig->descriptorA2S($aItem) . ":?'", "", $sCartItems), ":");
+
+			$bResult = true;
+        }
+
+        if($bTypeSingle)
+			$this->_oDb->setCartItems($iClientId, $sCartItems);
+
+        if($bResult) {
+        	$this->_oDb->updateOrderPending($aPending['id'], array('processed' => 1));
+
+			//--- 'System' -> 'Register Payment' for Alerts Engine ---//
+			bx_import('BxDolAlerts');
+	        $oZ = new BxDolAlerts('system', 'register_payment', 0, $iClientId, array('pending' => $aPending));
+	        $oZ->alert();
+			//--- 'System' -> 'Register Payment' for Alerts Engine ---//
+        }
+
+        return $bResult;
+    }
+
+	public function refundPayment($mixedPending)
+	{
+		$aPending = is_array($mixedPending) ? $mixedPending : $this->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
+    	if(empty($aPending) || !is_array($aPending))
+    		return false;
+
+		$bTypeSingle = $aPending['type'] == BX_PAYMENT_TYPE_SINGLE;
+
+		$iCanceled = 0;
+		$aOrders = $this->_oDb->getOrderProcessed(array('type' => 'pending_id', 'pending_id' => (int)$aPending['id']));
+		foreach($aOrders as $aOrder) {
+			$sMethod = $bTypeSingle ? 'callUnregisterCartItem' : 'callUnregisterSubscriptionItem';
+			$bResult = $this->$sMethod((int)$aOrder['module_id'], array($aOrder['client_id'], $aOrder['seller_id'], $aOrder['item_id'], $aOrder['item_count'], $aPending['order'], $aOrder['license']));
+			if(!$bResult)
+                continue;
+
+            if($this->_oDb->deleteOrderProcessed($aOrder['id']))
+            	$iCanceled++;
+		}
+
+		if($iCanceled != count($aOrders))
+			return false;
+
+		return $this->_oDb->deleteOrderPending($aPending['id']);
+	}
+
+	public function cancelSubscription($mixedPending)
+	{
+		$aPending = is_array($mixedPending) ? $mixedPending : $this->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
+    	if(empty($aPending) || !is_array($aPending) || $aPending['type'] != BX_PAYMENT_TYPE_RECURRING)
+    		return false;
+
+		$aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+        foreach($aItems as $aItem)
+			$this->callCancelSubscriptionItem((int)$aItem['module_id'], array($aPending['client_id'], $aPending['seller_id'], $aItem['item_id'], $aItem['item_count'], $aPending['order']));
+	}
+}
+
+/** @} */

+ 280 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentProviderChargebee.php

@@ -0,0 +1,280 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+require_once(BX_DIRECTORY_PATH_PLUGINS . 'chargebee/ChargeBee.php');
+
+define('CBEE_MODE_LIVE', 1);
+define('CBEE_MODE_TEST', 2);
+
+class BxPaymentProviderChargebee extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+	protected $_iMode;
+	protected $_bCheckAmount;
+
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_bRedirectOnResult = false;
+        $this->_bUseSsl = $this->getOption('ssl') == 'on';
+        $this->_sLogFile = BX_DIRECTORY_PATH_LOGS . 'bx_pp_' . $this->_sName . '.log';        
+
+        $this->_iMode = (int)$this->getOption('mode');
+        $this->_bCheckAmount = false; // Disabled for easier processing of discounted subscriptions.
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo)
+    {
+    	$aItem = array_shift($aCartInfo['items']);
+    	if(empty($aItem) || !is_array($aItem))
+    		return $this->_sLangsPrefix . 'err_empty_items';
+
+		$aClient = $this->_oModule->getProfileInfo();
+		$aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+		$oPage = $this->createHostedPage($iPendingId, $aItem, $aClient, $aVendor);
+		if($oPage === false)
+			return $this->_sLangsPrefix . 'err_cannot_perform';
+
+		return array(
+			'code' => 0,
+			'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onSubscribeSubmit(oData);',
+			'redirect' => $oPage->url
+		);
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+    	$sPageId = bx_process_input($aData['id']);
+		$iPendingId = bx_process_input($aData['pending_id'], BX_DATA_INT);
+
+        if(empty($sPageId) || empty($iPendingId))
+        	return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_wrong_data');
+
+		$oPage = $this->retreiveHostedPage($sPageId);
+		if($oPage === false)
+			return $this->_sLangsPrefix . 'err_cannot_perform';
+		
+		$aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return array('code' => 3, 'message' => $this->_sLangsPrefix . 'err_already_processed');
+
+		$oCustomer = $oPage->content()->customer();
+		$oSubscription = $oPage->content()->subscription();
+
+		$aResult = array(
+			'code' => BX_PAYMENT_RESULT_SUCCESS,
+        	'message' => $this->_sLangsPrefix . 'cbee_msg_subscribed',
+			'pending_id' => $iPendingId,
+			'client_name' => _t($this->_sLangsPrefix . 'txt_buyer_name_mask', $oCustomer->firstName, $oCustomer->lastName),
+			'client_email' => $oCustomer->email,
+			'paid' => false
+		);
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $oSubscription->id,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        return $aResult;
+    }
+
+    public function notify()
+    {
+		$iResult = $this->_processEvent();
+		http_response_code($iResult);
+    }
+
+	public function createHostedPage($iPendingId, $aItem, $aClient, $aVendor) {
+		$oPage = false;
+
+		try {
+			ChargeBee_Environment::configure($this->_getSite(), $this->_getApiKey());
+			$oResult = ChargeBee_HostedPage::checkoutNew(array(
+				'redirectUrl' => bx_append_url_params($this->getReturnDataUrl($aVendor['id']), array(
+					'pending_id' => $iPendingId
+				)),
+				'subscription' => array(
+					'planId' => $aItem['name']
+				), 
+				'customer' => array(
+					'email' => $aClient['email'],
+					'firstName' => $aClient['name']
+				), 
+			));
+
+			$oPage = $oResult->hostedPage();
+		}
+		catch (Exception $oException) {
+			$iError = $oException->getCode();
+			$sError = $oException->getMessage();
+
+			$this->log('Create Hosted Page Error: ' . $sError . '(' . $iError . ')');
+
+			return false;
+		}
+
+		return $oPage;
+	}
+
+	public function retreiveHostedPage($sPageId) {
+		$oPage = null;
+
+		try {
+			ChargeBee_Environment::configure($this->_getSite(), $this->_getApiKey());
+			$oResult = ChargeBee_HostedPage::retrieve($sPageId);
+
+			$oPage = $oResult->hostedPage();
+		}
+		catch (Exception $oException) {
+			$iError = $oException->getCode();
+			$sError = $oException->getMessage();
+
+			$this->log('Retrieve Hosted Page Error: ' . $sError . '(' . $iError . ')');
+
+			return false;
+		}
+
+		return $oPage;
+	}
+
+	public function retrieveSubscription($sSubscriptionId)
+	{
+		$oSubscription = null;
+
+		try {
+			ChargeBee_Environment::configure($this->_getSite(), $this->_getApiKey());
+			$oResult = ChargeBee_Subscription::retrieve($sSubscriptionId);
+
+			$oSubscription = $oResult->subscription();
+			if($oSubscription->id != $sSubscriptionId)
+				return false;
+		}
+		catch (Exception $oException) {
+			$iError = $oException->getCode();
+			$sError = $oException->getMessage();
+
+			$this->log('Retrieve Subscription Error: ' . $sError . '(' . $iError . ')');
+
+			return false;
+		}
+
+		return $oSubscription;
+	}
+
+	public function deleteSubscription($sSubscriptionId)
+	{
+		try {
+			ChargeBee_Environment::configure($this->_getSite(), $this->_getApiKey());
+			$oResult = ChargeBee_Subscription::cancel($sSubscriptionId);
+
+			$oSubscription = $oResult->subscription();
+			if($oSubscription->status != 'cancelled')
+				return false;
+		}
+		catch (Exception $oException) {
+			$aError = $oException->getJsonBody();
+
+			$this->log('Delete Subscription Error: ' . $aError['error']['message']);
+			$this->log($aError);
+
+			return false;
+		}
+
+		return true;
+	}
+
+	protected function _getSite()
+	{
+		return $this->_iMode == CBEE_MODE_LIVE ? $this->getOption('live_site') : $this->getOption('test_site');
+	}
+
+	protected function _getApiKey()
+	{
+		return $this->_iMode == CBEE_MODE_LIVE ? $this->getOption('live_api_key') : $this->getOption('test_api_key');
+	}
+
+	protected function _processEvent()
+	{
+    	$sInput = @file_get_contents("php://input");
+		$aEvent = json_decode($sInput, true);
+		if(empty($aEvent) || !is_array($aEvent)) 
+			return 404;
+
+		$sType = $aEvent['event_type'];
+		if(!in_array($sType, array('payment_succeeded', ' payment_refunded', 'subscription_cancelled')))
+			return 200;
+
+		$this->log('Webhooks: ' . (!empty($sType) ? $sType : ''));
+		$this->log($aEvent);
+
+		$sMethod = '_processEvent' . bx_gen_method_name($sType, array('.', '_', '-'));
+    	if(!method_exists($this, $sMethod))
+    		return 200;
+
+    	return $this->$sMethod($aEvent) ? 200 : 403;
+    }
+
+	protected function _processEventPaymentSucceeded(&$aEvent)
+	{
+		$mixedResult = $this->_getData($aEvent, true);
+		if($mixedResult === false)
+			return false;
+
+		list($aPending, $aTransaction) = $mixedResult;
+
+		$fTransactionAmount = (float)$aTransaction['amount'] / 100;
+		$sTransactionCurrency = strtoupper($aTransaction['currency_code']);
+		if($this->_bCheckAmount && ((float)$aPending['amount'] != $fTransactionAmount || strcasecmp($this->_oModule->_oConfig->getDefaultCurrencyCode(), $sTransactionCurrency) != 0))
+			return false;
+
+		return $this->_oModule->registerPayment($aPending);
+	}
+
+	protected function _processEventPaymentRefunded(&$aEvent)
+	{
+		$mixedResult = $this->_getData($aEvent);
+		if($mixedResult === false)
+			return false;
+
+		list($aPending) = $mixedResult;
+		return $this->_oModule->refundPayment($aPending);
+	}
+
+	protected function _processEventSubscriptionCancelled(&$aEvent)
+	{
+		$mixedResult = $this->_getData($aEvent);
+		if($mixedResult === false)
+			return false;
+
+		list($aPending) = $mixedResult;
+		return $this->_oModule->cancelSubscription($aPending);
+	}
+
+	protected function _getData(&$aEvent, $bWithStatusCheck = false)
+	{
+		$aTransaction = $aEvent['content']['transaction'];
+		if(empty($aTransaction) || ($bWithStatusCheck && $aTransaction['status'] != 'success'))
+			return false;
+
+		$aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'order', 'order' => $aTransaction['subscription_id']));
+		if(empty($aPending) || !is_array($aPending))
+			return false;
+
+		return array($aPending, $aTransaction);
+	}
+}
+
+/** @} */

+ 256 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentProviderPayPal.php

@@ -0,0 +1,256 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+define('PP_MODE_LIVE', 1);
+define('PP_MODE_TEST', 2);
+
+define('PP_PRC_TYPE_DIRECT', 1);
+define('PP_PRC_TYPE_PDT', 2);
+define('PP_PRC_TYPE_IPN', 3);
+
+class BxPaymentProviderPayPal extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_bRedirectOnResult = false;
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $bRecurring = false, $iRecurringDays = 0)
+    {
+        $iMode = (int)$this->getOption('mode');
+        $sActionURL = $iMode == PP_MODE_LIVE ? 'https://www.paypal.com/cgi-bin/webscr' : 'https://www.sandbox.paypal.com/cgi-bin/webscr';
+
+        if($bRecurring)
+            $aFormData = array(
+                'cmd' => '_xclick-subscriptions',
+                'a3' => sprintf("%.2f", (float)$aCartInfo['items_price']),
+                'p3' => $iRecurringDays,
+                't3' => 'D',
+                'src' => '1', // repeat billings unles member cancels subscription
+                'sra' => '1' // reattempt on failure
+            );
+        else
+            $aFormData = array(
+                'cmd' => '_xclick',
+                'amount' => sprintf( "%.2f", (float)$aCartInfo['items_price'])
+            );
+
+        $aFormData = array_merge($aFormData, array(
+            'business' => $iMode == PP_MODE_LIVE ? $this->getOption('business') : $this->getOption('sandbox'),
+            'bn' => 'Boonex_SP',
+            'item_name' => _t($this->_sLangsPrefix . 'txt_payment_to_for', $aCartInfo['vendor_name']),
+            'item_number' => $iPendingId,
+            'currency_code' => $aCartInfo['vendor_currency_code'],
+            'no_note' => '1',
+            'no_shipping' => '1',
+            'custom' => md5($aCartInfo['vendor_id'] . $iPendingId)
+        ));
+
+        foreach($aCartInfo['items'] as $aItem)
+            $aFormData['item_name'] .= ' ' . $aItem['title'] . ',';
+		$aFormData['item_name'] = trim($aFormData['item_name'], ', ');
+
+        switch($this->getOption('prc_type')) {
+            case PP_PRC_TYPE_PDT:
+            case PP_PRC_TYPE_DIRECT:
+                $aFormData = array_merge($aFormData, array(
+                    'return' => $this->getReturnDataUrl($aCartInfo['vendor_id']),
+                    'rm' => '2'
+                ));
+                break;
+            case PP_PRC_TYPE_IPN:
+                $aFormData = array_merge($aFormData, array(
+                    'return' => $this->getReturnUrl(),
+                    'notify_url' => $this->getReturnDataUrl($aCartInfo['vendor_id']),
+                    'rm' => '1'
+                ));
+                break;
+        }
+
+        $this->_oModule->_oTemplate->displayPageCodeRedirect($sActionURL, $aFormData);
+        exit;
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        if($aData['txn_type'] != 'web_accept' && !isset($aData['tx']))
+        	return array('code' => 1, 'message' => $this->_sLangsPrefix . 'pp_err_no_data_given');
+
+		return $this->_registerCheckout($aData);
+    }
+
+    /**
+     *
+     * @param $aData - data from payment provider.
+     * @param $bSubscription - Is not needed. May be used in the future for subscriptions.
+     * @param $iPendingId - Is not needed. May be used in the future for subscriptions.
+     * @return array with results.
+     */
+    protected function _registerCheckout(&$aData, $bSubscription = false, $iPendingId = 0)
+    {
+        if(empty($this->_aOptions) && isset($aData['item_number']))
+            $this->_aOptions = $this->getOptionsByPending($aData['item_number']);
+
+        if(empty($this->_aOptions))
+            return array('code' => 2, 'message' => $this->_sLangsPrefix . 'err_unknown_vendor');
+
+        $iPrcType = (int)$this->getOption('prc_type');
+        if(($iPrcType == PP_PRC_TYPE_IPN || $iPrcType == PP_PRC_TYPE_DIRECT) && (!isset($aData['item_number']) || !isset($aData['txn_id'])))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'pp_err_no_data_given');
+        else if($iPrcType == PP_PRC_TYPE_PDT && !isset($aData['tx']))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'pp_err_no_data_given');
+
+        $aResult = $this->_validateCheckout($aData);
+
+        if(!$bSubscription || empty($iPendingId))
+            $iPendingId = (int)$aData['item_number'];
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return array('code' => 3, 'message' => $this->_sLangsPrefix . 'err_already_processed');
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $aData['txn_id'],
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        $aResult['pending_id'] = $iPendingId;
+        $aResult['client_name'] = _t($this->_sLangsPrefix . 'txt_buyer_name_mask', bx_process_input($aData['first_name']), bx_process_input($aData['last_name'])); 
+		$aResult['client_email'] = bx_process_input($aData['payer_email']);
+		$aResult['paid'] = true;
+        return $aResult;
+    }
+
+    protected function _validateCheckout(&$aData)
+    {
+        $iMode = (int)$this->getOption('mode');
+        if($iMode == PP_MODE_LIVE) {
+           $sBusiness = $this->getOption('business');
+           $sConnectionUrl = 'www.paypal.com';
+        } else {
+            $sBusiness = $this->getOption('sandbox');
+            $sConnectionUrl = 'www.sandbox.paypal.com';
+        }
+
+        $iPrcType = $this->getOption('prc_type');
+        if($iPrcType == PP_PRC_TYPE_DIRECT || $iPrcType == PP_PRC_TYPE_IPN) {
+            if($aData['payment_status'] != 'Completed' )
+                return array('code' => 4, 'message' => $this->_sLangsPrefix . 'pp_err_not_completed');
+
+            if($aData['business'] != $sBusiness)
+                return array('code' => 5, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_business');
+
+            $sRequest = 'cmd=_notify-validate';
+            foreach($aData as $sKey => $sValue) {
+                if(in_array($sKey, array('cmd')))
+                    continue;
+
+                $sRequest .= '&' . urlencode($sKey) . '=' . urlencode(bx_process_pass($sValue));
+            }
+
+            $aResponse = $this->_readValidationData($sConnectionUrl, $sRequest);
+            if((int)$aResponse['code'] !== 0)
+               return $aResponse;
+
+            array_walk($aResponse['content'], create_function('&$arg', "\$arg = trim(\$arg);"));
+            if(strcmp($aResponse['content'][1], "INVALID") == 0)
+                return array('code' => 7, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_transaction');
+            else if(strcmp($aResponse['content'][1], "VERIFIED") != 0)
+                return array('code' => 8, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_verification_status');
+        }
+         else if($iPrcType == PP_PRC_TYPE_PDT) {
+            $sRequest = "cmd=_notify-synch&tx=" . $aData['tx'] . "&at=" . $this->getOption('token');
+            $aResponse = $this->_readValidationData($sConnectionUrl, $sRequest);
+
+            if((int)$aResponse['code'] !== 0)
+               return $aResponse;
+
+            if(strcmp($aResponse['content'][1], "FAIL") == 0)
+                return array('code' => 7, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_transaction');
+            else if(strcmp($aResponse['content'][1], "SUCCESS") != 0)
+                return array('code' => 8, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_verification_status');
+
+            $aKeys = array();
+            foreach($aResponse['content'] as $sLine) {
+                list($sKey, $sValue) = explode("=", $sLine);
+                $aKeys[urldecode($sKey)] = urldecode($sValue);
+            }
+
+            $aData = array_merge($aData, $aKeys);
+
+            if($aData['payment_status'] != 'Completed' )
+                return array('code' => 4, 'message' => $this->_sLangsPrefix . 'pp_err_not_completed');
+
+            if($aData['business'] != $sBusiness)
+                return array('code' => 5, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_business');
+        }
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $aData['item_number']));
+        $aVendor = $this->_oModule->getVendorInfo($aPending['seller_id']);
+        $fAmount = (float)$this->_getReceivedAmount($aVendor['currency_code'], $aData);
+        if($fAmount != (float)$aPending['amount'])
+            return array('code' => 9, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_amount');
+
+        if($aData['custom'] != md5($aPending['seller_id'] . $aPending['id']))
+            return array('code' => 10, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_custom_data');
+
+        return array('code' => BX_PAYMENT_RESULT_SUCCESS, 'message' => $this->_sLangsPrefix . 'pp_msg_verified');
+    }
+
+    protected function _readValidationData($sConnectionUrl, $sRequest)
+    {
+        $sHeader = "POST /cgi-bin/webscr HTTP/1.1\r\n";
+        $sHeader .= "Host: " . $sConnectionUrl . "\r\n";
+        $sHeader .= "Content-Type: application/x-www-form-urlencoded\r\n";
+        $sHeader .= "Content-Length: " . strlen($sRequest) . "\r\n";
+        $sHeader .= "Connection: close\r\n\r\n";
+
+        $iErrCode = 0;
+        $sErrMessage = "";
+
+        $rSocket = fsockopen("ssl://" . $sConnectionUrl, 443, $iErrCode, $sErrMessage, 60);
+		if(!$rSocket)
+            return array('code' => 6, 'message' => $this->_sLangsPrefix . 'err_cannot_validate');
+
+        fputs($rSocket, $sHeader);
+        fputs($rSocket, $sRequest);
+
+        $sResponse = '';
+        while(!feof($rSocket))
+            $sResponse .= fread($rSocket, 1024);
+        fclose($rSocket);
+
+        list($sResponseHeader, $sResponseContent) = explode("\r\n\r\n", $sResponse);
+
+        return array('code' => 0, 'content' => explode("\n", $sResponseContent));
+    }
+    protected function _getReceivedAmount($sCurrencyCode, &$aResultData)
+    {
+        $fAmount = 0.00;
+
+        if($aResultData['mc_currency'] == $sCurrencyCode && isset($aResultData['payment_gross']) && !empty($aResultData['payment_gross']))
+            $fAmount = (float)$aResultData['payment_gross'];
+        else if($aResultData['mc_currency'] == $sCurrencyCode && isset($aResultData['mc_gross']) && !empty($aResultData['mc_gross']))
+            $fAmount = (float)$aResultData['mc_gross'];
+        else if($aResultData['settle_currency'] == $sCurrencyCode && isset($aResultData['settle_amount']) && !empty($aResultData['settle_amount']))
+            $fAmount = (float)$aResultData['settle_amount'];
+
+        return $fAmount;
+    }
+}
+
+/** @} */

+ 324 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentProviderRecurly.php

@@ -0,0 +1,324 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+require_once(BX_DIRECTORY_PATH_PLUGINS . 'recurly/recurly.php');
+
+define('RCRL_MODE_LIVE', 1);
+define('RCRL_MODE_TEST', 2);
+
+class BxPaymentProviderRecurly extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+	protected $_aIncludeJs;
+	protected $_aIncludeCss;
+
+	protected $_sFormCard;
+	protected $_sFormDisplayCardAdd;
+
+	protected $_iMode;
+	protected $_bCheckAmount;
+
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_aIncludeJs = array(
+        	'https://js.recurly.com/v4/recurly.js'
+        );
+        $this->_aIncludeCss = array(
+        	'recurly.css'
+        );
+
+        $this->_sFormCard = 'bx_payment_form_rcrl_card';
+        $this->_sFormDisplayCardAdd = 'bx_payment_form_rcrl_card_add';
+
+        $this->_bRedirectOnResult = false;
+        $this->_bUseSsl = true;
+        $this->_sLogFile = BX_DIRECTORY_PATH_LOGS . 'bx_pp_' . $this->_sName . '.log';        
+
+        $this->_iMode = (int)$this->getOption('mode');
+        $this->_bCheckAmount = false; // Disabled for easier processing of discounted subscriptions.
+    }
+
+	public function addJsCss()
+    {
+    	if(!$this->isActive())
+    		return;
+
+		$this->_oModule->_oTemplate->addJs($this->_aIncludeJs);
+		$this->_oModule->_oTemplate->addCss($this->_aIncludeCss);
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo)
+    {
+    	$aItem = array_shift($aCartInfo['items']);
+    	if(empty($aItem) || !is_array($aItem))
+    		return $this->_sLangsPrefix . 'err_empty_items';
+
+		$aClient = $this->_oModule->getProfileInfo();
+		$aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+		$mixedResult = $this->createCardForm($iPendingId, $aItem, $aClient, $aVendor);
+		if($mixedResult === false)
+			return $this->_sLangsPrefix . 'err_cannot_perform';
+
+		return array_merge(array('code' => 0), $mixedResult);
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+    	$iPendingId = bx_process_input($aData['pending_id'], BX_DATA_INT);
+    	$sItem = bx_process_input($aData['item']);
+    	$sToken = bx_process_input($aData['token']);
+    	$aClient = array(
+    		'first_name' => bx_process_input($aData['first_name']),
+    		'last_name' => bx_process_input($aData['last_name']),
+    		'email' => bx_process_input($aData['email'])
+    	);
+
+        if(empty($sToken) || empty($iPendingId))
+        	return array('code' => 1, 'message' => $this->_sLangsPrefix . 'pp_err_no_data_given');
+		
+		$aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return array('code' => 3, 'message' => $this->_sLangsPrefix . 'err_already_processed');
+
+		$oSubscription = $this->createSubscription($sToken, $sItem, $aClient);
+		if($oSubscription === false)
+			return $this->_sLangsPrefix . 'err_cannot_perform';
+
+		/*
+		 * TODO: Need to get subscription ID to save it in DB as Order
+		 */
+		$sSubscription = '';
+
+		$aResult = array(
+			'code' => BX_PAYMENT_RESULT_SUCCESS,
+        	'message' => $this->_sLangsPrefix . 'rcrl_msg_subscribed',
+			'pending_id' => $iPendingId,
+			'client_name' => _t($this->_sLangsPrefix . 'txt_buyer_name_mask', $aClient['first_name'], $aClient['last_name']),
+			'client_email' => $aClient['email'],
+			'paid' => false
+		);
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $sSubscription,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        return $aResult;
+    }
+
+    public function notify()
+    {
+    	/*
+    	 * TODO: Integrate necessary Webhook events. 
+    	 */
+		//$iResult = $this->_processEvent();
+		//http_response_code($iResult);
+    }
+
+    public function createCardForm($iPendingId, $aItem, $aClient, $aVendor)
+    {
+		$oForm = BxDolForm::getObjectInstance($this->_sFormCard, $this->_sFormDisplayCardAdd, $this->_oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = bx_append_url_params($this->getReturnDataUrl($aVendor['id']), array(
+			'pending_id' => $iPendingId
+		));
+
+        $oForm->aInputs['pending_id']['value'] = $iPendingId;
+        $oForm->aInputs['item']['value'] = $aItem['name'];
+
+		$aCardFields = array('card_number', 'card_cvv');
+		foreach($aCardFields as $sCardField) {
+			$oForm->aInputs[$sCardField]['content'] = $this->_oModule->_oTemplate->parseHtmlByName('rcrl_card_field.html', array(
+				'attrs' => bx_convert_array2attrs($oForm->aInputs[$sCardField]['attrs'])
+			));
+		}
+		$oForm->aInputs['card_expire']['content'] = $this->_oModule->_oTemplate->parseHtmlByName('rcrl_card_field_date.html', array(
+			'attrs_month' => bx_convert_array2attrs(array('data-recurly' => 'month')),
+			'attrs_year' => bx_convert_array2attrs(array('data-recurly' => 'year'))
+		));
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+        	$sFormMethod = $oForm->aFormAttrs['method'];
+
+        	/*
+        	 * TODO: Need to reload form on internal error or update the code to work via this check and then redirect to Finalize.
+        	 * Issue with "form reloading". Currently Recurly doesn't allow to "call payment form" multiple times (https://github.com/recurly/recurly-js/issues/239). 
+        	 */ 
+        }
+
+        $aTmplConfig = BxTemplConfig::getInstance()->__get('aLessConfig');
+        
+        $sId = 'bx-payment-rcrl-card-add';
+    	$sTitle = _t($this->_sLangsPrefix . 'popup_title_rcrl_card_add');
+		$sContent = BxTemplStudioFunctions::getInstance()->popupBox($sId, $sTitle, $this->_oModule->_oTemplate->parseHtmlByName('rcrl_card_popup_add.html', array(
+			'public_key' => $this->getOption('api_key_public'),
+			'font_family' => $aTmplConfig['bx-font-family'],
+			'font_size' => $aTmplConfig['bx-font-size-default'],
+			'font_color' => $aTmplConfig['bx-font-color-default'],
+			'form_id' => $oForm->aFormAttrs['id'],
+			'form' => $oForm->getCode(true),
+		)));
+
+		return array('popup' => array(
+			'html' => $sContent, 
+			'options' => array(
+				'closeOnOuterClick' => false, 
+				'onBeforeShow' => 'bxRecurlyFieldsInit();', 
+				'onHide' => 'bxRecurlyFieldsDestroy();'
+			)
+		));
+    }
+
+	public function createSubscription($sToken, $sItem, $aClient)
+	{
+		$oSubscription = false;
+
+		try {
+			$oSubscription = new Recurly_Subscription();
+			$oSubscription->plan_code = $sItem;
+
+			$oSubscription->account = new Recurly_Account();
+			$oSubscription->account->account_code = 'pat_smith';
+			$oSubscription->account->first_name = $aClient['first_name'];
+			$oSubscription->account->last_name = $aClient['last_name'];
+			$oSubscription->account->email = $aClient['email'];
+
+			$oSubscription->account->billing_info = new Recurly_BillingInfo();
+			$oSubscription->account->billing_info->token_id = $sToken;
+
+			$oSubscription->create();
+		}
+		catch (Exception $oException) {
+			$iError = $oException->getCode();
+			$sError = $oException->getMessage();
+
+			$this->log('Create Subscription Error: ' . $sError . '(' . $iError . ')');
+
+			return false;
+		}
+
+		return $oSubscription;
+	}
+
+	public function retrieveSubscription($sSubscriptionId)
+	{
+		$oSubscription = null;
+
+		try {
+			
+		}
+		catch (Exception $oException) {
+			$iError = $oException->getCode();
+			$sError = $oException->getMessage();
+
+			$this->log('Retrieve Subscription Error: ' . $sError . '(' . $iError . ')');
+
+			return false;
+		}
+
+		return $oSubscription;
+	}
+
+	public function deleteSubscription($sSubscriptionId)
+	{
+		try {
+
+		}
+		catch (Exception $oException) {
+			$aError = $oException->getJsonBody();
+
+			$this->log('Delete Subscription Error: ' . $aError['error']['message']);
+			$this->log($aError);
+
+			return false;
+		}
+
+		return true;
+	}
+
+	protected function _processEvent()
+	{
+    	$sInput = @file_get_contents("php://input");
+		$aEvent = json_decode($sInput, true);
+		if(empty($aEvent) || !is_array($aEvent)) 
+			return 404;
+
+		$sType = $aEvent['event_type'];
+		if(!in_array($sType, array('payment_succeeded', ' payment_refunded', 'subscription_cancelled')))
+			return 200;
+
+		$this->log('Webhooks: ' . (!empty($sType) ? $sType : ''));
+		$this->log($aEvent);
+
+		$sMethod = '_processEvent' . bx_gen_method_name($sType, array('.', '_', '-'));
+    	if(!method_exists($this, $sMethod))
+    		return 200;
+
+    	return $this->$sMethod($aEvent) ? 200 : 403;
+    }
+
+	protected function _processEventPaymentSucceeded(&$aEvent)
+	{
+		$mixedResult = $this->_getData($aEvent, true);
+		if($mixedResult === false)
+			return false;
+
+		list($aPending, $aTransaction) = $mixedResult;
+
+		$fTransactionAmount = (float)$aTransaction['amount'] / 100;
+		$sTransactionCurrency = strtoupper($aTransaction['currency_code']);
+		if($this->_bCheckAmount && ((float)$aPending['amount'] != $fTransactionAmount || strcasecmp($this->_oModule->_oConfig->getDefaultCurrencyCode(), $sTransactionCurrency) != 0))
+			return false;
+
+		return $this->_oModule->registerPayment($aPending);
+	}
+
+	protected function _processEventPaymentRefunded(&$aEvent)
+	{
+		$mixedResult = $this->_getData($aEvent);
+		if($mixedResult === false)
+			return false;
+
+		list($aPending) = $mixedResult;
+		return $this->_oModule->refundPayment($aPending);
+	}
+
+	protected function _processEventSubscriptionCancelled(&$aEvent)
+	{
+		$mixedResult = $this->_getData($aEvent);
+		if($mixedResult === false)
+			return false;
+
+		list($aPending) = $mixedResult;
+		return $this->_oModule->cancelSubscription($aPending);
+	}
+
+	protected function _getData(&$aEvent, $bWithStatusCheck = false)
+	{
+		$aTransaction = $aEvent['content']['transaction'];
+		if(empty($aTransaction) || ($bWithStatusCheck && $aTransaction['status'] != 'success'))
+			return false;
+
+		$aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'order', 'order' => $aTransaction['subscription_id']));
+		if(empty($aPending) || !is_array($aPending))
+			return false;
+
+		return array($aPending, $aTransaction);
+	}
+}
+
+/** @} */

+ 517 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentProviderStripe.php

@@ -0,0 +1,517 @@
+<?php use Symfony\Component\Finder\Tests\FakeAdapter\DummyAdapter;
+defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+require_once(BX_DIRECTORY_PATH_PLUGINS . 'stripe/init.php');
+
+define('STRP_MODE_LIVE', 1);
+define('STRP_MODE_TEST', 2);
+
+class BxPaymentProviderStripe extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+	protected $_aIncludeJs;
+	protected $_aIncludeCss;
+
+	protected $_iMode;
+	protected $_bCheckAmount;
+
+	protected $_oCustomer;
+
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_bRedirectOnResult = false;
+        $this->_iMode = (int)$this->getOption('mode');
+        $this->_bCheckAmount = $this->getOption('check_amount') == 'on'; 
+        $this->_bUseSsl = $this->getOption('ssl') == 'on';
+        $this->_sLogFile = BX_DIRECTORY_PATH_LOGS . 'bx_pp_' . $this->_sName . '.log';
+
+        $this->_aIncludeJs = array(
+        	'https://checkout.stripe.com/checkout.js',
+        	'main.js',
+        	'stripe.js'
+        );
+        $this->_aIncludeCss = array(
+        	'stripe.css'
+        );
+
+        $this->_oCustomer = null;
+
+        \Stripe\Stripe::setApiKey($this->_getSecretKey());
+    }
+
+	public function addJsCss()
+    {
+    	if(!$this->isActive())
+    		return;
+
+		$this->_oModule->_oTemplate->addJs($this->_aIncludeJs);
+		$this->_oModule->_oTemplate->addCss($this->_aIncludeCss);
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo)
+    {
+    	$sToken = bx_process_input(bx_get('token'));
+
+    	if(empty($aCartInfo['items']) || !is_array($aCartInfo['items']))
+    		return $this->_sLangsPrefix . 'err_empty_items';
+
+		$aClient = $this->_oModule->getProfileInfo();
+		$aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+		$aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+		if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return $this->_sLangsPrefix . 'err_already_processed';
+
+		switch($aPending['type']) {
+			case BX_PAYMENT_TYPE_SINGLE:
+				$aCartInfo['items_title'] = '';
+				foreach($aCartInfo['items'] as $aItem)
+		            $aCartInfo['items_title'] .= ' ' . $aItem['title'] . ',';
+				$aCartInfo['items_title'] = trim($aCartInfo['items_title'], ', ');
+
+				$mixedResult = $this->_createCharge($sToken, $iPendingId, $aClient, $aCartInfo);
+				if($mixedResult === false)
+					return $this->_sLangsPrefix . 'err_cannot_perform';
+
+				header("Location: " . $this->getReturnDataUrl($aVendor['id'], array(
+					'order_id' => $mixedResult['order'],
+					'customer_id' => $mixedResult['customer'], 
+					'pending_id' => $aPending['id']
+				)));
+				exit;
+
+			case BX_PAYMENT_TYPE_RECURRING:
+				$mixedResult = $this->_createSubscription($sToken, $iPendingId, $aClient, $aCartInfo);
+				if($mixedResult === false)
+					return $this->_sLangsPrefix . 'err_cannot_perform';
+
+				return array(
+					'code' => 0,
+					'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onSubscribeSubmit(oData);',
+					'redirect' => $this->getReturnDataUrl($aVendor['id'], array(
+						'order_id' => $mixedResult['order'],
+						'customer_id' => $mixedResult['customer'],
+						'pending_id' => $aPending['id']
+					))
+				);
+		}
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+    	$sOrderId = bx_process_input($aData['order_id']);
+    	$sCustomerId = bx_process_input($aData['customer_id']);
+		$iPendingId = bx_process_input($aData['pending_id'], BX_DATA_INT);
+        if(empty($iPendingId))
+        	return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_wrong_data');
+
+		$aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return array('code' => 3, 'message' => $this->_sLangsPrefix . 'err_already_processed');
+
+		$aResult = array(
+			'code' => BX_PAYMENT_RESULT_SUCCESS,
+        	'message' => '',
+			'pending_id' => $iPendingId,
+			'client_name' => '',
+			'client_email' => '',
+			'paid' => false
+		);
+
+		switch($aPending['type']) {
+			case BX_PAYMENT_TYPE_SINGLE:
+				$aCustomer = $this->_retrieveCustomer($sCustomerId)->jsonSerialize();
+				$aCharge = $this->_retrieveCharge($sOrderId)->jsonSerialize();
+				if(empty($aCustomer) || !is_array($aCustomer) || empty($aCharge) || !is_array($aCharge))
+					return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+				$aResult = array_merge($aResult, array(
+					'message' => $this->_sLangsPrefix . 'strp_msg_charged',
+					'client_email' => $aCustomer['email'],
+					'paid' => (bool)$aCharge['paid']
+				));
+				break;
+
+			case BX_PAYMENT_TYPE_RECURRING:
+				$aCustomer = $this->_retrieveCustomer($sCustomerId)->jsonSerialize();
+				$aSubscription = $this->_retrieveSubscription($sCustomerId, $sOrderId)->jsonSerialize();
+				if(empty($aCustomer) || !is_array($aCustomer) || empty($aSubscription) || !is_array($aSubscription))
+					return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+				$aResult = array_merge($aResult, array(
+					'message' => $this->_sLangsPrefix . 'strp_msg_subscribed',
+					'client_email' => $aCustomer['email']
+				));
+				break;
+		}
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $sOrderId,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        return $aResult;
+    }
+
+    public function notify()
+    {
+		$iResult = $this->_processEvent();
+		http_response_code($iResult);
+    }
+
+    public function getButtonSingle($iClientId, $iVendorId, $aParams = array())
+    {
+    	$aItems = array();
+    	$aCartInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, (int)$iVendorId, $aItems);
+
+    	return $this->_getButton(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iVendorId, array_merge($aParams, array(
+			'sVendorName' => _t($this->_sLangsPrefix . 'txt_payment_to', $aCartInfo['vendor_name']),
+			'sVendorCurrency' => $aCartInfo['vendor_currency_code'],
+			'sVendorIcon' => $aCartInfo['vendor_icon'],
+    	)));
+    }
+
+    public function getButtonRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+    	$aVendor = $this->_oModule->getVendorInfo((int)$iVendorId);
+
+		return $this->_getButton(BX_PAYMENT_TYPE_RECURRING, $iClientId, $iVendorId, array_merge($aParams, array(
+			'sVendorName' => _t($this->_sLangsPrefix . 'txt_payment_to', $aVendor['name']),
+			'sVendorCurrency' => $aVendor['currency_code'],
+			'sVendorIcon' => $aVendor['icon'],
+		)));
+    }
+
+    public function getCheckoutParamsSingle($aParams, &$oGrid)
+    {
+    	if(bx_get('token') !== false)
+    		$aParams['token'] = bx_process_input(bx_get('token'));
+
+    	return $aParams;
+    }
+
+	protected function _getPublicKey()
+	{
+		return $this->_iMode == STRP_MODE_LIVE ? $this->getOption('live_pub_key') : $this->getOption('test_pub_key');
+	}
+
+	protected function _getSecretKey()
+	{
+		return $this->_iMode == STRP_MODE_LIVE ? $this->getOption('live_sec_key') : $this->getOption('test_sec_key');
+	}
+
+	protected function _createCustomer($sToken, $aClient) {
+		try {
+			$aClientParams = array(
+				'card'  => $sToken,
+				'email' => !empty($aClient['email']) ? $aClient['email'] : ''
+			);
+
+			$this->_oCustomer = \Stripe\Customer::create($aClientParams);
+		}
+		catch (Stripe\Error\Base $oException) {
+			return $this->_processException('Create Customer Error: ', $oException);
+		}
+
+		return $this->_oCustomer->jsonSerialize();
+	}
+
+	protected function _retrieveCustomer($sId) {
+		try {
+			$oCustomer = \Stripe\Customer::retrieve($sId);
+		}
+		catch (Exception $oException) {
+			return $this->_processException('Retrieve Customer Error: ', $oException);
+		}
+
+		return $oCustomer;
+	}
+
+	protected function _createCharge($sToken, $iPendingId, &$aClient, &$aCartInfo) {
+		if(empty($this->_oCustomer))
+			$this->_createCustomer($sToken, $aClient);
+
+		if(empty($this->_oCustomer))
+			return false;
+
+		$fAmount = 100 * (float)$aCartInfo['items_price'];
+
+		try {
+			$oCharge = \Stripe\Charge::create(array(
+				'customer' => $this->_oCustomer->id,
+				'amount' => $fAmount,
+				'currency' => $aCartInfo['vendor_currency_code'],
+				'description' => $aCartInfo['items_title'],
+				'metadata' => array(
+					'vendor' => $aCartInfo['vendor_id'],
+					'client' => $aClient['id'],
+					'product' => $iPendingId,
+					'verification' => $this->_getVerificationCodeCharge($aCartInfo['vendor_id'], $aClient['id'], $fAmount, $aCartInfo['vendor_currency_code'])
+				)
+			));
+		}
+		catch (Exception $oException) {
+			return $this->_processException('Create Charge Error: ', $oException);
+		}
+
+		$aResult = $oCharge->jsonSerialize();
+		if(empty($aResult) || !is_array($aResult) || empty($aResult['paid']))
+			return false;
+
+		$aMetadata = $aResult['metadata'];
+		if(empty($aMetadata['verification']) || $aMetadata['verification'] != $this->_getVerificationCodeCharge($aCartInfo['vendor_id'], $aClient['id'], $aResult['amount'], $aResult['currency']))
+			return false;
+
+		return array(
+			'pending' => $iPendingId,
+			'amount' =>(float)$aResult['amount'] / 100,
+			'customer' => $this->_oCustomer->id,
+			'order' => $aResult['id']
+		);
+	}
+
+	protected function _retrieveCharge($sId) {
+		try {
+			$oCharge = \Stripe\Charge::retrieve($sId);
+		}
+		catch (Exception $oException) {
+			return $this->_processException('Retrieve Charge Error: ', $oException);
+		}
+
+		return $oCharge;
+	}
+
+	protected function _createSubscription($sToken, $iPendingId, &$aClient, &$aCartInfo)
+	{
+		$bTrial = false;
+
+		if(empty($this->_oCustomer))
+			$this->_createCustomer($sToken, $aClient);
+
+		if(empty($this->_oCustomer))
+			return false;
+
+		try {
+			$aItem = array_shift($aCartInfo['items']);
+			if(empty($aItem) || !is_array($aItem))
+				return false;
+
+			//TODO: "Trial" wasn't finaly relized. It's just a draft.
+			if(isset($aItem['trial']) && $aItem['trial'] === true)
+				$bTrial = true;
+
+			$oSubscription = $this->_oCustomer->subscriptions->create(array(
+				'plan' => $aItem['name'],
+				'metadata' => array(
+					'vendor' => $aCartInfo['vendor_id'],
+					'client' => $aClient['id'],
+					'product' => $iPendingId,
+					'verification' => $this->_getVerificationCodeSubscription($aCartInfo['vendor_id'], $aClient['id'], $aItem['name'], $aCartInfo['vendor_currency_code'])
+				)
+			));
+		}
+		catch (Exception $oException) {
+			return $this->_processException('Create Subscription Error: ', $oException);
+		}
+
+		$aResult = $oSubscription->jsonSerialize();
+		if(empty($aResult) || !is_array($aResult) || (!$bTrial && $aResult['status'] != 'active') || ($bTrial && !in_array($aResult['status'], array('active', 'trialing'))))
+			return false;
+
+		$aMetadata = $aResult['metadata'];
+		if(empty($aMetadata['verification']) || $aMetadata['verification'] != $this->_getVerificationCodeSubscription($aCartInfo['vendor_id'], $aClient['id'], $aResult['plan']['id'], $aResult['plan']['currency']))
+			return false;
+
+		return array(
+			'pending' => $iPendingId,
+			'amount' =>(float)$aCartInfo['items_price'],
+			'customer' => $this->_oCustomer->id, 
+			'order' => $aResult['id'],
+			'trial' => $bTrial
+		);
+	}
+
+	protected function _retrieveSubscription($sCustomerId, $sSubscriptionId) {
+		try {
+			$oCustomer = \Stripe\Customer::retrieve($sCustomerId);
+			$oSubscription = $oCustomer->subscriptions->retrieve($sSubscriptionId);
+		}
+		catch (Exception $oException) {
+			return $this->_processException('Retrieve Subscription Error: ', $oException);
+		}
+
+		return $oSubscription;
+	}
+
+	protected function _retrieveCoupon($sId) {
+		try {
+			$oCoupon = \Stripe\Coupon::retrieve($sId);
+		}
+		catch (Exception $oException) {
+			return $this->_processException('Retrieve Coupon Error: ', $oException);
+		}
+
+		return $oCoupon;
+	}
+
+	protected function _retrieveEvent($sId) {
+		try {
+			$oEvent = \Stripe\Event::retrieve($sId);
+		}
+		catch (Exception $oException) {
+			return $this->_processException('Retrieve Event Error: ', $oException);
+		}
+
+		return $oEvent;
+	}
+
+	protected function _processEvent()
+	{
+    	$sInput = @file_get_contents("php://input");
+		$aEvent = json_decode($sInput, true);
+		if(empty($aEvent) || !is_array($aEvent)) 
+			return 404;
+
+		$sType = $aEvent['type'];
+		if(!in_array($sType, array('invoice.payment_succeeded', 'charge.refunded', 'customer.subscription.deleted')))
+			return 200;
+
+		$this->log('Webhooks: ' . (!empty($sType) ? $sType : ''));
+		$this->log($aEvent);
+
+		$sMethod = '_processEvent' . bx_gen_method_name($sType, array('.', '_', '-'));
+    	if(!method_exists($this, $sMethod))
+    		return 200;
+
+    	return $this->$sMethod($aEvent) ? 200 : 403;
+    }
+
+	protected function _processEventInvoicePaymentSucceeded(&$aEvent)
+	{
+		$mixedResult = $this->_getData($aEvent);
+		if($mixedResult === false)
+			return false;
+
+		list($aPending, $oCharge) = $mixedResult;
+
+		$fChargeAmount = (float)$oCharge->amount / 100;
+		$sChargeCurrency = strtoupper($oCharge->currency);
+		if($this->_bCheckAmount && ((float)$aPending['amount'] != $fChargeAmount || strcasecmp($this->_oModule->_oConfig->getDefaultCurrencyCode(), $sChargeCurrency) != 0))
+			return false;
+
+		return $this->_oModule->registerPayment($aPending);
+	}
+
+	protected function _processEventChargeRefunded(&$aEvent)
+	{
+		$mixedResult = $this->_getData($aEvent);
+		if($mixedResult === false)
+			return false;
+
+		list($aPending) = $mixedResult;
+		return $this->_oModule->refundPayment($aPending);
+	}
+
+	protected function _processEventCustomerSubscriptionDeleted(&$aEvent)
+	{
+		$mixedResult = $this->_getData($aEvent);
+		if($mixedResult === false)
+			return false;
+
+		list($aPending) = $mixedResult;
+		return $this->_oModule->cancelSubscription($aPending);
+	}
+
+	protected function _processException($sMessage, &$oException)
+	{
+		$aError = $oException->getJsonBody();
+
+		$sMessage = $aError['error']['message'];
+		if(empty($sMessage))
+			$sMessage = $oException->getMessage();
+
+		$this->log($sMessage . $aError['error']['message']);
+		$this->log($aError);
+
+		return false;
+	}
+
+	protected function _getData(&$aEvent, $bRetrieve = true)
+	{
+		if($bRetrieve)
+			$oEvent = $this->_retrieveEvent($aEvent['id']);
+		else 
+			$oEvent = \Stripe\Util\Util::convertToStripeObject($aEvent, array());
+
+		if(empty($oEvent))
+			return false;
+
+		$aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'order', 'order' => $oEvent->data->object->subscription));
+		if(empty($aPending) || !is_array($aPending))
+			return false;
+
+		$oCharge = $this->_retrieveCharge($oEvent->data->object->charge);
+		if(empty($oCharge))
+			return false;
+
+		return array($aPending, $oCharge);
+	}
+
+	protected function _getVerificationCodeCharge($iVendorId, $iCustomerId, $fAmount, $sCurrency) {
+		return md5(implode('#-#', array(
+			(int)$iVendorId,
+			(int)$iCustomerId,
+			(float)$fAmount,
+			strtoupper($sCurrency)
+		)));
+	}
+
+	protected function _getVerificationCodeSubscription($iVendorId, $iCustomerId, $sSubscription, $sCurrency) {
+		return md5(implode('#-#', array(
+			(int)$iVendorId,
+			(int)$iCustomerId,
+			strtoupper($sSubscription),
+			strtoupper($sCurrency)
+		)));
+	}
+
+    protected function _getButton($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+    	$sClientEmail = '';
+    	if(!empty($iClientId)) {
+    		$oClient = BxDolProfile::getInstance($iClientId);
+    		if($oClient)
+    			$sClientEmail = $oClient->getAccountObject()->getEmail();
+    	}
+
+    	return $this->_oModule->_oTemplate->parseHtmlByName('strp_button_' . $sType . '.html', array(
+    		'type' => $sType,
+    		'caption' => _t($this->_sLangsPrefix . 'strp_txt_checkout_with_' . $sType, $this->_sCaption),
+    		'js_object' => $this->_oModule->_oConfig->getJsObject($this->_sName),
+    		'js_code' => $this->_oModule->_oTemplate->getJsCode($this->_sName, array_merge(array(
+	    		'sProvider' => $this->_sName,
+	    		'sPublicKey' => $this->_getPublicKey(),
+	    		'sVendorName' => '',
+	    		'sVendorCurrency' => '',
+	    		'sVendorIcon' => '',
+	    		'sClientEmail' => $sClientEmail,
+	    	), $aParams))
+    	));
+    }
+}
+
+/** @} */

+ 318 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/classes/BxPaymentTemplate.php

@@ -0,0 +1,318 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentTemplate extends BxBaseModPaymentTemplate
+{
+	protected $_sLangsPrefix;
+
+    function __construct(&$oConfig, &$oDb)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($oConfig, $oDb);
+
+        $this->_sLangsPrefix = $this->_oConfig->getPrefix('langs');
+    }
+
+    public function addJsCssOrders()
+    {
+    	$this->addJs(array(
+    		'jquery-ui/jquery.ui.widget.min.js',
+    		'jquery-ui/jquery.ui.menu.min.js', 
+    		'jquery-ui/jquery.ui.autocomplete.min.js', 
+    		'jquery.form.min.js', 
+    		'jquery.anim.js', 
+    		'jquery.webForms.js',
+    		'orders.js'
+    	));
+    	$this->addCss(array('orders.css'));
+    }
+
+    public function addJsCssCart($sType = '', $iVendorId = 0)
+    {
+    	$this->addJsTranslation(array('_bx_payment_err_nothing_selected'));
+    	$this->addJs(array('jquery.anim.js', 'main.js', 'cart.js'));
+    	$this->addCss(array('orders.css', 'cart.css'));
+
+    	$oModule = $this->_getModule();
+    	if(!empty($iVendorId)) {
+    		$sMethod = 'getVendorInfoProviders' . bx_gen_method_name($sType);
+    		$aProviders = $this->_oDb->$sMethod($iVendorId);
+    		foreach($aProviders as $sProvider => $aProvider)
+				$oModule->getObjectProvider($sProvider, $iVendorId)->addJsCss();
+    	}
+    }
+
+	public function displayCartJs($sType = '', $iVendorId = 0)
+    {
+        $this->addJsCssCart($sType, $iVendorId);
+        return $this->displayJsCode('cart');
+    }
+
+    public function displayAddToCartJs($iVendorId, $iModuleId, $iItemId, $iItemCount, $bNeedRedirect = false)
+    {
+        $sJsCode = $this->displayCartJs(BX_PAYMENT_TYPE_SINGLE, $iVendorId);
+        $sJsMethod = $this->parseHtmlByName('add_to_cart_js.html', array(
+            'js_object' => $this->_oConfig->getJsObject('cart'),
+            'vendor_id' => $iVendorId,
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+            'item_count' => $iItemCount,
+            'need_redirect' => (int)$bNeedRedirect
+        ));
+
+        return array($sJsCode, $sJsMethod);
+    }
+
+    public function displayAddToCartLink($iVendorId, $iModuleId, $iItemId, $iItemCount, $bNeedRedirect = false)
+    {
+        $this->addJsCssCart(BX_PAYMENT_TYPE_SINGLE, $iVendorId);
+        return $this->parseHtmlByName('add_to_cart.html', array(
+        	'js_object' => $this->_oConfig->getJsObject('cart'),
+        	'js_content' => $this->displayJsCode('cart'),
+        	'txt_add_to_cart' => _t($this->_sLangsPrefix . 'txt_add_to_cart'),
+            'vendor_id' => $iVendorId,
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+            'item_count' => $iItemCount,
+            'need_redirect' => (int)$bNeedRedirect
+        ));
+    }
+
+	public function displaySubscribeJs($iVendorId, $sVendorProvider, $iModuleId, $iItemId, $iItemCount = 1)
+    {
+        $sJsCode = $this->displayCartJs(BX_PAYMENT_TYPE_RECURRING, $iVendorId);
+        $sJsMethod = $this->parseHtmlByName('subscribe_js.html', array(
+            'js_object' => $this->_oConfig->getJsObject('cart'),
+            'vendor_id' => $iVendorId,
+        	'vendor_provider' => $sVendorProvider,
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+            'item_count' => $iItemCount
+        ));
+
+        return array($sJsCode, $sJsMethod);
+    }
+
+    public function displaySubscribeLink($iVendorId, $sVendorProvider, $iModuleId, $iItemId, $iItemCount = 1)
+    {
+        $this->addJsCssCart(BX_PAYMENT_TYPE_RECURRING, $iVendorId);
+        return $this->parseHtmlByName('subscribe.html', array(
+        	'js_object' => $this->_oConfig->getJsObject('cart'),
+        	'js_content' => $this->displayJsCode('cart'),
+        	'txt_add_to_cart' => _t($this->_sLangsPrefix . 'txt_subscribe'),
+            'vendor_id' => $iVendorId,
+        	'vendor_provider' => $sVendorProvider,
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+            'item_count' => $iItemCount,
+        ));
+    }
+
+	public function displayBlockCarts($iClientId)
+    {
+    	$oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_carts'));
+        if(!$oGrid)
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+		$oGrid->addQueryParam('client_id', $iClientId);
+
+		$this->addJsCssCart(BX_PAYMENT_TYPE_SINGLE);
+        return $this->displayJsCode('cart') . $oGrid->getCode();
+    }
+
+	public function displayBlockCart($iClientId, $iSellerId = 0)
+    {
+    	$oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_cart'));
+        if(!$oGrid || empty($iSellerId))
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+		$oGrid->addQueryParam('client_id', $iClientId);
+		$oGrid->addQueryParam('seller_id', $iSellerId);
+
+		$this->addJsCssCart(BX_PAYMENT_TYPE_SINGLE, $iSellerId);
+        return $this->displayJsCode('cart') . $oGrid->getCode();
+    }
+
+    public function displayBlockHistory($iClientId, $iSellerId)
+    {
+    	$oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_history'));
+        if(!$oGrid || empty($iClientId))
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+		$oGrid->addQueryParam('client_id', $iClientId);
+		if(!empty($iSellerId))
+			$oGrid->addQueryParam('seller_id', $iSellerId);
+
+		$this->addJsCssOrders();
+        return $this->displayJsCode('history') . $oGrid->getCode();
+    }
+
+	public function displayBlockOrders($sType, $iSellerId)
+    {
+    	$oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_' . $sType));
+        if(!$oGrid || empty($iSellerId))
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+		$oGrid->addQueryParam('seller_id', $iSellerId);
+
+		$this->addJsCssOrders();
+        return $this->displayJsCode($sType) . $oGrid->getCode();
+    }
+
+	public function displayOrder($sType, $iId)
+    {
+        $sMethodName = 'getOrder' . bx_gen_method_name($sType);
+        $aOrder = $this->_oDb->$sMethodName(array('type' => 'id', 'id' => $iId));
+
+        $oModule = $this->_getModule();
+        $aSeller = $oModule->getVendorInfo((int)$aOrder['seller_id']);
+        $aClient = $oModule->getProfileInfo((int)$aOrder['client_id']);
+
+        $aResult = array(
+        	'txt_client' => _t($this->_sLangsPrefix . 'txt_client'),
+        	'txt_seller' => _t($this->_sLangsPrefix . 'txt_seller'),
+        	'txt_order' => _t($this->_sLangsPrefix . 'txt_order'),
+        	'txt_processed_with' => _t($this->_sLangsPrefix . 'txt_processed_with'),
+        	'txt_message' => _t($this->_sLangsPrefix . 'txt_message'),
+        	'txt_date' => _t($this->_sLangsPrefix . 'txt_date'),
+        	'txt_products' => _t($this->_sLangsPrefix . 'txt_products'),
+            'client_name' => $aClient['name'],
+            'client_url' => $aClient['link'],
+            'bx_if:show_link' => array(
+                'condition' => !empty($aSeller['link']),
+                'content' => array(
+                    'seller_name' => $aSeller['name'],
+                    'seller_url' => $aSeller['link'],
+                )
+            ),
+            'bx_if:show_text' => array(
+                'condition' => empty($aSeller['link']),
+                'content' => array(
+                    'seller_name' => $aSeller['name']
+                )
+            ),
+            'order' => $aOrder['order'],
+            'provider' => $aOrder['provider'],
+            'error' => $aOrder['error_msg'],
+            'date' => bx_time_js($aOrder['date']),
+            'bx_repeat:items' => array()
+        );
+
+        if($sType == BX_PAYMENT_ORDERS_TYPE_PENDING)
+            $aItems = $this->_oConfig->descriptorsM2A($aOrder['items']);
+        else
+            $aItems = $this->_oConfig->descriptorsM2A($this->_oConfig->descriptorA2S(array($aOrder['seller_id'], $aOrder['module_id'], $aOrder['item_id'], $aOrder['item_count'])));
+
+        foreach($aItems as $aItem) {
+            $aInfo = $oModule->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id']));
+            if(!empty($aInfo) && is_array($aInfo))
+	            $aResult['bx_repeat:items'][] = array(
+	                'bx_if:link' => array(
+	                    'condition' => !empty($aInfo['url']),
+	                    'content' => array(
+	                        'title' => $aInfo['title'],
+	                        'url' => $aInfo['url']
+	                    )
+	                ),
+	                'bx_if:text' => array(
+	                    'condition' => empty($aInfo['url']),
+	                    'content' => array(
+	                        'title' => $aInfo['title'],
+	                    )
+	                ),
+	                'quantity' => $aItem['item_count'],
+	                'price' => $this->_oConfig->getPrice($aOrder['type'], $aInfo),
+	                'currency_code' => $aSeller['currency_code']
+	            );
+        }
+
+        return $this->parseHtmlByName('order_' . $sType . '.html', $aResult);
+    }
+
+    public function displayItems($sType, $aItems = array())
+    {
+        $aTmplVarsItems = array();
+
+        foreach($aItems as $aItem) {
+            $aTmplVarsItems[] = array(
+                'id' => $aItem['id'],
+                'price' => $this->_oConfig->getPrice($sType, $aItem),
+                'bx_if:link' => array(
+                    'condition' => !empty($aItem['url']),
+                    'content' => array(
+                        'url' => $aItem['url'],
+                        'title' => $aItem['title']
+                    )
+                ),
+                'bx_if:text' => array(
+                    'condition' => empty($aItem['url']),
+                    'content' => array(
+                        'title' => $aItem['title']
+                    )
+                ),
+            );
+        }
+
+        if(empty($aTmplVarsItems))
+        	$aTmplVarsItems = MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        return $this->parseHtmlByName('items.html', array(
+        	'html_id' => $this->_oConfig->getHtmlIds('processed', 'order_processed_items'),
+        	'bx_repeat:items' => $aTmplVarsItems
+        ));
+    }
+
+    public function displayProvidersSelector($aCartItem, $aProviders)
+    {
+    	$oModule = $this->_getModule();
+
+		$oCart = $oModule->getObjectCart();
+		list($iSellerId, $iModuleId, $iItemId, $iItemCount) = $aCartItem;
+
+		$aTmplVarsProviders = array();
+		foreach($aProviders as $sProvider => $aProvider) {
+			$oProvider = $oModule->getObjectProvider($sProvider, $iSellerId);
+			if($oProvider !== false && method_exists($oProvider, 'getButtonRecurring'))
+				$sButton = $oProvider->getButtonRecurring($oModule->getProfileId(), $iSellerId, array(
+					'sObjNameCart' => $oModule->_oConfig->getJsObject('cart'),
+					'iSellerId' => $iSellerId,
+					'iModuleId' => $iModuleId,
+					'iItemId' => $iItemId,
+					'iItemCount' => $iItemCount
+				));
+			else {
+				list($sJsCode, $sJsOnclick) = $oCart->serviceGetSubscribeJs($iSellerId, $aProvider['name'], $iModuleId, $iItemId, $iItemCount);
+
+				$sButton = $this->parsePageByName('providers_select_button.html', array(
+					'onclick' => $sJsOnclick,
+					'title' => _t('_bx_payment_txt_checkout_with', _t($aProvider['caption']))
+				));
+			}
+
+			$aTmplVarsProviders[] = array(
+				'button' => $sButton
+			);
+		}
+
+		return $this->parseHtmlByName('providers_select.html', array(
+			'bx_repeat:providers' => $aTmplVarsProviders
+		));
+    }
+
+	protected function _getModule()
+    {
+        $sName = $this->_oConfig->getName();
+        return BxDolModule::getInstance($sName);
+    }
+}
+
+/** @} */

+ 70 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/install/config.php

@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+	'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_payment',
+    'title' => 'Payment',
+    'note' => 'Payment module.',
+    'version' => '9.0.1',
+    'vendor' => 'Boonex',
+    'help_url' => 'http://feed.boonex.com/?section={module_name}',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/payment/',
+    'home_uri' => 'payment',
+
+    'db_prefix' => 'bx_payment_',
+    'class_prefix' => 'BxPayment',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Payment',
+
+    /**
+     * 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(),
+);
+
+/** @} */

+ 20 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/install/installer.php

@@ -0,0 +1,20 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentInstaller extends BxBaseModPaymentInstaller
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}
+
+/** @} */

+ 364 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/install/langs/en.xml

@@ -0,0 +1,364 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string name="_bx_payment"><![CDATA[Payments]]></string>
+
+	<!-- OPTIONS -->
+	<string name="_bx_payment_option_default_currency_code"><![CDATA[Currency]]></string>
+	<string name="_bx_payment_option_err_default_currency_code"><![CDATA[Currency code cannot be empty.]]></string>
+	<string name="_bx_payment_option_site_admin"><![CDATA[Site administrator]]></string>
+
+	<!-- PAGES and BLOCKS -->
+	<string name="_bx_payment_page_title_sys_carts"><![CDATA[Shopping Carts]]></string>
+	<string name="_bx_payment_page_title_carts"><![CDATA[Shopping Carts]]></string>
+	<string name="_bx_payment_page_title_sys_cart"><![CDATA[Shopping Cart]]></string>
+	<string name="_bx_payment_page_title_cart"><![CDATA[Shopping Cart]]></string>
+	<string name="_bx_payment_page_block_title_carts"><![CDATA[Shopping Carts]]></string>
+	<string name="_bx_payment_page_block_title_cart"><![CDATA[{0}'s Shopping Cart]]></string>
+
+	<string name="_bx_payment_page_title_sys_history"><![CDATA[Shopping History]]></string>
+	<string name="_bx_payment_page_title_history"><![CDATA[Shopping History]]></string>
+	<string name="_bx_payment_page_block_title_history"><![CDATA[Shopping History]]></string>
+
+	<string name="_bx_payment_page_title_sys_orders"><![CDATA[Orders]]></string>
+	<string name="_bx_payment_page_title_orders"><![CDATA[Orders]]></string>
+	<string name="_bx_payment_page_block_title_orders"><![CDATA[Orders]]></string>
+
+	<string name="_bx_payment_page_title_sys_details"><![CDATA[Payments Details]]></string>
+	<string name="_bx_payment_page_title_details"><![CDATA[Payments Details]]></string>
+	<string name="_bx_payment_page_block_title_details"><![CDATA[Payments Details]]></string>
+
+	<string name="_bx_payment_page_block_title_orders_processed"><![CDATA[Processed Orders]]></string>
+	<string name="_bx_payment_page_block_title_orders_pending"><![CDATA[Pending Orders]]></string>
+
+	<string name="_bx_payment_page_title_response"><![CDATA[Payment Response]]></string>
+	<string name="_bx_payment_page_title_error"><![CDATA[Payment Error]]></string>
+
+	<string name="_bx_payment_page_title_sys_join"><![CDATA[Join]]></string>
+	<string name="_bx_payment_page_title_join"><![CDATA[Join]]></string>
+	<string name="_bx_payment_page_block_title_join"><![CDATA[Join]]></string>
+
+	<!-- MENUS -->
+	<string name="_bx_payment_menu_title_orders_submenu"><![CDATA[Orders Submenu]]></string>
+    <string name="_bx_payment_menu_set_title_orders_submenu"><![CDATA[Orders Submenu]]></string>
+    <string name="_bx_payment_menu_item_title_system_orders_processed"><![CDATA[Processed Orders]]></string>
+    <string name="_bx_payment_menu_item_title_orders_processed"><![CDATA[Processed]]></string>
+    <string name="_bx_payment_menu_item_title_system_orders_pending"><![CDATA[Pending Orders]]></string>
+    <string name="_bx_payment_menu_item_title_orders_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_payment_menu_item_title_system_details"><![CDATA[Payments Details]]></string>
+    <string name="_bx_payment_menu_item_title_details"><![CDATA[Settings]]></string>
+
+	<string name="_bx_payment_menu_title_cart_submenu"><![CDATA[Cart Submenu]]></string>
+    <string name="_bx_payment_menu_set_title_cart_submenu"><![CDATA[Cart Submenu]]></string>
+    <string name="_bx_payment_menu_item_title_system_cart"><![CDATA[Cart]]></string>
+    <string name="_bx_payment_menu_item_title_cart"><![CDATA[Cart]]></string>
+    <string name="_bx_payment_menu_item_title_system_cart_history"><![CDATA[Cart History]]></string>
+    <string name="_bx_payment_menu_item_title_cart_history"><![CDATA[Cart History]]></string>
+
+	<!-- GRIDS -->
+	<string name="_bx_payment_grid_column_title_ods_client_id"><![CDATA[Client]]></string>
+	<string name="_bx_payment_grid_column_title_ods_seller_id"><![CDATA[Seller]]></string>
+	<string name="_bx_payment_grid_column_title_ods_transaction"><![CDATA[Transaction]]></string>
+	<string name="_bx_payment_grid_column_title_ods_license"><![CDATA[License]]></string>
+	<string name="_bx_payment_grid_column_title_ods_amount"><![CDATA[Amount]]></string>
+	<string name="_bx_payment_grid_column_title_ods_date"><![CDATA[Date]]></string>
+	<string name="_bx_payment_grid_column_title_crts_vendor_id"><![CDATA[Vendor]]></string>
+	<string name="_bx_payment_grid_column_title_crts_items_count"><![CDATA[Count]]></string>
+	<string name="_bx_payment_grid_column_title_crts_items_price"><![CDATA[Price]]></string>
+	<string name="_bx_payment_grid_column_title_crt_title"><![CDATA[Product]]></string>
+	<string name="_bx_payment_grid_column_title_crt_description"><![CDATA[Description]]></string>
+	<string name="_bx_payment_grid_column_title_crt_quantity"><![CDATA[Quantity]]></string>
+	<string name="_bx_payment_grid_column_title_crt_price"><![CDATA[Price]]></string>
+
+	<string name="_bx_payment_grid_action_title_ods_add"><![CDATA[Manual Order]]></string>
+	<string name="_bx_payment_grid_action_title_ods_cancel"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_grid_action_title_ods_process"><![CDATA[Process]]></string>
+	<string name="_bx_payment_grid_action_title_ods_view_order"><![CDATA[View]]></string>
+	<string name="_bx_payment_grid_action_title_crts_delete"><![CDATA[Delete]]></string>
+	<string name="_bx_payment_grid_action_title_crts_continue"><![CDATA[Continue]]></string>
+	<string name="_bx_payment_grid_action_title_crt_delete"><![CDATA[Delete]]></string>
+
+	<string name="_bx_payment_popup_title_ods_order_history_view"><![CDATA[Order]]></string>
+	<string name="_bx_payment_popup_title_ods_order_pending_view"><![CDATA[Pending Order]]></string>
+	<string name="_bx_payment_popup_title_ods_order_pending_process"><![CDATA[Process Pending Order]]></string>
+	<string name="_bx_payment_popup_title_ods_order_processed_view"><![CDATA[Processed Order]]></string>
+	<string name="_bx_payment_popup_title_ods_order_processed_add"><![CDATA[Manual Order]]></string>
+	<string name="_bx_payment_popup_title_crd_providers_select"><![CDATA[Select Payment Method]]></string>
+
+	<!-- FORMS -->
+	<string name="_bx_payment_form_cart_input_do_delete"><![CDATA[Delete]]></string>
+	<string name="_bx_payment_form_cart_input_do_checkout"><![CDATA[Checkout]]></string>
+	<string name="_bx_payment_form_details_input_do_submit"><![CDATA[Save]]></string>
+
+	<string name="_bx_payment_form_pendings_form"><![CDATA[Pendings Form]]></string>
+	<string name="_bx_payment_form_processed_form"><![CDATA[Processed Form]]></string>
+	<string name="_bx_payment_form_pendings_display_process"><![CDATA[Process Pending Display]]></string>
+	<string name="_bx_payment_form_processed_display_add"><![CDATA[Add Processed Display]]></string>
+	<string name="_bx_payment_form_pendings_input_id_sys"><![CDATA[ID]]></string>
+	<string name="_bx_payment_form_pendings_input_seller_id_sys"><![CDATA[Seller ID]]></string>
+	<string name="_bx_payment_form_pendings_input_order_sys"><![CDATA[Order]]></string>
+	<string name="_bx_payment_form_pendings_input_order"><![CDATA[Order]]></string>
+	<string name="_bx_payment_form_pendings_input_order_err"><![CDATA[You need to fill in order number here.]]></string>
+	<string name="_bx_payment_form_pendings_input_process_sys"><![CDATA[Process]]></string>
+	<string name="_bx_payment_form_pendings_input_process"><![CDATA[Process]]></string>
+	<string name="_bx_payment_form_pendings_input_cancel_sys"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_form_pendings_input_cancel"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_form_processed_input_seller_id_sys"><![CDATA[Seller ID]]></string>
+	<string name="_bx_payment_form_processed_input_client_id_sys"><![CDATA[Client ID]]></string>
+	<string name="_bx_payment_form_processed_input_client_sys"><![CDATA[Client]]></string>
+	<string name="_bx_payment_form_processed_input_client"><![CDATA[Client]]></string>
+	<string name="_bx_payment_form_processed_input_client_err"><![CDATA[You need to enter a name of an existed member here.]]></string>
+	<string name="_bx_payment_form_processed_input_order_sys"><![CDATA[Order]]></string>
+	<string name="_bx_payment_form_processed_input_order"><![CDATA[Order]]></string>
+	<string name="_bx_payment_form_processed_input_order_err"><![CDATA[You need to fill in order number here.]]></string>
+	<string name="_bx_payment_form_processed_input_module_id_sys"><![CDATA[Module]]></string>
+	<string name="_bx_payment_form_processed_input_module_id"><![CDATA[Module]]></string>
+	<string name="_bx_payment_form_processed_input_module_id_err"><![CDATA[You need to select a module here.]]></string>
+	<string name="_bx_payment_form_processed_input_items_sys"><![CDATA[Items]]></string>
+	<string name="_bx_payment_form_processed_input_items"><![CDATA[Items]]></string>
+	<string name="_bx_payment_form_processed_input_items_err"><![CDATA[You need to select at least one item from the list here.]]></string>
+	<string name="_bx_payment_form_processed_input_add"><![CDATA[Add]]></string>
+	<string name="_bx_payment_form_processed_input_add_sys"><![CDATA[Add]]></string>
+	<string name="_bx_payment_form_processed_input_cancel"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_form_processed_input_cancel_sys"><![CDATA[Cancel]]></string>
+
+	<!-- ACL -->
+	<string name="_bx_payment_acl_action_purchase"><![CDATA[Purchase]]></string>
+	<string name="_bx_payment_acl_action_sell"><![CDATA[Sell]]></string>
+
+	<!-- EMAIL TEMPLATES -->
+	<string name="_bx_payment_et_txt_name_paid_need_join"><![CDATA[Paid and need to join.]]></string>
+	<string name="_bx_payment_et_txt_subject_paid_need_join"><![CDATA[Payment was accepted.]]></string>
+	<string name="_bx_payment_et_txt_body_paid_need_join"><![CDATA[<bx_include_auto:_email_header.html />
+<p><b>Dear {RealName}</b>,</p>
+<p>Your payment was accepted. If you did not fill in the join form yet, then you may do it using the following link.</p>
+<p><a href="{JoinLink}">Join Now</a></p>
+<bx_include_auto:_email_footer.html />]]></string>
+
+	<!-- MESSAGES, WARNINGS and ERRORS -->
+	<string name="_bx_payment_msg_no_results"><![CDATA[Empty]]></string>
+	<string name="_bx_payment_msg_redirecting"><![CDATA[Redirecting... Please wait.]]></string>
+	<string name="_bx_payment_msg_item_added"><![CDATA[The item was successfully added to your shopping cart.]]></string>
+	<string name="_bx_payment_msg_item_deleted"><![CDATA[The item was successfully deleted from your shopping cart.]]></string>
+	<string name="_bx_payment_msg_successfully_processed_free"><![CDATA[Free item was successfully processed]]></string>
+	<string name="_bx_payment_err_access_db"><![CDATA[Database access error.]]></string>
+	<string name="_bx_payment_err_cannot_validate"><![CDATA[Can't connect to remote host for validation.]]></string>
+	<string name="_bx_payment_err_empty_items"><![CDATA[There are no items selected.]]></string>
+	<string name="_bx_payment_err_empty_order"><![CDATA[The order is empty.]]></string>
+	<string name="_bx_payment_err_inactive_vendor"><![CDATA[The vendor status is not active.]]></string>
+	<string name="_bx_payment_err_incorrect_provider"><![CDATA[Incorrect or unavailable payment provider.]]></string>
+	<string name="_bx_payment_err_not_accept_payments"><![CDATA[The vendor does not accept payments.]]></string>
+	<string name="_bx_payment_err_nothing_selected"><![CDATA[You need to select at least one item.]]></string>
+	<string name="_bx_payment_err_self_purchase"><![CDATA[You cannot purchase your own item. It's just a bad luck thing, you know.]]></string>
+	<string name="_bx_payment_err_required_login"><![CDATA[You need to login.]]></string>
+	<string name="_bx_payment_err_unknown_vendor"><![CDATA[Unknown vendor.]]></string>
+	<string name="_bx_payment_err_wrong_data"><![CDATA[Incorrect input data.]]></string>
+	<string name="_bx_payment_err_not_found_pending"><![CDATA[Pending order was not found.]]></string>
+	<string name="_bx_payment_err_cannot_perform"><![CDATA[Cannot perform the action. Please report.]]></string>
+	<string name="_bx_payment_err_wrong_quantity"><![CDATA[Incorrect quantity specified.]]></string>
+	<string name="_bx_payment_err_already_processed"><![CDATA[This payment has already processed.]]></string>
+
+	<!-- Other -->
+	<string name="_bx_payment_txt_add_to_cart"><![CDATA[Add to Cart]]></string>
+	<string name="_bx_payment_txt_subscribe"><![CDATA[Subscribe]]></string>
+	<string name="_bx_payment_txt_payment_to"><![CDATA[Payment to {0}]]></string>
+	<string name="_bx_payment_txt_payment_to_for"><![CDATA[Payment to {0} for:]]></string>
+	<string name="_bx_payment_txt_checkout_to"><![CDATA[Continue checkouting to {0}]]></string>
+	<string name="_bx_payment_txt_checkout_with"><![CDATA[Checkout with {0}]]></string>
+	<string name="_bx_payment_txt_client"><![CDATA[Client]]></string>
+	<string name="_bx_payment_txt_seller"><![CDATA[Seller]]></string>
+	<string name="_bx_payment_txt_order"><![CDATA[Order ID]]></string>
+	<string name="_bx_payment_txt_processed_with"><![CDATA[Processed with]]></string>
+	<string name="_bx_payment_txt_message"><![CDATA[Result]]></string>
+	<string name="_bx_payment_txt_date"><![CDATA[Date]]></string>
+	<string name="_bx_payment_txt_products"><![CDATA[Products]]></string>
+	<string name="_bx_payment_txt_buyer_name_mask"><![CDATA[{0} {1}]]></string>
+
+	<!-- PayPal payment provider -->
+	<string name="_bx_payment_pp_cpt"><![CDATA[PayPal]]></string>
+	<string name="_bx_payment_pp_dsc"><![CDATA[PayPal payment provider]]></string>
+	<string name="_bx_payment_pp_active_cpt"><![CDATA[Active]]></string>
+	<string name="_bx_payment_pp_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+	<string name="_bx_payment_pp_mode_cpt"><![CDATA[Mode]]></string>
+	<string name="_bx_payment_pp_mode_dsc"><![CDATA[Mode to process payments]]></string>
+	<string name="_bx_payment_pp_mode_live"><![CDATA[live]]></string>
+	<string name="_bx_payment_pp_mode_test"><![CDATA[test]]></string>
+	<string name="_bx_payment_pp_business_cpt"><![CDATA[Business]]></string>
+	<string name="_bx_payment_pp_business_dsc"><![CDATA[Business email address]]></string>
+	<string name="_bx_payment_pp_prc_type_cpt"><![CDATA[Process type]]></string>
+	<string name="_bx_payment_pp_prc_type_dsc"><![CDATA[The type in which data is to be processed. In IPN mode use URL like the following http://www.your-site.com/your-path/m/payment/act_finalize_checkout/paypal as notify URL in your PayPal account]]></string>
+	<string name="_bx_payment_pp_prc_type_direct"><![CDATA[direct]]></string>
+	<string name="_bx_payment_pp_prc_type_pdt"><![CDATA[PDT]]></string>
+	<string name="_bx_payment_pp_prc_type_ipn"><![CDATA[IPN]]></string>
+	<string name="_bx_payment_pp_token_cpt"><![CDATA[Identity token]]></string>
+	<string name="_bx_payment_pp_token_dsc"><![CDATA[Identity token]]></string>
+	<string name="_bx_payment_pp_sandbox_cpt"><![CDATA[Sandbox]]></string>
+	<string name="_bx_payment_pp_sandbox_dsc"><![CDATA[Sandbox email address]]></string>
+	<string name="_bx_payment_pp_return_data_url_cpt"><![CDATA[Data return URL]]></string>
+	<string name="_bx_payment_pp_err_no_data_given"><![CDATA[No data given.]]></string>
+	<string name="_bx_payment_pp_err_not_completed"><![CDATA[Payment is not completed.]]></string>
+	<string name="_bx_payment_pp_err_wrong_business"><![CDATA[Wrong receiver email.]]></string>
+	<string name="_bx_payment_pp_err_wrong_transaction"><![CDATA[Transaction verification failed.]]></string>
+	<string name="_bx_payment_pp_err_wrong_verification_status"><![CDATA[No verification status received.]]></string>
+	<string name="_bx_payment_pp_err_wrong_amount"><![CDATA[Wrong amount.]]></string>
+	<string name="_bx_payment_pp_err_wrong_custom_data"><![CDATA[Incorrect custom data.]]></string>
+	<string name="_bx_payment_pp_msg_verified"><![CDATA[Payment was successfully accepted.]]></string>
+	<string name="_bx_payment_txt_cart_paypal"><![CDATA[PayPal]]></string>
+
+	<!-- 2Checkout payment provider -->
+	<string name="_bx_payment_2co_cpt"><![CDATA[2Checkout]]></string>
+	<string name="_bx_payment_2co_dsc"><![CDATA[2Checkout payment provider]]></string>
+	<string name="_bx_payment_2co_active_cpt"><![CDATA[Active]]></string>
+	<string name="_bx_payment_2co_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+	<string name="_bx_payment_2co_mode_cpt"><![CDATA[Mode]]></string>
+	<string name="_bx_payment_2co_mode_dsc"><![CDATA[Mode to process payments]]></string>
+	<string name="_bx_payment_2co_mode_live"><![CDATA[live]]></string>
+	<string name="_bx_payment_2co_mode_test"><![CDATA[test]]></string>
+	<string name="_bx_payment_2co_account_id_cpt"><![CDATA[Account number]]></string>
+	<string name="_bx_payment_2co_account_id_dsc"><![CDATA[Your 2Checkout vendor account number]]></string>
+	<string name="_bx_payment_2co_payment_method_cpt"><![CDATA[Payment Method]]></string>
+	<string name="_bx_payment_2co_payment_method_dsc"><![CDATA[This will set the default selection on the payment method step during the checkout process]]></string>
+	<string name="_bx_payment_2co_payment_method_cc"><![CDATA[Credit Card(CC)]]></string>
+	<string name="_bx_payment_2co_payment_method_ppi"><![CDATA[PayPal(PPI)]]></string>
+	<string name="_bx_payment_2co_secret_word_cpt"><![CDATA[Secret Word]]></string>
+	<string name="_bx_payment_2co_secret_word_dsc"><![CDATA[Secret word is used to calculate a check hash]]></string>
+	<string name="_bx_payment_2co_return_data_url_cpt"><![CDATA[Data return URL]]></string>
+	<string name="_bx_payment_2co_err_no_vendor_given"><![CDATA[Unknown vendor]]></string>
+	<string name="_bx_payment_2co_err_no_data_given"><![CDATA[No data given.]]></string>
+	<string name="_bx_payment_2co_err_wrong_key"><![CDATA[Check key is incorrect.]]></string>
+	<string name="_bx_payment_2co_err_wrong_payment"><![CDATA[Wrong payment.]]></string>
+	<string name="_bx_payment_2co_err_already_processed"><![CDATA[This payment has already processed]]></string>
+	<string name="_bx_payment_2co_msg_verified"><![CDATA[Successfully verified.]]></string>
+	<string name="_bx_payment_txt_cart_2checkout"><![CDATA[2Checkout]]></string>
+
+	<!-- BitPay payment provider -->
+	<string name="_bx_payment_bp_cpt"><![CDATA[BitPay]]></string>
+	<string name="_bx_payment_bp_dsc"><![CDATA[BitPay payment provider]]></string>
+	<string name="_bx_payment_bp_active_cpt"><![CDATA[Active]]></string>
+	<string name="_bx_payment_bp_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+	<string name="_bx_payment_bp_active_err"><![CDATA[You should have SSL certificate (HTTPS connection) to activate and use BitPay on your site.]]></string>
+	<string name="_bx_payment_bp_api_key_cpt"><![CDATA[API Key]]></string>
+	<string name="_bx_payment_bp_api_key_dsc"><![CDATA[Your merchant BitPay API Access key]]></string>
+	<string name="_bx_payment_bp_transaction_speed_cpt"><![CDATA[Transaction speed]]></string>
+	<string name="_bx_payment_bp_transaction_speed_dsc"><![CDATA[Determines when an invoice is confirmed]]></string>
+	<string name="_bx_payment_bp_transaction_speed_high"><![CDATA[High]]></string>
+	<string name="_bx_payment_bp_transaction_speed_medium"><![CDATA[Medium]]></string>
+	<string name="_bx_payment_bp_transaction_speed_low"><![CDATA[Low]]></string>
+	<string name="_bx_payment_bp_full_notifications_cpt"><![CDATA[Enable full notifications]]></string>
+	<string name="_bx_payment_bp_full_notifications_dsc"><![CDATA[When enabled notifications will be sent on every status change, otherwise when an invoice is confirmed only.]]></string>
+	<string name="_bx_payment_bp_notification_email_cpt"><![CDATA[Notification Email]]></string>
+	<string name="_bx_payment_bp_notification_email_dsc"><![CDATA[Email where invoice update notifications will be sent. Leave empty to disable.]]></string>
+	<string name="_bx_payment_bp_err_posdata_exceed_limit"><![CDATA[The value of posData exceeds limit. Contact with administrator.]]></string>
+	<string name="_bx_payment_bp_err_no_data_given"><![CDATA[No data given.]]></string>
+	<string name="_bx_payment_bp_err_no_vendor_given"><![CDATA[Unknown vendor.]]></string>
+	<string name="_bx_payment_bp_err_incorrect_data"><![CDATA[Incorrect order data.]]></string>
+	<string name="_bx_payment_bp_err_wrong_amount"><![CDATA[Wrong payment amount.]]></string>
+	<string name="_bx_payment_bp_err_already_processed"><![CDATA[This payment has already processed.]]></string>
+	<string name="_bx_payment_bp_err_no_confirmation_given"><![CDATA[Payment is waiting for full confirmation from the Bitcoin network.]]></string>
+	<string name="_bx_payment_bp_msg_checkout_finished"><![CDATA[A payment has been confirmed. Once the transaction is fully confirmed on the Bitcoin network, the payment will be processed automatically here. Then the purchased product(s) will be displayed in shopping cart history.<br /><b>Note.</b> If it doesn't happen for some reason, you need to contact with product\'s vendor and provide him with your payment's details. He'll be able to process payment manually if the payment was received.]]></string>
+	<string name="_bx_payment_txt_cart_bitpay"><![CDATA[BitPay]]></string>
+
+	<!-- Chargebee payment provider -->
+	<string name="_bx_payment_cbee_cpt"><![CDATA[Chargebee]]></string>
+	<string name="_bx_payment_cbee_dsc"><![CDATA[Chargebee payment provider]]></string>
+	<string name="_bx_payment_cbee_active_cpt"><![CDATA[Active]]></string>
+	<string name="_bx_payment_cbee_active_dsc"><![CDATA[Activate(Deactivate) provider. Note. It's recommended to use SSL for better payment processing.]]></string>
+	<string name="_bx_payment_cbee_mode_cpt"><![CDATA[Mode]]></string>
+	<string name="_bx_payment_cbee_mode_dsc"><![CDATA[Mode to process payments]]></string>
+	<string name="_bx_payment_cbee_mode_live"><![CDATA[live]]></string>
+	<string name="_bx_payment_cbee_mode_test"><![CDATA[test]]></string>
+	<string name="_bx_payment_cbee_live_site_cpt"><![CDATA[Site (live)]]></string>
+	<string name="_bx_payment_cbee_live_site_dsc"><![CDATA[Your site name registered in Chargebee for 'live' mode]]></string>
+	<string name="_bx_payment_cbee_live_api_key_cpt"><![CDATA[API Key (live)]]></string>
+	<string name="_bx_payment_cbee_live_api_key_dsc"><![CDATA[Your Chargebee API Access key for 'live' mode]]></string>
+	<string name="_bx_payment_cbee_test_site_cpt"><![CDATA[Site (test)]]></string>
+	<string name="_bx_payment_cbee_test_site_dsc"><![CDATA[Your site name registered in Chargebee for 'test' mode]]></string>
+	<string name="_bx_payment_cbee_test_api_key_cpt"><![CDATA[API Key (test)]]></string>
+	<string name="_bx_payment_cbee_test_api_key_dsc"><![CDATA[Your Chargebee API Access key for 'test' mode]]></string>
+	<string name="_bx_payment_cbee_ssl_cpt"><![CDATA[Enable SSL]]></string>
+	<string name="_bx_payment_cbee_ssl_dsc"><![CDATA[Enable SSL connection to communicate with Chargebee. Note. URLs below will be updated after saving.]]></string>
+	<string name="_bx_payment_cbee_return_data_url_cpt"><![CDATA[Data return URL]]></string>
+	<string name="_bx_payment_cbee_notify_url_cpt"><![CDATA[Webhooks URL]]></string>
+	<string name="_bx_payment_cbee_msg_subscribed"><![CDATA[Subscription was successfully created.]]></string>
+	<string name="_bx_payment_txt_cart_chargebee"><![CDATA[Chargebee]]></string>
+
+	<!-- Recurly payment provider -->
+	<string name="_bx_payment_rcrl_cpt"><![CDATA[Recurly]]></string>
+	<string name="_bx_payment_rcrl_dsc"><![CDATA[Recurly payment provider]]></string>
+	<string name="_bx_payment_rcrl_active_cpt"><![CDATA[Active]]></string>
+	<string name="_bx_payment_rcrl_active_dsc"><![CDATA[Activate(Deactivate) provider.]]></string>
+	<string name="_bx_payment_rcrl_active_err"><![CDATA[You should have SSL certificate (HTTPS connection) to activate and use Recurly on your site.]]></string>
+	<string name="_bx_payment_rcrl_mode_cpt"><![CDATA[Mode]]></string>
+	<string name="_bx_payment_rcrl_mode_dsc"><![CDATA[Mode to process payments]]></string>
+	<string name="_bx_payment_rcrl_mode_live"><![CDATA[live]]></string>
+	<string name="_bx_payment_rcrl_mode_test"><![CDATA[test]]></string>
+	<string name="_bx_payment_rcrl_site_cpt"><![CDATA[Site]]></string>
+	<string name="_bx_payment_rcrl_site_dsc"><![CDATA[Your site name registered in Recurly]]></string>
+	<string name="_bx_payment_rcrl_api_key_private_cpt"><![CDATA[Private API Key]]></string>
+	<string name="_bx_payment_rcrl_api_key_private_dsc"><![CDATA[Your Recurly Private API Access key]]></string>
+	<string name="_bx_payment_rcrl_api_key_public_cpt"><![CDATA[Public API Key]]></string>
+	<string name="_bx_payment_rcrl_api_key_public_dsc"><![CDATA[Your Recurly Public API Access key]]></string>
+	<string name="_bx_payment_rcrl_return_data_url_cpt"><![CDATA[Data return URL]]></string>
+	<string name="_bx_payment_rcrl_notify_url_cpt"><![CDATA[Webhooks URL]]></string>
+	<string name="_bx_payment_rcrl_msg_subscribed"><![CDATA[Subscription was successfully created.]]></string>
+	<string name="_bx_payment_txt_cart_chargebee"><![CDATA[Recurly]]></string>
+
+	<string name="_bx_payment_form_rcrl_card"><![CDATA[Recurly: Card Form]]></string>
+	<string name="_bx_payment_form_rcrl_card_display_add"><![CDATA[Recurly: Add Card Display]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_pending_id_sys"><![CDATA[Pending ID]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_item_sys"><![CDATA[Item]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_token_sys"><![CDATA[Token]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_first_name_sys"><![CDATA[First Name]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_first_name"><![CDATA[First Name]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_first_name_err"><![CDATA[You need to fill in your first name here.]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_last_name_sys"><![CDATA[Last Name]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_last_name"><![CDATA[Last Name]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_last_name_err"><![CDATA[You need to fill in your last name here.]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_email_sys"><![CDATA[Email]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_email"><![CDATA[Email]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_email_err"><![CDATA[You need to fill in your email here.]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_number_sys"><![CDATA[Card Number]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_number"><![CDATA[Card Number]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_number_inf"><![CDATA[16 digits without spaces describing your card number]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_expire_sys"><![CDATA[Expire Date]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_expire"><![CDATA[Expire Date]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_expire_month"><![CDATA[Month]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_expire_year"><![CDATA[Year]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_expire_inf"><![CDATA[Use 'mm yyyy' format]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_cvv_sys"><![CDATA[CVV]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_cvv"><![CDATA[CVV]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_cvv_inf"><![CDATA[Three digits from the back side of your card.]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_submit_sys"><![CDATA[Submit]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_cancel_sys"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_cancel"><![CDATA[Cancel]]></string>
+	
+	<string name="_bx_payment_popup_title_rcrl_card_add"><![CDATA[Card details]]></string>
+
+	<!-- Stripe payment provider -->
+	<string name="_bx_payment_strp_cpt"><![CDATA[Stripe]]></string>
+	<string name="_bx_payment_strp_dsc"><![CDATA[Stripe payment provider]]></string>
+	<string name="_bx_payment_strp_active_cpt"><![CDATA[Active]]></string>
+	<string name="_bx_payment_strp_active_dsc"><![CDATA[Activate(Deactivate) provider. Note. It's recommended to use SSL for better payment processing.]]></string>
+	<string name="_bx_payment_strp_mode_cpt"><![CDATA[Mode]]></string>
+	<string name="_bx_payment_strp_mode_dsc"><![CDATA[Mode to process payments]]></string>
+	<string name="_bx_payment_strp_mode_live"><![CDATA[live]]></string>
+	<string name="_bx_payment_strp_mode_test"><![CDATA[test]]></string>
+	<string name="_bx_payment_strp_live_pub_key_cpt"><![CDATA[Public Key (live)]]></string>
+	<string name="_bx_payment_strp_live_pub_key_dsc"><![CDATA[Your Public Key generated in Stripe for 'live' mode]]></string>
+	<string name="_bx_payment_strp_live_sec_key_cpt"><![CDATA[Secret Key (live)]]></string>
+	<string name="_bx_payment_strp_live_sec_key_dsc"><![CDATA[Your Stripe Secret Key for 'live' mode]]></string>
+	<string name="_bx_payment_strp_test_pub_key_cpt"><![CDATA[Public Key (test)]]></string>
+	<string name="_bx_payment_strp_test_pub_key_dsc"><![CDATA[Your Public Key generated in Stripe for 'test' mode]]></string>
+	<string name="_bx_payment_strp_test_sec_key_cpt"><![CDATA[Secret Key (test)]]></string>
+	<string name="_bx_payment_strp_test_sec_key_dsc"><![CDATA[Your Stripe Secret Key for 'test' mode]]></string>
+	<string name="_bx_payment_strp_check_amount_cpt"><![CDATA[Enable amount checking]]></string>
+	<string name="_bx_payment_strp_check_amount_dsc"><![CDATA[Enable amount checking for Stripe Webhooks (recomended). However checking should be disabled when discounts and coupons are used.]]></string>
+	<string name="_bx_payment_strp_ssl_cpt"><![CDATA[Enable SSL]]></string>
+	<string name="_bx_payment_strp_ssl_dsc"><![CDATA[Enable SSL connection to communicate with Stripe. Note. URLs below will be updated after saving.]]></string>
+	<string name="_bx_payment_strp_notify_url_cpt"><![CDATA[Webhooks URL]]></string>
+	<string name="_bx_payment_strp_msg_charged"><![CDATA[Payment was successfully accepted.]]></string>
+	<string name="_bx_payment_strp_msg_subscribed"><![CDATA[Subscription was successfully created.]]></string>
+	<string name="_bx_payment_strp_txt_checkout_with_single"><![CDATA[{0}]]></string>
+	<string name="_bx_payment_strp_txt_checkout_with_recurring"><![CDATA[Checkout with {0}]]></string>
+	<string name="_bx_payment_txt_cart_stripe"><![CDATA[Stripe]]></string>
+</resources>

+ 331 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/install/sql/install.sql

@@ -0,0 +1,331 @@
+SET @sName = 'bx_payment';
+
+
+-- TABLES
+CREATE TABLE IF NOT EXISTS `bx_payment_providers` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(64) NOT NULL default '',
+  `caption` varchar(128) NOT NULL default '',
+  `description` varchar(128) NOT NULL default '',
+  `option_prefix` varchar(32) NOT NULL default '',
+  `for_visitor` tinyint(4) NOT NULL default '0',
+  `for_single` tinyint(4) NOT NULL default '0',
+  `for_recurring` tinyint(4) NOT NULL default '0',
+  `class_name` varchar(128) NOT NULL default '',
+  `class_file` varchar(255) NOT NULL  default '',
+  PRIMARY KEY(`id`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_payment_providers_options` (
+  `id` int(11) NOT NULL auto_increment,
+  `provider_id` varchar(64) NOT NULL default '',
+  `name` varchar(64) NOT NULL default '',
+  `type` varchar(64) NOT NULL default 'text',
+  `caption` varchar(255) NOT NULL default '',
+  `description` text NOT NULL default '',
+  `extra` varchar(255) NOT NULL default '',
+  `check_type` varchar(64) NOT NULL default '',
+  `check_params` varchar(128) NOT NULL default '',
+  `check_error` varchar(128) NOT NULL default '',
+  `order` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `name`(`name`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_payment_user_values` (
+  `user_id` int(11) NOT NULL default '0',
+  `option_id` int(11) NOT NULL default '0',  
+  `value` varchar(255) NOT NULL default '',
+  UNIQUE KEY `value`(`user_id`, `option_id`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_payment_cart` (
+  `client_id` int(11) NOT NULL default '0',
+  `items` text NOT NULL default '',
+  PRIMARY KEY(`client_id`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_payment_transactions` (
+  `id` int(11) NOT NULL auto_increment,
+  `pending_id` int(11) NOT NULL default '0',
+  `client_id` int(11) NOT NULL default '0',
+  `seller_id` int(11) NOT NULL default '0',
+  `module_id` int(11) NOT NULL default '0',  
+  `item_id` int(11) NOT NULL default '0',
+  `item_count` int(11) NOT NULL default '0',
+  `amount` float NOT NULL default '0',
+  `license` varchar(16) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY(`id`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_payment_transactions_pending` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `client_id` int(11) NOT NULL default '0',
+  `seller_id` int(11) NOT NULL default '0',
+  `type` varchar(16) NOT NULL default 'single',
+  `provider` varchar(32) NOT NULL default '',
+  `items` text NOT NULL default '',
+  `amount` float NOT NULL default '0',
+  `order` varchar(32) NOT NULL default '',
+  `error_code` varchar(16) NOT NULL default '',
+  `error_msg` varchar(255) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  `processed` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY(`id`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_payment_modules` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(32) NOT NULL default '',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `uri`(`name`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+
+-- PayPal payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `class_name`) VALUES
+('paypal', '_bx_payment_pp_cpt', '_bx_payment_pp_dsc', 'pp_', 1, 1, 0, 'BxPaymentProviderPayPal');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'pp_active', 'checkbox', '_bx_payment_pp_active_cpt', '_bx_payment_pp_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'pp_mode', 'select', '_bx_payment_pp_mode_cpt', '_bx_payment_pp_mode_dsc', '1|_bx_payment_pp_mode_live,2|_bx_payment_pp_mode_test', '', '', '', 2),
+(@iProviderId, 'pp_business', 'text', '_bx_payment_pp_business_cpt', '_bx_payment_pp_business_dsc', '', '', '', '', 3),
+(@iProviderId, 'pp_prc_type', 'select', '_bx_payment_pp_prc_type_cpt', '_bx_payment_pp_prc_type_dsc', '1|_bx_payment_pp_prc_type_direct,2|_bx_payment_pp_prc_type_pdt,3|_bx_payment_pp_prc_type_ipn', '', '', '', 4),
+(@iProviderId, 'pp_token', 'text', '_bx_payment_pp_token_cpt', '_bx_payment_pp_token_dsc', '', '', '', '', 5),
+(@iProviderId, 'pp_sandbox', 'text', '_bx_payment_pp_sandbox_cpt', '_bx_payment_pp_sandbox_dsc', '', '', '', '', 6),
+(@iProviderId, 'pp_return_data_url', 'value', '_bx_payment_pp_return_data_url_cpt', '', '', '', '', '', 7);
+
+
+-- 2Checkout payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `class_name`) VALUES
+('2checkout', '_bx_payment_2co_cpt', '_bx_payment_2co_dsc', '2co_', 1, 1, 0, 'BxPaymentProvider2Checkout');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, '2co_active', 'checkbox', '_bx_payment_2co_active_cpt', '_bx_payment_2co_active_dsc', '', '', '', '', 1),
+(@iProviderId, '2co_mode', 'select', '_bx_payment_2co_mode_cpt', '_bx_payment_2co_mode_dsc', '1|_bx_payment_2co_mode_live,2|_bx_payment_2co_mode_test', '', '', '', 2),
+(@iProviderId, '2co_account_id', 'text', '_bx_payment_2co_account_id_cpt', '_bx_payment_2co_account_id_dsc', '', '', '', '', 3),
+(@iProviderId, '2co_payment_method', 'select', '_bx_payment_2co_payment_method_cpt', '_bx_payment_2co_payment_method_dsc', 'CC|_bx_payment_2co_payment_method_cc,PPI|_bx_payment_2co_payment_method_ppi', '', '', '', 4),
+(@iProviderId, '2co_secret_word', 'text', '_bx_payment_2co_secret_word_cpt', '_bx_payment_2co_secret_word_dsc', '', '', '', '', 5),
+(@iProviderId, '2co_return_data_url', 'value', '_bx_payment_2co_return_data_url_cpt', '', '', '', '', '', 6);
+
+
+-- BitPay payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `class_name`) VALUES
+('bitpay', '_bx_payment_bp_cpt', '_bx_payment_bp_dsc', 'bp_', 0, 1, 0, 'BxPaymentProviderBitPay');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'bp_active', 'checkbox', '_bx_payment_bp_active_cpt', '_bx_payment_bp_active_dsc', '', 'https', '', '_bx_payment_bp_active_err', 1),
+(@iProviderId, 'bp_api_key', 'text', '_bx_payment_bp_api_key_cpt', '_bx_payment_bp_api_key_dsc', '', '', '', '', 2),
+(@iProviderId, 'bp_transaction_speed', 'select', '_bx_payment_bp_transaction_speed_cpt', '_bx_payment_bp_transaction_speed_dsc', 'high|_bx_payment_bp_transaction_speed_high,medium|_bx_payment_bp_transaction_speed_medium,low|_bx_payment_bp_transaction_speed_low', '', '', '', 3),
+(@iProviderId, 'bp_full_notifications', 'checkbox', '_bx_payment_bp_full_notifications_cpt', '_bx_payment_bp_full_notifications_dsc', '', '', '', '', 4),
+(@iProviderId, 'bp_notification_email', 'text', '_bx_payment_bp_notification_email_cpt', '_bx_payment_bp_notification_email_dsc', '', '', '', '', 5);
+
+
+-- Chargebee payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `class_name`) VALUES
+('chargebee', '_bx_payment_cbee_cpt', '_bx_payment_cbee_dsc', 'cbee_', 1, 0, 1, 'BxPaymentProviderChargebee');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'cbee_active', 'checkbox', '_bx_payment_cbee_active_cpt', '_bx_payment_cbee_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'cbee_mode', 'select', '_bx_payment_cbee_mode_cpt', '_bx_payment_cbee_mode_dsc', '1|_bx_payment_cbee_mode_live,2|_bx_payment_cbee_mode_test', '', '', '', 2),
+(@iProviderId, 'cbee_live_site', 'text', '_bx_payment_cbee_live_site_cpt', '_bx_payment_cbee_live_site_dsc', '', '', '', '', 3),
+(@iProviderId, 'cbee_live_api_key', 'text', '_bx_payment_cbee_live_api_key_cpt', '_bx_payment_cbee_live_api_key_dsc', '', '', '', '', 4),
+(@iProviderId, 'cbee_test_site', 'text', '_bx_payment_cbee_test_site_cpt', '_bx_payment_cbee_test_site_dsc', '', '', '', '', 5),
+(@iProviderId, 'cbee_test_api_key', 'text', '_bx_payment_cbee_test_api_key_cpt', '_bx_payment_cbee_test_api_key_dsc', '', '', '', '', 6),
+(@iProviderId, 'cbee_ssl', 'checkbox', '_bx_payment_cbee_ssl_cpt', '_bx_payment_cbee_ssl_dsc', '', '', '', '', 7),
+(@iProviderId, 'cbee_return_data_url', 'value', '_bx_payment_cbee_return_data_url_cpt', '', '', '', '', '', 8),
+(@iProviderId, 'cbee_notify_url', 'value', '_bx_payment_cbee_notify_url_cpt', '', '', '', '', '', 9);
+
+-- Recurly payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `class_name`) VALUES
+('recurly', '_bx_payment_rcrl_cpt', '_bx_payment_rcrl_dsc', 'rcrl_', 1, 0, 1, 'BxPaymentProviderRecurly');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'rcrl_active', 'checkbox', '_bx_payment_rcrl_active_cpt', '_bx_payment_rcrl_active_dsc', '', 'https', '', '_bx_payment_rcrl_active_err', 1),
+(@iProviderId, 'rcrl_mode', 'select', '_bx_payment_rcrl_mode_cpt', '_bx_payment_rcrl_mode_dsc', '1|_bx_payment_rcrl_mode_live,2|_bx_payment_rcrl_mode_test', '', '', '', 2),
+(@iProviderId, 'rcrl_site', 'text', '_bx_payment_rcrl_site_cpt', '_bx_payment_rcrl_site_dsc', '', '', '', '', 3),
+(@iProviderId, 'rcrl_api_key_private', 'text', '_bx_payment_rcrl_api_key_private_cpt', '_bx_payment_rcrl_api_key_private_dsc', '', '', '', '', 4),
+(@iProviderId, 'rcrl_api_key_public', 'text', '_bx_payment_rcrl_api_key_public_cpt', '_bx_payment_rcrl_api_key_public_dsc', '', '', '', '', 5),
+(@iProviderId, 'rcrl_return_data_url', 'value', '_bx_payment_rcrl_return_data_url_cpt', '', '', '', '', '', 6),
+(@iProviderId, 'rcrl_notify_url', 'value', '_bx_payment_rcrl_notify_url_cpt', '', '', '', '', '', 7);
+
+-- Stripe payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `class_name`) VALUES
+('stripe', '_bx_payment_strp_cpt', '_bx_payment_strp_dsc', 'strp_', 1, 1, 1, 'BxPaymentProviderStripe');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'strp_active', 'checkbox', '_bx_payment_strp_active_cpt', '_bx_payment_strp_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'strp_mode', 'select', '_bx_payment_strp_mode_cpt', '_bx_payment_strp_mode_dsc', '1|_bx_payment_strp_mode_live,2|_bx_payment_strp_mode_test', '', '', '', 2),
+(@iProviderId, 'strp_live_pub_key', 'text', '_bx_payment_strp_live_pub_key_cpt', '_bx_payment_strp_live_pub_key_dsc', '', '', '', '', 3),
+(@iProviderId, 'strp_live_sec_key', 'text', '_bx_payment_strp_live_sec_key_cpt', '_bx_payment_strp_live_sec_key_dsc', '', '', '', '', 4),
+(@iProviderId, 'strp_test_pub_key', 'text', '_bx_payment_strp_test_pub_key_cpt', '_bx_payment_strp_test_pub_key_dsc', '', '', '', '', 5),
+(@iProviderId, 'strp_test_sec_key', 'text', '_bx_payment_strp_test_sec_key_cpt', '_bx_payment_strp_test_sec_key_dsc', '', '', '', '', 6),
+(@iProviderId, 'strp_check_amount', 'checkbox', '_bx_payment_strp_check_amount_cpt', '_bx_payment_strp_check_amount_dsc', '', '', '', '', 7),
+(@iProviderId, 'strp_ssl', 'checkbox', '_bx_payment_strp_ssl_cpt', '_bx_payment_strp_ssl_dsc', '', '', '', '', 8),
+(@iProviderId, 'strp_notify_url', 'value', '_bx_payment_strp_notify_url_cpt', '', '', '', '', '', 9);
+
+
+-- 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_payment_grid_carts', 'Array', '', '', 'vendor_id', '', '', '', 20, NULL, 'start', '', '', '', 'like', '', '', 2147483647, 'BxPaymentGridCarts', 'modules/boonex/payment/classes/BxPaymentGridCarts.php'),
+('bx_payment_grid_cart', 'Array', '', '', 'descriptor', '', '', '', 20, NULL, 'start', '', 'title,description', '', 'like', '', '', 2147483647, 'BxPaymentGridCart', 'modules/boonex/payment/classes/BxPaymentGridCart.php'),
+
+('bx_payment_grid_orders_history', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`seller_id` AS `seller_id`, `ttp`.`order` AS `transaction`, `tt`.`license` AS `license`, `tt`.`amount` AS `amount`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` WHERE 1 ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 'BxPaymentGridHistory', 'modules/boonex/payment/classes/BxPaymentGridHistory.php'),
+('bx_payment_grid_orders_processed', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`client_id` AS `client_id`, `tt`.`seller_id` AS `seller_id`, `tt`.`module_id` AS `module_id`, `tt`.`item_id` AS `item_id`, `tt`.`item_count` AS `item_count`, `ttp`.`order` AS `transaction`, `ttp`.`error_msg` AS `error_msg`, `ttp`.`provider` AS `provider`, `tt`.`license` AS `license`, `tt`.`amount` AS `amount`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` WHERE 1 ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 'BxPaymentGridProcessed', 'modules/boonex/payment/classes/BxPaymentGridProcessed.php'),
+('bx_payment_grid_orders_pending', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`client_id` AS `client_id`, `tt`.`seller_id` AS `seller_id`, `tt`.`items` AS `items`, `tt`.`amount` AS `amount`, `tt`.`order` AS `transaction`, `tt`.`error_msg` AS `error_msg`, `tt`.`provider` AS `provider`, `tt`.`date` AS `date` FROM `bx_payment_transactions_pending` AS `tt` WHERE 1 AND (ISNULL(`tt`.`order`) OR (NOT ISNULL(`tt`.`order`) AND `tt`.`error_code`<>''0'')) ', 'bx_payment_transactions_pending', 'id', 'date', '', '', 100, NULL, 'start', '', 'tt`.`order,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 'BxPaymentGridPending', 'modules/boonex/payment/classes/BxPaymentGridPending.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_payment_grid_carts', 'checkbox', '', '2%', 0, '', '', 1),
+('bx_payment_grid_carts', 'vendor_id', '_bx_payment_grid_column_title_crts_vendor_id', '40%', 0, '36', '', 2),
+('bx_payment_grid_carts', 'items_count', '_bx_payment_grid_column_title_crts_items_count', '20%', 0, '16', '', 3),
+('bx_payment_grid_carts', 'items_price', '_bx_payment_grid_column_title_crts_items_price', '20%', 0, '16', '', 4),
+('bx_payment_grid_carts', 'actions', '', '18%', 0, '', '', 5),
+
+('bx_payment_grid_cart', 'checkbox', '', '2%', 0, '', '', 1),
+('bx_payment_grid_cart', 'title', '_bx_payment_grid_column_title_crt_title', '25%', 0, '24', '', 2),
+('bx_payment_grid_cart', 'description', '_bx_payment_grid_column_title_crt_description', '35%', 0, '48', '', 3),
+('bx_payment_grid_cart', 'quantity', '_bx_payment_grid_column_title_crt_quantity', '10%', 0, '16', '', 4),
+('bx_payment_grid_cart', 'price_single', '_bx_payment_grid_column_title_crt_price', '10%', 0, '16', '', 5),
+('bx_payment_grid_cart', 'actions', '', '18%', 0, '', '', 6),
+
+('bx_payment_grid_orders_history', 'seller_id', '_bx_payment_grid_column_title_ods_seller_id', '24%', 0, '20', '', 1),
+('bx_payment_grid_orders_history', 'transaction', '_bx_payment_grid_column_title_ods_transaction', '22%', 0, '18', '', 2),
+('bx_payment_grid_orders_history', 'license', '_bx_payment_grid_column_title_ods_license', '22%', 0, '18', '', 3),
+('bx_payment_grid_orders_history', 'amount', '_bx_payment_grid_column_title_ods_amount', '10%', 1, '10', '', 4),
+('bx_payment_grid_orders_history', 'date', '_bx_payment_grid_column_title_ods_date', '10%', 0, '10', '', 5),
+('bx_payment_grid_orders_history', 'actions', '', '12%', 0, '', '', 6),
+
+('bx_payment_grid_orders_processed', 'checkbox', '', '2%', 0, '', '', 1),
+('bx_payment_grid_orders_processed', 'client_id', '_bx_payment_grid_column_title_ods_client_id', '22%', 0, '18', '', 2),
+('bx_payment_grid_orders_processed', 'transaction', '_bx_payment_grid_column_title_ods_transaction', '20%', 0, '18', '', 3),
+('bx_payment_grid_orders_processed', 'license', '_bx_payment_grid_column_title_ods_license', '20%', 0, '18', '', 4),
+('bx_payment_grid_orders_processed', 'amount', '_bx_payment_grid_column_title_ods_amount', '10%', 1, '10', '', 5),
+('bx_payment_grid_orders_processed', 'date', '_bx_payment_grid_column_title_ods_date', '10%', 0, '10', '', 6),
+('bx_payment_grid_orders_processed', 'actions', '', '16%', 0, '', '', 7),
+
+('bx_payment_grid_orders_pending', 'checkbox', '', '2%', 0, '', '', 1),
+('bx_payment_grid_orders_pending', 'client_id', '_bx_payment_grid_column_title_ods_client_id', '25%', 0, '25', '', 2),
+('bx_payment_grid_orders_pending', 'transaction', '_bx_payment_grid_column_title_ods_transaction', '25%', 0, '25', '', 3),
+('bx_payment_grid_orders_pending', 'amount', '_bx_payment_grid_column_title_ods_amount', '14%', 1, '14', '', 4),
+('bx_payment_grid_orders_pending', 'date', '_bx_payment_grid_column_title_ods_date', '14%', 0, '14', '', 5),
+('bx_payment_grid_orders_pending', 'actions', '', '20%', 0, '', '', 6);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_payment_grid_carts', 'bulk', 'delete', '_bx_payment_grid_action_title_crts_delete', '', 0, 1, 1),
+('bx_payment_grid_carts', 'single', 'continue', '_bx_payment_grid_action_title_crts_continue', 'money', 1, 0, 1),
+('bx_payment_grid_carts', 'single', 'delete', '_bx_payment_grid_action_title_crts_delete', 'remove', 1, 1, 2),
+
+('bx_payment_grid_cart', 'bulk', 'delete', '_bx_payment_grid_action_title_crt_delete', '', 0, 1, 1),
+('bx_payment_grid_cart', 'single', 'delete', '_bx_payment_grid_action_title_crt_delete', 'remove', 1, 1, 1),
+
+('bx_payment_grid_orders_history', 'single', 'view_order', '_bx_payment_grid_action_title_ods_view_order', 'ellipsis-h', 1, 0, 1),
+
+('bx_payment_grid_orders_processed', 'independent', 'add', '_bx_payment_grid_action_title_ods_add', '', 0, 0, 1),
+('bx_payment_grid_orders_processed', 'bulk', 'cancel', '_bx_payment_grid_action_title_ods_cancel', '', 0, 1, 1),
+('bx_payment_grid_orders_processed', 'single', 'view_order', '_bx_payment_grid_action_title_ods_view_order', 'ellipsis-h', 1, 0, 1),
+('bx_payment_grid_orders_processed', 'single', 'cancel', '_bx_payment_grid_action_title_ods_cancel', 'times', 1, 1, 2),
+
+('bx_payment_grid_orders_pending', 'bulk', 'cancel', '_bx_payment_grid_action_title_ods_cancel', '', 0, 1, 1),
+('bx_payment_grid_orders_pending', 'single', 'view_order', '_bx_payment_grid_action_title_ods_view_order', 'ellipsis-h', 1, 0, 1),
+('bx_payment_grid_orders_pending', 'single', 'process', '_bx_payment_grid_action_title_ods_process', 'refresh', 1, 0, 2),
+('bx_payment_grid_orders_pending', 'single', 'cancel', '_bx_payment_grid_action_title_ods_cancel', 'times', 1, 1, 3);
+
+
+-- 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_payment_form_pendings', @sName, '_bx_payment_form_pendings_form', '', '', 'do_submit', 'bx_payment_transactions_pending', 'id', '', '', '', 0, 1, 'BxPaymentFormView', 'modules/boonex/payment/classes/BxPaymentFormView.php'),
+('bx_payment_form_processed', @sName, '_bx_payment_form_processed_form', '', '', 'do_submit', 'bx_payment_transactions', 'id', '', '', '', 0, 1, 'BxPaymentFormView', 'modules/boonex/payment/classes/BxPaymentFormView.php'),
+-- FORMS: Recurly
+('bx_payment_form_rcrl_card', @sName, '_bx_payment_form_rcrl_card', '', '', 'do_submit', '', '', '', '', '', 0, 1, '', '');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_payment_form_pendings_process', @sName, 'bx_payment_form_pendings', '_bx_payment_form_pendings_display_process', 0),
+('bx_payment_form_processed_add', @sName, 'bx_payment_form_processed', '_bx_payment_form_processed_display_add', 0),
+-- FORMS: Recurly
+('bx_payment_form_rcrl_card_add', @sName, 'bx_payment_form_rcrl_card', '_bx_payment_form_rcrl_card_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_payment_form_pendings', @sName, 'id', '0', '', 0, 'hidden', '_bx_payment_form_pendings_input_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'seller_id', '0', '', 0, 'hidden', '_bx_payment_form_pendings_input_seller_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'order', '', '', 0, 'text', '_bx_payment_form_pendings_input_order_sys', '_bx_payment_form_pendings_input_order', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_pendings_input_order_err', 'Xss', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'do_submit', '_bx_payment_form_pendings_input_process', '', 0, 'submit', '_bx_payment_form_pendings_input_process_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'do_cancel', '_bx_payment_form_pendings_input_cancel', '', 0, 'button', '_bx_payment_form_pendings_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+('bx_payment_form_processed', @sName, 'id', '0', '', 0, 'hidden', '_bx_payment_form_processed_input_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_processed', @sName, 'seller_id', '0', '', 0, 'hidden', '_bx_payment_form_processed_input_seller_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_processed', @sName, 'client_id', '0', '', 0, 'hidden', '_bx_payment_form_processed_input_client_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_processed', @sName, 'client', '0', '', 0, 'text', '_bx_payment_form_processed_input_client_sys', '_bx_payment_form_processed_input_client', '', 0, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_processed_input_client_err', 'Xss', '', 0, 0),
+('bx_payment_form_processed', @sName, 'order', '0', '', 0, 'text', '_bx_payment_form_processed_input_order_sys', '_bx_payment_form_processed_input_order', '', 0, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_processed_input_order_err', 'Xss', '', 0, 0),
+('bx_payment_form_processed', @sName, 'module_id', '0', '', 0, 'select', '_bx_payment_form_processed_input_module_id_sys', '_bx_payment_form_processed_input_module_id', '', 0, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_processed_input_module_id_err', 'Int', '', 0, 0),
+('bx_payment_form_processed', @sName, 'items', '0', '', 0, 'custom', '_bx_payment_form_processed_input_items_sys', '_bx_payment_form_processed_input_items', '', 0, 0, 0, '', '', '', '', '', '_bx_payment_form_processed_input_items_err', '', '', 0, 0),
+('bx_payment_form_processed', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_processed', @sName, 'do_submit', '_bx_payment_form_processed_input_add', '', 0, 'submit', '_bx_payment_form_processed_input_add_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_processed', @sName, 'do_cancel', '_bx_payment_form_processed_input_cancel', '', 0, 'button', '_bx_payment_form_processed_input_cancel_sys', '', '', 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),
+
+-- FORMS: Recurly
+('bx_payment_form_rcrl_card', @sName, 'pending_id', '0', '', 0, 'hidden', '_bx_payment_form_rcrl_card_input_pending_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'item', '', '', 0, 'hidden', '_bx_payment_form_rcrl_card_input_item_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'token', '', '', 0, 'hidden', '_bx_payment_form_rcrl_card_input_token_sys', '', '', 0, 0, 0, 'a:1:{s:12:"data-recurly";s:5:"token";}', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'first_name', '', '', 0, 'text', '_bx_payment_form_rcrl_card_input_first_name_sys', '_bx_payment_form_rcrl_card_input_first_name', '', 1, 0, 0, 'a:1:{s:12:"data-recurly";s:10:"first_name";}', '', '', 'Avail', '', '_bx_payment_form_rcrl_card_input_first_name_err', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'last_name', '', '', 0, 'text', '_bx_payment_form_rcrl_card_input_last_name_sys', '_bx_payment_form_rcrl_card_input_last_name', '', 1, 0, 0, 'a:1:{s:12:"data-recurly";s:9:"last_name";}', '', '', 'Avail', '', '_bx_payment_form_rcrl_card_input_last_name_err', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'email', '', '', 0, 'text', '_bx_payment_form_rcrl_card_input_email_sys', '_bx_payment_form_rcrl_card_input_email', '', 1, 0, 0, '', '', '', 'Email', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'card_number', '', '', 0, 'custom', '_bx_payment_form_rcrl_card_input_card_number_sys', '_bx_payment_form_rcrl_card_input_card_number', '_bx_payment_form_rcrl_card_input_card_number_inf', 1, 0, 0, 'a:1:{s:12:"data-recurly";s:6:"number";}', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'card_expire', '', '', 0, 'custom', '_bx_payment_form_rcrl_card_input_card_expire_sys', '_bx_payment_form_rcrl_card_input_card_expire', '_bx_payment_form_rcrl_card_input_card_expire_inf', 1, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'card_cvv', '', '', 0, 'custom', '_bx_payment_form_rcrl_card_input_card_cvv_sys', '_bx_payment_form_rcrl_card_input_card_cvv', '_bx_payment_form_rcrl_card_input_card_cvv_inf', 1, 0, 0, 'a:1:{s:12:"data-recurly";s:3:"cvv";}', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'do_submit', '_bx_payment_form_rcrl_card_input_submit', '', 0, 'submit', '_bx_payment_form_rcrl_card_input_submit_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'do_cancel', '_bx_payment_form_rcrl_card_input_cancel', '', 0, 'button', '_bx_payment_form_rcrl_card_input_cancel_sys', '', '', 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_payment_form_pendings_process', 'id', 2147483647, 1, 1),
+('bx_payment_form_pendings_process', 'seller_id', 2147483647, 1, 2),
+('bx_payment_form_pendings_process', 'order', 2147483647, 1, 3),
+('bx_payment_form_pendings_process', 'controls', 2147483647, 1, 4),
+('bx_payment_form_pendings_process', 'do_submit', 2147483647, 1, 5),
+('bx_payment_form_pendings_process', 'do_cancel', 2147483647, 1, 6),
+
+('bx_payment_form_processed_add', 'id', 2147483647, 0, 1),
+('bx_payment_form_processed_add', 'seller_id', 2147483647, 1, 2),
+('bx_payment_form_processed_add', 'client_id', 2147483647, 1, 3),
+('bx_payment_form_processed_add', 'client', 2147483647, 1, 4),
+('bx_payment_form_processed_add', 'order', 2147483647, 1, 5),
+('bx_payment_form_processed_add', 'module_id', 2147483647, 1, 6),
+('bx_payment_form_processed_add', 'items', 2147483647, 1, 7),
+('bx_payment_form_processed_add', 'controls', 2147483647, 1, 8),
+('bx_payment_form_processed_add', 'do_submit', 2147483647, 1, 9),
+('bx_payment_form_processed_add', 'do_cancel', 2147483647, 1, 10),
+
+-- FORMS: Recurly
+('bx_payment_form_rcrl_card_add', 'pending_id', 2147483647, 1, 1),
+('bx_payment_form_rcrl_card_add', 'item', 2147483647, 1, 2),
+('bx_payment_form_rcrl_card_add', 'token', 2147483647, 1, 3),
+('bx_payment_form_rcrl_card_add', 'first_name', 2147483647, 1, 4),
+('bx_payment_form_rcrl_card_add', 'last_name', 2147483647, 1, 5),
+('bx_payment_form_rcrl_card_add', 'email', 2147483647, 1, 6),
+('bx_payment_form_rcrl_card_add', 'card_number', 2147483647, 1, 7),
+('bx_payment_form_rcrl_card_add', 'card_expire', 2147483647, 1, 8),
+('bx_payment_form_rcrl_card_add', 'card_cvv', 2147483647, 1, 9),
+('bx_payment_form_rcrl_card_add', 'controls', 2147483647, 1, 10),
+('bx_payment_form_rcrl_card_add', 'do_submit', 2147483647, 1, 11),
+('bx_payment_form_rcrl_card_add', 'do_cancel', 2147483647, 1, 12);
+
+
+-- STUDIO PAGE & WIDGET
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, @sName, '_bx_payment', '_bx_payment', 'bx_payment@modules/boonex/payment/|std-pi.png');
+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`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, @sName, '{url_studio}module.php?name=bx_payment', '', 'bx_payment@modules/boonex/payment/|std-wi.png', '_bx_payment', '', '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));

+ 91 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/js/cart.js

@@ -0,0 +1,91 @@
+function BxPaymentCart(oOptions) {
+	this.init(oOptions);
+}
+
+BxPaymentCart.prototype = new BxPaymentMain();
+
+BxPaymentCart.prototype.init = function(oOptions) {
+	if($.isEmptyObject(oOptions))
+		return;
+
+	this._sActionsUrl = oOptions.sActionUrl;
+    this._sObjName = oOptions.sObjName == undefined ? 'oPmtCart' : oOptions.sObjName;
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+};
+
+BxPaymentCart.prototype.addToCart = function(iSellerId, iModuleId, iItemId, iItemCount, iNeedRedirect) {
+	var $this = this;
+    var oDate = new Date();
+
+    iNeedRedirect = parseInt(iNeedRedirect);
+    if(!iNeedRedirect)
+    	iNeedRedirect = 0;
+
+    $.post(
+        this._sActionsUrl + 'add_to_cart/' + iSellerId + '/' + iModuleId + '/' + iItemId + '/' + iItemCount + '/',
+        {
+            _t:oDate.getTime()
+        },
+        function(oData){
+        	$this.processResult(oData);
+
+            if(oData.code == 0) {
+            	/*
+            	 * TODO: Display counter somewhere if it's needed.
+            	 * 
+            	$('#bx-menu-object-sys_account_notifications').html(oData.total_quantity);
+                $('#bx-payment-tbar-content').replaceWith(oData.content);
+                */
+
+            	if(iNeedRedirect == 1)
+            		window.location.href = sUrlRoot + 'cart.php';
+            }
+        },
+        'json'
+    );
+};
+
+BxPaymentCart.prototype.onCartContinue = function(oData) {
+	if (!oData || oData.link == undefined)
+		return;
+
+	location.href = oData.link;
+};
+
+BxPaymentCart.prototype.onCartCheckout = function(oData) {
+	if (!oData || oData.link == undefined)
+		return;
+
+	location.href = oData.link;
+};
+
+BxPaymentCart.prototype.subscribe = function(iSellerId, sSellerProvider, iModuleId, iItemId, iItemCount) {
+    var $this = this;
+    var oDate = new Date();
+
+    var oParams = {
+    	seller_id: iSellerId,
+    	seller_provider: sSellerProvider,
+    	module_id: iModuleId,
+    	item_id: iItemId,
+    	item_count: 1,
+    	_t: oDate.getTime()
+    };
+
+    if(iItemCount != undefined && iItemCount.length > 0)
+    	oParams.item_count = parseInt(iItemCount);
+
+    $.post(
+        this._sActionsUrl + 'subscribe_json/',
+        oParams,
+        function(oData){
+        	$this.processResult(oData);
+        },
+        'json'
+    );
+};
+
+BxPaymentCart.prototype.onSubscribeSubmit = function(oData) {
+	document.location = oData.redirect;
+};

+ 47 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/js/main.js

@@ -0,0 +1,47 @@
+function BxPaymentMain() {}
+
+BxPaymentMain.prototype.processResult = function(oData) {
+	var $this = this;
+
+	if(oData && oData.message != undefined && oData.message.length != 0)
+    	alert(oData.message);
+
+    if(oData && oData.reload != undefined && parseInt(oData.reload) == 1)
+    	document.location = document.location;
+
+    if(oData && oData.popup != undefined) {
+    	var oPopup = null;
+    	var oOptions = {
+            fog: {
+				color: '#fff',
+				opacity: .7
+            },
+            closeOnOuterClick: false
+        };
+
+    	if(typeof(oData.popup) == 'object') {
+    		oOptions = $.extend({}, oOptions, oData.popup.options);
+    		oPopup = $(oData.popup.html);
+    	}
+    	else 
+    		oPopup = $(oData.popup);
+
+    	$('#' + oPopup.attr('id')).remove();
+        oPopup.hide().prependTo('body').dolPopup(oOptions);
+    }
+
+    if (oData && oData.eval != undefined)
+        eval(oData.eval);
+};
+
+BxPaymentMain.prototype.loadingInButton = function(e, bShow) {
+	if($(e).length)
+		bx_loading_btn($(e), bShow);
+	else
+		bx_loading($('body'), bShow);	
+};
+
+BxPaymentMain.prototype.loadingInPopup = function(e, bShow) {
+	var oParent = $(e).length ? $(e).parents('.bx-popup-content:first') : $('body'); 
+	bx_loading(oParent, bShow);
+};

+ 93 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/js/stripe.js

@@ -0,0 +1,93 @@
+function BxPaymentProviderStripe(oOptions) {
+	this.init(oOptions);
+}
+
+BxPaymentProviderStripe.prototype = new BxPaymentMain();
+
+BxPaymentProviderStripe.prototype.init = function(oOptions) {
+	this._sProvider = oOptions.sProvider;
+	this._sActionsUrl = oOptions.sActionUrl;
+    this._sObjName = oOptions.sObjName == undefined ? 'oPaymentProviderStripe' : oOptions.sObjName;
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+
+    this._rHandler = StripeCheckout.configure({
+	  key: oOptions.sPublicKey,
+	  name: oOptions.sVendorName,
+	  currency: oOptions.sVendorCurrency,
+	  image: oOptions.sVendorIcon,
+	  locale: 'auto',
+	  email: oOptions.sClientEmail
+	});
+
+    //--- For Single payment
+    this._sObjNameGrid = oOptions.sObjNameGrid;
+
+    //--- For Recurring payment
+    this._sObjNameCart = oOptions.sObjNameCart;
+    this._iSellerId  = oOptions.iSellerId;
+    this._iModuleId  = oOptions.iModuleId;
+    this._iItemId  = oOptions.iItemId;
+    this._iItemCount  = oOptions.iItemCount;
+};
+
+BxPaymentProviderStripe.prototype.checkout = function(oLink) {
+  	oLink = jQuery(oLink);
+	if(oLink.hasClass('bx-btn-disabled'))
+		return;
+
+	oLink.toggleClass('bx-btn-disabled');
+
+	var $this = this;
+	this._rHandler.open({
+		token: function(token) {
+			glGrids[$this._sObjNameGrid]._oQueryAppend['provider'] = $this._sProvider;
+			glGrids[$this._sObjNameGrid]._oQueryAppend['token'] = token.id;
+			glGrids[$this._sObjNameGrid].actionWithSelected('', 'checkout', {}, '', false, false);
+		},
+		closed: function() {
+			oLink.toggleClass('bx-btn-disabled');
+		}
+	});
+};
+
+BxPaymentProviderStripe.prototype.subscribe = function(oLink) {
+	var $this = this;
+    var oDate = new Date();
+
+  	oLink = jQuery(oLink);
+	if(oLink.hasClass('bx-btn-disabled'))
+		return;
+
+	oLink.addClass('bx-btn-disabled');
+
+	this._rHandler.open({
+		token: function(token) {
+			$this.loadingInButton(oLink, true);
+
+		    var oParams = {
+		    	seller_id: $this._iSellerId,
+		    	seller_provider: $this._sProvider,
+		    	module_id: $this._iModuleId,
+		    	item_id: $this._iItemId,
+		    	item_count: $this._iItemCount,
+		    	token: token.id,
+		    	_t: oDate.getTime()
+		    };
+
+		    $.post(
+		        $this._sActionsUrl + 'subscribe_json/',
+		        oParams,
+		        function(oData){
+		        	$this.loadingInButton(oLink, true);
+
+		        	$this.processResult(oData);
+		        },
+		        'json'
+		    );
+		},
+		closed: function() {
+			oLink.removeClass('bx-btn-disabled');
+		}
+	});
+};

+ 5 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/template/css/stripe.css

@@ -0,0 +1,5 @@
+/*--- Single payments ---*/
+.bx-payment-strp-button-single {
+	position: relative;
+	float: left;
+}

+ 8 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/template/providers_select.html

@@ -0,0 +1,8 @@
+<div class="bx-payment-providers-select bx-def-color-bg-block">
+    <div class="bx-payment-providers-select-cnt bx-def-padding">
+		<bx_repeat:providers>__button__</bx_repeat:providers>
+		<a class="bx-btn bx-def-margin-top-auto" href="javascript:void(0)" onclick="javascript:$('.bx-popup-applied:visible').dolPopupHide();">
+			<bx_text:_adm_txt_confirm_cancel />
+		</a>
+    </div>
+</div>

+ 1 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/template/providers_select_button.html

@@ -0,0 +1 @@
+<a class="bx-btn bx-def-margin-top-auto" href="javascript:void(0)" onclick="javascript:__onclick__">__title__</a>

+ 2 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/template/strp_button_recurring.html

@@ -0,0 +1,2 @@
+<a class="bx-btn bx-def-margin-top-auto" href="javascript:void(0)" onclick="javascript:__js_object__.subscribe(this)">__caption__</a>
+__js_code__

+ 4 - 0
modules/boonex/payment/updates/9.0.0_9.0.1/source/template/strp_button_single.html

@@ -0,0 +1,4 @@
+<div class="bx-payment-strp-button-__type__">
+	<button class="bx-btn bx-def-margin-thd" type="button" onclick="javascript:__js_object__.checkout(this)">__caption__</button>
+	__js_code__
+</div>

+ 1 - 1
modules/boonex/persons/updates/9.0.0_9.0.1/source/install/config.php

@@ -23,7 +23,7 @@ $aConfig = array(
 	'help_url' => 'http://feed.boonex.com/?section={module_name}',
 
     'compatible_with' => array(
-        '9.0.x'
+        '9.0.0-B2'
     ),
 
     /**

+ 53 - 0
modules/boonex/posts/updates/9.0.0_9.0.1/install/config.php

@@ -0,0 +1,53 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Posts',
+    'version_from' => '9.0.0',
+	'version_to' => '9.0.1',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/posts/updates/update_9.0.0_9.0.1/',
+	'home_uri' => 'posts_update_900_901',
+
+	'module_dir' => 'boonex/posts/',
+	'module_uri' => 'posts',
+
+    'db_prefix' => 'bx_posts_',
+    'class_prefix' => 'BxPosts',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+		'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+		'clear_db_cache' => 1,
+    ),
+
+	/**
+     * Category for language keys.
+     */
+    'language_category' => 'Posts',
+
+	/**
+     * Files Section
+     */
+    'delete_files' => array(
+		'template/form_field_location.html'
+	),
+);

+ 29 - 0
modules/boonex/posts/updates/9.0.0_9.0.1/install/installer.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+class BxPostsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+	{
+        parent::__construct($aConfig);
+    }
+
+	public function actionExecuteSql($sOperation)
+    {
+    	if($sOperation == 'install') {
+    		if(!$this->oDb->isFieldExists('bx_posts_posts', 'status_admin'))
+        		$this->oDb->query("ALTER TABLE `bx_posts_posts` ADD `status_admin` enum('active','hidden') NOT NULL DEFAULT 'active' AFTER `status`");
+
+			if(!$this->oDb->isFieldExists('bx_posts_meta_locations', 'street'))
+	        		$this->oDb->query("ALTER TABLE `bx_posts_meta_locations` ADD `street` varchar(255) NOT NULL AFTER `zip`");
+	
+			if(!$this->oDb->isFieldExists('bx_posts_meta_locations', 'street_number'))
+	        		$this->oDb->query("ALTER TABLE `bx_posts_meta_locations` ADD `street_number` varchar(255) NOT NULL AFTER `street`");
+    	}
+
+    	return parent::actionExecuteSql($sOperation);
+    }
+}

+ 4 - 0
modules/boonex/posts/updates/9.0.0_9.0.1/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_posts_option_searchable_fields"><![CDATA[Searchable fields]]></string_add>
+</resources>

+ 14 - 0
modules/boonex/posts/updates/9.0.0_9.0.1/install/sql/enable.sql

@@ -0,0 +1,14 @@
+-- SETTINGS
+SET @iCategoryId = (SELECT `id` FROM `sys_options_categories` WHERE `name`='bx_posts' LIMIT 1);
+DELETE FROM `sys_options` WHERE `name` IN ('bx_posts_searchable_fields');
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_posts_searchable_fields', 'title,text', @iCategoryId, '_bx_posts_option_searchable_fields', 'list', '', '', 'a:2:{s:6:"module";s:8:"bx_posts";s:6:"method";s:21:"get_searchable_fields";}', 30);
+
+
+-- MENUS
+UPDATE `sys_menu_items` SET `active`='0' WHERE `set_name`='bx_posts_view_submenu' AND `module`='bx_posts' AND `name` IN ('view-post', 'view-post-comments');
+
+
+-- GRIDS
+UPDATE `sys_objects_grid` SET `visible_for_levels`='192' WHERE `object`='bx_posts_administration';
+UPDATE `sys_objects_grid` SET `visible_for_levels`='2147483647' WHERE `object`='bx_posts_common';

+ 2 - 0
modules/boonex/posts/updates/9.0.0_9.0.1/install/sql/install.sql

@@ -0,0 +1,2 @@
+-- FORMS
+UPDATE `sys_form_inputs` SET `type`='location', `caption`='_sys_form_input_location' WHERE `object`='bx_posts' AND `name`='location';

+ 135 - 0
modules/boonex/posts/updates/9.0.0_9.0.1/source/classes/BxPostsConfig.php

@@ -0,0 +1,135 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Posts Posts
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPostsConfig extends BxBaseModTextConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $aMenuItems2Methods = array (
+            'edit-post' => 'checkAllowedEdit',
+            'delete-post' => 'checkAllowedDelete',
+        );
+
+        $this->CNF = array (
+
+            // module icon
+            'ICON' => 'file-text col-red3',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'posts',
+        	'TABLE_ENTRIES_FULLTEXT' => 'title_text',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => 'author',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => 'changed',
+            'FIELD_TITLE' => 'title',
+            'FIELD_TEXT' => 'text',
+            'FIELD_TEXT_ID' => 'post-text',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_PHOTO' => 'pictures',
+            'FIELD_THUMB' => 'thumb',
+            'FIELD_COMMENTS' => 'comments',
+	        'FIELD_STATUS' => 'status',
+        	'FIELD_STATUS_ADMIN' => 'status_admin',
+            'FIELD_LOCATION_PREFIX' => 'location',
+            'FIELDS_WITH_KEYWORDS' => 'auto', // can be 'auto', array of fields or comma separated string of field names, works only when OBJECT_METATAGS is specified
+
+            // page URIs
+            'URI_VIEW_ENTRY' => 'view-post',
+            'URI_AUTHOR_ENTRIES' => 'posts-author',
+            'URI_ADD_ENTRY' => 'create-post',
+        	'URI_EDIT_ENTRY' => 'edit-post',
+        	'URI_MANAGE_COMMON' => 'posts-manage',
+
+            'URL_HOME' => 'page.php?i=posts-home',
+            'URL_POPULAR' => 'page.php?i=posts-popular',
+            'URL_UPDATED' => 'page.php?i=posts-updated',
+        	'URL_MANAGE_COMMON' => 'page.php?i=posts-manage',
+        	'URL_MANAGE_ADMINISTRATION' => 'page.php?i=posts-administration',
+
+            // some params
+            'PARAM_CHARS_SUMMARY' => 'bx_posts_summary_chars',
+            'PARAM_CHARS_SUMMARY_PLAIN' => 'bx_posts_plain_summary_chars',
+            'PARAM_NUM_RSS' => 'bx_posts_rss_num',
+        	'PARAM_SEARCHABLE_FIELDS' => 'bx_posts_searchable_fields',
+
+            // objects
+            'OBJECT_STORAGE' => 'bx_posts_files',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW' => 'bx_posts_preview',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => 'bx_posts_gallery',
+            'OBJECT_VIDEOS_TRANSCODERS' => array(),
+        	'OBJECT_REPORTS' => 'bx_posts',
+            'OBJECT_VIEWS' => 'bx_posts',
+            'OBJECT_VOTES' => 'bx_posts',
+            'OBJECT_METATAGS' => 'bx_posts',
+            'OBJECT_COMMENTS' => 'bx_posts',
+            'OBJECT_PRIVACY_VIEW' => 'bx_posts_allow_view_to',
+            'OBJECT_FORM_ENTRY' => 'bx_posts',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => 'bx_posts_entry_view',
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_posts_entry_add',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => 'bx_posts_entry_edit',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_posts_entry_delete',
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_posts_view', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_posts_my', // actions menu on my entries page
+            'OBJECT_MENU_SUBMENU' => 'bx_posts_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => 'bx_posts_view_submenu', // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'posts-home', // first item in view entry submenu from main module submenu
+            'OBJECT_MENU_MANAGE_TOOLS' => 'bx_posts_menu_manage_tools', //manage menu in content administration tools
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_posts_administration',
+        	'OBJECT_GRID_COMMON' => 'bx_posts_common',
+            'OBJECT_UPLOADERS' => array('sys_simple', 'sys_html5'),
+
+            // menu items which visibility depends on custom visibility checking
+            'MENU_ITEM_TO_METHOD' => array (
+                'bx_posts_my' => array (
+                    'create-post' => 'checkAllowedAdd',
+                ),
+                'bx_posts_view' => $aMenuItems2Methods,
+            ),
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_posts_txt_sample_single',
+            	'txt_sample_comment_single' => '_bx_posts_txt_sample_comment_single',
+            	'txt_sample_vote_single' => '_bx_posts_txt_sample_vote_single',
+            	'grid_action_err_delete' => '_bx_posts_grid_action_err_delete',
+            	'grid_txt_account_manager' => '_bx_posts_grid_txt_account_manager',
+				'filter_item_active' => '_bx_posts_grid_filter_item_title_adm_active',
+            	'filter_item_hidden' => '_bx_posts_grid_filter_item_title_adm_hidden',
+            	'filter_item_select_one_filter1' => '_bx_posts_grid_filter_item_title_adm_select_one_filter1',
+            	'menu_item_manage_my' => '_bx_posts_menu_item_title_manage_my',
+            	'menu_item_manage_all' => '_bx_posts_menu_item_title_manage_all',
+                'txt_all_entries_by' => '_bx_posts_txt_all_entries_by',
+            	'txt_pict_use_as_thumb' => '_bx_posts_form_entry_input_picture_use_as_thumb'
+            ),
+        );
+
+        $this->_aJsClasses = array(
+        	'manage_tools' => 'BxPostsManageTools'
+        );
+
+        $this->_aJsObjects = array(
+        	'manage_tools' => 'oBxPostsManageTools'
+        );
+
+        $this->_aGridObjects = array(
+        	'common' => $this->CNF['OBJECT_GRID_COMMON'],
+        	'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION'],
+        	
+        );
+    }
+}
+
+/** @} */

+ 32 - 0
modules/boonex/posts/updates/9.0.0_9.0.1/source/classes/BxPostsPageEntry.php

@@ -0,0 +1,32 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Posts Posts
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/**
+ * Entry create/edit pages
+ */
+class BxPostsPageEntry extends BxBaseModTextPageEntry
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_posts';
+        parent::__construct($aObject, $oTemplate);
+    }
+
+    protected function _setSubmenu($aParams)
+    {
+    	parent::_setSubmenu(array_merge($aParams, array(
+    		'title' => '',
+    		'icon' => ''
+    	)));
+    }
+}
+
+/** @} */

+ 127 - 0
modules/boonex/posts/updates/9.0.0_9.0.1/source/classes/BxPostsSearchResult.php

@@ -0,0 +1,127 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Posts Posts
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPostsSearchResult extends BxBaseModTextSearchResult
+{
+    function __construct($sMode = '', $aParams = array())
+    {
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent = array(
+            'name' => 'bx_posts',
+            'module_name' => 'bx_posts',
+            'object_metatags' => 'bx_posts',
+            'title' => _t('_bx_posts_page_title_browse'),
+            'table' => 'bx_posts_posts',
+            'ownFields' => array('id', 'title', 'text', 'thumb', 'author', 'added'),
+            'searchFields' => array(),
+            'restriction' => array(
+                'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
+        		'status' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
+            ),
+            'paginate' => array('perPage' => getParam('bx_posts_per_page_browse'), 'start' => 0),
+            'sorting' => 'last',
+            'rss' => array(
+                'title' => '',
+                'link' => '',
+                'image' => '',
+                'profile' => 0,
+                'fields' => array (
+                    'Guid' => 'link',
+                    'Link' => 'link',
+                    'Title' => 'title',
+                    'DateTimeUTS' => 'added',
+                    'Desc' => 'text',
+                ),
+            ),
+            'ident' => 'id',
+        );
+
+        $this->sFilterName = 'bx_posts_filter';
+        $this->oModule = $this->getMain();
+        $this->aCurrent['searchFields'] = explode(',', getParam($this->oModule->_oConfig->CNF['PARAM_SEARCHABLE_FIELDS']));
+
+        $oProfileAuthor = null;
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        switch ($sMode) {
+
+            case 'author':
+                $oProfileAuthor = BxDolProfile::getInstance((int)$aParams['author']);
+                if (!$oProfileAuthor) {
+                    $this->isError = true;
+                    break;
+                }
+
+                $this->aCurrent['restriction']['author']['value'] = $oProfileAuthor->id();
+
+                $this->sBrowseUrl = 'page.php?i=' . $CNF['URI_AUTHOR_ENTRIES'] . '&profile_id={profile_id}';
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_by_author');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode . '/' . $oProfileAuthor->id();
+                break;
+
+            case 'public':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_recent');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                break;
+
+            case 'popular':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_POPULAR']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_popular');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'popular';
+                break;
+
+            case 'updated':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_UPDATED']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_updated');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'updated';
+                break;
+
+            case '': // search results
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_posts');
+                $this->aCurrent['paginate']['perPage'] = 3;
+                unset($this->aCurrent['rss']);
+                break;
+
+            default:
+                $sMode = '';
+                $this->isError = true;
+        }
+
+        $this->processReplaceableMarkers($oProfileAuthor);
+
+        $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+    }
+
+    function getAlterOrder()
+    {
+        $aSql = array();
+        switch ($this->aCurrent['sorting']) {
+            case 'last':
+                $aSql['order'] = ' ORDER BY `bx_posts_posts`.`added` DESC';
+                break;
+            case 'updated':
+                $aSql['order'] = ' ORDER BY `bx_posts_posts`.`changed` DESC';
+                break;
+            case 'popular':
+                $aSql['order'] = ' ORDER BY `bx_posts_posts`.`views` DESC';
+                break;
+        }
+        return $aSql;
+    }
+}
+
+/** @} */

+ 124 - 0
modules/boonex/posts/updates/9.0.0_9.0.1/source/install/config.php

@@ -0,0 +1,124 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Posts Posts
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_posts',
+    'title' => 'Posts',
+    'note' => 'Basic blogging module.',
+    'version' => '9.0.1',
+    'vendor' => 'BoonEx',
+	'help_url' => 'http://feed.boonex.com/?section={module_name}',
+
+    'compatible_with' => array(
+        '9.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/posts/',
+    'home_uri' => 'posts',
+
+    'db_prefix' => 'bx_posts_',
+    'class_prefix' => 'BxPosts',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Posts',
+
+    /**
+     * List of page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry',
+    ),
+    
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+    	'trigger_profile_view_submenu'
+    ),
+
+    /**
+     * Storages.
+     */
+    'storages' => array(
+    	'bx_posts_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+		'bx_posts_preview',
+        'bx_posts_gallery',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_storages' => 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,
+    	'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'
+    ),
+
+);
+
+/** @} */

+ 199 - 0
modules/boonex/posts/updates/9.0.0_9.0.1/source/install/langs/en.xml

@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+	<string name="_bx_posts"><![CDATA[Posts]]></string>
+	<string name="_bx_posts_cmts"><![CDATA[Posts' Comments]]></string>
+
+	<string name="_bx_posts_option_summary_chars"><![CDATA[Number of characters in auto-cropped post summary]]></string>
+	<string name="_bx_posts_option_plain_summary_chars"><![CDATA[Number of characters in plain post description when post hasn't thumb]]></string>
+	<string name="_bx_posts_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+	<string name="_bx_posts_option_rss_num"><![CDATA[Number of items in RSS feed]]></string>
+	<string name="_bx_posts_option_searchable_fields"><![CDATA[Searchable fields]]></string>
+
+	<string name="_bx_posts_form_entry"><![CDATA[Posts]]></string>
+	<string name="_bx_posts_form_entry_display_add"><![CDATA[Add Post]]></string>
+	<string name="_bx_posts_form_entry_display_edit"><![CDATA[Edit Post]]></string>
+	<string name="_bx_posts_form_entry_display_delete"><![CDATA[Delete Post]]></string>
+	<string name="_bx_posts_form_entry_display_view"><![CDATA[View Post]]></string>
+	<string name="_bx_posts_form_entry_input_sys_do_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_posts_form_entry_input_do_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_posts_form_entry_input_sys_do_publish"><![CDATA[Publish]]></string>
+	<string name="_bx_posts_form_entry_input_do_publish"><![CDATA[Publish]]></string>
+	<string name="_bx_posts_form_entry_input_sys_title"><![CDATA[Title]]></string>
+	<string name="_bx_posts_form_entry_input_title"><![CDATA[Title]]></string>
+	<string name="_bx_posts_form_entry_input_title_err"><![CDATA[Title is essential. Please, fill in this field]]></string>
+	<string name="_bx_posts_form_entry_input_sys_cat"><![CDATA[Category]]></string>
+	<string name="_bx_posts_form_entry_input_cat"><![CDATA[Category]]></string>
+    <string name="_bx_posts_form_entry_input_cat_err"><![CDATA[Please select category]]></string>
+	<string name="_bx_posts_form_entry_input_sys_text"><![CDATA[Text]]></string>
+	<string name="_bx_posts_form_entry_input_text"><![CDATA[Text]]></string>
+	<string name="_bx_posts_form_entry_input_text_err"><![CDATA[Text field can't be empty]]></string>
+	<string name="_bx_posts_form_entry_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+	<string name="_bx_posts_form_entry_input_delete_confirm"><![CDATA[I am sure I want to delete this post]]></string>
+	<string name="_bx_posts_form_entry_input_delete_confirm_info"><![CDATA[This action can not be undone]]></string>
+	<string name="_bx_posts_form_entry_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete the post]]></string>
+	<string name="_bx_posts_form_entry_input_sys_pictures"><![CDATA[Pictures]]></string>
+	<string name="_bx_posts_form_entry_input_pictures"><![CDATA[Pictures]]></string>
+    <string name="_bx_posts_form_entry_input_sys_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_posts_form_entry_input_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_posts_form_entry_input_picture_use_as_thumb"><![CDATA[Cover Image]]></string>
+    <string name="_bx_posts_form_entry_input_sys_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_posts_form_entry_input_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_posts_form_entry_input_sys_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_posts_form_entry_input_date_changed"><![CDATA[Updated]]></string>
+
+	<string name="_bx_posts_acl_action_create_entry"><![CDATA[Create Post]]></string>
+	<string name="_bx_posts_acl_action_delete_entry"><![CDATA[Delete Post]]></string>
+	<string name="_bx_posts_acl_action_view_entry"><![CDATA[View Post]]></string>
+	<string name="_bx_posts_acl_action_set_thumb"><![CDATA[Set Post Thumbnail]]></string>
+	<string name="_bx_posts_acl_action_edit_any_entry"><![CDATA[Edit Any Post]]></string>
+
+	<string name="_bx_posts_page_title_sys_create_entry"><![CDATA[New Post]]></string>
+	<string name="_bx_posts_page_title_create_entry"><![CDATA[New Post]]></string>
+	<string name="_bx_posts_page_block_title_create_entry"><![CDATA[New Post]]></string>
+	<string name="_bx_posts_page_title_sys_edit_entry"><![CDATA[Edit]]></string>
+	<string name="_bx_posts_page_title_edit_entry"><![CDATA[Edit]]></string>
+	<string name="_bx_posts_page_block_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_page_title_sys_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_page_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_page_block_title_delete_entry"><![CDATA[Delete]]></string>
+	<string name="_bx_posts_page_title_sys_view_entry"><![CDATA[View Post]]></string>
+	<string name="_bx_posts_page_title_view_entry"><![CDATA[{title}]]></string>
+	<string name="_bx_posts_page_block_title_entry_text"><![CDATA[Post Text]]></string>
+	<string name="_bx_posts_page_title_browse"><![CDATA[Posts]]></string>
+	<string name="_bx_posts_page_title_search_results"><![CDATA[Posts matching "{0}"]]></string>
+	<string name="_bx_posts_page_title_browse_by_author"><![CDATA[Posts of {display_name}]]></string>
+    <string name="_bx_posts_page_title_browse_recent"><![CDATA[Latest]]></string>
+    <string name="_bx_posts_page_title_browse_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_posts_page_title_browse_updated"><![CDATA[Updated Posts]]></string>
+    <string name="_bx_posts_page_title_sys_home"><![CDATA[Posts Home]]></string>
+    <string name="_bx_posts_page_title_home"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_page_block_title_recent_entries"><![CDATA[Latest (Gallery View)]]></string>
+    <string name="_bx_posts_page_block_title_recent_entries_view_extended"><![CDATA[Latest]]></string>
+    <string name="_bx_posts_page_block_title_recent_entries_view_full"><![CDATA[Latest (Full View)]]></string>
+    <string name="_bx_posts_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+    <string name="_bx_posts_page_block_title_entry_author"><![CDATA[Author]]></string>
+    <string name="_bx_posts_page_block_title_entry_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_posts_page_block_title_entry_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_posts_page_block_title_entry_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_posts_page_block_title_entry_location"><![CDATA[Location]]></string>
+    <string name="_bx_posts_page_block_title_entry_attachments"><![CDATA[Attachments]]></string>
+    <string name="_bx_posts_page_block_title_entry_all_actions"><![CDATA[All Actions]]></string>
+    <string name="_bx_posts_page_title_sys_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_posts_page_title_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_posts_page_title_sys_entries_updated"><![CDATA[Updated Posts]]></string>
+    <string name="_bx_posts_page_title_entries_updated"><![CDATA[Updated Posts]]></string>
+    <string name="_bx_posts_page_block_title_popular_entries"><![CDATA[Popular]]></string>
+    <string name="_bx_posts_page_block_title_popular_entries_view_extended"><![CDATA[Popular (Extended View)]]></string>
+    <string name="_bx_posts_page_block_title_popular_entries_view_full"><![CDATA[Popular (Full View)]]></string>
+    <string name="_bx_posts_page_block_title_updated_entries"><![CDATA[Updated Posts]]></string>
+    <string name="_bx_posts_page_title_sys_view_entry_comments"><![CDATA[Post Comments]]></string>
+    <string name="_bx_posts_page_title_view_entry_comments"><![CDATA[Comments to {title}]]></string>
+    <string name="_bx_posts_page_title_sys_entries_of_author"><![CDATA[Posts of author]]></string>
+    <string name="_bx_posts_page_title_entries_of_author"><![CDATA[Posts by {display_name}]]></string>
+    <string name="_bx_posts_page_block_title_entries_of_author"><![CDATA[Posts by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_posts_page_block_title_sys_entries_of_author"><![CDATA[Posts of author]]></string>   
+    <string name="_bx_posts_page_block_title_entries_actions"><![CDATA[Posts actions]]></string>
+    <string name="_bx_posts_page_block_title_browse_cmts"><![CDATA[Posts' Comments]]></string>
+	<string name="_bx_posts_page_title_sys_manage"><![CDATA[Manage Own]]></string>
+	<string name="_bx_posts_page_title_sys_manage_administration"><![CDATA[Manage All]]></string>
+	<string name="_bx_posts_page_title_manage"><![CDATA[Manage]]></string>
+	<string name="_bx_posts_page_block_title_system_manage"><![CDATA[Manage Own]]></string>
+	<string name="_bx_posts_page_block_title_system_manage_administration"><![CDATA[Manage All]]></string>
+	<string name="_bx_posts_page_block_title_manage"><![CDATA[Manage]]></string>    
+	<string name="_bx_posts_page_block_title_popular_keywords"><![CDATA[Popular Hashtags]]></string>
+	<string name="_bx_posts_page_block_title_cats"><![CDATA[Posts Categories]]></string>
+	<string name="_bx_posts_page_block_title_entry_info"><![CDATA[Info]]></string>
+	<string name="_bx_posts_page_block_title_my_entries"><![CDATA[My Posts]]></string>
+
+    <string name="_bx_posts_menu_set_title_view_entry"><![CDATA[Post Actions]]></string>
+    <string name="_bx_posts_menu_title_view_entry"><![CDATA[Post Actions]]></string>
+    <string name="_bx_posts_menu_title_submenu"><![CDATA[Posts Submenu]]></string>
+    <string name="_bx_posts_menu_set_title_submenu"><![CDATA[Posts Submenu]]></string>
+    <string name="_bx_posts_menu_item_title_system_create_entry"><![CDATA[New Post]]></string>
+    <string name="_bx_posts_menu_item_title_create_entry"><![CDATA[New Post]]></string>
+    <string name="_bx_posts_menu_item_title_system_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_menu_item_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_menu_item_title_system_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_menu_item_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_menu_item_title_system_view_entry"><![CDATA[View Post]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_home"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_entries_home"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_public"><![CDATA[Latest]]></string>
+    <string name="_bx_posts_menu_item_title_entries_public"><![CDATA[Latest]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_posts_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_posts_menu_item_title_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_posts_menu_title_view_entry_submenu"><![CDATA[View Post Submenu]]></string>
+    <string name="_bx_posts_menu_set_title_view_entry_submenu"><![CDATA[View Post Submenu]]></string>
+    <string name="_bx_posts_menu_item_title_view_entry_submenu_entry"><![CDATA[Post]]></string>
+    <string name="_bx_posts_menu_item_title_view_entry_submenu_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_posts_menu_item_title_system_view_entry_comments"><![CDATA[Post Comments]]></string>
+    <string name="_bx_posts_menu_item_title_system_view_entries_author"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_view_entries_author"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_title_entries_my"><![CDATA[My Posts Action Menu]]></string>
+    <string name="_bx_posts_menu_set_title_entries_my"><![CDATA[My Posts Menu]]></string>
+	<string name="_bx_posts_menu_item_title_system_manage_my_posts"><![CDATA[My posts]]></string>
+    <string name="_bx_posts_menu_item_title_manage_my_posts"><![CDATA[{addon} posts]]></string>
+    <string name="_bx_posts_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_posts_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_posts_menu_item_title_system_manage_account"><![CDATA[Manage account]]></string>
+    <string name="_bx_posts_menu_item_title_manage_account"><![CDATA[Manage account]]></string>
+	<string name="_bx_posts_menu_item_title_system_admt_posts"><![CDATA[Posts]]></string>
+	<string name="_bx_posts_menu_item_title_admt_posts"><![CDATA[Posts - {addon} hidden]]></string>
+	<string name="_bx_posts_menu_item_title_manage_my"><![CDATA[My Posts]]></string>
+	<string name="_bx_posts_menu_item_title_manage_all"><![CDATA[All Posts]]></string>
+
+	<string name="_bx_posts_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+	<string name="_bx_posts_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+	<string name="_bx_posts_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+	<string name="_bx_posts_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_posts_grid_column_title_adm_title"><![CDATA[Title]]></string>
+    <string name="_bx_posts_grid_column_title_adm_added"><![CDATA[Added]]></string>
+    <string name="_bx_posts_grid_column_title_adm_author"><![CDATA[Author]]></string>
+    <string name="_bx_posts_grid_action_title_adm_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_posts_grid_action_err_delete"><![CDATA[Cannot delete the selected post(s).]]></string>
+    <string name="_bx_posts_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_posts_pre_lists_cats"><![CDATA[Post categories]]></string>
+    <string name="_bx_posts_cat_Animals_Pets"><![CDATA[Animals & Pets]]></string>
+    <string name="_bx_posts_cat_Architecture"><![CDATA[Architecture]]></string>
+    <string name="_bx_posts_cat_Art"><![CDATA[Art]]></string>
+    <string name="_bx_posts_cat_Cars_Motorcycles"><![CDATA[Cars & Motorcycles]]></string>
+    <string name="_bx_posts_cat_Celebrities"><![CDATA[Celebrities]]></string>
+    <string name="_bx_posts_cat_Design"><![CDATA[Design]]></string>
+    <string name="_bx_posts_cat_DIY_Crafts"><![CDATA[DIY & Crafts]]></string>
+    <string name="_bx_posts_cat_Education"><![CDATA[Education]]></string>
+    <string name="_bx_posts_cat_Film_Music_Books"><![CDATA[Film, Music & Books]]></string>
+    <string name="_bx_posts_cat_Food_Drink"><![CDATA[Food & Drink]]></string>
+    <string name="_bx_posts_cat_Gardening"><![CDATA[Gardening]]></string>
+    <string name="_bx_posts_cat_Geek"><![CDATA[Geek]]></string>
+    <string name="_bx_posts_cat_Hair_Beauty"><![CDATA[Hair & Beauty]]></string>
+    <string name="_bx_posts_cat_Health_Fitness"><![CDATA[Health & Fitness]]></string>
+    <string name="_bx_posts_cat_History"><![CDATA[History]]></string>
+    <string name="_bx_posts_cat_Holidays_Events"><![CDATA[Holidays & Events]]></string>
+    <string name="_bx_posts_cat_Home_Decor"><![CDATA[Home Decor]]></string>
+    <string name="_bx_posts_cat_Humor"><![CDATA[Humor]]></string>
+    <string name="_bx_posts_cat_Illustrations_Posters"><![CDATA[Illustrations & Posters]]></string>
+    <string name="_bx_posts_cat_Kids_Parenting"><![CDATA[Kids & Parenting]]></string>
+    <string name="_bx_posts_cat_Mens_Fashion"><![CDATA[Men's Fashion]]></string>
+    <string name="_bx_posts_cat_Outdoors"><![CDATA[Outdoors]]></string>
+    <string name="_bx_posts_cat_Photography"><![CDATA[Photography]]></string>
+    <string name="_bx_posts_cat_Products"><![CDATA[Products]]></string>
+    <string name="_bx_posts_cat_Quotes"><![CDATA[Quotes]]></string>
+    <string name="_bx_posts_cat_Science_Nature"><![CDATA[Science & Nature]]></string>
+    <string name="_bx_posts_cat_Sports"><![CDATA[Sports]]></string>
+    <string name="_bx_posts_cat_Tattoos"><![CDATA[Tattoos]]></string>
+    <string name="_bx_posts_cat_Technology"><![CDATA[Technology]]></string>
+    <string name="_bx_posts_cat_Travel"><![CDATA[Travel]]></string>
+    <string name="_bx_posts_cat_Weddings"><![CDATA[Weddings]]></string>
+    <string name="_bx_posts_cat_Womens_Fashion"><![CDATA[Women's Fashion]]></string>
+
+    <string name="_bx_posts_txt_all_entries_by"><![CDATA[<a href="{0}">All Posts by {1} ({2})</a>]]></string>
+    <string name="_bx_posts_txt_sample_single"><![CDATA[post]]></string>
+    <string name="_bx_posts_txt_sample_comment_single"><![CDATA[post's comment]]></string>
+    <string name="_bx_posts_txt_sample_vote_single"><![CDATA[post's vote]]></string>
+</resources>

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