1
0
Эх сурвалжийг харах

Merge remote-tracking branch 'origin/master'

Alexander 5 жил өмнө
parent
commit
a2d3d25a46
100 өөрчлөгдсөн 2876 нэмэгдсэн , 266 устгасан
  1. 2 0
      .gitignore
  2. 5 1
      build.xml
  3. 108 0
      composer.json
  4. 1479 0
      composer.lock
  5. 4 4
      inc/classes/BxDolAuditGrid.php
  6. 35 0
      inc/classes/BxDolCmtsQuery.php
  7. 1 1
      inc/classes/BxDolDb.php
  8. 7 4
      inc/classes/BxDolForm.php
  9. 1 1
      inc/classes/BxDolHTMLPurifierFilterAddBxLinksClass.php
  10. 1 1
      inc/classes/BxDolHTMLPurifierFilterLocalIframe.php
  11. 1 1
      inc/classes/BxDolHTMLPurifierFilterYouTube.php
  12. 1 1
      inc/classes/BxDolHTMLPurifierFilterYoutubeIframe.php
  13. 0 10
      inc/classes/BxDolImageResize.php
  14. 4 4
      inc/classes/BxDolMetatags.php
  15. 0 6
      inc/classes/BxDolMinify.php
  16. 10 1
      inc/classes/BxDolModuleQuery.php
  17. 47 23
      inc/classes/BxDolModuleTemplate.php
  18. 5 0
      inc/classes/BxDolReport.php
  19. 6 0
      inc/classes/BxDolReportQuery.php
  20. 1 1
      inc/classes/BxDolSearch.php
  21. 18 0
      inc/classes/BxDolStorage.php
  22. 24 1
      inc/classes/BxDolStorageQuery.php
  23. 1 1
      inc/classes/BxDolStorageS3.php
  24. 2 2
      inc/classes/BxDolStorageS3v4.php
  25. 29 12
      inc/classes/BxDolTemplate.php
  26. 36 0
      inc/classes/BxDolUploader.php
  27. 1 1
      inc/js/classes/BxDolCategories.js
  28. 3 0
      inc/js/classes/BxDolForm.js
  29. 3 0
      inc/js/classes/BxDolPage.js
  30. 54 17
      inc/js/classes/BxDolUploader.js
  31. 18 4
      inc/js/functions.js
  32. 1 0
      inc/params.inc.php
  33. 2 9
      inc/utils.inc.php
  34. 0 1
      install/classes/BxDolInstallView.php
  35. 2 0
      install/index.php
  36. 15 9
      install/sql/system.sql
  37. 5 0
      modules/base/general/classes/BxBaseModGeneralDb.php
  38. 2 0
      modules/base/general/classes/BxBaseModGeneralGridAdministration.php
  39. 49 17
      modules/base/general/classes/BxBaseModGeneralMenuViewActions.php
  40. 59 30
      modules/base/general/classes/BxBaseModGeneralModule.php
  41. 1 1
      modules/base/general/classes/BxBaseModGeneralSearchResult.php
  42. 3 0
      modules/base/general/template/css/forms.css
  43. 0 1
      modules/base/general/template/unit_meta_item.html
  44. 59 0
      modules/base/groups/classes/BxBaseModGroupsMenuViewMeta.php
  45. 0 2
      modules/base/groups/template/css/main.css
  46. 5 7
      modules/base/notifications/classes/BxBaseModNotificationsTemplate.php
  47. 2 0
      modules/base/payment/classes/BxBaseModPaymentConfig.php
  48. 1 1
      modules/base/payment/classes/BxBaseModPaymentGridOrders.php
  49. 4 1
      modules/base/profile/classes/BxBaseModProfileAlertsResponse.php
  50. 4 0
      modules/base/profile/classes/BxBaseModProfileFormsEntryHelper.php
  51. 1 1
      modules/base/profile/classes/BxBaseModProfileGridAdministration.php
  52. 35 0
      modules/base/profile/classes/BxBaseModProfileMenuViewActionsAll.php
  53. 167 0
      modules/base/profile/classes/BxBaseModProfileMenuViewMeta.php
  54. 30 1
      modules/base/profile/classes/BxBaseModProfileModule.php
  55. 59 12
      modules/base/profile/classes/BxBaseModProfileTemplate.php
  56. 14 2
      modules/base/profile/classes/BxBaseModProfileUploaderCoverCrop.php
  57. 14 2
      modules/base/profile/classes/BxBaseModProfileUploaderPictureCrop.php
  58. 70 0
      modules/base/profile/template/cover_block.html
  59. 0 3
      modules/base/profile/template/css/main.css
  60. 1 1
      modules/base/text/classes/BxBaseModTextModule.php
  61. 1 2
      modules/base/text/classes/BxBaseModTextTemplate.php
  62. 0 2
      modules/base/text/template/css/main.css
  63. 1 3
      modules/base/text/template/css/polls.css
  64. 1 1
      modules/base/text/template/poll_items_showcase.html
  65. 0 1
      modules/base/text/template/unit_meta_item.html
  66. 41 0
      modules/boonex/accounts/classes/BxAccntGridAdministration.php
  67. 9 0
      modules/boonex/accounts/install/langs/en.xml
  68. 1 0
      modules/boonex/accounts/install/sql/enable.sql
  69. 13 3
      modules/boonex/accounts/install/sql/install.sql
  70. 19 0
      modules/boonex/accounts/template/manage_item.html
  71. 1 1
      modules/boonex/ads/classes/BxAdsDb.php
  72. 1 1
      modules/boonex/ads/classes/BxAdsFormEntry.php
  73. 22 4
      modules/boonex/ads/classes/BxAdsModule.php
  74. 1 1
      modules/boonex/ads/install/sql/enable.sql
  75. 0 2
      modules/boonex/ads/template/css/main.css
  76. 0 3
      modules/boonex/ads/template/unit.html
  77. 0 1
      modules/boonex/ads/template/unit_full.html
  78. 0 3
      modules/boonex/ads/template/unit_full_private.html
  79. 0 1
      modules/boonex/ads/template/unit_gallery.html
  80. 0 3
      modules/boonex/ads/template/unit_gallery_private.html
  81. 0 3
      modules/boonex/ads/template/unit_live_search.html
  82. 0 1
      modules/boonex/ads/template/unit_meta_item.html
  83. 0 3
      modules/boonex/ads/template/unit_private.html
  84. 0 1
      modules/boonex/ads/template/unit_showcase.html
  85. 4 0
      modules/boonex/albums/classes/BxAlbumsConfig.php
  86. 11 1
      modules/boonex/albums/classes/BxAlbumsDb.php
  87. 5 0
      modules/boonex/albums/classes/BxAlbumsFormEntry.php
  88. 72 0
      modules/boonex/albums/classes/BxAlbumsFormMedia.php
  89. 18 0
      modules/boonex/albums/classes/BxAlbumsMenuViewActionsMedia.php
  90. 40 3
      modules/boonex/albums/classes/BxAlbumsModule.php
  91. 37 8
      modules/boonex/albums/classes/BxAlbumsSearchResultMedia.php
  92. 1 1
      modules/boonex/albums/classes/BxAlbumsTemplate.php
  93. 7 0
      modules/boonex/albums/install/langs/en.xml
  94. 6 1
      modules/boonex/albums/install/sql/enable.sql
  95. 10 3
      modules/boonex/albums/install/sql/install.sql
  96. 42 0
      modules/boonex/albums/js/main.js
  97. 0 4
      modules/boonex/albums/template/css/main.css
  98. 0 3
      modules/boonex/albums/template/unit_gallery_private.html
  99. 0 3
      modules/boonex/albums/template/unit_live_search.html
  100. 0 1
      modules/boonex/albums/template/unit_meta_item.html

+ 2 - 0
.gitignore

@@ -4,6 +4,7 @@ cache/*
 cache_public/*
 tmp/*
 logs/*
+plugins/*
 
 # Exclude main config file
 inc/header*
@@ -23,6 +24,7 @@ cs_fixer_tmp*
 
 # Exclude tests files
 build.properties
+composer.phar
 tests/vendor
 tests/composer.phar
 samples/img/*

+ 5 - 1
build.xml

@@ -7,7 +7,7 @@
 
     <if>
         <not><isset property="composer" /></not>
-        <then><property name="composer" value="${project.basedir}/tests/composer.phar" override="yes" /></then>
+        <then><property name="composer" value="${project.basedir}/composer.phar" override="yes" /></then>
     </if>
     <if>
         <not><isset property="php" /></not>
@@ -56,6 +56,9 @@
         <exclude name="inc/header*" />
         <exclude name="build.xml" />
         <exclude name="build.properties" />
+        <exclude name="composer.json" />
+        <exclude name="composer.lock" />
+        <exclude name="composer.phar" />
         <exclude name="storage/**/*" />
         <exclude name="samples/**" />
         <exclude name="scripts/**" />
@@ -96,6 +99,7 @@
     <!-- ============================================  -->
     <target name="prepare">
         <echo msg="Prepage: installing necessary components" />
+        <exec command="${php} ${composer} install" dir="${project.basedir}" checkreturn="true" />
         <exec command="${php} ${composer} install" dir="${project.basedir}/tests" checkreturn="true" />
     </target>
 

+ 108 - 0
composer.json

@@ -0,0 +1,108 @@
+{
+    "name": "unaio/una",
+    "description": "UNA - Community Management System",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "UNA, Inc",
+            "homepage": "https://una.io"
+        }
+    ],
+    "config": {
+        "vendor-dir": "plugins"
+    },
+    "repositories": [
+        {
+            "type": "vcs",
+            "url": "https://github.com/unaio/composer-cleanup-plugin.git",
+            "reference": "dev-master"
+        },
+        {
+            "type": "vcs",
+            "url": "https://github.com/unaio/amazon-s3-php-class.git",
+            "reference": "dev-master"
+        },
+        {
+            "type": "package",
+            "package": {
+                "name": "curl/cacert",
+                "version": "0.0.1",
+                "dist": {
+                    "url": "https://curl.se/ca/cacert.pem",
+                    "type": "file"
+                }
+            }
+        },
+        {
+            "type": "package",
+            "package": {
+                "name": "ffmpeg/ffmpeg",
+                "version": "4.4.0",
+                "dist": {
+                    "url": "https://github.com/eugeneware/ffmpeg-static/releases/download/b4.4/linux-x64",
+                    "type": "file"
+                }
+            }
+        },
+        {
+            "type": "package",
+            "package": {
+                "name": "achingbrain/php5-akismet",
+                "version": "0.5",
+                "source": {
+                    "url": "https://github.com/achingbrain/php5-akismet",
+                    "type": "git",
+                    "reference": "master"
+                }
+            }
+        },
+        {
+            "type": "package",
+            "package": {
+                "name": "unaio/amazon-s3-php-class-hmac-v2",
+                "version": "0.5",
+                "source": {
+                    "url": "https://github.com/unaio/amazon-s3-php-class-hmac-v2",
+                    "type": "git",
+                    "reference": "main"
+                }
+            }
+        }
+    ],
+    "require": {
+        "php": ">=5.6",
+        "akeeba/s3": "dev-main",
+        "achingbrain/php5-akismet": "0.5",
+        "unaio/amazon-s3-php-class-hmac-v2": "*",
+        "tpyo/amazon-s3-php-class": "dev-master",
+        "snipe/banbuilder": "dev-master",
+        "chargebee/chargebee-php": "^2.0",
+        "curl/cacert": "*",
+        "facebook/graph-sdk": "^5.6.0",
+        "ffmpeg/ffmpeg": "*",
+        "ezyang/htmlpurifier": "^4.13",
+        "intervention/image": "^2.6",
+        "wikimedia/less.php": "*",
+        "matthiasmullie/minify": "^1.3",
+        "lusitanian/oauth": "^0.8.11",
+        "bshaffer/oauth2-server-php": "^1.11",
+        "erusev/parsedown": "@dev",
+        "paypal/paypal-checkout-sdk": "^1.0",
+        "phpmailer/phpmailer": "^6.5",
+        "recurly/recurly-client": "2.10.*",
+        "stripe/stripe-php": "^7.95",
+        "twilio/sdk": "^5.19",
+        "avto-dev/composer-cleanup-plugin": "dev-master"
+    },
+    "scripts": {
+        "post-update-cmd": [
+            "@relocate-ffmpeg"
+        ],
+        "post-install-cmd": [
+            "@relocate-ffmpeg"
+        ],
+        "relocate-ffmpeg": [
+            "test -f ./plugins/ffmpeg/ffmpeg/linux-x64 && mv ./plugins/ffmpeg/ffmpeg/linux-x64 ./plugins/ffmpeg/ffmpeg.exe && rm -rf ./plugins/ffmpeg/ffmpeg || true"
+        ]
+    }
+}

+ 1479 - 0
composer.lock

@@ -0,0 +1,1479 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+        "This file is @generated automatically"
+    ],
+    "content-hash": "3d1f04931a4d3d5f0352d496c7f93a9c",
+    "packages": [
+        {
+            "name": "achingbrain/php5-akismet",
+            "version": "0.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/achingbrain/php5-akismet",
+                "reference": "master"
+            },
+            "type": "library"
+        },
+        {
+            "name": "akeeba/s3",
+            "version": "dev-main",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/akeeba/s3.git",
+                "reference": "96208915514b19e7789ea053c6a109b212864001"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/akeeba/s3/zipball/96208915514b19e7789ea053c6a109b212864001",
+                "reference": "96208915514b19e7789ea053c6a109b212864001",
+                "shasum": ""
+            },
+            "require": {
+                "ext-curl": "*",
+                "php": ">=5.3.4"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Akeeba\\Engine\\Postproc\\Connector\\S3v4\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "GPL-3.0+"
+            ],
+            "authors": [
+                {
+                    "name": "Nicholas K. Dionysopoulos",
+                    "email": "nicholas_NO_SPAM_PLEASE@akeebabackup.com",
+                    "homepage": "http://www.dionysopoulos.me",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "Akeeba Engine connector for Amazon S3",
+            "homepage": "https://github.com/akeeba/s3",
+            "keywords": [
+                "s3"
+            ],
+            "support": {
+                "issues": "https://github.com/akeeba/s3/issues",
+                "source": "https://github.com/akeeba/s3/tree/1.0.0"
+            },
+            "time": "2020-01-02T07:13:47+00:00"
+        },
+        {
+            "name": "avto-dev/composer-cleanup-plugin",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/unaio/composer-cleanup-plugin.git",
+                "reference": "75187ca4854265174021765e3b67cb973dc37723"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/unaio/composer-cleanup-plugin/zipball/75187ca4854265174021765e3b67cb973dc37723",
+                "reference": "75187ca4854265174021765e3b67cb973dc37723",
+                "shasum": ""
+            },
+            "require": {
+                "composer-plugin-api": "^1.0 || ^2.0",
+                "php": "^7.2 || ^8.0"
+            },
+            "require-dev": {
+                "composer/composer": "^1.8.6 || ^2.0",
+                "phpstan/phpstan": "~0.12.34",
+                "phpunit/phpunit": "^8.5.4 || ^9.3"
+            },
+            "default-branch": true,
+            "type": "composer-plugin",
+            "extra": {
+                "class": "AvtoDev\\Composer\\Cleanup\\Plugin"
+            },
+            "autoload": {
+                "psr-4": {
+                    "AvtoDev\\Composer\\Cleanup\\": "src/"
+                }
+            },
+            "autoload-dev": {
+                "psr-4": {
+                    "AvtoDev\\Composer\\Cleanup\\Tests\\": "tests/"
+                }
+            },
+            "scripts": {
+                "post-update-cmd": [
+                    "AvtoDev\\Composer\\Cleanup\\Plugin::cleanupAllPackages"
+                ],
+                "post-install-cmd": [
+                    "AvtoDev\\Composer\\Cleanup\\Plugin::cleanupAllPackages"
+                ],
+                "phpunit": [
+                    "@php ./vendor/bin/phpunit --no-coverage --colors=always"
+                ],
+                "phpunit-cover": [
+                    "@php ./vendor/bin/phpunit --coverage-html='./coverage/html'"
+                ],
+                "phpstan": [
+                    "@php ./vendor/bin/phpstan analyze -c ./phpstan.neon.dist --no-progress --ansi"
+                ],
+                "test": [
+                    "@phpstan",
+                    "@phpunit"
+                ],
+                "test-cover": [
+                    "@phpstan",
+                    "@phpunit-cover"
+                ]
+            },
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "avto-dev",
+                    "homepage": "https://github.com/avto-dev"
+                },
+                {
+                    "name": "Barry vd. Heuvel",
+                    "email": "barryvdh@gmail.com"
+                }
+            ],
+            "description": "A composer cleanup plugin, to remove tests and documentation to save space",
+            "support": {
+                "issues": "https://github.com/avto-dev/composer-cleanup-plugin/issues",
+                "source": "https://github.com/avto-dev/composer-cleanup-plugin"
+            },
+            "time": "2021-09-04T13:12:22+00:00"
+        },
+        {
+            "name": "bshaffer/oauth2-server-php",
+            "version": "v1.11.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/bshaffer/oauth2-server-php.git",
+                "reference": "5a0c8000d4763b276919e2106f54eddda6bc50fa"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/bshaffer/oauth2-server-php/zipball/5a0c8000d4763b276919e2106f54eddda6bc50fa",
+                "reference": "5a0c8000d4763b276919e2106f54eddda6bc50fa",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.9"
+            },
+            "require-dev": {
+                "aws/aws-sdk-php": "~2.8",
+                "firebase/php-jwt": "~2.2",
+                "mongodb/mongodb": "^1.1",
+                "phpunit/phpunit": "^4.0",
+                "predis/predis": "dev-master",
+                "thobbs/phpcassa": "dev-master"
+            },
+            "suggest": {
+                "aws/aws-sdk-php": "~2.8 is required to use DynamoDB storage",
+                "firebase/php-jwt": "~2.2 is required to use JWT features",
+                "mongodb/mongodb": "^1.1 is required to use MongoDB storage",
+                "predis/predis": "Required to use Redis storage",
+                "thobbs/phpcassa": "Required to use Cassandra storage"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "OAuth2": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Brent Shaffer",
+                    "email": "bshafs@gmail.com",
+                    "homepage": "http://brentertainment.com"
+                }
+            ],
+            "description": "OAuth2 Server for PHP",
+            "homepage": "http://github.com/bshaffer/oauth2-server-php",
+            "keywords": [
+                "auth",
+                "oauth",
+                "oauth2"
+            ],
+            "support": {
+                "issues": "https://github.com/bshaffer/oauth2-server-php/issues",
+                "source": "https://github.com/bshaffer/oauth2-server-php/tree/master"
+            },
+            "time": "2018-12-04T00:29:32+00:00"
+        },
+        {
+            "name": "chargebee/chargebee-php",
+            "version": "v2.8.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/chargebee/chargebee-php.git",
+                "reference": "e0819230cd7a8364337a0a228f7aecab80b6776b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/chargebee/chargebee-php/zipball/e0819230cd7a8364337a0a228f7aecab80b6776b",
+                "reference": "e0819230cd7a8364337a0a228f7aecab80b6776b",
+                "shasum": ""
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "lib/ChargeBee.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "ChargeBee API client implementation for PHP",
+            "homepage": "https://github.com/chargebee/chargebee-php",
+            "keywords": [
+                "chargebee",
+                "payments",
+                "recurring billing",
+                "subscription billing"
+            ],
+            "support": {
+                "issues": "https://github.com/chargebee/chargebee-php/issues",
+                "source": "https://github.com/chargebee/chargebee-php/tree/v2.8.3"
+            },
+            "time": "2021-07-22T06:25:07+00:00"
+        },
+        {
+            "name": "curl/cacert",
+            "version": "0.0.1",
+            "dist": {
+                "type": "file",
+                "url": "https://curl.se/ca/cacert.pem"
+            },
+            "type": "library"
+        },
+        {
+            "name": "erusev/parsedown",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/erusev/parsedown.git",
+                "reference": "6598f3860c2698fe2f0f1bc98212fc01d0a1893c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/erusev/parsedown/zipball/6598f3860c2698fe2f0f1bc98212fc01d0a1893c",
+                "reference": "6598f3860c2698fe2f0f1bc98212fc01d0a1893c",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8.35"
+            },
+            "default-branch": true,
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Parsedown": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Emanuil Rusev",
+                    "email": "hello@erusev.com",
+                    "homepage": "http://erusev.com"
+                }
+            ],
+            "description": "Parser for Markdown.",
+            "homepage": "http://parsedown.org",
+            "keywords": [
+                "markdown",
+                "parser"
+            ],
+            "support": {
+                "issues": "https://github.com/erusev/parsedown/issues",
+                "source": "https://github.com/erusev/parsedown/tree/master"
+            },
+            "time": "2020-08-09T14:12:21+00:00"
+        },
+        {
+            "name": "ezyang/htmlpurifier",
+            "version": "v4.13.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ezyang/htmlpurifier.git",
+                "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/08e27c97e4c6ed02f37c5b2b20488046c8d90d75",
+                "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2"
+            },
+            "require-dev": {
+                "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "HTMLPurifier": "library/"
+                },
+                "files": [
+                    "library/HTMLPurifier.composer.php"
+                ],
+                "exclude-from-classmap": [
+                    "/library/HTMLPurifier/Language/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1-or-later"
+            ],
+            "authors": [
+                {
+                    "name": "Edward Z. Yang",
+                    "email": "admin@htmlpurifier.org",
+                    "homepage": "http://ezyang.com"
+                }
+            ],
+            "description": "Standards compliant HTML filter written in PHP",
+            "homepage": "http://htmlpurifier.org/",
+            "keywords": [
+                "html"
+            ],
+            "support": {
+                "issues": "https://github.com/ezyang/htmlpurifier/issues",
+                "source": "https://github.com/ezyang/htmlpurifier/tree/master"
+            },
+            "time": "2020-06-29T00:56:53+00:00"
+        },
+        {
+            "name": "facebook/graph-sdk",
+            "version": "5.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/facebook/php-graph-sdk.git",
+                "reference": "2d8250638b33d73e7a87add65f47fabf91f8ad9b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/facebook/php-graph-sdk/zipball/2d8250638b33d73e7a87add65f47fabf91f8ad9b",
+                "reference": "2d8250638b33d73e7a87add65f47fabf91f8ad9b",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.4|^7.0"
+            },
+            "require-dev": {
+                "guzzlehttp/guzzle": "~5.0",
+                "mockery/mockery": "~0.8",
+                "phpunit/phpunit": "~4.0"
+            },
+            "suggest": {
+                "guzzlehttp/guzzle": "Allows for implementation of the Guzzle HTTP client",
+                "paragonie/random_compat": "Provides a better CSPRNG option in PHP 5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Facebook\\": "src/Facebook/"
+                },
+                "files": [
+                    "src/Facebook/polyfills.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Facebook Platform"
+            ],
+            "authors": [
+                {
+                    "name": "Facebook",
+                    "homepage": "https://github.com/facebook/php-graph-sdk/contributors"
+                }
+            ],
+            "description": "Facebook SDK for PHP",
+            "homepage": "https://github.com/facebook/php-graph-sdk",
+            "keywords": [
+                "facebook",
+                "sdk"
+            ],
+            "support": {
+                "issues": "https://github.com/facebook/php-graph-sdk/issues",
+                "source": "https://github.com/facebook/php-graph-sdk/tree/5.7.0"
+            },
+            "time": "2018-12-11T22:56:31+00:00"
+        },
+        {
+            "name": "ffmpeg/ffmpeg",
+            "version": "4.4.0",
+            "dist": {
+                "type": "file",
+                "url": "https://github.com/eugeneware/ffmpeg-static/releases/download/b4.4/linux-x64"
+            },
+            "type": "library"
+        },
+        {
+            "name": "guzzlehttp/psr7",
+            "version": "2.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/psr7.git",
+                "reference": "1dc8d9cba3897165e16d12bb13d813afb1eb3fe7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/psr7/zipball/1dc8d9cba3897165e16d12bb13d813afb1eb3fe7",
+                "reference": "1dc8d9cba3897165e16d12bb13d813afb1eb3fe7",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2.5 || ^8.0",
+                "psr/http-factory": "^1.0",
+                "psr/http-message": "^1.0",
+                "ralouphie/getallheaders": "^3.0"
+            },
+            "provide": {
+                "psr/http-factory-implementation": "1.0",
+                "psr/http-message-implementation": "1.0"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.4.1",
+                "http-interop/http-factory-tests": "^0.9",
+                "phpunit/phpunit": "^8.5.8 || ^9.3.10"
+            },
+            "suggest": {
+                "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GuzzleHttp\\Psr7\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                },
+                {
+                    "name": "Tobias Schultze",
+                    "homepage": "https://github.com/Tobion"
+                },
+                {
+                    "name": "Márk Sági-Kazár",
+                    "email": "mark.sagikazar@gmail.com",
+                    "homepage": "https://sagikazarmark.hu"
+                }
+            ],
+            "description": "PSR-7 message implementation that also provides common utility methods",
+            "keywords": [
+                "http",
+                "message",
+                "psr-7",
+                "request",
+                "response",
+                "stream",
+                "uri",
+                "url"
+            ],
+            "support": {
+                "issues": "https://github.com/guzzle/psr7/issues",
+                "source": "https://github.com/guzzle/psr7/tree/2.0.0"
+            },
+            "time": "2021-06-30T20:03:07+00:00"
+        },
+        {
+            "name": "intervention/image",
+            "version": "2.6.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Intervention/image.git",
+                "reference": "0925f10b259679b5d8ca58f3a2add9255ffcda45"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Intervention/image/zipball/0925f10b259679b5d8ca58f3a2add9255ffcda45",
+                "reference": "0925f10b259679b5d8ca58f3a2add9255ffcda45",
+                "shasum": ""
+            },
+            "require": {
+                "ext-fileinfo": "*",
+                "guzzlehttp/psr7": "~1.1 || ^2.0",
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "mockery/mockery": "~0.9.2",
+                "phpunit/phpunit": "^4.8 || ^5.7 || ^7.5.15"
+            },
+            "suggest": {
+                "ext-gd": "to use GD library based image processing.",
+                "ext-imagick": "to use Imagick based image processing.",
+                "intervention/imagecache": "Caching extension for the Intervention Image library"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.4-dev"
+                },
+                "laravel": {
+                    "providers": [
+                        "Intervention\\Image\\ImageServiceProvider"
+                    ],
+                    "aliases": {
+                        "Image": "Intervention\\Image\\Facades\\Image"
+                    }
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Intervention\\Image\\": "src/Intervention/Image"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Oliver Vogel",
+                    "email": "oliver@olivervogel.com",
+                    "homepage": "http://olivervogel.com/"
+                }
+            ],
+            "description": "Image handling and manipulation library with support for Laravel integration",
+            "homepage": "http://image.intervention.io/",
+            "keywords": [
+                "gd",
+                "image",
+                "imagick",
+                "laravel",
+                "thumbnail",
+                "watermark"
+            ],
+            "support": {
+                "issues": "https://github.com/Intervention/image/issues",
+                "source": "https://github.com/Intervention/image/tree/2.6.1"
+            },
+            "funding": [
+                {
+                    "url": "https://www.paypal.me/interventionphp",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/Intervention",
+                    "type": "github"
+                }
+            ],
+            "time": "2021-07-22T14:31:53+00:00"
+        },
+        {
+            "name": "lusitanian/oauth",
+            "version": "v0.8.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Lusitanian/PHPoAuthLib.git",
+                "reference": "fc11a53db4b66da555a6a11fce294f574a8374f9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Lusitanian/PHPoAuthLib/zipball/fc11a53db4b66da555a6a11fce294f574a8374f9",
+                "reference": "fc11a53db4b66da555a6a11fce294f574a8374f9",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "3.7.*",
+                "predis/predis": "0.8.*@dev",
+                "squizlabs/php_codesniffer": "2.*",
+                "symfony/http-foundation": "~2.1"
+            },
+            "suggest": {
+                "ext-openssl": "Allows for usage of secure connections with the stream-based HTTP client.",
+                "predis/predis": "Allows using the Redis storage backend.",
+                "symfony/http-foundation": "Allows using the Symfony Session storage backend."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "0.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "OAuth": "src",
+                    "OAuth\\Unit": "tests"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "David Desberg",
+                    "email": "david@daviddesberg.com"
+                },
+                {
+                    "name": "Elliot Chance",
+                    "email": "elliotchance@gmail.com"
+                },
+                {
+                    "name": "Pieter Hordijk",
+                    "email": "info@pieterhordijk.com"
+                }
+            ],
+            "description": "PHP 5.3+ oAuth 1/2 Library",
+            "keywords": [
+                "Authentication",
+                "authorization",
+                "oauth",
+                "security"
+            ],
+            "support": {
+                "issues": "https://github.com/Lusitanian/PHPoAuthLib/issues",
+                "source": "https://github.com/Lusitanian/PHPoAuthLib/tree/master"
+            },
+            "time": "2018-02-14T22:37:14+00:00"
+        },
+        {
+            "name": "matthiasmullie/minify",
+            "version": "1.3.66",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/matthiasmullie/minify.git",
+                "reference": "45fd3b0f1dfa2c965857c6d4a470bea52adc31a6"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/45fd3b0f1dfa2c965857c6d4a470bea52adc31a6",
+                "reference": "45fd3b0f1dfa2c965857c6d4a470bea52adc31a6",
+                "shasum": ""
+            },
+            "require": {
+                "ext-pcre": "*",
+                "matthiasmullie/path-converter": "~1.1",
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "~2.0",
+                "matthiasmullie/scrapbook": "dev-master",
+                "phpunit/phpunit": ">=4.8"
+            },
+            "suggest": {
+                "psr/cache-implementation": "Cache implementation to use with Minify::cache"
+            },
+            "bin": [
+                "bin/minifycss",
+                "bin/minifyjs"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "MatthiasMullie\\Minify\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Matthias Mullie",
+                    "email": "minify@mullie.eu",
+                    "homepage": "http://www.mullie.eu",
+                    "role": "Developer"
+                }
+            ],
+            "description": "CSS & JavaScript minifier, in PHP. Removes whitespace, strips comments, combines files (incl. @import statements and small assets in CSS files), and optimizes/shortens a few common programming patterns.",
+            "homepage": "http://www.minifier.org",
+            "keywords": [
+                "JS",
+                "css",
+                "javascript",
+                "minifier",
+                "minify"
+            ],
+            "support": {
+                "issues": "https://github.com/matthiasmullie/minify/issues",
+                "source": "https://github.com/matthiasmullie/minify/tree/1.3.66"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/[user1",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/matthiasmullie] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g.",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/user2",
+                    "type": "github"
+                }
+            ],
+            "time": "2021-01-06T15:18:10+00:00"
+        },
+        {
+            "name": "matthiasmullie/path-converter",
+            "version": "1.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/matthiasmullie/path-converter.git",
+                "reference": "e7d13b2c7e2f2268e1424aaed02085518afa02d9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/matthiasmullie/path-converter/zipball/e7d13b2c7e2f2268e1424aaed02085518afa02d9",
+                "reference": "e7d13b2c7e2f2268e1424aaed02085518afa02d9",
+                "shasum": ""
+            },
+            "require": {
+                "ext-pcre": "*",
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.8"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "MatthiasMullie\\PathConverter\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Matthias Mullie",
+                    "email": "pathconverter@mullie.eu",
+                    "homepage": "http://www.mullie.eu",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Relative path converter",
+            "homepage": "http://github.com/matthiasmullie/path-converter",
+            "keywords": [
+                "converter",
+                "path",
+                "paths",
+                "relative"
+            ],
+            "support": {
+                "issues": "https://github.com/matthiasmullie/path-converter/issues",
+                "source": "https://github.com/matthiasmullie/path-converter/tree/1.1.3"
+            },
+            "time": "2019-02-05T23:41:09+00:00"
+        },
+        {
+            "name": "paypal/paypal-checkout-sdk",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paypal/Checkout-PHP-SDK.git",
+                "reference": "ed6a55075448308b87a8b59dcb7fedf04a048cb1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paypal/Checkout-PHP-SDK/zipball/ed6a55075448308b87a8b59dcb7fedf04a048cb1",
+                "reference": "ed6a55075448308b87a8b59dcb7fedf04a048cb1",
+                "shasum": ""
+            },
+            "require": {
+                "paypal/paypalhttp": "1.0.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^5.7"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "PayPalCheckoutSdk\\": "lib/PayPalCheckoutSdk",
+                    "Sample\\": "samples/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "https://github.com/paypal/Checkout-PHP-SDK/blob/master/LICENSE"
+            ],
+            "authors": [
+                {
+                    "name": "PayPal",
+                    "homepage": "https://github.com/paypal/Checkout-PHP-SDK/contributors"
+                }
+            ],
+            "description": "PayPal's PHP SDK for Checkout REST APIs",
+            "homepage": "http://github.com/paypal/Checkout-PHP-SDK/",
+            "keywords": [
+                "checkout",
+                "orders",
+                "payments",
+                "paypal",
+                "rest",
+                "sdk"
+            ],
+            "support": {
+                "issues": "https://github.com/paypal/Checkout-PHP-SDK/issues",
+                "source": "https://github.com/paypal/Checkout-PHP-SDK/tree/1.0.1"
+            },
+            "time": "2019-11-07T23:16:44+00:00"
+        },
+        {
+            "name": "paypal/paypalhttp",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paypal/paypalhttp_php.git",
+                "reference": "1ad9b846a046f09d6135cbf2cbaa7701bbc630a3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paypal/paypalhttp_php/zipball/1ad9b846a046f09d6135cbf2cbaa7701bbc630a3",
+                "reference": "1ad9b846a046f09d6135cbf2cbaa7701bbc630a3",
+                "shasum": ""
+            },
+            "require": {
+                "ext-curl": "*"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^5.7",
+                "wiremock-php/wiremock-php": "1.43.2"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "PayPalHttp\\": "lib/PayPalHttp"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PayPal",
+                    "homepage": "https://github.com/paypal/paypalhttp_php/contributors"
+                }
+            ],
+            "support": {
+                "issues": "https://github.com/paypal/paypalhttp_php/issues",
+                "source": "https://github.com/paypal/paypalhttp_php/tree/1.0.0"
+            },
+            "abandoned": true,
+            "time": "2019-11-06T21:27:12+00:00"
+        },
+        {
+            "name": "phpmailer/phpmailer",
+            "version": "v6.5.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/PHPMailer/PHPMailer.git",
+                "reference": "dd803df5ad7492e1b40637f7ebd258fee5ca7355"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/dd803df5ad7492e1b40637f7ebd258fee5ca7355",
+                "reference": "dd803df5ad7492e1b40637f7ebd258fee5ca7355",
+                "shasum": ""
+            },
+            "require": {
+                "ext-ctype": "*",
+                "ext-filter": "*",
+                "ext-hash": "*",
+                "php": ">=5.5.0"
+            },
+            "require-dev": {
+                "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
+                "doctrine/annotations": "^1.2",
+                "php-parallel-lint/php-console-highlighter": "^0.5.0",
+                "php-parallel-lint/php-parallel-lint": "^1.3",
+                "phpcompatibility/php-compatibility": "^9.3.5",
+                "roave/security-advisories": "dev-latest",
+                "squizlabs/php_codesniffer": "^3.6.0",
+                "yoast/phpunit-polyfills": "^1.0.0"
+            },
+            "suggest": {
+                "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
+                "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
+                "league/oauth2-google": "Needed for Google XOAUTH2 authentication",
+                "psr/log": "For optional PSR-3 debug logging",
+                "stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication",
+                "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "PHPMailer\\PHPMailer\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1-only"
+            ],
+            "authors": [
+                {
+                    "name": "Marcus Bointon",
+                    "email": "phpmailer@synchromedia.co.uk"
+                },
+                {
+                    "name": "Jim Jagielski",
+                    "email": "jimjag@gmail.com"
+                },
+                {
+                    "name": "Andy Prevost",
+                    "email": "codeworxtech@users.sourceforge.net"
+                },
+                {
+                    "name": "Brent R. Matzelle"
+                }
+            ],
+            "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
+            "support": {
+                "issues": "https://github.com/PHPMailer/PHPMailer/issues",
+                "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.5.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/Synchro",
+                    "type": "github"
+                }
+            ],
+            "time": "2021-08-18T09:14:16+00:00"
+        },
+        {
+            "name": "psr/http-factory",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-factory.git",
+                "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+                "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.0.0",
+                "psr/http-message": "^1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Message\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interfaces for PSR-7 HTTP message factories",
+            "keywords": [
+                "factory",
+                "http",
+                "message",
+                "psr",
+                "psr-17",
+                "psr-7",
+                "request",
+                "response"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/http-factory/tree/master"
+            },
+            "time": "2019-04-30T12:38:16+00:00"
+        },
+        {
+            "name": "psr/http-message",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-message.git",
+                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Message\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for HTTP messages",
+            "homepage": "https://github.com/php-fig/http-message",
+            "keywords": [
+                "http",
+                "http-message",
+                "psr",
+                "psr-7",
+                "request",
+                "response"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/http-message/tree/master"
+            },
+            "time": "2016-08-06T14:39:51+00:00"
+        },
+        {
+            "name": "ralouphie/getallheaders",
+            "version": "3.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ralouphie/getallheaders.git",
+                "reference": "120b605dfeb996808c31b6477290a714d356e822"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
+                "reference": "120b605dfeb996808c31b6477290a714d356e822",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.6"
+            },
+            "require-dev": {
+                "php-coveralls/php-coveralls": "^2.1",
+                "phpunit/phpunit": "^5 || ^6.5"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/getallheaders.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ralph Khattar",
+                    "email": "ralph.khattar@gmail.com"
+                }
+            ],
+            "description": "A polyfill for getallheaders.",
+            "support": {
+                "issues": "https://github.com/ralouphie/getallheaders/issues",
+                "source": "https://github.com/ralouphie/getallheaders/tree/develop"
+            },
+            "time": "2019-03-08T08:55:37+00:00"
+        },
+        {
+            "name": "recurly/recurly-client",
+            "version": "2.10.7",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/recurly/recurly-client-php.git",
+                "reference": "f60e9247b56617c9d5a9c6368b701a17b957992b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/recurly/recurly-client-php/zipball/f60e9247b56617c9d5a9c6368b701a17b957992b",
+                "reference": "f60e9247b56617c9d5a9c6368b701a17b957992b",
+                "shasum": ""
+            },
+            "require": {
+                "ext-curl": "*",
+                "php": ">= 5.6.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.2.*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.4.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "lib"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "The PHP client library for the Recurly API",
+            "homepage": "https://github.com/recurly/recurly-client-php",
+            "keywords": [
+                "pay",
+                "payments",
+                "recurly"
+            ],
+            "support": {
+                "issues": "https://github.com/recurly/recurly-client-php/issues",
+                "source": "https://github.com/recurly/recurly-client-php/tree/2.10.7"
+            },
+            "time": "2020-10-01T22:47:27+00:00"
+        },
+        {
+            "name": "snipe/banbuilder",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/snipe/banbuilder.git",
+                "reference": "621d6d857400983d0fd6cd291f105a835a317748"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/snipe/banbuilder/zipball/621d6d857400983d0fd6cd291f105a835a317748",
+                "reference": "621d6d857400983d0fd6cd291f105a835a317748",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.6.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^5.7.0"
+            },
+            "default-branch": true,
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Snipe\\BanBuilder\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "AGPL-3.0"
+            ],
+            "authors": [
+                {
+                    "name": "snipe",
+                    "email": "snipe@snipe.net",
+                    "role": "Creator & Developer"
+                }
+            ],
+            "description": "Library to easily handle profanity filtering in PHP projects.",
+            "homepage": "http://banbuilder.com",
+            "keywords": [
+                "filter",
+                "language",
+                "profanity",
+                "strings",
+                "swear"
+            ],
+            "support": {
+                "issues": "https://github.com/snipe/banbuilder/issues",
+                "source": "https://github.com/snipe/banbuilder/tree/2.3.0"
+            },
+            "time": "2018-08-30T22:45:56+00:00"
+        },
+        {
+            "name": "stripe/stripe-php",
+            "version": "v7.95.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/stripe/stripe-php.git",
+                "reference": "ed372a1f6430b06dda408bb33b27d2be35ceaf07"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/stripe/stripe-php/zipball/ed372a1f6430b06dda408bb33b27d2be35ceaf07",
+                "reference": "ed372a1f6430b06dda408bb33b27d2be35ceaf07",
+                "shasum": ""
+            },
+            "require": {
+                "ext-curl": "*",
+                "ext-json": "*",
+                "ext-mbstring": "*",
+                "php": ">=5.6.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "2.17.1",
+                "php-coveralls/php-coveralls": "^2.1",
+                "phpunit/phpunit": "^5.7",
+                "squizlabs/php_codesniffer": "^3.3",
+                "symfony/process": "~3.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Stripe\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Stripe and contributors",
+                    "homepage": "https://github.com/stripe/stripe-php/contributors"
+                }
+            ],
+            "description": "Stripe PHP Library",
+            "homepage": "https://stripe.com/",
+            "keywords": [
+                "api",
+                "payment processing",
+                "stripe"
+            ],
+            "support": {
+                "issues": "https://github.com/stripe/stripe-php/issues",
+                "source": "https://github.com/stripe/stripe-php/tree/v7.95.0"
+            },
+            "time": "2021-09-02T02:30:40+00:00"
+        },
+        {
+            "name": "tpyo/amazon-s3-php-class",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/unaio/amazon-s3-php-class.git",
+                "reference": "3f720a0144843c214b9444e626119dbe12ecc180"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/unaio/amazon-s3-php-class/zipball/3f720a0144843c214b9444e626119dbe12ecc180",
+                "reference": "3f720a0144843c214b9444e626119dbe12ecc180",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2.0"
+            },
+            "default-branch": true,
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "S3.php"
+                ]
+            },
+            "license": [
+                "BSD-2-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Donovan Schönknecht",
+                    "email": "don@tpyo.net"
+                }
+            ],
+            "description": "A standalone Amazon S3 (REST) client for PHP 5.2.x using CURL that does not require PEAR.",
+            "homepage": "https://github.com/tpyo/amazon-s3-php-class",
+            "support": {
+                "source": "https://github.com/unaio/amazon-s3-php-class/tree/master"
+            },
+            "time": "2021-09-02T09:17:14+00:00"
+        },
+        {
+            "name": "twilio/sdk",
+            "version": "5.42.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/twilio/twilio-php.git",
+                "reference": "0cfcb871b18a9c427dd9e8f0ed7458d43009b48a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/twilio/twilio-php/zipball/0cfcb871b18a9c427dd9e8f0ed7458d43009b48a",
+                "reference": "0cfcb871b18a9c427dd9e8f0ed7458d43009b48a",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.0"
+            },
+            "require-dev": {
+                "apigen/apigen": "^4.1",
+                "guzzlehttp/guzzle": "^6.3",
+                "phpunit/phpunit": ">=4.5"
+            },
+            "suggest": {
+                "guzzlehttp/guzzle": "An HTTP client to execute the API requests"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Twilio\\": "src/Twilio/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Twilio API Team",
+                    "email": "api@twilio.com"
+                }
+            ],
+            "description": "A PHP wrapper for Twilio's API",
+            "homepage": "http://github.com/twilio/twilio-php",
+            "keywords": [
+                "api",
+                "sms",
+                "twilio"
+            ],
+            "support": {
+                "issues": "https://github.com/twilio/twilio-php/issues",
+                "source": "https://github.com/twilio/twilio-php/tree/5.42.2"
+            },
+            "time": "2020-02-05T19:55:13+00:00"
+        },
+        {
+            "name": "unaio/amazon-s3-php-class-hmac-v2",
+            "version": "0.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/unaio/amazon-s3-php-class-hmac-v2",
+                "reference": "main"
+            },
+            "type": "library"
+        },
+        {
+            "name": "wikimedia/less.php",
+            "version": "v3.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/wikimedia/less.php.git",
+                "reference": "a486d78b9bd16b72f237fc6093aa56d69ce8bd13"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/wikimedia/less.php/zipball/a486d78b9bd16b72f237fc6093aa56d69ce8bd13",
+                "reference": "a486d78b9bd16b72f237fc6093aa56d69ce8bd13",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.9"
+            },
+            "require-dev": {
+                "mediawiki/mediawiki-codesniffer": "34.0.0",
+                "mediawiki/minus-x": "1.0.0",
+                "php-parallel-lint/php-console-highlighter": "0.5.0",
+                "php-parallel-lint/php-parallel-lint": "1.2.0",
+                "phpunit/phpunit": "^8.5"
+            },
+            "bin": [
+                "bin/lessc"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Less": "lib/"
+                },
+                "classmap": [
+                    "lessc.inc.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "Josh Schmidt",
+                    "homepage": "https://github.com/oyejorge"
+                },
+                {
+                    "name": "Matt Agar",
+                    "homepage": "https://github.com/agar"
+                },
+                {
+                    "name": "Martin Jantošovič",
+                    "homepage": "https://github.com/Mordred"
+                }
+            ],
+            "description": "PHP port of the Javascript version of LESS http://lesscss.org (Originally maintained by Josh Schmidt)",
+            "keywords": [
+                "css",
+                "less",
+                "less.js",
+                "lesscss",
+                "php",
+                "stylesheet"
+            ],
+            "support": {
+                "issues": "https://github.com/wikimedia/less.php/issues",
+                "source": "https://github.com/wikimedia/less.php/tree/v3.1.0"
+            },
+            "time": "2020-12-11T19:33:31+00:00"
+        }
+    ],
+    "packages-dev": [],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": {
+        "akeeba/s3": 20,
+        "tpyo/amazon-s3-php-class": 20,
+        "snipe/banbuilder": 20,
+        "erusev/parsedown": 20,
+        "avto-dev/composer-cleanup-plugin": 20
+    },
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": [],
+    "platform-dev": [],
+    "plugin-api-version": "2.1.0"
+}

+ 4 - 4
inc/classes/BxDolAuditGrid.php

@@ -53,7 +53,8 @@ class BxDolAuditGrid extends BxTemplGrid
         $this->_aFilterProfileValues[''] = _t('_sys_audit_filter_profile_select');
         foreach($aProfiles as $iProfile){
             $oProfile = BxDolProfile::getInstance($iProfile);
-            $this->_aFilterProfileValues[$iProfile] = $oProfile->getDisplayName();
+			if ($oProfile)
+				$this->_aFilterProfileValues[$iProfile] = $oProfile->getDisplayName();
         }
 
     	$sFilterProfile = bx_get($this->_sFilterProfileName);
@@ -110,9 +111,8 @@ class BxDolAuditGrid extends BxTemplGrid
         
         if(bx_get('content_id') && is_numeric(bx_get('content_id')))
             $this->_aOptions['source'] .= $this->oDb->prepareAsString(" AND `content_id` = ?", (int)bx_get('content_id'));
-        if(bx_get('actor_id')  && is_numeric(bx_get('actor_id')))
-            $this->_aOptions['source'] .= $this->oDb->prepareAsString(" AND `profile_id` = ?", (int)bx_get('actor_id'));
-        if(bx_get('context_id')  && is_numeric(bx_get('context_id')))
+        
+		if(bx_get('context_id')  && is_numeric(bx_get('context_id')))
             $this->_aOptions['source'] .= $this->oDb->prepareAsString(" AND `context_profile_id` = ?", (int)bx_get('context_id'));
         
         return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);

+ 35 - 0
inc/classes/BxDolCmtsQuery.php

@@ -46,6 +46,41 @@ class BxDolCmtsQuery extends BxDolDb
         parent::__construct();
     }
 
+    public static function getInfoBy($aParams)
+    {
+        $oDb = BxDolDb::getInstance();
+
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query', 1 => array()));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+        
+        $sSelectClause = "`ti`.*";
+
+        switch($aParams['type']) {
+            case 'uniq_id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1]['uniq_id'] = (int)$aParams['uniq_id'];
+
+                $sWhereClause .= " AND `ti`.`id` = :uniq_id";
+                break;
+
+            case 'all':
+                if(isset($aParams['count']) && $aParams['count'] === true) {
+                    $aMethod['name'] = 'getOne';
+                    $sSelectClause = "COUNT(`ti`.`id`)";
+                }
+                break;
+        }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = 'ORDER BY ' . $sOrderClause;
+
+        if(!empty($sLimitClause))
+            $sLimitClause = 'LIMIT ' . $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . " FROM `" . BxDolCmts::$sTableIds . "` " . $sJoinClause . " AS `ti` WHERE 1 " . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+        return call_user_func_array(array($oDb, $aMethod['name']), $aMethod['params']);
+    }
+
     public static function getInfoByUniqId($iUniqId)
     {
         $oDb = BxDolDb::getInstance();

+ 1 - 1
inc/classes/BxDolDb.php

@@ -549,7 +549,7 @@ class BxDolDb extends BxDolFactory implements iBxDolSingleton
             }
 
 	    	// if mysql connection is lost - reconnect and try again
-            if(!$bResult && !$this->ping()) {
+            if(!$bResult && (2006 == $iErrorCode || !$this->ping())) {
                 $this->disconnect();
                 $this->connect();
                 continue;

+ 7 - 4
inc/classes/BxDolForm.php

@@ -734,6 +734,7 @@ class BxDolForm extends BxDol implements iBxDolReplaceable
     public $id; ///< Form element id
 
     protected $_aFieldsCheckForSpam = array(); ///< additional fields names to check for spam(profanity filter), now only fields with 'textarea' and 'text' are checked for spam, 'textarea' fields are checked for spam and filter for profanity, while 'text' fields are filtetered for profanity only
+    protected $_aFieldsExcludeFromCheckForSpam = array(); ///<  fields names('textarea' and 'text') to exclude from  check for spam(profanity filter)
 
     
     protected $_iAuthorId;
@@ -820,7 +821,7 @@ class BxDolForm extends BxDol implements iBxDolReplaceable
         $oChecker = new $this->_sChecker($this->_sCheckerHelper);
         $oChecker->setFormMethod($this->aFormAttrs['method'], $aSpecificValues);
         $oChecker->setFormParams($this->aParams);
-        $oChecker->setFieldsCheckForSpam($this->_aFieldsCheckForSpam);
+        $oChecker->setFieldsCheckForSpam($this->_aFieldsCheckForSpam, $this->_aFieldsExcludeFromCheckForSpam);
 
         // init form with default values
 
@@ -1212,6 +1213,7 @@ class BxDolFormChecker
     protected $_bFormCsrfChecking;
     protected $_aSpecificValues;
     protected $_aFieldsCheckForSpam;
+    protected $_aFieldsExcludeFromCheckForSpam;
 
     function __construct ($sHelper = '')
     {
@@ -1233,9 +1235,10 @@ class BxDolFormChecker
         $this->_aFormParams = $aParams;
     }
 
-    function setFieldsCheckForSpam($a)
+    function setFieldsCheckForSpam($aFieldsCheckForSpam, $aFieldsExcludeFromCheckForSpam)
     {
-        $this->_aFieldsCheckForSpam = $a;
+        $this->_aFieldsCheckForSpam = $aFieldsCheckForSpam;
+        $this->_aFieldsExcludeFromCheckForSpam = $aFieldsExcludeFromCheckForSpam;
     }
     
     function enableFormCsrfChecking($bFormCsrfChecking)
@@ -1385,7 +1388,7 @@ class BxDolFormChecker
 
                 $a['name'] = str_replace('[]', '', $a['name']);
 
-                if ($a['type'] != 'textarea' && $a['type'] != 'text' && !in_array($a['name'], $this->_aFieldsCheckForSpam))
+                if ($a['type'] != 'textarea' && $a['type'] != 'text' && !in_array($a['name'], $this->_aFieldsCheckForSpam) || in_array($a['name'], $this->_aFieldsExcludeFromCheckForSpam))
                     continue;
                 
                 $val = BxDolForm::getSubmittedValue($a['name'], $this->_sFormMethod, $this->_aSpecificValues);

+ 1 - 1
plugins/htmlpurifier/standalone/HTMLPurifier/Filter/AddBxLinksClass.php → inc/classes/BxDolHTMLPurifierFilterAddBxLinksClass.php

@@ -1,6 +1,6 @@
 <?php
 
-class HTMLPurifier_Filter_AddBxLinksClass extends HTMLPurifier_Filter
+class BxDolHTMLPurifierFilterAddBxLinksClass extends HTMLPurifier_Filter
 {
     public $name = 'AddBxLinksClass';
     protected $class = BX_DOL_LINK_CLASS;

+ 1 - 1
plugins/htmlpurifier/standalone/HTMLPurifier/Filter/LocalIframe.php → inc/classes/BxDolHTMLPurifierFilterLocalIframe.php

@@ -1,6 +1,6 @@
 <?php
 
-class HTMLPurifier_Filter_LocalIframe extends HTMLPurifier_Filter
+class BxDolHTMLPurifierFilterLocalIframe extends HTMLPurifier_Filter
 {
     public $name = 'LocalIframe';
 

+ 1 - 1
plugins/htmlpurifier/standalone/HTMLPurifier/Filter/YouTube.php → inc/classes/BxDolHTMLPurifierFilterYouTube.php

@@ -1,6 +1,6 @@
 <?php
 
-class HTMLPurifier_Filter_YouTube extends HTMLPurifier_Filter
+class BxDolHTMLPurifierFilterYouTube extends HTMLPurifier_Filter
 {
 
     /**

+ 1 - 1
plugins/htmlpurifier/standalone/HTMLPurifier/Filter/YoutubeIframe.php → inc/classes/BxDolHTMLPurifierFilterYoutubeIframe.php

@@ -1,6 +1,6 @@
 <?php
 
-class HTMLPurifier_Filter_YoutubeIframe extends HTMLPurifier_Filter
+class BxDolHTMLPurifierFilterYoutubeIframe extends HTMLPurifier_Filter
 {
     public $name = 'YouTubeIframe';
 

+ 0 - 10
inc/classes/BxDolImageResize.php

@@ -7,16 +7,6 @@
  * @{
  */
 
-spl_autoload_register(function ($sClass) {
-    // autoload Intervention Image files
-    $sClass = trim($sClass, '\\');
-    if (0 === strncmp('Intervention', $sClass, 12)) {
-        $sFile = BX_DIRECTORY_PATH_PLUGINS . 'intervention-image/' . str_replace('\\', '/', $sClass) . '.php';
-        if (file_exists($sFile))
-            require_once($sFile);
-    }
-});
-
 define('IMAGE_ERROR_SUCCESS', 0); ///< operation was successfull
 define('IMAGE_ERROR_WRONG_TYPE', 2); ///< operation failed, most probably because incorrect image format(or not image file) was provided
 

+ 4 - 4
inc/classes/BxDolMetatags.php

@@ -723,20 +723,20 @@ class BxDolMetatags extends BxDolFactory implements iBxDolFactoryObject
         }
         
         if (!$s) {
-            $sCountryUrl = '<a href="' . BX_DOL_URL_ROOT . 'searchKeyword.php?type=location_country&keyword=' . $aLocation['country'] . '">' . $aCountries[$aLocation['country']] . '</a>';
+            $sCountryUrl = '<a href="' . BX_DOL_URL_ROOT . 'searchKeyword.php?type=location_country&keyword=' . rawurlencode($aLocation['country']) . '">' . $aCountries[$aLocation['country']] . '</a>';
             
             if(empty($aLocation['state']) || empty($aLocation['city']) || (isset($aParams['country_only']) && $aParams['country_only']))
                 $s = _t('_sys_location_country', $sCountryUrl);
         }
 
         if (!$s) {
-            $sCityUrl = '<a href="' . BX_DOL_URL_ROOT . 'searchKeyword.php?type=location_country_city&keyword=' . $aLocation['country'] . '&state=' . rawurlencode($aLocation['state']) . '&city=' . rawurlencode($aLocation['city']) . '">' . $aLocation['city'] . '</a>';
-            $sStateUrl = '<a href="' . BX_DOL_URL_ROOT . 'searchKeyword.php?type=location_country_state&keyword=' . $aLocation['country'] . '&state=' . rawurlencode($aLocation['state']) . '">' . $aLocation['state'] . '</a>';
+            $sCityUrl = '<a href="' . BX_DOL_URL_ROOT . 'searchKeyword.php?type=location_country_city&keyword=' . $aLocation['country'] . '&state=' . rawurlencode($aLocation['state']) . '&city=' . rawurlencode($aLocation['city']) . '">' . bx_process_output($aLocation['city']) . '</a>';
+            $sStateUrl = '<a href="' . BX_DOL_URL_ROOT . 'searchKeyword.php?type=location_country_state&keyword=' . $aLocation['country'] . '&state=' . rawurlencode($aLocation['state']) . '">' . bx_process_output($aLocation['state']) . '</a>';
 
             if (empty($aLocation['street']) || empty($aLocation['street_number']) || (isset($aParams['country_city_only']) && $aParams['country_city_only']))
         	    $s = _t('_sys_location_country_city', $sCountryUrl, $sStateUrl, $sCityUrl);
             elseif (!isset($aParams['country_city_only']) || !$aParams['country_city_only'])
-                $s = _t('_sys_location_country_city_street', $sCountryUrl, $sStateUrl, $sCityUrl, $aLocation['street'], $aLocation['street_number']);
+                $s = _t('_sys_location_country_city_street', $sCountryUrl, $sStateUrl, $sCityUrl, bx_process_output($aLocation['street']), bx_process_output($aLocation['street_number']));
         }
 
         return $bHTML ? $s : trim(strip_tags($s));

+ 0 - 6
inc/classes/BxDolMinify.php

@@ -9,12 +9,6 @@
 
 use MatthiasMullie\Minify;
 
-require_once(BX_DIRECTORY_PATH_PLUGINS . 'matthiasmullie/path-converter/ConverterInterface.php');
-require_once(BX_DIRECTORY_PATH_PLUGINS . 'matthiasmullie/path-converter/Converter.php');
-require_once(BX_DIRECTORY_PATH_PLUGINS . 'matthiasmullie/minify/Minify.php');
-require_once(BX_DIRECTORY_PATH_PLUGINS . 'matthiasmullie/minify/CSS.php');
-require_once(BX_DIRECTORY_PATH_PLUGINS . 'matthiasmullie/minify/JS.php');
-
 class BxDolMinify extends BxDolFactory implements iBxDolSingleton
 {
     protected function __construct()

+ 10 - 1
inc/classes/BxDolModuleQuery.php

@@ -202,7 +202,16 @@ class BxDolModuleQuery extends BxDolDb implements iBxDolSingleton
 
     function getDependent($sName, $sUri)
     {
-        return $this->getAll("SELECT `id`, `title`, `enabled` FROM `sys_modules` WHERE (`dependencies` LIKE " . $this->escape('%' . $sName . '%') . " OR `dependencies` LIKE " . $this->escape('%' . $sUri . '%') . ") AND `enabled`='1'");
+        $aResults = array();
+
+        $aModules = $this->getAll("SELECT `id`, `title`, `dependencies`, `enabled` FROM `sys_modules` WHERE (`dependencies` LIKE " . $this->escape('%' . $sName . '%') . " OR `dependencies` LIKE " . $this->escape('%' . $sUri . '%') . ") AND `enabled`='1'");
+        foreach($aModules as $aModule) {
+            $aDependencies = explode(',', $aModule['dependencies']);
+            if(in_array($sName, $aDependencies) || in_array($sUri, $aDependencies))
+                $aResults[] = $aModule;
+        }
+
+        return $aResults;
     }
 
     public function updateModule($aParamsSet, $aParamsWhere = array())

+ 47 - 23
inc/classes/BxDolModuleTemplate.php

@@ -55,18 +55,38 @@ class BxDolModuleTemplate extends BxDolTemplate
         $this->_oTemplateFunctions = BxTemplFunctions::getInstance($this);
     }
 
-    public function addLocationBase()
-    {        
-    }
+    public function addLocationBase() {}
 
     function addCssSystem($mixedFiles, $bDynamic = false)
     {
-        return $this->_addFiles(BxDolTemplate::getInstance(), 'addCssSystem', 'isLocation', 'addLocation', 'removeLocation', '', $mixedFiles, $bDynamic, true);
+        $sResult = '';
+        $bResult = false;
+
+        foreach($this->getLocations() as $sKey => $aLocation) {
+            $mixedResult = $this->_addFiles(BxDolTemplate::getInstance(), 'addCssSystem', 'isLocation', 'addLocation', 'removeLocation', '', $mixedFiles, $bDynamic, true, [$sKey => $aLocation]);
+            if($bDynamic)
+                $sResult .= $mixedResult;
+            else
+                $bResult |= $mixedResult;
+        }
+
+        return $bDynamic ? $sResult : $bResult;
     }
 
     function addCss($mixedFiles, $bDynamic = false)
     {
-        return $this->_addFiles(BxDolTemplate::getInstance(), 'addCss', 'isLocation', 'addLocation', 'removeLocation', '', $mixedFiles, $bDynamic, true);
+        $sResult = '';
+        $bResult = false;
+
+        foreach($this->getLocations() as $sKey => $aLocation) {
+            $mixedResult = $this->_addFiles(BxDolTemplate::getInstance(), 'addCss', 'isLocation', 'addLocation', 'removeLocation', '', $mixedFiles, $bDynamic, true, [$sKey => $aLocation]);
+            if($bDynamic)
+                $sResult .= $mixedResult;
+            else
+                $bResult |= $mixedResult;
+        }
+
+        return $bDynamic ? $sResult : $bResult;
     }
 
     function addJsSystem($mixedFiles, $bDynamic = false)
@@ -89,12 +109,12 @@ class BxDolModuleTemplate extends BxDolTemplate
         return $this->_addFiles(BxDolStudioTemplate::getInstance(), 'addCss', 'isLocation', 'addLocation', 'removeLocation', '', $mixedFiles, $bDynamic, $bSearchInModule);
     }
 
-	function addStudioCssSystem($mixedFiles, $bDynamic = false, $bSearchInModule = true)
+    function addStudioCssSystem($mixedFiles, $bDynamic = false, $bSearchInModule = true)
     {
         return $this->_addFiles(BxDolStudioTemplate::getInstance(), 'addCssSystem', 'isLocation', 'addLocation', 'removeLocation', '', $mixedFiles, $bDynamic, $bSearchInModule);
     }
 
-	function addStudioJs($mixedFiles, $bDynamic = false, $bSearchInModule = true)
+    function addStudioJs($mixedFiles, $bDynamic = false, $bSearchInModule = true)
     {
         return $this->_addFiles(BxDolStudioTemplate::getInstance(), 'addJs', 'isLocationJs', 'addLocationJs', 'removeLocationJs', 'js/', $mixedFiles, $bDynamic, $bSearchInModule);
     }
@@ -109,29 +129,33 @@ class BxDolModuleTemplate extends BxDolTemplate
         BxDolStudioTemplate::getInstance()->addJsTranslation($mixedKey);
     }
 
-    function _addFiles($oTemplate, $sFuncAddFiles, $sFuncIsLocation, $sFuncAddLocation, $sFuncRemoveLocation, $sPath, $mixedFiles, $bDynamic = false, $bSearchInModule = true)
+    function _addFiles($oTemplate, $sFuncAddFiles, $sFuncIsLocation, $sFuncAddLocation, $sFuncRemoveLocation, $sPath, $mixedFiles, $bDynamic = false, $bSearchInModule = true, $aLocations = array())
     {
-        $sLocationKey = '';
-        $bLocationRemove = false;
-
         if($bSearchInModule) {
-            if(strpos($sFuncAddLocation, 'Dynamic') === false) {
-                $sLocationKey = $this->_oConfig->getName();
-                if(!$oTemplate->$sFuncIsLocation($sLocationKey)) {
-                    $sLocationKey = $oTemplate->$sFuncAddLocation($sLocationKey, $this->_oConfig->getHomePath() . $sPath, $this->_oConfig->getHomeUrl() . $sPath);
-                    $bLocationRemove = true;
-                }
-            }
-            else {
-                $sLocationKey = $oTemplate->$sFuncAddLocation($this->_oConfig->getHomePath() . $sPath, $this->_oConfig->getHomeUrl() . $sPath);
-                $bLocationRemove = true;
+            if(empty($aLocations))
+                $aLocations = [
+                    $this->_oConfig->getName() => [
+                        'path' => $this->_oConfig->getHomePath() . $sPath,
+                        'url' => $this->_oConfig->getHomeUrl() . $sPath
+                    ]
+                ];
+
+            foreach($aLocations as $sLocationKey => $aLocation) {
+                if($oTemplate->$sFuncIsLocation($sLocationKey))
+                    continue;
+
+                $oTemplate->$sFuncAddLocation($sLocationKey, $aLocation['path'], $aLocation['url']);
+                
+                $aLocations[$sLocationKey]['delete'] = true;
             }
         }
 
         $mixedResult = $oTemplate->$sFuncAddFiles($mixedFiles, $bDynamic);
 
-        if($bLocationRemove && $sLocationKey != '')
-            $oTemplate->$sFuncRemoveLocation($sLocationKey);
+        if($bSearchInModule && !empty($aLocations))
+            foreach($aLocations as $sLocationKey => $aLocation) 
+                if(isset($aLocation['delete']) && $aLocation['delete'] === true)
+                    $oTemplate->$sFuncRemoveLocation($sLocationKey);           
 
         return $mixedResult;
     }

+ 5 - 0
inc/classes/BxDolReport.php

@@ -199,6 +199,11 @@ class BxDolReport extends BxDolObject
         return $aReport['count'];
     }
     
+    public function getCountByStatus($iStatus)
+    {
+        return $this->_oQuery->getReportsCountByStatus($iStatus);
+    }
+    
     /**
      * Actions functions
      */

+ 6 - 0
inc/classes/BxDolReportQuery.php

@@ -55,6 +55,12 @@ class BxDolReportQuery extends BxDolObjectQuery
 
         return $aResult;
     }
+    
+    public function getReportsCountByStatus($iStatus)
+    {
+        $sQuery = $this->prepare("SELECT COUNT(*) FROM {$this->_sTableTrack} WHERE `status` = ?", $iStatus);
+        return $this->getOne($sQuery);
+    }
 
     public function putReport($iObjectId, $iAuthorId, $bUndo = false)
     {

+ 1 - 1
inc/classes/BxDolSearch.php

@@ -665,7 +665,7 @@ class BxDolSearchResult implements iBxDolReplaceable
                 if (isset($aValue['groupTable']))
                     $aSql['groupBy'] =  "GROUP BY `{$aValue['groupTable']}`.`{$aValue['groupField']}`, ";
                 $sOn = isset($aValue['mainTable']) ? $aValue['mainTable'] : $this->aCurrent['table'];
-                $aSql['join'] .= " {$aValue['type']} JOIN `{$aValue['table']}` $sTableAlias ON `{$sAlias}`.`{$aValue['onField']}`=`$sOn`.`{$aValue['mainField']}`";
+                $aSql['join'] .= " {$aValue['type']} JOIN `{$aValue['table']}` $sTableAlias ON " . (!empty($aValue['on_sql']) ? $aValue['on_sql'] : "`{$sAlias}`.`{$aValue['onField']}`=`$sOn`.`{$aValue['mainField']}`");
                 $aSql['ownFields'] .= $this->setFieldUnit($aValue['mainField'], $sOn, '', $bRenameMode);
             }
             $aSql['joinFields'] = trim($aSql['joinFields'], ', ');

+ 18 - 0
inc/classes/BxDolStorage.php

@@ -785,6 +785,24 @@ abstract class BxDolStorage extends BxDolFactory implements iBxDolFactoryObject
         
         return $this->_oDb->getGhosts($iProfileId, $iContentId, $isAdmin);
     }
+    
+    /**
+     * Reorder ghost/orphaned files for particular content/user.
+     * @param $iProfileId profile id
+     * @param $iContentId content id, or false to not consider content id at all
+     * @param $aGhosts an ordered list of ghost/orphaned files' IDs.
+     * @return boolean result of operation
+     */
+    public function reorderGhosts($iProfileId, $iContentId, $aGhosts)
+    {
+        $bResult = true;
+
+        $iGhosts = count($aGhosts);
+        for($i = 0; $i < $iGhosts; $i++)
+            $bResult &= $this->_oDb->updateGhostOrder($iProfileId, $iContentId, (int)$aGhosts[$i], $i);
+
+        return $bResult;
+    }
 
     /**
      * Update ghosts' content id.

+ 24 - 1
inc/classes/BxDolStorageQuery.php

@@ -235,6 +235,26 @@ class BxDolStorageQuery extends BxDolDb
         return $iCount;
     }
 
+    public function updateGhostOrder($iProfileId, $iContentId, $iFileId, $iOrder)
+    {
+        $aBindings = array(
+            'object' => $this->_aObject['object'],
+            'content_id' => $iContentId,
+            'id' => $iFileId,
+            'order' => $iOrder,
+        );
+
+        $sWhereClause = " AND `object`=:object AND `content_id`=:content_id AND `id`=:id";
+
+        if(!empty($iProfileId)) {
+            $aBindings['profile_id'] = $iProfileId;
+            
+            $sWhereClause .= " AND `profile_id`=:profile_id";
+        }
+
+        return $this->query("UPDATE `sys_storage_ghosts` SET `order`=:order WHERE 1" . $sWhereClause, $aBindings) !== false;
+    }
+
     public function updateGhostsContentId($mixedFileIds, $iProfileId, $iContentId, $aProfiles = array(), $isAdmin = false)
     {
         $aBindings = array(
@@ -289,6 +309,7 @@ class BxDolStorageQuery extends BxDolDb
 
         $sWhere = '';
         $sJoin = '';
+        $sOrder = '';
         if ($isGhostsOnly) {
             $aBindings['object'] = $this->_aObject['object'];
 
@@ -313,6 +334,8 @@ class BxDolStorageQuery extends BxDolDb
             }
 
             $sJoin .= ')';
+
+            $sOrder = ' ORDER BY `g`.`order` ASC';
         } 
         else {
             if (is_array($mixedProfileId) && $mixedProfileId) {
@@ -325,7 +348,7 @@ class BxDolStorageQuery extends BxDolDb
             }
         }
 
-        $sQuery = "SELECT `f`.* FROM " . $this->_sTableFiles . " AS `f` " . $sJoin . $sWhere;
+        $sQuery = "SELECT `f`.* FROM " . $this->_sTableFiles . " AS `f` " . $sJoin . $sWhere . $sOrder;
         return $this->getAll($sQuery, $aBindings);
     }
 

+ 1 - 1
inc/classes/BxDolStorageS3.php

@@ -42,7 +42,7 @@ class BxDolStorageS3 extends BxDolStorage
 
     protected function init ($aObject)
     {
-        require_once(BX_DIRECTORY_PATH_PLUGINS . 'amazon-s3/S3.php');
+        require_once(BX_DIRECTORY_PATH_PLUGINS . 'unaio/amazon-s3-php-class-hmac-v2/S3.php');
         $this->_s3 = new S3(
             getParam('sys_storage_s3_access_key'), 
             getParam('sys_storage_s3_secret_key'), 

+ 2 - 2
inc/classes/BxDolStorageS3v4.php

@@ -15,8 +15,8 @@ class BxDolStorageS3v4 extends BxDolStorageS3
 {
     protected function init ($aObject)
     {
-        require_once(BX_DIRECTORY_PATH_PLUGINS . 'amazon-s3/S3.php');
-        require_once(BX_DIRECTORY_PATH_PLUGINS . 'amazon-s3/S3v4.php');
+        require_once(BX_DIRECTORY_PATH_PLUGINS . 'unaio/amazon-s3-php-class-hmac-v2/S3.php');
+        require_once(BX_DIRECTORY_PATH_PLUGINS . 'tpyo/amazon-s3-php-class/S3.php'); // HMAC v4
         $this->_s3 = new S3v4\S3(
             getParam('sys_storage_s3_access_key'), 
             getParam('sys_storage_s3_secret_key'), 

+ 29 - 12
inc/classes/BxDolTemplate.php

@@ -885,6 +885,15 @@ class BxDolTemplate extends BxDolFactory implements iBxDolSingleton
         return isset($this->_aLocations[$sKey]);
     }
 
+    /**
+     * Get a lis of all added locations.
+     * @return array with locations.
+     */
+    function getLocations()
+    {
+        return $this->_aLocations;
+    }
+
     /**
      * Add location in array of locations.
      * Note. Location is the path/url to folder where 'templates' folder is stored.
@@ -2178,15 +2187,12 @@ class BxDolTemplate extends BxDolFactory implements iBxDolSingleton
      */
     function _lessCss($mixed)
     {
-    	require_once(BX_DIRECTORY_PATH_PLUGINS . 'lessphp/Less.php');
-
         if(is_array($mixed) && isset($mixed['url']) && isset($mixed['path'])) {
             $sPathFile = realpath($mixed['path']);
             $aInfoFile = pathinfo($sPathFile);
             if (!isset($aInfoFile['extension']) || $aInfoFile['extension'] != 'less')
                 return $mixed;
 
-            require_once(BX_DIRECTORY_PATH_PLUGINS . 'lessphp/Cache.php');
         	$aFiles = array($mixed['path'] => $mixed['url']);
         	$aOptions = array('cache_dir' => $this->_sCachePublicFolderPath, 'prefix' => $this->_sCssLessPrefix);
         	$sFile = Less_Cache::Get($aFiles, $aOptions, $this->_oTemplateConfig->aLessConfig);
@@ -2750,15 +2756,26 @@ class BxDolTemplate extends BxDolFactory implements iBxDolSingleton
 
         $sResult = '';
         $aLocations = array_reverse($this->_aLocations, true);
-        foreach($aLocations as $sKey => $aLocation) {
-            if((in_array($sCheckIn, array(BX_DOL_TEMPLATE_CHECK_IN_BOTH, BX_DOL_TEMPLATE_CHECK_IN_TMPL)) || (isset($sCheckIn['in'], $sCheckIn['sub']) && in_array($sCheckIn['in'], array(BX_DOL_TEMPLATE_CHECK_IN_BOTH, BX_DOL_TEMPLATE_CHECK_IN_TMPL)) && $sCheckIn['sub'] == $sKey)) && extFileExists(BX_DIRECTORY_PATH_MODULES . $this->getPath(). 'data' . DIRECTORY_SEPARATOR . BX_DOL_TEMPLATE_FOLDER_ROOT . DIRECTORY_SEPARATOR . $sKey . DIRECTORY_SEPARATOR . $sFolder . $sName))
-                $sResult = $sRoot . 'modules' . $sDivider . $sDirectory. 'data' . $sDivider . BX_DOL_TEMPLATE_FOLDER_ROOT . $sDivider . $sKey . $sDivider . $sFolder . $sName;
-            else if((in_array($sCheckIn, array(BX_DOL_TEMPLATE_CHECK_IN_BOTH, BX_DOL_TEMPLATE_CHECK_IN_BASE)) || (isset($sCheckIn['in'], $sCheckIn['sub']) && in_array($sCheckIn['in'], array(BX_DOL_TEMPLATE_CHECK_IN_BOTH, BX_DOL_TEMPLATE_CHECK_IN_BASE)) && $sCheckIn['sub'] == $sKey)) && extFileExists($aLocation['path'] . BX_DOL_TEMPLATE_FOLDER_ROOT . DIRECTORY_SEPARATOR . $sFolder . $sName))
-                $sResult = $aLocation[$sType] . BX_DOL_TEMPLATE_FOLDER_ROOT . $sDivider . $sFolder . $sName;
-            else
-                continue;
-            break;
-        }
+
+        //--- Check it Template.
+        $bInSub = false;
+        $aCheckIn = [BX_DOL_TEMPLATE_CHECK_IN_BOTH, BX_DOL_TEMPLATE_CHECK_IN_TMPL];
+        if(in_array($sCheckIn, $aCheckIn) || $bInSub = (isset($sCheckIn['in'], $sCheckIn['sub']) && in_array($sCheckIn['in'], $aCheckIn)))
+            foreach($aLocations as $sKey => $aLocation)
+                if((!$bInSub || $sCheckIn['sub'] == $sKey) && extFileExists(BX_DIRECTORY_PATH_MODULES . $this->getPath(). 'data' . DIRECTORY_SEPARATOR . BX_DOL_TEMPLATE_FOLDER_ROOT . DIRECTORY_SEPARATOR . $sKey . DIRECTORY_SEPARATOR . $sFolder . $sName)) {
+                    $sResult = $sRoot . 'modules' . $sDivider . $sDirectory. 'data' . $sDivider . BX_DOL_TEMPLATE_FOLDER_ROOT . $sDivider . $sKey . $sDivider . $sFolder . $sName;
+                    break;
+                }
+
+        //--- Check it Base.
+        $bInSub = false;
+        $aCheckIn = [BX_DOL_TEMPLATE_CHECK_IN_BOTH, BX_DOL_TEMPLATE_CHECK_IN_BASE];
+        if(empty($sResult) && (in_array($sCheckIn, $aCheckIn) || $bInSub = (isset($sCheckIn['in'], $sCheckIn['sub']) && in_array($sCheckIn['in'], $aCheckIn))))
+            foreach($aLocations as $sKey => $aLocation)
+                if((!$bInSub || $sCheckIn['sub'] == $sKey) && extFileExists($aLocation['path'] . BX_DOL_TEMPLATE_FOLDER_ROOT . DIRECTORY_SEPARATOR . $sFolder . $sName)) {
+                    $sResult = $aLocation[$sType] . BX_DOL_TEMPLATE_FOLDER_ROOT . $sDivider . $sFolder . $sName;
+                    break;
+                }
 
         /**
          * try to find from received path

+ 36 - 0
inc/classes/BxDolUploader.php

@@ -341,12 +341,48 @@ abstract class BxDolUploader extends BxDolFactory
             $a[$aFile['id']] = array_merge($aVars, $this->getGhostTemplateVars($aFile, $iProfileId, $iContentId, $oStorage, $oImagesTranscoder));
         }
 
+        if ('array' == $sFormat) {
+            return $a;
+        }
+        else if ('json' == $sFormat) {
+            return json_encode($a);
+        } else { // html format is not suported for this data type
+            return false;
+        }
+    }
+
+    public function getGhostsWithOrder($iProfileId, $sFormat, $sImagesTranscoder = false, $iContentId = false)
+    {
+        $a = $this->getGhosts($iProfileId, 'array', $sImagesTranscoder, $iContentId);
+        if(!empty($a) && is_array($a))
+            $a = ['g' => $a, 'o' => array_keys($a)];
+
         if ('json' == $sFormat) {
             return json_encode($a);
         } else { // html format is not suported for this data type
             return false;
         }
     }
+    
+    /**
+     * Reorder uploaded ghosts.
+     * @param $iProfileId - profile id to get orphaned files from
+     * @param $sFormat - output format, only 'json' output formt is supported
+     * @param $aGhosts - an array of ordered ghosts' IDs.
+     * @param $iContentId - content id to order orphaned files for, false by default
+     * @return JSON string
+     */
+    public function reorderGhosts($iProfileId, $sFormat, $aGhosts, $iContentId = false)
+    {
+        $bResult = true;
+        if(($oStorage = BxDolStorage::getObjectInstance($this->_sStorageObject)) !== false)
+            $bResult = $oStorage->reorderGhosts($this->isAdmin($iContentId) && $iContentId ? false : $iProfileId, $iContentId, $aGhosts);
+
+        if($sFormat == 'json')
+            return json_encode($bResult ? [] : ['msg' => _t('_error occured')]);
+        else
+            return $bResult;
+    }
 
     /**
      * Delete file by file id, usually ghost file

+ 1 - 1
inc/js/classes/BxDolCategories.js

@@ -35,7 +35,7 @@ BxDolCategories.prototype.categoryAddNew = function (oButton, sName) {
     oCategory.find("input[type = 'text']").val('');
     oCategory.find("input[type = 'hidden']").remove();
 
-    $('.bx-form-input-categories .bx-form-input-category-add:first').before(oCategory);
+    oButton.parents('#bx-form-element-' + sName).find('.bx-form-input-categories .bx-form-input-category-add:first').before(oCategory);
 };
 
 BxDolCategories.prototype.categoryDelete = function (oButton) {

+ 3 - 0
inc/js/classes/BxDolForm.js

@@ -34,6 +34,9 @@ BxDolForm.prototype.showHelp = function(oLink, sInputName)
         url: bx_append_url_params(this._sActionsUri, oData),
         closeOnOuterClick: true,
         removeOnClose: false,
+        onBeforeShow: function(oPopup) {
+            oPopup.addClass('bx-popup-help');
+        }
     });
 };
 

+ 3 - 0
inc/js/classes/BxDolPage.js

@@ -42,6 +42,9 @@ BxDolPage.prototype.showHelp = function(oLink, iBlockId)
         url: bx_append_url_params(this._sActionsUri, oData),
         closeOnOuterClick: true,
         removeOnClose: false,
+        onBeforeShow: function(oPopup) {
+            oPopup.addClass('bx-popup-help');
+        }
     });
 };
 

+ 54 - 17
inc/js/classes/BxDolUploader.js

@@ -132,7 +132,7 @@ BxDolUploaderSimple.prototype.cancelAll = function () {
     this.onUploadCompleted(_t('_sys_uploader_upload_canceled'));
 }
 
-BxDolUploaderSimple.prototype.restoreGhosts = function () {
+BxDolUploaderSimple.prototype.restoreGhosts = function (bInitReordering, onComplete) {
     var sUrl = this._getUrlWithStandardParams() + '&img_trans=' + this._sImagesTranscoder + '&a=restore_ghosts&f=json' + '&c=' + this._iContentId + '&_t=' + escape(new Date());
     var $this = this;
 
@@ -146,28 +146,65 @@ BxDolUploaderSimple.prototype.restoreGhosts = function () {
             $('#' + $this._sResultContainerId + ' .bx-uploader-ghost').remove();
 
         if ('object' === typeof(aData)) {
-            $.each(aData, function(iFileId, oVars) {
-            	var oFileContainer = $('#' + $this._getFileContainerId(iFileId));
-                if (oFileContainer.length > 0)
-                    return;
-                var sHTML;
-                if (typeof $this._sTemplateGhost == 'object')
-                    sHTML = $this._sTemplateGhost[iFileId];
-                else
-                    sHTML = $this._sTemplateGhost;
-                for (var i in oVars)
-                    sHTML = sHTML.replace (new RegExp('{'+i+'}', 'g'), oVars[i]);
-                
-                $('#' + $this._sResultContainerId).prepend(sHTML);
-
-                oFileContainer.find('.bx-uploader-ghost-preview img').hide().fadeIn(1000);
-            });
+            if('object' === typeof(aData.g) && 'object' === typeof(aData.o)) 
+                for(var i in aData.o) {
+                    var iFileId = aData.o[i];
+                    $this.showGhost(iFileId, aData.g[iFileId]);
+                }
+            else
+                $.each(aData, function(iFileId, oVars) {
+                    $this.showGhost(iFileId, oVars);
+                });
 
             $('#' + $this._sResultContainerId).bx_show_more_check_overflow();
+
+            if(bInitReordering) {
+                $('#' + $this._sResultContainerId).sortable({
+                    items: '.bx-uploader-ghost', 
+                    start: function(oEvent, oUi) {
+                        oUi.item.addClass('bx-uploader-ghost-dragging');
+                    },
+                    stop: function(oEvent, oUi) {
+                        oUi.item.removeClass('bx-uploader-ghost-dragging');
+
+                        $this.reorderGhosts(oUi.item);
+                    }
+                });
+            }
         }
+
+        if(typeof onComplete === 'function')
+            return onComplete(aData);
     });
 };
 
+BxDolUploaderSimple.prototype.reorderGhosts = function(oDraggable) {
+    var sUrl = this._getUrlWithStandardParams() + '&a=reorder_ghosts&f=json' + '&c=' + this._iContentId + '&' + $('#' + this._sResultContainerId).sortable('serialize', {key: 'ghosts[]'}) + '&_t=' + escape(new Date());
+
+    $.getJSON(sUrl, function (aData) {
+        processJsonData(aData);
+    });
+};
+
+BxDolUploaderSimple.prototype.showGhost = function(iId, oVars) {
+    var oFileContainer = $('#' + this._getFileContainerId(iId));
+    if(oFileContainer.length > 0)
+        return;
+
+    var sHTML;
+    if (typeof this._sTemplateGhost == 'object')
+        sHTML = this._sTemplateGhost[iId];
+    else
+        sHTML = this._sTemplateGhost;
+
+    for(var i in oVars)
+        sHTML = sHTML.replace (new RegExp('{' + i + '}', 'g'), oVars[i]);
+
+    $('#' + this._sResultContainerId).append(sHTML);
+
+    oFileContainer.find('.bx-uploader-ghost-preview img').hide().fadeIn(1000);
+};
+
 BxDolUploaderSimple.prototype.deleteGhost = function (iFileId) {
     var sUrl = this._getUrlWithStandardParams() + '&a=delete&id=' + iFileId;
     var $this = this;

+ 18 - 4
inc/js/functions.js

@@ -127,6 +127,11 @@ function loadDynamicBlockAutoPaginate (e, iStart, iPerPage, sAdditionalUrlParams
     if ('undefined' != typeof(sAdditionalUrlParams))
         sUrl = bx_append_url_params(sUrl, sAdditionalUrlParams);
 
+	if ($(e).parents('.bx-search-result-block-pagination').length > 0){
+		$([document.documentElement, document.body]).animate({
+			scrollTop: $(e).parents('.bx-search-result-block-pagination').first().offset().top
+		}, 500);
+	}
     return loadDynamicBlockAuto(e, sUrl);
 }
 
@@ -979,7 +984,7 @@ function bx_append_url_params (sUrl, mixedParams) {
     return sUrl + sParams + sHash;
 }
 
-function bx_search_on_type (e, n, sFormSel, sResultsContSel, sLoadingContSel, bSortResults, iMinLen) {
+function bx_search_on_type (e, n, sFormSel, sResultsContSel, sLoadingContSel, bSortResults, iMinLen, onComplete) {
     var oForm = $(e.target).parents(sFormSel + ':first');
 
     if ('undefined' != typeof(e) && 13 == e.keyCode) {
@@ -996,13 +1001,13 @@ function bx_search_on_type (e, n, sFormSel, sResultsContSel, sLoadingContSel, bS
         clearTimeout(glBxSearchTimeoutHandler);
 
     glBxSearchTimeoutHandler = setTimeout(function () {
-        bx_search (n, sFormSel, sResultsContSel, sLoadingContSel, bSortResults);
+        bx_search (n, sFormSel, sResultsContSel, sLoadingContSel, bSortResults, onComplete);
     }, 500);
 
     return true;
 }
 
-function bx_search (n, sFormSel, sResultsContSel, sLoadingContSel, bSortResults) {
+function bx_search (n, sFormSel, sResultsContSel, sLoadingContSel, bSortResults, onComplete) {
     if ('undefined' == typeof(sLoadingContSel))
         sLoadingContSel = sResultsContSel;
     if ('undefined' == typeof(bSortResults))
@@ -1013,6 +1018,10 @@ function bx_search (n, sFormSel, sResultsContSel, sLoadingContSel, bSortResults)
     bx_loading($(sLoadingContSel), true);
     $.post(sUrlRoot + 'searchKeywordContent.php', sQuery, function(data) {
         bx_loading($(sLoadingContSel), false);
+
+        if(!data)
+            return;
+
         if (bSortResults) {
             var aSortedUnits = $(data).find(".bx-def-unit-live-search").toArray().sort(function (a, b) {
                 return b.getAttribute('data-ts') - a.getAttribute('data-ts');
@@ -1022,7 +1031,12 @@ function bx_search (n, sFormSel, sResultsContSel, sLoadingContSel, bSortResults)
                 data += e.outerHTML;
             });
         } 
-        $(sResultsContSel).html(data).bxProcessHtml();
+
+        var oContainer = $(sResultsContSel);
+        oContainer.html(data).bxProcessHtml();
+
+        if(typeof onComplete === 'function')
+            onComplete(oContainer, data);
     });
 
     return false;

+ 1 - 0
inc/params.inc.php

@@ -98,6 +98,7 @@ require_once(BX_DIRECTORY_PATH_INC . 'utils.inc.php');
 require_once(BX_DIRECTORY_PATH_INC . 'version.inc.php');
 
 spl_autoload_register('bx_autoload');
+require BX_DIRECTORY_PATH_PLUGINS . 'autoload.php';
 
 BxDolDb::getInstance()->cacheParams();
 

+ 2 - 9
inc/utils.inc.php

@@ -573,8 +573,6 @@ function clear_xss($val)
     global $oHtmlPurifier;
     if (!isset($oHtmlPurifier) && !$GLOBALS['logged']['admin']) {
 
-        require_once( BX_DIRECTORY_PATH_PLUGINS . 'htmlpurifier/HTMLPurifier.standalone.php' );
-
         HTMLPurifier_Bootstrap::registerAutoload();
 
         $oConfig = HTMLPurifier_Config::createDefault();
@@ -593,7 +591,7 @@ function clear_xss($val)
             $oConfig->set('HTML.Nofollow', 'true');
         }
 
-        $oConfig->set('Filter.Custom', array (new HTMLPurifier_Filter_YouTube(), new HTMLPurifier_Filter_YoutubeIframe(), new HTMLPurifier_Filter_AddBxLinksClass(), new HTMLPurifier_Filter_LocalIframe()));
+        $oConfig->set('Filter.Custom', array (new BxDolHTMLPurifierFilterYouTube(), new BxDolHTMLPurifierFilterYoutubeIframe(), new BxDolHTMLPurifierFilterAddBxLinksClass(), new BxDolHTMLPurifierFilterLocalIframe()));
 
 	    $oConfig->set('HTML.DefinitionID', 'html5-definitions');
 		$oConfig->set('HTML.DefinitionRev', 1);
@@ -781,11 +779,6 @@ function bx_autoload($sClassName)
 {
     if (0 === strncmp($sClassName, 'BxDol', 5) || 0 === strncmp($sClassName, 'BxBase', 6) || 0 === strncmp($sClassName, 'BxTempl', 7))
         bx_import($sClassName);
-    else {
-        if (0 === strpos($sClassName, 'Akeeba\Engine\Postproc\Connector\S3v4')) {
-            require_once(BX_DIRECTORY_PATH_PLUGINS . 'akeeba-s3/src' . str_replace('\\', '/', substr($sClassName, 37)) . '.php');
-        }
-    }
 }
 
 /**
@@ -953,7 +946,7 @@ function bx_file_get_contents($sFileUrl, $aParams = array(), $sMethod = 'get', $
         $sResult = curl_exec($rConnect);
 
         if (curl_errno($rConnect) == 60) { // CURLE_SSL_CACERT
-            curl_setopt($rConnect, CURLOPT_CAINFO, BX_DIRECTORY_PATH_PLUGINS . 'curl/cacert.pem');
+            curl_setopt($rConnect, CURLOPT_CAINFO, BX_DIRECTORY_PATH_PLUGINS . 'curl/cacert/cacert.pem');
             $sResult = curl_exec($rConnect);
         }
 

+ 0 - 1
install/classes/BxDolInstallView.php

@@ -93,7 +93,6 @@ class BxDolInstallView
 
     protected function _getInlineCSS()
     {
-        require_once($this->_sDirPlugins . 'lessphp/Less.php');
         $oLessParser = new Less_Parser();
 
         $oConfigBase = new BxBaseConfig();

+ 2 - 0
install/index.php

@@ -49,6 +49,8 @@ require_once(BX_INSTALL_DIR_CLASSES . 'BxDolInstallModulesTools.php');
 require_once(BX_INSTALL_DIR_CLASSES . 'BxDolInstallLang.php');
 require_once(BX_INSTALL_DIR_CLASSES . 'BxDolInstallSiteConfig.php');
 
+require BX_INSTALL_DIR_PLUGINS . 'autoload.php';
+
 $oController = new BxDolInstallController ();
 $oController->run(isset($_REQUEST['action']) ? $_REQUEST['action'] : '');
 

+ 15 - 9
install/sql/system.sql

@@ -1352,6 +1352,7 @@ CREATE TABLE `sys_modules` (
   `enabled` tinyint(1) NOT NULL default '0',
   `pending_uninstall` tinyint(4) NOT NULL,
   `hash` varchar(32) NOT NULL default '',
+  `updated` int(11) unsigned NOT NULL default '0',
   PRIMARY KEY  (`id`),
   UNIQUE KEY `name` (`name`),
   UNIQUE KEY `path` (`path`(191)),
@@ -1361,7 +1362,7 @@ CREATE TABLE `sys_modules` (
 );
 
 INSERT INTO `sys_modules` (`type`, `name`, `title`, `vendor`, `version`, `path`, `uri`, `class_prefix`, `db_prefix`, `lang_category`, `dependencies`, `date`, `enabled`) VALUES
-('module', 'system', 'System', 'UNA, Inc', '9', '', 'system', 'Bx', 'sys_', 'System', '', 0, 1);
+('module', 'system', 'System', 'UNA, Inc', '9', '', 'system', 'Bx', 'sys_', 'System', '', UNIX_TIMESTAMP(), 1);
 
 
 CREATE TABLE `sys_modules_file_tracks` (
@@ -2094,6 +2095,7 @@ CREATE TABLE IF NOT EXISTS `sys_storage_ghosts` (
   `object` varchar(64) NOT NULL,
   `content_id` int(11) NOT NULL,
   `created` int(10) unsigned NOT NULL,
+  `order` int(11) NOT NULL default '0',
   UNIQUE KEY `id` (`id`,`object`),
   KEY `created` (`created`),
   KEY `profile_object_content` (`profile_id`,`object`,`content_id`)
@@ -4041,7 +4043,7 @@ INSERT INTO `sys_menu_templates` (`id`, `template`, `title`, `visible`) VALUES
 (5, 'menu_toolbar.html', '_sys_menu_template_title_toolbar', 0),
 (6, 'menu_vertical.html', '_sys_menu_template_title_ver', 1),
 (7, 'menu_floating_blocks.html', '_sys_menu_template_title_floating_blocks', 1),
-(8, 'menu_main_submenu.html', '_sys_menu_template_title_main_submenu', 8),
+(8, 'menu_main_submenu.html', '_sys_menu_template_title_main_submenu', 0),
 (9, 'menu_buttons_hor.html', '_sys_menu_template_title_buttons_hor', 1),
 (10, 'menu_inline.html', '_sys_menu_template_title_inline', 1),
 (11, 'menu_interactive_vertical.html', '_sys_menu_template_title_interactive_vertical', 0),
@@ -4051,7 +4053,7 @@ INSERT INTO `sys_menu_templates` (`id`, `template`, `title`, `visible`) VALUES
 (15, 'menu_custom_hor.html', '_sys_menu_template_title_custom_hor', 0),
 (16, 'menu_buttons_ver.html', '_sys_menu_template_title_buttons_ver', 1),
 (17, 'menu_inline_sbtn.html', '_sys_menu_template_title_inline_sbtn', 1),
-(18, 'menu_main_submenu_more_auto.html', '_sys_menu_template_title_main_submenu_more_auto', 8),
+(18, 'menu_main_submenu_more_auto.html', '_sys_menu_template_title_main_submenu_more_auto', 0),
 (19, 'menu_floating_blocks_wide.html', '_sys_menu_template_title_floating_blocks_wide', 0),
 (20, 'menu_custom_ver.html', '_sys_menu_template_title_custom_ver', 0),
 (21, 'menu_profile_stats.html', '_sys_menu_template_title_profile_stats', 0),
@@ -4060,7 +4062,9 @@ INSERT INTO `sys_menu_templates` (`id`, `template`, `title`, `visible`) VALUES
 (24, 'menu_floating_blocks_dash.html', '_sys_menu_template_title_floating_blocks_dash', 0),
 (25, 'menu_block_submenu_hor.html', '_sys_menu_template_title_block_submenu_hor', 1),
 (26, 'menu_block_submenu_ver.html', '_sys_menu_template_title_block_submenu_ver', 1),
-(27, 'menu_profile_followings.html', '_sys_menu_template_title_profile_followings', 0);
+(27, 'menu_profile_followings.html', '_sys_menu_template_title_profile_followings', 0),
+(28, 'menu_main.html', '_sys_menu_template_title_main', 0),
+(29, 'menu_add_content.html', '_sys_menu_template_title_add_content', 0);
 
 CREATE TABLE IF NOT EXISTS `sys_objects_menu` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -4078,14 +4082,14 @@ CREATE TABLE IF NOT EXISTS `sys_objects_menu` (
 );
 
 INSERT INTO `sys_objects_menu` (`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
-('sys_site', '_sys_menu_title_main', 'sys_site', 'system', 7, 0, 1, 'BxTemplMenuSite', ''),
+('sys_site', '_sys_menu_title_main', 'sys_site', 'system', 28, 0, 1, 'BxTemplMenuSite', ''),
 ('sys_homepage', '_sys_menu_title_homepage', 'sys_homepage', 'system', 7, 0, 1, 'BxTemplMenuHomepage', ''),
 ('sys_homepage_submenu', '_sys_menu_title_homepage_submenu', 'sys_homepage_submenu', 'system', 8, 0, 1, '', ''),
 ('sys_site_submenu', '_sys_menu_title_submenu', 'sys_site', 'system', 1, 0, 1, 'BxTemplMenuSubmenu', ''),
 ('sys_footer', '_sys_menu_title_footer', 'sys_footer', 'system', 2, 0, 1, 'BxTemplMenuFooter', ''),
 ('sys_toolbar_site', '_sys_menu_title_toolbar_site', 'sys_toolbar_site', 'system', 5, 0, 1, 'BxTemplMenuToolbar', ''),
 ('sys_toolbar_member', '_sys_menu_title_toolbar_member', 'sys_toolbar_member', 'system', 5, 0, 1, 'BxTemplMenuToolbar', ''),
-('sys_add_content', '_sys_menu_title_add_content', 'sys_add_content_links', 'system', 7, 0, 1, 'BxTemplMenuSite', ''),
+('sys_add_content', '_sys_menu_title_add_content', 'sys_add_content_links', 'system', 29, 0, 1, 'BxTemplMenuSite', ''),
 ('sys_add_profile', '_sys_menu_title_add_profile', 'sys_add_profile_links', 'system', 14, 0, 1, 'BxTemplMenuProfileAdd', ''),
 ('sys_add_profile_vertical', '_sys_menu_title_add_profile_vertical', 'sys_add_profile_links', 'system', 6, 0, 1, 'BxTemplMenuProfileAdd', ''),
 ('sys_account_dashboard', '_sys_menu_title_account_dashboard', 'sys_account_dashboard', 'system', 8, 0, 1, 'BxTemplMenuAccountDashboard', ''),
@@ -4174,6 +4178,7 @@ CREATE TABLE IF NOT EXISTS `sys_menu_items` (
   `visible_for_levels` int(11) NOT NULL DEFAULT '2147483647',
   `visibility_custom` text NOT NULL,
   `hidden_on` varchar(255) NOT NULL DEFAULT '',
+  `primary` tinyint(4) NOT NULL DEFAULT '0',
   `active` tinyint(4) NOT NULL DEFAULT '1',
   `copyable` tinyint(4) NOT NULL DEFAULT '1',
   `editable` tinyint(4) NOT NULL DEFAULT '1',
@@ -4372,7 +4377,7 @@ INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `fie
 ('sys_studio_categories', 'Sql', 'SELECT * FROM `sys_categories` WHERE 1 ', 'sys_categories', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'value', '', 'like', '', '', 'BxTemplStudioFormsCategories', ''),
 ('sys_studio_groups_roles', 'Sql', 'SELECT * FROM `sys_form_pre_values` WHERE 1 ', 'sys_form_pre_values', 'id', 'Order', '', '', 20, NULL, 'start', '', '', 'LKey', 'like', '', '', 'BxTemplStudioFormsGroupsRoles', ''),
 
-('sys_audit_administration', 'Sql', 'SELECT * FROM `sys_audit` WHERE 1 ', 'sys_audit', 'id', 'added', '', '', 20, NULL, 'start', '', 'value', '', 'like', 'content_module,profile_id,content_id,context_profile_id,added', 'action_lang_key', 'BxTemplAuditGrid', ''),
+('sys_audit_administration', 'Sql', 'SELECT * FROM `sys_audit` WHERE 1 ', 'sys_audit', 'id', 'added', '', '', 20, NULL, 'start', '', 'value', '', 'like', 'content_module,profile_id,content_id,author_id,context_profile_id,added', 'action_lang_key', 'BxTemplAuditGrid', ''),
 
 ('sys_badges_administration', 'Sql', 'SELECT * FROM `sys_badges` WHERE 1 ', 'sys_badges', 'id', 'added', '', '', 20, NULL, 'start', '', 'text', '', 'like', '', '', 'BxTemplStudioBadgesGrid', ''),
 
@@ -4524,7 +4529,7 @@ INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable
 ('sys_audit_administration', 'content_id', '_adm_form_txt_audit_content', '20%', 1, 25, '', 3),
 ('sys_audit_administration', 'author_id', '_adm_form_txt_audit_author_content', '10%', 1, 25, '', 4),
 ('sys_audit_administration', 'content_module', '_adm_form_txt_audit_module', '10%', 1, 25, '', 5),
-('sys_audit_administration', 'context_id', '_adm_pgt_txt_audit_context', '15%', 1, 25, '', 6),
+('sys_audit_administration', 'context_profile_id', '_adm_pgt_txt_audit_context', '15%', 1, 25, '', 6),
 ('sys_audit_administration', 'action_lang_key', '_adm_pgt_txt_audit_action', '15%', 1, 25, '', 7),
 
 ('sys_badges_administration', 'checkbox', '_sys_select', '2%', 0, 0, '', 1),
@@ -4635,7 +4640,8 @@ INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `conf
 
 INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`, `icon_only`) VALUES
 ('sys_reports_administration', 'single', 'check_in', '_adm_form_btn_reports_check_in', 'lock-open', 0, 1, 1),
-('sys_reports_administration', 'single', 'check_out', '_adm_form_btn_reports_check_out', 'lock', 0, 2, 1);
+('sys_reports_administration', 'single', 'check_out', '_adm_form_btn_reports_check_out', 'lock', 0, 2, 1),
+('sys_reports_administration', 'single', 'audit', '_adm_form_btn_reports_audit', 'history', 0, 3, 1);
 
 
 INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES

+ 5 - 0
modules/base/general/classes/BxBaseModGeneralDb.php

@@ -90,6 +90,11 @@ class BxBaseModGeneralDb extends BxDolModuleDb
                 break;
 
             case 'all':
+                if(isset($aParams['count']) && $aParams['count'] === true) {
+                    $aMethod['name'] = 'getOne';
+                    $sSelectClause = 'COUNT(`' . $CNF['TABLE_ENTRIES'] . "`.`" . $CNF['FIELD_ID'] . '`)';
+                }
+
                 $sOrderClause .=  "`" . $CNF['TABLE_ENTRIES'] . "`.`" . $CNF['FIELD_ADDED'] . "` ASC";
                 break;
         }

+ 2 - 0
modules/base/general/classes/BxBaseModGeneralGridAdministration.php

@@ -30,6 +30,8 @@ class BxBaseModGeneralGridAdministration extends BxTemplGrid
 
         parent::__construct ($aOptions, $oTemplate);
 
+        $this->_aQueryReset = array($this->_aOptions['filter_get'], $this->_aOptions['paginate_get_start'], $this->_aOptions['paginate_get_per_page']);
+        
         $this->_sManageType = BX_DOL_MANAGE_TOOLS_ADMINISTRATION;
         $this->_sParamsDivider = '#-#';
 

+ 49 - 17
modules/base/general/classes/BxBaseModGeneralMenuViewActions.php

@@ -110,7 +110,7 @@ class BxBaseModGeneralMenuViewActions extends BxTemplMenuCustom
         $aItem['class_wrp'] = 'bx-base-general-entity-action' . (!empty($aItem['class_wrp']) ? ' ' . $aItem['class_wrp'] : '');
 
         if($this->_bShowAsButton)
-            $aItem['class_link'] = 'bx-btn' . (!empty($aItem['class_link']) ? ' ' . $aItem['class_link'] : '');
+            $aItem['class_link'] = 'bx-btn' . (isset($aItem['primary']) && (int)$aItem['primary'] == 1 ? ' bx-btn-primary' : '') . (!empty($aItem['class_link']) ? ' ' . $aItem['class_link'] : '');
 
         if(!$this->_bShowTitle)
             $aItem['bx_if:title']['condition'] = false;
@@ -134,11 +134,15 @@ class BxBaseModGeneralMenuViewActions extends BxTemplMenuCustom
         if(!$oObject || !$oObject->isEnabled())
             return '';
 
-        $sResult = $oObject->getElementBlock(array(
+        $aObjectOptions = array(
             'dynamic_mode' => $this->_bDynamicMode,
             'show_do_view_as_button' => $this->_bShowAsButton,
             'show_do_view_label' => $this->_bShowTitle
-        ));
+        );
+        if(!empty($aParams['object_options']) && is_array($aParams['object_options']))
+            $aObjectOptions = array_merge($aObjectOptions, $aParams['object_options']);
+
+        $sResult = $oObject->getElementBlock($aObjectOptions);
         if(empty($sResult))
             return '';
 
@@ -161,12 +165,16 @@ class BxBaseModGeneralMenuViewActions extends BxTemplMenuCustom
         if(!$oObject || !$oObject->isEnabled())
             return '';
 
-        $sResult = $oObject->getElementBlock(array(
+        $aObjectOptions = array(
             'dynamic_mode' => $this->_bDynamicMode,
             'show_do_comment_as_button' => $this->_bShowAsButton,
             'show_do_comment_label' => $this->_bShowTitle,
             'show_counter' => false
-        ));
+        );
+        if(!empty($aParams['object_options']) && is_array($aParams['object_options']))
+            $aObjectOptions = array_merge($aObjectOptions, $aParams['object_options']);
+
+        $sResult = $oObject->getElementBlock($aObjectOptions);
         if(empty($sResult))
             return '';
 
@@ -189,11 +197,15 @@ class BxBaseModGeneralMenuViewActions extends BxTemplMenuCustom
         if(!$oObject || !$oObject->isEnabled())
             return '';
 
-        $sResult = $oObject->getElementBlock(array(
+        $aObjectOptions = array(
             'dynamic_mode' => $this->_bDynamicMode,
             'show_do_vote_as_button' => $this->_bShowAsButton,
             'show_do_vote_label' => $this->_bShowTitle
-        ));
+        );
+        if(!empty($aParams['object_options']) && is_array($aParams['object_options']))
+            $aObjectOptions = array_merge($aObjectOptions, $aParams['object_options']);
+
+        $sResult = $oObject->getElementBlock($aObjectOptions);
         if(empty($sResult))
             return '';
 
@@ -216,11 +228,15 @@ class BxBaseModGeneralMenuViewActions extends BxTemplMenuCustom
         if(!$oObject || !$oObject->isEnabled())
             return '';
 
-        $sResult = $oObject->getElementBlock(array(
+        $aObjectOptions = array(
             'dynamic_mode' => $this->_bDynamicMode,
             'show_do_vote_as_button' => $this->_bShowAsButton,
             'show_do_vote_label' => $this->_bShowTitle
-        ));
+        );
+        if(!empty($aParams['object_options']) && is_array($aParams['object_options']))
+            $aObjectOptions = array_merge($aObjectOptions, $aParams['object_options']);
+
+        $sResult = $oObject->getElementBlock($aObjectOptions);
         if(empty($sResult))
             return '';
 
@@ -243,11 +259,15 @@ class BxBaseModGeneralMenuViewActions extends BxTemplMenuCustom
         if(!$oObject || !$oObject->isEnabled())
             return '';
 
-        $sResult = $oObject->getElementBlock(array(
+        $aObjectOptions = array(
             'dynamic_mode' => $this->_bDynamicMode,
             'show_do_vote_as_button' => $this->_bShowAsButton,
             'show_do_vote_label' => $this->_bShowTitle
-        ));
+        );
+        if(!empty($aParams['object_options']) && is_array($aParams['object_options']))
+            $aObjectOptions = array_merge($aObjectOptions, $aParams['object_options']);
+
+        $sResult = $oObject->getElementBlock($aObjectOptions);
         if(empty($sResult))
             return '';
 
@@ -270,11 +290,15 @@ class BxBaseModGeneralMenuViewActions extends BxTemplMenuCustom
         if(!$oObject || !$oObject->isEnabled())
             return '';
 
-        $sResult = $oObject->getElementBlock(array(
+        $aObjectOptions = array(
             'dynamic_mode' => $this->_bDynamicMode,
             'show_do_favorite_as_button' => $this->_bShowAsButton,
             'show_do_favorite_label' => $this->_bShowTitle
-        ));
+        );
+        if(!empty($aParams['object_options']) && is_array($aParams['object_options']))
+            $aObjectOptions = array_merge($aObjectOptions, $aParams['object_options']);
+
+        $sResult = $oObject->getElementBlock($aObjectOptions);
         if(empty($sResult))
             return '';
 
@@ -300,11 +324,15 @@ class BxBaseModGeneralMenuViewActions extends BxTemplMenuCustom
         if(!$oObject || !$oObject->isEnabled())
             return '';
 
-        $sResult = $oObject->getElementBlock(array(
+        $aObjectOptions = array(
             'dynamic_mode' => $this->_bDynamicMode,
             'show_do_feature_as_button' => $this->_bShowAsButton,
             'show_do_feature_label' => $this->_bShowTitle
-        ));
+        );
+        if(!empty($aParams['object_options']) && is_array($aParams['object_options']))
+            $aObjectOptions = array_merge($aObjectOptions, $aParams['object_options']);
+
+        $sResult = $oObject->getElementBlock($aObjectOptions);
         if(empty($sResult))
             return '';
 
@@ -365,11 +393,15 @@ class BxBaseModGeneralMenuViewActions extends BxTemplMenuCustom
         if(!$oObject || !$oObject->isEnabled())
             return '';
 
-        $sResult = $oObject->getElementBlock(array(
+        $aObjectOptions = array(
             'dynamic_mode' => $this->_bDynamicMode,
             'show_do_report_as_button' => $this->_bShowAsButton,
             'show_do_report_label' => $this->_bShowTitle
-        ));
+        );
+        if(!empty($aParams['object_options']) && is_array($aParams['object_options']))
+            $aObjectOptions = array_merge($aObjectOptions, $aParams['object_options']);
+
+        $sResult = $oObject->getElementBlock($aObjectOptions);
         if(empty($sResult))
             return '';
 

+ 59 - 30
modules/base/general/classes/BxBaseModGeneralModule.php

@@ -422,45 +422,44 @@ class BxBaseModGeneralModule extends BxDolModule
 
         return $aTextFields;
     }
-    
+
     public function serviceManageTools($sType = 'common')
     {
         $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getGridObject($sType));
         if(!$oGrid)
             return '';
 
-		$CNF = &$this->_oConfig->CNF;
-
-		$sMenu = '';
-		if(BxDolAcl::getInstance()->isMemberLevelInSet(192)) {
-			$oPermalink = BxDolPermalinks::getInstance();
-
-			$aMenuItems = array();
-			if(!empty($CNF['OBJECT_GRID_COMMON']) && !empty($CNF['T']['menu_item_manage_my']))
-				$aMenuItems[] = array('id' => 'manage-common', 'name' => 'manage-common', 'class' => '', 'link' => $oPermalink->permalink($CNF['URL_MANAGE_COMMON']), 'target' => '_self', 'title' => _t($CNF['T']['menu_item_manage_my']), 'active' => 1);
-			if(!empty($CNF['OBJECT_GRID_ADMINISTRATION']) && !empty($CNF['T']['menu_item_manage_all']))
-				$aMenuItems[] = array('id' => 'manage-administration', 'name' => 'manage-administration', 'class' => '', 'link' => $oPermalink->permalink($CNF['URL_MANAGE_ADMINISTRATION']), 'target' => '_self', 'title' => _t($CNF['T']['menu_item_manage_all']), 'active' => 1);
-
-			if(count($aMenuItems) > 1) {
-	            $oMenu = new BxTemplMenu(array(
-	            	'template' => 'menu_vertical.html', 
-	            	'menu_items' => $aMenuItems
-	            ), $this->_oTemplate);
-	            $oMenu->setSelected($this->_aModule['name'], 'manage-' . $sType);
-	            $sMenu = $oMenu->getCode();
-			}
-		}
+        $CNF = &$this->_oConfig->CNF;
 
-		if(!empty($CNF['OBJECT_MENU_SUBMENU']) && isset($CNF['URI_MANAGE_COMMON'])) {
-			BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_SUBMENU'])->setSelected($this->_aModule['name'], $CNF['URI_MANAGE_COMMON']);
-		}
+        $mixedMenu = '';
+        if(BxDolAcl::getInstance()->isMemberLevelInSet(192)) {
+            $oPermalink = BxDolPermalinks::getInstance();
+
+            $aMenuItems = array();
+            if(!empty($CNF['OBJECT_GRID_COMMON']) && !empty($CNF['T']['menu_item_manage_my']))
+                $aMenuItems[] = array('id' => 'manage-common', 'name' => 'manage-common', 'class' => '', 'link' => $oPermalink->permalink($CNF['URL_MANAGE_COMMON']), 'target' => '_self', 'title' => _t($CNF['T']['menu_item_manage_my']), 'active' => 1);
+            if(!empty($CNF['OBJECT_GRID_ADMINISTRATION']) && !empty($CNF['T']['menu_item_manage_all']))
+                $aMenuItems[] = array('id' => 'manage-administration', 'name' => 'manage-administration', 'class' => '', 'link' => $oPermalink->permalink($CNF['URL_MANAGE_ADMINISTRATION']), 'target' => '_self', 'title' => _t($CNF['T']['menu_item_manage_all']), 'active' => 1);
+
+            if(count($aMenuItems) > 1) {
+                $mixedMenu = new BxTemplMenu(array(
+                    'template' => 'menu_block_submenu_ver.html', 
+                    'menu_items' => $aMenuItems
+                ), $this->_oTemplate);
+                $mixedMenu->setSelected($this->_aModule['name'], 'manage-' . $sType);
+            }
+        }
+
+        if(!empty($CNF['OBJECT_MENU_SUBMENU']) && isset($CNF['URI_MANAGE_COMMON'])) {
+            BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_SUBMENU'])->setSelected($this->_aModule['name'], $CNF['URI_MANAGE_COMMON']);
+        }
 
         $this->_oTemplate->addCss(array('manage_tools.css'));
         $this->_oTemplate->addJs(array('manage_tools.js'));
         $this->_oTemplate->addJsTranslation(array('_sys_grid_search'));
         return array(
-        	'content' => $this->_oTemplate->getJsCode('manage_tools', array('sObjNameGrid' => $this->_oConfig->getGridObject($sType))) . $oGrid->getCode(),
-        	'menu' => $sMenu
+            'content' => $this->_oTemplate->getJsCode('manage_tools', array('sObjNameGrid' => $this->_oConfig->getGridObject($sType))) . $oGrid->getCode(),
+            'menu' => $mixedMenu
         );
     }
 
@@ -468,7 +467,7 @@ class BxBaseModGeneralModule extends BxDolModule
     {
     	return 0;
     }
-    
+
     public function serviceGetMenuAddonManageToolsProfileStats()
     {
     	return 0;
@@ -1258,7 +1257,7 @@ class BxBaseModGeneralModule extends BxDolModule
                 $aMarkers['img_url'] = $sImageUrl;
         }
 
-        $oActions = BxDolMenu::getObjectInstance($sObjectMenu);
+        $oActions = BxDolMenu::getObjectInstance($sObjectMenu, $this->_oTemplate);
         if(!$oActions)
             return false;
 
@@ -1329,6 +1328,33 @@ class BxBaseModGeneralModule extends BxDolModule
         return $oReport->getReportedByWithComments($CNF['OBJECT_NOTES']);
     }
     
+     /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-page_blocks Page Blocks
+     * @subsubsection bx_base_general-reports_count_by_status reports_count_by_status
+     * 
+     * @code bx_srv('bx_posts', 'reports_count_by_status', [...]); @endcode
+     * 
+     * Get number of reports with specified status
+     * @param $iStatus status ID
+     * 
+     * @see BxBaseModGeneralModule::serviceReportsCountByStatus
+     */
+    /** 
+     * @ref bx_base_general-entity_reports "entity_reports"
+     */
+    public function serviceReportsCountByStatus ($iStatus)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        if (!isset($CNF['OBJECT_REPORTS']) || !isset($CNF['OBJECT_NOTES']))
+            return false;
+        
+        $oReport = BxDolReport::getObjectInstance($CNF['OBJECT_REPORTS'], 0, false);
+        return $oReport->getCountByStatus($iStatus);
+    }
+    
     /**
      * @page service Service Calls
      * @section bx_base_general Base General
@@ -2095,7 +2121,10 @@ class BxBaseModGeneralModule extends BxDolModule
         if($sResult !== false)
             return $sResult;
 
-        if($bIsSingle && count($aBadges) > 0)
+        if(empty($aBadges) || !is_array($aBadges))
+            return '';
+
+        if($bIsSingle)
             return BxDolService::call('system', 'get_badge', array($aBadges[0], $bIsCompact), 'TemplServices');
 
         $aBadgesOutput = array();

+ 1 - 1
modules/base/general/classes/BxBaseModGeneralSearchResult.php

@@ -104,7 +104,7 @@ class BxBaseModGeneralSearchResult extends BxTemplSearchResult
         if(empty($sPagination))
             return '';
 
-        return '<div class="bx-search-result-block-pagination bx-def-margin-top">' . $sPagination . '</div>';
+        return $sPagination;
     }
 
     protected function getItemPerPageInShowCase ()

+ 3 - 0
modules/base/general/template/css/forms.css

@@ -1,5 +1,8 @@
 
 /* uploader */
+.bx-form-input-files-result.ui-sortable .bx-uploader-ghost {
+    cursor: move;
+}
 
 .bx-uploader-ghost .bx-base-general-icon-wrapper {
     float:left;

+ 0 - 1
modules/base/general/template/unit_meta_item.html

@@ -1 +0,0 @@
-<bx_include_base:../../../../template/unit_meta_item.html />

+ 59 - 0
modules/base/groups/classes/BxBaseModGroupsMenuViewMeta.php

@@ -0,0 +1,59 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    BaseGroups Base classes for groups modules
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * View entry meta menu
+ */
+class BxBaseModGroupsMenuViewMeta extends BxBaseModProfileMenuViewMeta
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+    }
+
+    protected function _getMenuItemMembers($aItem)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(!$this->_bContentPublic || !$this->_oContentProfile || empty($CNF['OBJECT_CONNECTIONS']))
+            return false;
+
+        $oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS']);
+        if(!$oConnection)
+            return false;
+
+        $iMembers = $oConnection->getConnectedInitiatorsCount($this->_oContentProfile->id(), true);
+        if(!$iMembers)
+            return false;
+
+        return $this->getUnitMetaItemText(_t(!empty($aItem['title']) ? $aItem['title'] : '_sys_menu_item_title_sm_members', $iMembers));
+    }
+
+    protected function _getMenuItemSubscribers($aItem)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(!$this->_bContentPublic || !$this->_oContentProfile)
+            return false;
+
+        $oConnection = BxDolConnection::getObjectInstance('sys_profiles_subscriptions');
+        if(!$oConnection)
+            return false;
+
+        $iSubscribers = $oConnection->getConnectedInitiatorsCount($this->_oContentProfile->id());
+        if(!$iSubscribers)
+            return false;
+
+        return $this->getUnitMetaItemText(_t(!empty($aItem['title']) ? $aItem['title'] : '_sys_menu_item_title_sm_subscribers', $iSubscribers));
+    }
+}
+
+/** @} */

+ 0 - 2
modules/base/groups/template/css/main.css

@@ -1,5 +1,3 @@
-@import url(../../../../base/profile/template/css/main.css);
-
 .bx-base-group-cover-wrapper .bx-base-pofile-cover-info .bx-def-ava {
     border-width:0.0625rem;
     border-radius:0.1875rem;

+ 5 - 7
modules/base/notifications/classes/BxBaseModNotificationsTemplate.php

@@ -76,17 +76,15 @@ class BxBaseModNotificationsTemplate extends BxBaseModGeneralTemplate
     	$this->getCssJs();
 
     	if($sTemplateName == 'unit.html')
-    		return $this->getUnit($aData);
+            return $this->getUnit($aData);
 
         $oModule = $this->getModule();
         $CNF = &$this->_oConfig->CNF;
 
-        if ($isCheckPrivateContent && CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $oModule->isAllowedView($aData))) {
-            $aVars = array (
-                'summary' => $sMsg,
-            );
-            return $this->parseHtmlByName('unit_private.html', $aVars);
-        }
+        if ($isCheckPrivateContent && !$oModule->isAllowedView($aData))
+            return $this->parseHtmlByName('unit_private.html', array (
+                'summary' => _t('_sys_access_denied_to_private_content'),
+            ));
 
         list($sAuthorName, $sAuthorUrl, $sAuthorIcon) = $oModule->getUserInfo($aData['object_id']);
         $bAuthorIcon = !empty($sAuthorIcon);

+ 2 - 0
modules/base/payment/classes/BxBaseModPaymentConfig.php

@@ -55,6 +55,8 @@ class BxBaseModPaymentConfig extends BxBaseModGeneralConfig
         );
 
         $this->_aObjects = array_merge($this->_aObjects, array(
+            'form_details' => $this->_sName . '_form_details',
+            'form_display_details_edit' => $this->_sName . '_form_details_edit',
             'form_pendings' => $this->_sName . '_form_pendings',
             'form_processed' => $this->_sName . '_form_processed',
             'form_display_pendings_process' => $this->_sName . '_form_pendings_process',

+ 1 - 1
modules/base/payment/classes/BxBaseModPaymentGridOrders.php

@@ -206,7 +206,7 @@ class BxBaseModPaymentGridOrders extends BxTemplGrid
             )
         );
 
-        $oForm = new BxTemplStudioFormView(array());
+        $oForm = new BxTemplFormView(array());
         return $oForm->genRow($aInput);
     }
 }

+ 4 - 1
modules/base/profile/classes/BxBaseModProfileAlertsResponse.php

@@ -91,8 +91,11 @@ class BxBaseModProfileAlertsResponse extends BxBaseModGeneralAlertsResponse
             $this->processTimelineView($oAlert, $oAlert->iObject);
             break;
 
-        case 'timeline_comment':
         case 'timeline_report':
+            $this->processTimelineEventsBoolResult($oAlert, $oAlert->iObject,'checkAllowedView');
+            break;    
+            
+        case 'timeline_comment':
         case 'timeline_vote':
         case 'timeline_score':
             $this->processTimelineEventsBoolResult($oAlert, $oAlert->iObject);

+ 4 - 0
modules/base/profile/classes/BxBaseModProfileFormsEntryHelper.php

@@ -221,6 +221,10 @@ class BxBaseModProfileFormsEntryHelper extends BxBaseModGeneralFormsEntryHelper
                 if($sRedirectCustom) {
                     $sRedirectUrl = $this->prepareCustomRedirectUrl($sRedirectCustom, $aContentInfo);
                 }
+                
+            case BX_DOL_PROFILE_REDIRECT_HOMEPAGE:
+                $sRedirectUrl =  BX_DOL_URL_ROOT;  
+                break;
         }
 
         $sCustomReferrer = $oSession->getValue('custom-referrer');

+ 1 - 1
modules/base/profile/classes/BxBaseModProfileGridAdministration.php

@@ -21,7 +21,7 @@ class BxBaseModProfileGridAdministration extends BxBaseModGeneralGridAdministrat
 
         $CNF = &$this->_oModule->_oConfig->CNF;
 
-        $this->_aQueryReset = array('order_field', 'order_dir', $this->_aOptions['paginate_get_start'], $this->_aOptions['paginate_get_per_page']);
+        $this->_aQueryReset = array($this->_aOptions['paginate_get_start'], $this->_aOptions['paginate_get_per_page']);
 
         $this->_sStatusField = !empty($CNF['FIELD_STATUS']) ? $CNF['FIELD_STATUS'] : 'status';
         $this->_aStatusValues = array('active', 'pending', 'suspended');

+ 35 - 0
modules/base/profile/classes/BxBaseModProfileMenuViewActionsAll.php

@@ -75,6 +75,41 @@ class BxBaseModProfileMenuViewActionsAll extends BxBaseModGeneralMenuViewActions
     {
         return $this->_getMenuItemByNameActions($aItem);
     }
+
+    protected function _getMenuItemView($aItem, $aParams = array())
+    {
+        return parent::_getMenuItemView($aItem, array_merge($aParams, [
+            'object_options' => ['show_counter' => false]
+        ]));
+    }
+
+    protected function _getMenuItemComment($aItem, $aParams = array())
+    {
+        return parent::_getMenuItemComment($aItem, array_merge($aParams, [
+            'object_options' => ['show_counter' => false]
+        ]));
+    }
+
+    protected function _getMenuItemVote($aItem, $aParams = array())
+    {
+        return parent::_getMenuItemVote($aItem, array_merge($aParams, [
+            'object_options' => ['show_counter' => false]
+        ]));
+    }
+
+    protected function _getMenuItemReaction($aItem, $aParams = array())
+    {
+        return parent::_getMenuItemReaction($aItem, array_merge($aParams, [
+            'object_options' => ['show_counter' => false]
+        ]));
+    }
+
+    protected function _getMenuItemScore($aItem, $aParams = array())
+    {
+        return parent::_getMenuItemScore($aItem, array_merge($aParams, [
+            'object_options' => ['show_counter' => false]
+        ]));
+    }
 }
 
 /** @} */

+ 167 - 0
modules/base/profile/classes/BxBaseModProfileMenuViewMeta.php

@@ -0,0 +1,167 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    BaseProfile Base classes for profile modules
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * View entry meta menu
+ */
+class BxBaseModProfileMenuViewMeta extends BxTemplMenuUnitMeta
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_bShowZeros;
+
+    protected $_iContentId;
+    protected $_aContentInfo;
+    protected $_bContentPublic;
+    protected $_oContentProfile;
+    protected $_aContentProfileInfo;
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct($aObject, $oTemplate);
+
+        $this->_bShowZeros = false;
+
+        $this->_iContentId = 0;
+        $this->_aContentInfo = [];
+        $this->_bContentPublic = false;
+        $this->_oContentProfile = null;
+        $this->_aContentProfileInfo = [];
+    }
+
+    public function setContentId($iContentId)
+    {
+        $this->_iContentId = $iContentId;
+        $this->_aContentInfo = $this->_oModule->_oDb->getContentInfoById($this->_iContentId);
+        if(empty($this->_aContentInfo) || !is_array($this->_aContentInfo))
+            return;
+
+        $this->_oContentProfile = BxDolProfile::getInstanceByContentAndType($this->_iContentId, $this->_sModule);
+        if(!$this->_oContentProfile) 
+            return;
+
+        $this->_aContentProfileInfo = $this->_oContentProfile->getInfo();     
+
+        $this->addMarkers($this->_aContentProfileInfo);
+        $this->addMarkers(array(
+            'profile_id' => $this->_oContentProfile->id()
+        ));
+    }
+
+    public function setContentPublic($bContentPublic)
+    {
+        $this->_bContentPublic = $bContentPublic;
+    }
+
+    public function getCode()
+    {
+        if(empty($this->_iContentId))
+            $this->_retrieveContentId();
+
+        return parent::getCode();
+    }
+
+    protected function _getMenuItemMembership($aItem)
+    {
+        if(!$this->_bContentPublic || !$this->_oContentProfile)
+            return false;
+
+        $aMembership = BxDolAcl::getInstance()->getMemberMembershipInfo($this->_oContentProfile->id());
+        return $aMembership ? $this->getUnitMetaItemText(_t($aMembership['name'])) : false;
+    }
+    
+    protected function _getMenuItemBadges($aItem)
+    {
+        $sResult = $this->_oModule->serviceGetBadges($this->_iContentId);
+        if(!empty($sResult))
+            $sResult = $this->getUnitMetaItemText($sResult, ['class' => 'bx-base-bages-container']);
+
+        return $sResult;
+    }
+
+    protected function _getMenuItemViews($aItem)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(empty($CNF['OBJECT_VIEWS']) || empty($CNF['FIELD_VIEWS']) || (empty($this->_aContentInfo[$CNF['FIELD_VIEWS']]) && !$this->_bShowZeros))
+            return false;
+
+        return $this->getUnitMetaItemText(_t('_view_n_views', $this->_aContentInfo[$CNF['FIELD_VIEWS']]));
+    }
+
+    protected function _getMenuItemVotes($aItem)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(empty($CNF['OBJECT_VOTES']) || empty($CNF['FIELD_VOTES']) || (empty($this->_aContentInfo[$CNF['FIELD_VOTES']]) && !$this->_bShowZeros))
+            return false;
+        
+        return $this->getUnitMetaItemText(_t('_vote_n_votes', $this->_aContentInfo[$CNF['FIELD_VOTES']]));
+    }
+
+    protected function _getMenuItemReactions($aItem)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(empty($CNF['OBJECT_REACTIONS']))
+            return false;
+
+        $oVotes = BxDolVote::getObjectInstance($CNF['OBJECT_REACTIONS'], $this->_aContentInfo[$CNF['FIELD_ID']]);
+        if(!$oVotes)
+            return false;
+
+        return $this->getUnitMetaItemCustom($oVotes->getElementInline(array('show_counter' => false)));
+    }
+    
+    protected function _getMenuItemScores($aItem)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(empty($CNF['OBJECT_SCORES']))
+            return false;
+
+        $oScores = BxDolScore::getObjectInstance($CNF['OBJECT_SCORES'], $this->_aContentInfo[$CNF['FIELD_ID']]);
+        if(!$oScores)
+            return false;
+
+        return $this->getUnitMetaItemCustom($oScores->getElementInline(array('show_counter' => false)));
+    }
+
+    protected function _getMenuItemComments($aItem)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(empty($CNF['OBJECT_COMMENTS']) || empty($CNF['FIELD_COMMENTS']) || (empty($this->_aContentInfo[$CNF['FIELD_COMMENTS']]) && !$this->_bShowZeros))
+            return false;
+
+        $oComments = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], $this->_aContentInfo[$CNF['FIELD_ID']]);
+        if(!$oComments || !$oComments->isEnabled())
+            return false;
+
+        return $this->getUnitMetaItemLink(_t('_cmt_txt_n_comments', $this->_aContentInfo[$CNF['FIELD_COMMENTS']]), array(
+            'href' => $oComments->getListUrl()
+        ));
+    }
+
+    protected function _retrieveContentId()
+    {
+        if(bx_get('id') !== false)
+            $this->setContentId(bx_process_input(bx_get('id'), BX_DATA_INT));
+
+        if(empty($this->_iContentId) && bx_get('profile_id') !== false)
+            $this->setContentId(BxDolProfile::getInstance(bx_process_input(bx_get('profile_id'), BX_DATA_INT))->getContentId());
+    }
+}
+
+/** @} */

+ 30 - 1
modules/base/profile/classes/BxBaseModProfileModule.php

@@ -12,6 +12,7 @@
 define('BX_DOL_PROFILE_REDIRECT_PROFILE', 'profile');
 define('BX_DOL_PROFILE_REDIRECT_LAST', 'last');
 define('BX_DOL_PROFILE_REDIRECT_CUSTOM', 'custom');
+define('BX_DOL_PROFILE_REDIRECT_HOMEPAGE', 'homepage');
 
 define('BX_DOL_PROFILE_ACTIVATE_ALWAYS', 'on');
 define('BX_DOL_PROFILE_ACTIVATE_NEVER', 'off');
@@ -111,7 +112,7 @@ class BxBaseModProfileModule extends BxBaseModGeneralModule implements iBxDolCon
         $CNF = &$this->_oConfig->CNF;
 
         $aResult = array();
-        $aChoices = array(BX_DOL_PROFILE_REDIRECT_PROFILE, BX_DOL_PROFILE_REDIRECT_LAST, BX_DOL_PROFILE_REDIRECT_CUSTOM);
+        $aChoices = array(BX_DOL_PROFILE_REDIRECT_PROFILE, BX_DOL_PROFILE_REDIRECT_LAST, BX_DOL_PROFILE_REDIRECT_CUSTOM, BX_DOL_PROFILE_REDIRECT_HOMEPAGE);
         foreach($aChoices as $sChoice) 
             $aResult[] = array('key' => $sChoice, 'value' => _t($CNF['T']['option_redirect_aadd_' . $sChoice]));
 
@@ -878,6 +879,34 @@ class BxBaseModProfileModule extends BxBaseModGeneralModule implements iBxDolCon
         return $this->_serviceEntityForm ('editDataForm', $iContentId, $this->_oConfig->CNF['OBJECT_FORM_ENTRY_DISPLAY_EDIT_COVER']);
     }
 
+    /**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-page_blocks Page Blocks
+     * @subsubsection bx_base_profile-entity_cover entity_cover
+     * 
+     * @code bx_srv('bx_persons', 'entity_cover', [...]); @endcode
+     * 
+     * Get cover
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModProfileModule::serviceEntityCover
+     */
+    /** 
+     * @ref bx_base_general-entity_cover "entity_cover"
+     */
+    public function serviceEntityCover ($iContentId = 0)
+    {
+        $iContentId = $this->_getContent($iContentId, false);
+        if($iContentId === false)
+            return false;
+        
+        $sModule = $this->_oConfig->getName();
+        $aData = BxDolRequest::serviceExists($sModule, 'get_all') ? BxDolService::call($sModule, 'get_all', array(array('type' => 'id', 'id' => $iContentId))) : array();
+        
+        return $this->_oTemplate->getBlockCover($aData, $sModule);
+    }
+    
 	/**
      * Entry comments
      */

+ 59 - 12
modules/base/profile/classes/BxBaseModProfileTemplate.php

@@ -250,11 +250,43 @@ class BxBaseModProfileTemplate extends BxBaseModGeneralTemplate
 
         return $aTmplVarsMeta;
     }
-
-    /**
-     * Get profile cover
-     */
-    function setCover ($oPage, $aData, $sTemplateName = 'cover.html')
+    
+    function getBlockCover ($aData)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aData[$CNF['FIELD_ID']], $this->MODULE);
+        if(!$oProfile)
+            return '';
+        
+        $aVars = $this->prepareCover($aData, false);
+        
+        $oConnectionFriends = BxDolConnection::getObjectInstance('sys_profiles_friends');
+        $oConnectionFollowing = BxDolConnection::getObjectInstance('sys_profiles_subscriptions');
+        $aVars2 = [
+            'bx_if:show_following' => array (
+                'condition' => $oConnectionFollowing && $this->_oModule->serviceActAsProfile(),
+                'content' => array (
+                    'count' => $oConnectionFollowing->getConnectedContentCount($oProfile->id(), false),
+                ),
+            ),
+            'bx_if:show_followers' => array (
+                'condition' => $oConnectionFollowing,
+                'content' => array (
+                    'count' => $oConnectionFollowing->getConnectedInitiatorsCount($oProfile->id(), false),
+                ),
+            ),
+            'bx_if:show_friends' => array (
+                'condition' => $oConnectionFriends && $this->_oModule->serviceActAsProfile(),
+                'content' => array (
+                    'count' => $oConnectionFriends->getConnectedContentCount($oProfile->id(), true),
+                ),
+            ),
+            'info' => isset($CNF['FIELD_TEXT']) ? $aData[$CNF['FIELD_TEXT']] : ''
+        ];
+       
+        return $this->parseHtmlByName('cover_block.html', array_merge($aVars, $aVars2));
+    }
+    function prepareCover($aData, $oPage)
     {
         $CNF = &$this->_oConfig->CNF;
         $oModule = $this->getModule();
@@ -396,24 +428,31 @@ class BxBaseModProfileTemplate extends BxBaseModGeneralTemplate
         }
 
         $sActionsMenu = $oModule->serviceEntityAllActions();
-        if(!$sActionsMenu && ($oMenu = BxTemplMenu::getObjectInstance($CNF['OBJECT_MENU_ACTIONS_VIEW_ENTRY'])) !== false)
+        if(!$sActionsMenu && ($oMenu = BxTemplMenu::getObjectInstance($CNF['OBJECT_MENU_ACTIONS_VIEW_ENTRY'], $this)) !== false)
             $sActionsMenu = $oMenu->getCode();
 
+        $sMetaMenu = '';
+        if(!empty($CNF['OBJECT_MENU_VIEW_ENTRY_META']) && ($oMetaMenu = BxTemplMenu::getObjectInstance($CNF['OBJECT_MENU_VIEW_ENTRY_META'])) !== false) {
+            $oMetaMenu->setContentId($aData[$CNF['FIELD_ID']]);
+            $oMetaMenu->setContentPublic($this->isProfilePublic($aData));
+            $sMetaMenu = $oMetaMenu->getCode();
+        }
+
         // generate html
         $aVars = array (
             'module' => $this->_oConfig->getName(),
-
             'id' => $aData[$CNF['FIELD_ID']],
             'content_url' => $sUrl,
             'title' => $sTitle,
-            //'menu' => BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_SUBMENU_VIEW_ENTRY_COVER'])->getCode(), // TODO: check if menu is used somewhere
-
             'action_menu' => $sActionsMenu,
-
             'bx_if:show_avatar' => array(
                 'condition' => $bShowAvatar,
                 'content' => $aShowAvatar
             ),
+            'bx_if:show_avatar_placeholder' => array(
+                'condition' => !$bShowAvatar,
+                'content' => array()
+            ),
             'picture_popup' => $sPicturePopup,
             'cover_popup' => $sCoverPopup,
             'cover_popup_id' => $sCoverPopupId,
@@ -423,9 +462,17 @@ class BxBaseModProfileTemplate extends BxBaseModGeneralTemplate
             'additional_code' => $sAddCode,
             'cover_href' => !$aData[$CNF['FIELD_COVER']] && $bIsAllowEditCover ? $sUrlCoverChange : 'javascript:void(0);',
             'badges' => $oModule->serviceGetBadges($aData[$CNF['FIELD_ID']]),
+            'meta' => $sMetaMenu,
         );
-
-        BxDolCover::getInstance($this)->set($aVars, $sTemplateName);
+        
+        return $aVars;
+    }
+    /**
+     * Get profile cover
+     */
+    function setCover ($oPage, $aData, $sTemplateName = 'cover.html')
+    {
+        BxDolCover::getInstance($this)->set($this->prepareCover($aData, $oPage), $sTemplateName);
     }
 
     /**

+ 14 - 2
modules/base/profile/classes/BxBaseModProfileUploaderCoverCrop.php

@@ -49,7 +49,12 @@ class BxBaseModProfileUploaderCoverCrop extends BxTemplUploaderCrop
         if (!$s || !$iContentId) // if we're creating new profile return all ghosts
             return $s;
 
-        $a = json_decode($s, true);
+        $a = array();
+        if ($sFormat == 'array')
+            $a = $s;
+        else if ($sFormat == 'json')
+            $a = json_decode($s, true);
+
         if (!$a)
             return $s;
 
@@ -65,7 +70,14 @@ class BxBaseModProfileUploaderCoverCrop extends BxTemplUploaderCrop
 
         }
 
-        return json_encode($aResult);
+        if ('array' == $sFormat) {
+            return $a;
+        }
+        else if ('json' == $sFormat) {
+            return json_encode($a);
+        } else { // html format is not suported for this data type
+            return false;
+        }
     }
 
     protected function isAdmin ($iContentId = 0)

+ 14 - 2
modules/base/profile/classes/BxBaseModProfileUploaderPictureCrop.php

@@ -49,7 +49,12 @@ class BxBaseModProfileUploaderPictureCrop extends BxTemplUploaderCrop
         if (!$s || !$iContentId) // if we're creating new profile return all ghosts
             return $s;
 
-        $a = json_decode($s, true);
+        $a = array();
+        if ($sFormat == 'array')
+            $a = $s;
+        else if ($sFormat == 'json')
+            $a = json_decode($s, true);
+
         if (!$a)
             return $s;
 
@@ -64,7 +69,14 @@ class BxBaseModProfileUploaderPictureCrop extends BxTemplUploaderCrop
                 $aResult[] = $aFile;            
         }
 
-        return json_encode($aResult);
+        if ('array' == $sFormat) {
+            return $a;
+        }
+        else if ('json' == $sFormat) {
+            return json_encode($a);
+        } else { // html format is not suported for this data type
+            return false;
+        }
     }
 
     protected function isAdmin ($iContentId = 0)

+ 70 - 0
modules/base/profile/template/cover_block.html

@@ -0,0 +1,70 @@
+<div class="bx-menu-toolbar-padding">
+    <div class="bx-base-pofile-cover-wrapper __class__ bx-def-centered bx-def-box-sizing">
+        <div class="bx-base-pofile-cover bx-def-cover-color-bg bx-def-box-sizing">
+            <div class="bx-base-pofile-cover-image __add_class__" style="height: 15rem;">
+                <a class="bx-base-pofile-cover-image bx-def-box-sizing" href="__cover_href__" onclick="$('#__cover_popup_id__').dolPopupImage('__cover_url__', this)">
+                    <img class="bx-base-pofile-cover-image __img_class__" style="background-image:url(__cover_url__)" src="<bx_icon_url:spacer.gif />"/>
+                </a>
+                <div class="bx-cover-gradient"></div>
+            </div>
+            <div class="bx-base-pofile-cover-info">
+                <div class="bx-base-pofile-ci-cnt bx-def-padding-leftright" style="justify-content: center">
+                    <bx_if:show_avatar>
+                        <div class="bx-base-pofile-cover-thumb __add_class__">
+                            <a class="bx-base-pofile-cover-thumb" href="__picture_href__" onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();">
+                                <bx_if:show_ava_image>
+                                    <img class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size __img_class__" src="__ava_url__" />
+                                </bx_if:show_ava_image>
+                                <bx_if:show_ava_letter>
+                                    <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size bx-def-border" style="background-color:rgba(__color__)">__letter__</p>
+                                </bx_if:show_ava_letter>
+                            </a>
+                            <bx_if:show_online>
+                                <div class="bx-base-pofile-unit-online"></div>
+                            </bx_if:show_online>
+                        </div>
+                    </bx_if:show_avatar>
+                </div>
+            </div>
+        </div>
+		<div class="bx-base-pofile-cover-user bx-def-margin-sec-topbottom" style="align-items: center">
+			<div class="bx-base-profile-cover-title-bages">
+				<h1 class="bx-def-unit-info">__title__ </h1>
+				<div class="bx-base-profile-cover-bages bx-base-bages-container">
+					__badges__
+				</div>
+			</div>
+			<div class="bx-def-margin-sec" >__info__</div>
+			<div class="bx-base-pofile-cover-actions bx-def-margin-sec-leftright-neg" onclick="event.stopPropagation();">__action_menu__</div>
+		</div>
+    </div>
+    __cover_popup__
+    __picture_popup__
+	<div class="bx-def-margin-sec bx-base-pofile-informers" >
+		<div>
+			<bx_if:show_following>
+				following: __count__<br>
+			</bx_if:show_following>
+		</div>
+		<div>
+			<bx_if:show_followers>
+				followers: __count__<br>
+			</bx_if:show_followers>
+		</div>
+		<div>
+			<bx_if:show_friends>
+				friends: __count__<br>
+			</bx_if:show_friends>
+		</div>
+	</div>
+</div>
+<style>
+	#bx-persons-view-actions-all{
+		justify-content: center;
+	}
+	.bx-base-pofile-informers{
+		display: flex;
+		justify-content: space-between;
+		
+	}
+</style>

+ 0 - 3
modules/base/profile/template/css/main.css

@@ -1,7 +1,4 @@
-@import url(../../../general/template/css/main.css);
-
 /* browse unit */
-
 .bx-base-pofile-unit {
     width:184px;
     width:11.5rem;

+ 1 - 1
modules/base/text/classes/BxBaseModTextModule.php

@@ -567,7 +567,7 @@ class BxBaseModTextModule extends BxBaseModGeneralModule implements iBxDolConten
             $sAction = 'deferred';
 
         $aParams = $this->_alertParamsAdd($aContentInfo);
-        bx_alert('system', 'prepare_alert_params', 0, 0, array('unit'=> $this->getName(), 'action' => $sAction, 'object_id' => $iId, 'sender_id' => $iAuthorId, 'extras' => &$aParams));
+        bx_alert('system', 'prepare_alert_params', 0, 0, array('unit'=> $this->getName(), 'action' => &$sAction, 'object_id' => &$iId, 'sender_id' => &$iAuthorId, 'extras' => &$aParams));
         bx_alert($this->getName(), $sAction, $iId, $iAuthorId, $aParams);
     }
 

+ 1 - 2
modules/base/text/classes/BxBaseModTextTemplate.php

@@ -786,8 +786,7 @@ class BxBaseModTextTemplate extends BxBaseModGeneralTemplate
     
     function mediaExif ($aMediaInfo, $iProfileId = false, $sFuncAuthorDesc = '', $sTemplateName = 'media-exif.html') 
     {
-
-        if (!$aMediaInfo['exif'])
+        if (empty($aMediaInfo['exif']))
             return '';
 
         $a = unserialize($aMediaInfo['exif']);

+ 0 - 2
modules/base/text/template/css/main.css

@@ -1,5 +1,3 @@
-@import url(../../../general/template/css/main.css);
-
 /* unit */
 .bx-base-text-unit h2,
 .bx-base-text-unit h1 {

+ 1 - 3
modules/base/text/template/css/polls.css

@@ -186,8 +186,6 @@ div.bx-base-text-pr-graph .bx-base-text-prg-text {
 .bx-base-text-poll-embed {
     width: 100%;
     height: 240px;
-    margin-left: -0.5rem;
-    margin-right: -0.5rem;
 }
 
 .bx-page-iframe .bx-base-text-poll {
@@ -195,7 +193,7 @@ div.bx-base-text-pr-graph .bx-base-text-prg-text {
     height: 100vh;
 }
 .bx-page-iframe .bx-base-text-showcase-type-single .bx-base-text-poll {
-    width: 100vw;
+    width: 100%;
 }
 .bx-page-iframe .bx-base-text-poll-cnt {
     height: 100%;

+ 1 - 1
modules/base/text/template/poll_items_showcase.html

@@ -1,4 +1,4 @@
-<div id="__html_id__" class="bx-base-text-polls-showcase bx-base-text-showcase-type-__type__">__polls__</div>
+<div id="__html_id__" class="bx-base-text-polls-showcase bx-base-text-showcase-type-__type__ bx-def-margin-sec-leftright-neg">__polls__</div>
 <script>
     $(document).ready(function() {
         __js_object__.initFlickity('#__html_id__');

+ 0 - 1
modules/base/text/template/unit_meta_item.html

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

+ 41 - 0
modules/boonex/accounts/classes/BxAccntGridAdministration.php

@@ -58,6 +58,9 @@ class BxAccntGridAdministration extends BxBaseModProfileGridAdministration
                         case 'email_and_phone':
                             $this->_aOptions['source'] .= " AND (`ta`.`email_confirmed`='0' OR `ta`.`phone_confirmed`='0')";
                             break;
+                        case 'email_or_phone':
+                            $this->_aOptions['source'] .= " AND (`ta`.`email_confirmed`='0' AND `ta`.`phone_confirmed`='0')";
+                            break;
                     }
                     break;
 
@@ -158,6 +161,44 @@ class BxAccntGridAdministration extends BxBaseModProfileGridAdministration
             echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
         }
     }
+	
+	public function performActionSendMessage()
+    {
+		$sAction = 'send_message';
+		
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds))
+            return echoJson(array());
+		
+		$oForm = BxDolForm::getObjectInstance('bx_accounts_account', 'bx_accounts_send_test');
+        if (!$oForm)
+            return '';
+		
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?' . bx_encode_url_params($_GET, array('_r'));
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+        	$aIdsAffected = array();
+			foreach($aIds as $iId) {
+				if(sendMail(BxDolAccount::getInstance()->getEmail($iId), $oForm->getCleanValue('message_subject'), $oForm->getCleanValue('message_text'), 0, [], BX_EMAIL_MASS, 'text', false, ['From' => "=?UTF-8?B?" . base64_encode(getParam('site_title')) . "?= <" . getParam('site_email_notify') . ">"], false)){
+					$aIdsAffected[] = $iId;
+				}	
+			}
+			
+            echoJson(count($aIdsAffected) > 0 ? array('grid' => $this->getCode(false), 'blink' => $aIdsAffected) : array('msg' => _t($CNF['T']['grid_action_err_perform'])));
+        }
+        else {
+            
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('bx-account-send-message', _t('_bx_accounts_form_display_account_send_message'), $this->_oModule->_oTemplate->parseHtmlByName('manage_item.html', array(
+                'form_id' => $oForm->id,
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
     
     public function performActionAdd()
     {

+ 9 - 0
modules/boonex/accounts/install/langs/en.xml

@@ -9,6 +9,7 @@
     <string name="_bx_accounts_form_display_account_settings_email_popup"><![CDATA[Edit Email]]></string>
     <string name="_bx_accounts_form_display_account_create_popup"><![CDATA[Create new Account]]></string>
     <string name="_bx_accounts_form_display_account_settings_password_popup"><![CDATA[Reset Password]]></string>
+	 <string name="_bx_accounts_form_display_account_send_message"><![CDATA[Send test email]]></string>
 
     <string name="_bx_accnt_page_title_sys_manage_administration"><![CDATA[Manage All Accounts]]></string>
     <string name="_bx_accnt_page_title_manage"><![CDATA[Manage Accounts]]></string>
@@ -78,6 +79,7 @@
     <string name="_bx_accnt_grid_action_title_adm_unlock_account"><![CDATA[Unlock]]></string>
     <string name="_bx_accnt_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
     <string name="_bx_accnt_grid_action_title_adm_delete_with_content"><![CDATA[Delete With Content]]></string>
+	<string name="_bx_accnt_grid_action_title_adm_send_message"><![CDATA[Send email]]></string>
     <string name="_bx_accnt_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
     <string name="_bx_accnt_grid_action_title_adm_more_add"><![CDATA[Add new]]></string>
     <string name="_bx_accnt_grid_action_err_delete"><![CDATA[Cannot delete the selected account(s).]]></string>
@@ -91,6 +93,13 @@
 
     <string name="_bx_accnt_form_login_input_caption_system_email_confirmed"><![CDATA[Email confirmed]]></string>
     <string name="_bx_accnt_form_account_input_email_confirmed"><![CDATA[Email confirmed]]></string>
+	<string name="_bx_accnt_form_account_input_caption_system_message_subject"><![CDATA[Subject]]></string>
+    <string name="_bx_accnt_form_account_input_caption_message_subject"><![CDATA[Subject]]></string>
+	<string name="_bx_accnt_form_account_input_message_subject_error"><![CDATA[Subject can't be empty]]></string>
+	<string name="_bx_accnt_form_account_input_caption_system_message_text"><![CDATA[Text]]></string>
+    <string name="_bx_accnt_form_account_input_caption_message_text"><![CDATA[Text]]></string>
+	<string name="_bx_accnt_form_account_input_message_text_error"><![CDATA[Text can't be empty]]></string>
+	<string name="_bx_accnt_form_display_send_message"><![CDATA[Send email]]></string>
  
     <string name="_bx_accnt_txt_more"><![CDATA[{0} more]]></string>
     <string name="_bx_accnt_txt_see_more"><![CDATA[See more]]></string>

+ 1 - 0
modules/boonex/accounts/install/sql/enable.sql

@@ -103,6 +103,7 @@ INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon
 ('bx_accounts_administration', 'bulk', 'delete', '_bx_accnt_grid_action_title_adm_delete', '', 0, 1, 6),
 ('bx_accounts_administration', 'bulk', 'delete_with_content', '_bx_accnt_grid_action_title_adm_delete_with_content', '', 0, 1, 7),
 ('bx_accounts_administration', 'bulk', 'export', '_bx_accnt_grid_action_title_adm_export', '', 0, 0, 8),
+('bx_accounts_administration', 'bulk', 'send_message', '_bx_accnt_grid_action_title_adm_send_message', '', 0, 0, 9),
 ('bx_accounts_administration', 'single', 'edit_email', '_bx_accnt_grid_action_title_adm_edit_email', '', 0, 0, 0),
 ('bx_accounts_administration', 'single', 'reset_password', '_bx_accnt_grid_action_title_adm_reset_password', '', 0, 0, 0),
 ('bx_accounts_administration', 'single', 'resend_remail', '_bx_accnt_grid_action_title_adm_resend_remail', '', 0, 0, 0),

+ 13 - 3
modules/boonex/accounts/install/sql/install.sql

@@ -7,7 +7,8 @@ INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_att
 
 INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
 ('bx_accounts_account_settings_email', @sName, 'bx_accounts_account', '_sys_form_display_account_settings_email', 0),
-('bx_accounts_account_create', @sName, 'bx_accounts_account', '_sys_form_display_account_create', 0);
+('bx_accounts_account_create', @sName, 'bx_accounts_account', '_sys_form_display_account_create', 0),
+('bx_accounts_send_test', @sName, 'bx_accounts_account', '_bx_accnt_form_display_send_message', 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_accounts_account', @sName, 'email', '', '', 0, 'text', '_sys_form_login_input_caption_system_email', '_sys_form_account_input_email', '', 1, 0, 0, '', '', '', 'Email', '', '_sys_form_account_input_email_error', 'Xss', '', 0, 0),
@@ -18,7 +19,9 @@ INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `c
 ('bx_accounts_account', @sName, 'password', '', '', 0, 'password', '_sys_form_login_input_caption_system_password', '_sys_form_account_input_password', '', 1, 0, 0, '', '', '', 'Preg', 'a:1:{s:4:"preg";s:38:"~^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}~";}', '_sys_form_account_input_password_error', '', '', 0, 0),
 ('bx_accounts_account', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
 ('bx_accounts_account', @sName, 'do_cancel', '_adm_btn_cancel_submit', '', 0, 'button', '_adm_btn_cancel_submit', '', '', 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_accounts_account', @sName, 'email_confirmed', '1', '', 1, 'switcher', '_bx_accnt_form_login_input_caption_system_email_confirmed', '_bx_accnt_form_account_input_email_confirmed', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0);
+('bx_accounts_account', @sName, 'email_confirmed', '1', '', 1, 'switcher', '_bx_accnt_form_login_input_caption_system_email_confirmed', '_bx_accnt_form_account_input_email_confirmed', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_accounts_account', @sName, 'message_subject', '', '', 0, 'text', '_bx_accnt_form_account_input_caption_system_message_subject', '_bx_accnt_form_account_input_caption_system_message_subject', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_accnt_form_account_input_message_subject_error', 'Xss', '', 1, 0),
+('bx_accounts_account', @sName, 'message_text', '', '', 0, 'textarea', '_bx_accnt_form_account_input_caption_system_message_text', '_bx_accnt_form_account_input_caption_message_text', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_accnt_form_account_input_message_text_error', 'Xss', '', 1, 0);
 
 
 INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
@@ -35,7 +38,14 @@ INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_fo
 ('bx_accounts_account_create', 'email_confirmed', 2147483647, 1, 4),
 ('bx_accounts_account_create', 'controls', 2147483647, 1, 5),
 ('bx_accounts_account_create', 'do_submit', 2147483647, 1, 6),
-('bx_accounts_account_create', 'do_cancel', 2147483647, 1, 7);
+('bx_accounts_account_create', 'do_cancel', 2147483647, 1, 7),
+
+('bx_accounts_send_test', 'message_subject', 2147483647, 1, 1),
+('bx_accounts_send_test', 'message_text', 2147483647, 1, 2),
+('bx_accounts_send_test', 'controls', 2147483647, 1, 3),
+('bx_accounts_send_test', 'do_submit', 2147483647, 1, 4),
+('bx_accounts_send_test', 'do_cancel', 2147483647, 1, 5);
+
 
 
 -- STUDIO PAGE & WIDGET

+ 19 - 0
modules/boonex/accounts/template/manage_item.html

@@ -0,0 +1,19 @@
+<div class="bx-pgt-new-key">
+    <div class="bx-pgt-new-key-cnt">
+        __form__
+        <script language="javascript">
+            $(document).ready(function () {
+                $("#__form_id__").ajaxForm({ 
+                    dataType: "json",
+                    beforeSubmit: function (formData, jqForm, options) {
+                        bx_loading($("#__form_id__"), true);
+                    },
+                    success: function (data) {
+                        $(".bx-popup-applied:visible").dolPopupHide();
+                        glGrids.__object__.processJson(data, '__action__');
+                    }
+                });
+            });
+        </script>
+    </div>
+</div>

+ 1 - 1
modules/boonex/ads/classes/BxAdsDb.php

@@ -606,7 +606,7 @@ class BxAdsDb extends BxBaseModTextDb
         if(!isset($aSet[$CNF['FIELD_OFR_ADDED']]))
             $aSet[$CNF['FIELD_OFR_ADDED']] = time();
 
-        return (int)$this->query("INSERT INTO `" . $CNF['TABLE_OFFERS'] . "` SET " . $this->arrayToSQL($aSet)) > 0;
+        return (int)$this->query("INSERT INTO `" . $CNF['TABLE_OFFERS'] . "` SET " . $this->arrayToSQL($aSet)) > 0 ? $this->lastId() : false;
     }
 
     public function updateOffer($aSet, $aWhere)

+ 1 - 1
modules/boonex/ads/classes/BxAdsFormEntry.php

@@ -187,7 +187,7 @@ class BxAdsFormEntry extends BxBaseModTextFormEntry
 
     protected function genCustomViewRowValuePrice(&$aInput)
     {
-        return isset($aInput['value']) && $aInput['value'] !== '' ? getParam('currency_sign') . bx_process_output($aInput['value']) : null;
+        return isset($aInput['value']) && $aInput['value'] !== '' ? _t_format_currency(bx_process_output($aInput['value'])) : null;
     }
 
     protected function genCustomViewRowValueQuantity(&$aInput)

+ 22 - 4
modules/boonex/ads/classes/BxAdsModule.php

@@ -1527,10 +1527,28 @@ class BxAdsModule extends BxBaseModTextModule
         if(empty($aOffer) || !is_array($aOffer))
             return false;
 
-        return array('redirect' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php', array(
-            'i' => $CNF['URI_VIEW_ENTRY'], 
-            $CNF['FIELD_ID'] => $aOffer[$CNF['FIELD_OFR_CONTENT']]
-        )));
+        $iContent = (int)$aOffer[$CNF['FIELD_OFR_CONTENT']];
+        $aContent = $this->_oDb->getContentInfoById($iContent);
+        $iContentAuthor = (int)$aContent[$CNF['FIELD_AUTHOR']];
+
+        $aReturn = array(
+            'redirect' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php', array(
+                'i' => $CNF['URI_VIEW_ENTRY'], 
+                $CNF['FIELD_ID'] => $aOffer[$CNF['FIELD_OFR_CONTENT']]
+            ))
+        );
+
+        $oPayments = BxDolPayments::getInstance();
+        $aResult = $oPayments->addToCart($iContentAuthor, $this->getName(), $iContent, $aOffer[$CNF['FIELD_OFR_QUANTITY']]);
+        if(!empty($aResult) && is_array($aResult)) {
+            if(!empty($aResult['message']))
+                $aReturn['msg'] = $aResult['message'];
+
+            if(isset($aResult['code']) && (int)$aResult['code'] == 0)
+                $aReturn['redirect'] = $oPayments->getCartUrl($iContentAuthor);
+        }
+
+        return $aReturn;
     }
 
     public function processMetasAdd($iContentId)

+ 1 - 1
modules/boonex/ads/install/sql/enable.sql

@@ -375,7 +375,7 @@ INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES
 -- MENU: dashboard manage tools
 SET @iManageMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard_manage_tools' LIMIT 1);
 INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
-('sys_account_dashboard_manage_tools', 'bx_ads', 'ads-administration', '_bx_ads_menu_item_title_system_admt_ads', '_bx_ads_menu_item_title_admt_ads', 'page.php?i=ads-administration', '', '_self', 'ad col-green2', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
+('sys_account_dashboard_manage_tools', 'bx_ads', 'ads-administration', '_bx_ads_menu_item_title_system_admt_ads', '_bx_ads_menu_item_title_admt_ads', 'page.php?i=ads-administration', '', '_self', 'ad', 'a:2:{s:6:"module";s:6:"bx_ads";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
 
 -- MENU: account dashboard
 SET @iDashboardMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard' LIMIT 1);

+ 0 - 2
modules/boonex/ads/template/css/main.css

@@ -1,5 +1,3 @@
-@import url(../../../../base/text/template/css/main.css);
-
 /*--- Categories ---*/
 .bx-ads-subcategories .bx-ads-category:first-child {
     padding-top: 0;

+ 0 - 3
modules/boonex/ads/template/unit.html

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

+ 0 - 1
modules/boonex/ads/template/unit_full.html

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

+ 0 - 3
modules/boonex/ads/template/unit_full_private.html

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

+ 0 - 1
modules/boonex/ads/template/unit_gallery.html

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

+ 0 - 3
modules/boonex/ads/template/unit_gallery_private.html

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

+ 0 - 3
modules/boonex/ads/template/unit_live_search.html

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

+ 0 - 1
modules/boonex/ads/template/unit_meta_item.html

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

+ 0 - 3
modules/boonex/ads/template/unit_private.html

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

+ 0 - 1
modules/boonex/ads/template/unit_showcase.html

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

+ 4 - 0
modules/boonex/albums/classes/BxAlbumsConfig.php

@@ -20,7 +20,9 @@ class BxAlbumsConfig extends BxBaseModTextConfig
             'add-images-to-album' => 'checkAllowedEdit',
             'edit-album' => 'checkAllowedEdit',
             'edit-image' => 'checkAllowedEdit',
+            'move-image' => 'checkAllowedEdit',
             'delete-album' => 'checkAllowedDelete',
+            'delete-image' => 'checkAllowedDelete',
         );
 
         $this->CNF = array (
@@ -82,6 +84,7 @@ class BxAlbumsConfig extends BxBaseModTextConfig
             'PARAM_NUM_RSS' => 'bx_albums_rss_num',
             'PARAM_SEARCHABLE_FIELDS' => 'bx_albums_searchable_fields',
             'PARAM_PER_PAGE_FOR_FAVORITES_LISTS' => 'bx_albums_per_page_for_favorites_lists',
+            'PARAM_ORDER_BY_GHOSTS' => true,
 
             // objects
             'OBJECT_STORAGE' => 'bx_albums_files',
@@ -124,6 +127,7 @@ class BxAlbumsConfig extends BxBaseModTextConfig
             'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_albums_entry_delete',
             'OBJECT_FORM_MEDIA' => 'bx_albums_media',
             'OBJECT_FORM_MEDIA_DISPLAY_EDIT' => 'bx_albums_media_edit',
+            'OBJECT_FORM_MEDIA_DISPLAY_MOVE' => 'bx_albums_media_move',
             'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_albums_view', // actions menu on view entry page
             'OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL' => 'bx_albums_view_actions', // all actions menu on view entry page
             'OBJECT_MENU_ACTIONS_VIEW_MEDIA' => 'bx_albums_view_media', // actions menu on view media page

+ 11 - 1
modules/boonex/albums/classes/BxAlbumsDb.php

@@ -57,7 +57,17 @@ class BxAlbumsDb extends BxBaseModTextDb
 
     public function getMediaInfoById($iMediaId)
     {
-        $sQuery = $this->prepare ("SELECT `f2e`.*, `f`.`added` FROM `" . $this->_oConfig->CNF['TABLE_FILES2ENTRIES'] . "` AS `f2e` INNER JOIN `" . $this->_oConfig->CNF['TABLE_FILES'] . "` AS `f` ON (`f`.`id` = `f2e`.`file_id`) INNER JOIN `" . $this->_oConfig->CNF['TABLE_ENTRIES'] . "` AS `e` ON (`e`.`id` = `f2e`.`content_id`) WHERE `f2e`.`id` = ?", $iMediaId);
+        $CNF = &$this->_oConfig->CNF;
+
+        $sSelectClause = "`f2e`.*, `f`.`added`";
+        $sJoinClause = "INNER JOIN `" . $CNF['TABLE_FILES'] . "` AS `f` ON (`f`.`id` = `f2e`.`file_id`) INNER JOIN `" . $CNF['TABLE_ENTRIES'] . "` AS `e` ON (`e`.`id` = `f2e`.`content_id`)";
+
+        if($CNF['PARAM_ORDER_BY_GHOSTS']) {
+            $sSelectClause .= ", `g`.`order` as `gorder`";
+            $sJoinClause .= $this->prepareAsString("INNER JOIN `sys_storage_ghosts` AS `g` ON `g`.`id`=`f2e`.`file_id` AND `g`.`content_id`=`f2e`.`content_id` AND `g`.`object`=?", $CNF['OBJECT_STORAGE']);
+        }
+
+        $sQuery = $this->prepare("SELECT " . $sSelectClause . " FROM `" . $CNF['TABLE_FILES2ENTRIES'] . "` AS `f2e` " . $sJoinClause . " WHERE `f2e`.`id` = ?", $iMediaId);
         return $this->getRow($sQuery);
     }
 

+ 5 - 0
modules/boonex/albums/classes/BxAlbumsFormEntry.php

@@ -18,6 +18,11 @@ class BxAlbumsFormEntry extends BxBaseModTextFormEntry
     {
         $this->MODULE = 'bx_albums';
         parent::__construct($aInfo, $oTemplate);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if (isset($CNF['FIELD_PHOTO']) && isset($this->aInputs[$CNF['FIELD_PHOTO']]))
+            $this->aInputs[$CNF['FIELD_PHOTO']]['init_reordering'] = true;
     }
 
     public function processFiles ($sFieldFile, $iContentId = 0, $isAssociateWithContent = false)

+ 72 - 0
modules/boonex/albums/classes/BxAlbumsFormMedia.php

@@ -0,0 +1,72 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Albums Albums
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Create/Edit entry form
+ */
+class BxAlbumsFormMedia extends BxTemplFormView
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_iMediaId;
+    protected $_aMediaInfo;
+
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_albums';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct($aInfo, $oTemplate);
+    }
+
+    public function initChecker($aValues = array (), $aSpecificValues = array())
+    {
+        if(!empty($this->_aMediaInfo) && is_array($this->_aMediaInfo))
+            $aValues = $this->_aMediaInfo;
+
+        parent::initChecker($aValues, $aSpecificValues);
+    }
+
+    public function initForm($aAction, $iMediaId)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $this->_iMediaId = $iMediaId;
+        $this->_aMediaInfo = $this->_oModule->_oDb->getMediaInfoById($iMediaId);
+
+        $this->aFormAttrs['action'] = BX_DOL_URL_ROOT . $this->_oModule->_oConfig->getBaseUri() . $aAction . '_media/' . $iMediaId;
+
+        if(isset($this->aInputs['content_id'])) {
+            $aAlbums = $this->_oModule->_oDb->getEntriesBy(array('type' => 'author', 'author' => $this->_aMediaInfo['author']));
+            foreach($aAlbums as $aAlbum)
+                $this->aInputs['content_id']['values'][] = ['key' => $aAlbum[$CNF['FIELD_ID']], 'value' => $aAlbum[$CNF['FIELD_TITLE']]];
+        }
+    }
+    
+    public function update($val, $aValsToAdd = array(), &$aTrackTextFieldsChanges = null)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $sField = 'content_id';
+        if(isset($this->aInputs[$sField])) {
+            $iContentId = $this->getCleanValue($sField);
+
+            $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+            if(!$oStorage->updateGhostsContentId($this->_aMediaInfo['file_id'], $this->_aMediaInfo['author'], $iContentId))
+                return false;
+        }
+
+        return parent::update($val, $aValsToAdd, $aTrackTextFieldsChanges);
+    }
+}
+
+/** @} */

+ 18 - 0
modules/boonex/albums/classes/BxAlbumsMenuViewActionsMedia.php

@@ -89,6 +89,24 @@ class BxAlbumsMenuViewActionsMedia extends BxAlbumsMenuViewActions
             'object_menu' => $CNF['OBJECT_MENU_ACTIONS_VIEW_MEDIA']
         ));
     }
+	
+    protected function _getMenuItemDeleteImage($aItem)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        return $this->_getMenuItemByNameActions($aItem, array(
+            'object_menu' => $CNF['OBJECT_MENU_ACTIONS_VIEW_MEDIA']
+        ));
+    }
+
+    protected function _getMenuItemMoveImage($aItem)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        return $this->_getMenuItemByNameActions($aItem, array(
+            'object_menu' => $CNF['OBJECT_MENU_ACTIONS_VIEW_MEDIA']
+        ));
+    }
 
     protected function _getMenuItemView($aItem, $aParams = array())
     {

+ 40 - 3
modules/boonex/albums/classes/BxAlbumsModule.php

@@ -715,11 +715,10 @@ class BxAlbumsModule extends BxBaseModTextModule
         $CNF = &$this->_oConfig->CNF;
 
         $iMediaId = (int)$iMediaId;
-    	$aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
 
         $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_MEDIA'], $CNF['OBJECT_FORM_MEDIA_DISPLAY_EDIT']);
-        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'edit_media/' . $iMediaId;
-        $oForm->initChecker($aMediaInfo);
+        $oForm->initForm('edit', $iMediaId);
+        $oForm->initChecker();
 
         if($oForm->isSubmittedAndValid()) {
             if($oForm->update($iMediaId) !== false)
@@ -737,6 +736,44 @@ class BxAlbumsModule extends BxBaseModTextModule
 
         echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
     }
+	
+    public function actionDeleteMedia($iMediaId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        $oUploader = BxDolUploader::getObjectInstance($CNF['OBJECT_UPLOADERS'][0], $CNF['OBJECT_STORAGE'], '');
+        $oUploader->deleteGhost($aMediaInfo['file_id'], bx_get_logged_profile_id());
+        
+        echoJson(['redirect' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aMediaInfo['content_id'])]);
+    }
+
+    public function actionMoveMedia($iMediaId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iMediaId = (int)$iMediaId;
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_MEDIA'], $CNF['OBJECT_FORM_MEDIA_DISPLAY_MOVE']);
+        $oForm->initForm('move', $iMediaId);
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($iMediaId) !== false)
+                $aRes = array('reload' => 1);
+            else
+                $aRes = array('msg' => _t('_bx_albums_txt_err_cannot_perform_action'));
+
+            return echoJson($aRes);
+        }
+
+        $sContent = BxTemplStudioFunctions::getInstance()->transBox('bx-albums-move-media-popup', $this->_oTemplate->parseHtmlByName('media-edit.html', array(
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true)
+        )));
+
+        echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
 
     public function actionGetSiblingMedia($iMediaId, $mixedContext)
     {

+ 37 - 8
modules/boonex/albums/classes/BxAlbumsSearchResultMedia.php

@@ -15,10 +15,9 @@ class BxAlbumsSearchResultMedia extends BxBaseModTextSearchResult
 
     function __construct($sMode = '', $aParams = array())
     {
-       
         $this->sUnitTemplateLiveSearch = 'unit_media_live_search.html';
-		
-		$aParams['unit_views'] = array('gallery' => 'unit_media.html', 'showcase' => 'unit_showcase.html');
+
+        $aParams['unit_views'] = array('gallery' => 'unit_media.html', 'showcase' => 'unit_showcase.html');
         parent::__construct($sMode, $aParams);
 
         $this->aCurrent = array(
@@ -33,7 +32,7 @@ class BxAlbumsSearchResultMedia extends BxBaseModTextSearchResult
             'restriction' => array(
                 'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
                 'album' => array('value' => '', 'field' => 'content_id', 'operator' => '='),
-        		'featured' => array('value' => '', 'field' => 'featured', 'operator' => '<>'),
+                'featured' => array('value' => '', 'field' => 'featured', 'operator' => '<>'),
             ),
             'join' => array(
                 'albums' => array(
@@ -79,13 +78,17 @@ class BxAlbumsSearchResultMedia extends BxBaseModTextSearchResult
 
         switch ($sMode) {
             case 'album':
-                $this->aCurrent['restriction']['album']['value'] = (int)$aParams['album_id'];
-                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . (int)$aParams['album_id']);
+                $iAlbumId = (int)$aParams['album_id'];
+                $this->aCurrent['restriction']['album']['value'] = $iAlbumId;
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iAlbumId);
                 $this->aCurrent['title'] = _t('_bx_albums_page_title_browse_media_in_album');
-                $this->aCurrent['rss']['link'] = 'modules/?r=albums/rss_media/' . $sMode . '/' . (int)$aParams['album_id'];
+                $this->aCurrent['rss']['link'] = 'modules/?r=albums/rss_media/' . $sMode . '/' . $iAlbumId;
                 $this->aCurrent['sorting'] = 'order';
                 $this->sOrderDirection = 'ASC';
                 $this->setProcessPrivateContent(true);
+
+                if($CNF['PARAM_ORDER_BY_GHOSTS'])
+                    $this->_updateCurrentForOrderByGhosts();
                 break;
 
             case 'favorite':
@@ -159,6 +162,10 @@ class BxAlbumsSearchResultMedia extends BxBaseModTextSearchResult
                 $aSql['order'] = " ORDER BY `" . $sTable . "`.`order` " . $sWay . ", `" . $sTable . "`.`id` " . $sWay . " ";
                 break;
 
+            case 'order_by_ghosts':
+                $aSql['order'] = " ORDER BY `g`.`order` " . $sWay . ", `" . $sTable . "`.`id` " . $sWay . " ";
+                break;
+
             case 'last':
                 $aSql['order'] = " ORDER BY `f`.`added` " . $sWay . ", `" . $sTable . "`.`id` " . $sWay . " ";
                 break;
@@ -212,13 +219,18 @@ class BxAlbumsSearchResultMedia extends BxBaseModTextSearchResult
         foreach ($aRestrictions as $sKey) 
             if (0 === strpos($sKey, 'privacy_'))
                 unset($this->aCurrent['restriction'][$sKey]);
-        
+
         switch ($this->aCurrent['sorting']) {
             case 'order':
                 $this->sOrderDirection = $isNext ? 'ASC' : 'DESC';
                 $sOper = $isNext ? '>' : '<';
                 $this->aCurrent['restriction_sql'] = " AND (`{$this->aCurrent['table']}`.`order` {$sOper} {$aMediaInfo['order']} OR (`{$this->aCurrent['table']}`.`order` = {$aMediaInfo['order']} AND `{$this->aCurrent['table']}`.`id` {$sOper} {$aMediaInfo['id']})) ";
                 break;
+            case 'order_by_ghosts':
+                $this->sOrderDirection = $isNext ? 'ASC' : 'DESC';
+                $sOper = $isNext ? '>' : '<';
+                $this->aCurrent['restriction_sql'] = " AND (`g`.`order` {$sOper} {$aMediaInfo['gorder']} OR (`g`.`order` = {$aMediaInfo['gorder']} AND `{$this->aCurrent['table']}`.`id` {$sOper} {$aMediaInfo['id']})) ";
+                break;
             case 'last':
                 $this->aCurrent['restriction_sql'] = " AND (`f`.`added` {$sOper} {$aMediaInfo['added']} OR (`f`.`added` = {$aMediaInfo['added']} AND `{$this->aCurrent['table']}`.`id` {$sOper} {$aMediaInfo['id']})) ";
                 break;
@@ -241,6 +253,23 @@ class BxAlbumsSearchResultMedia extends BxBaseModTextSearchResult
     {
         return BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $this->oModule->_oConfig->CNF['URI_VIEW_MEDIA'] . '&id=' . $a['id']);
     }
+
+    protected function _updateCurrentForOrderByGhosts()
+    {
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        $this->aCurrent['join']['ghosts'] = [
+            'type' => 'INNER',
+            'table' => 'sys_storage_ghosts',
+            'table_alias' => 'g',
+            'mainField' => 'file_id',
+            'on_sql' => $this->oModule->_oDb->prepareAsString(" `g`.`id`=`bx_albums_files2albums`.`file_id` AND `g`.`content_id`=`bx_albums_files2albums`.`content_id` AND `g`.`object`=? ", $CNF['OBJECT_STORAGE']),
+            'joinFields' => array('order'),
+        ];
+        $this->aCurrent['sorting'] = 'order_by_ghosts';
+        $this->sOrderDirection = 'ASC';
+    }
+
 /*
     function displaySearchUnit ($aData)
     {

+ 1 - 1
modules/boonex/albums/classes/BxAlbumsTemplate.php

@@ -384,7 +384,7 @@ class BxAlbumsTemplate extends BxBaseModTextTemplate
         $oModule = BxDolModule::getInstance($this->MODULE);
         $CNF = &$oModule->_oConfig->CNF;
 
-        if (!($aAlbumInfo = $oModule->_oDb->getContentInfoById($aMediaInfo['content_id'])))
+        if (!($aAlbumInfo = $oModule->_oDb->getContentInfoById($aMediaInfo['id'])))
             return '';
 
         return $this->entryAuthor ($aMediaInfo, $aAlbumInfo[$CNF['FIELD_AUTHOR']]);

+ 7 - 0
modules/boonex/albums/install/langs/en.xml

@@ -48,8 +48,11 @@
 
         <string name="_bx_albums_form_media"><![CDATA[Medias]]></string>
         <string name="_bx_albums_form_media_display_edit"><![CDATA[Edit Media]]></string>
+        <string name="_bx_albums_form_media_display_move"><![CDATA[Move Media]]></string>
         <string name="_bx_albums_form_media_input_sys_title"><![CDATA[Caption]]></string>
 	<string name="_bx_albums_form_media_input_title"><![CDATA[Caption]]></string>
+        <string name="_bx_albums_form_media_input_sys_content_id"><![CDATA[Album]]></string>
+	<string name="_bx_albums_form_media_input_content_id"><![CDATA[Album]]></string>
         <string name="_bx_albums_form_media_input_sys_do_submit"><![CDATA[Submit]]></string>
 	<string name="_bx_albums_form_media_input_do_submit"><![CDATA[Submit]]></string>
         <string name="_bx_albums_form_media_input_sys_do_cancel"><![CDATA[Cancel]]></string>
@@ -197,6 +200,10 @@
     <string name="_bx_albums_menu_item_title_add_images"><![CDATA[Add/Edit Pictures]]></string>
     <string name="_bx_albums_menu_item_title_system_edit_image"><![CDATA[Edit Image]]></string>
     <string name="_bx_albums_menu_item_title_edit_image"><![CDATA[Edit Image]]></string>
+    <string name="_bx_albums_menu_item_title_system_delete_image"><![CDATA[Delete Image]]></string>
+    <string name="_bx_albums_menu_item_title_delete_image"><![CDATA[Delete Image]]></string>
+    <string name="_bx_albums_menu_item_title_system_move_image"><![CDATA[Move Image To]]></string>
+    <string name="_bx_albums_menu_item_title_move_image"><![CDATA[Move Image To]]></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>

+ 6 - 1
modules/boonex/albums/install/sql/enable.sql

@@ -275,7 +275,10 @@ INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES
 INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
 ('bx_albums_view_media', 'bx_albums', 'add-images-to-album', '_bx_albums_menu_item_title_system_add_images', '_bx_albums_menu_item_title_add_images', 'page.php?i=add-images&id={content_id}', '', '', 'plus', '', 2147483647, 1, 0, 10),
 ('bx_albums_view_media', 'bx_albums', 'edit-album', '_bx_albums_menu_item_title_system_edit_album', '_bx_albums_menu_item_title_edit_album', 'page.php?i=edit-album&id={content_id}', '', '', 'pencil-alt', '', 2147483647, 1, 0, 20),
-('bx_albums_view_media', 'bx_albums', 'edit-image', '_bx_albums_menu_item_title_system_edit_image', '_bx_albums_menu_item_title_edit_image', 'javascript:void(0)', 'javascript:{js_object}.editMedia(this, {media_id});', '', 'pencil-alt', '', 2147483647, 1, 0, 30);
+('bx_albums_view_media', 'bx_albums', 'edit-image', '_bx_albums_menu_item_title_system_edit_image', '_bx_albums_menu_item_title_edit_image', 'javascript:void(0)', 'javascript:{js_object}.editMedia(this, {media_id});', '', 'pencil-alt', '', 2147483647, 1, 0, 30),
+('bx_albums_view_media', 'bx_albums', 'delete-image', '_bx_albums_menu_item_title_system_delete_image', '_bx_albums_menu_item_title_delete_image', 'javascript:void(0)', 'javascript:{js_object}.deleteMedia(this, {media_id});', '', 'remove', '', 2147483647, 1, 0, 40),
+('bx_albums_view_media', 'bx_albums', 'move-image', '_bx_albums_menu_item_title_system_move_image', '_bx_albums_menu_item_title_move_image', 'javascript:void(0)', 'javascript:{js_object}.moveMedia(this, {media_id});', '', 'exchange-alt', '', 2147483647, 1, 0, 50);
+
 
 -- MENU: all actions menu for view media page 
 INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
@@ -288,6 +291,8 @@ INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `titl
 ('bx_albums_view_actions_media', 'bx_albums', 'add-images-to-album', '_bx_albums_menu_item_title_system_add_images', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 10),
 ('bx_albums_view_actions_media', 'bx_albums', 'edit-album', '_bx_albums_menu_item_title_system_edit_album', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 20),
 ('bx_albums_view_actions_media', 'bx_albums', 'edit-image', '_bx_albums_menu_item_title_system_edit_image', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 30),
+('bx_albums_view_actions_media', 'bx_albums', 'delete-image', '_bx_albums_menu_item_title_system_delete_image', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 40),
+('bx_albums_view_actions_media', 'bx_albums', 'move-image', '_bx_albums_menu_item_title_system_move_image', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 50),
 ('bx_albums_view_actions_media', 'bx_albums', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 200),
 ('bx_albums_view_actions_media', 'bx_albums', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 210),
 ('bx_albums_view_actions_media', 'bx_albums', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 220),

+ 10 - 3
modules/boonex/albums/install/sql/install.sql

@@ -443,13 +443,15 @@ INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_fo
 ('bx_albums_entry_delete', 'title', 2147483647, 0, 0);
 
 INSERT INTO `sys_objects_form`(`object`, `module`, `title`, `action`, `form_attrs`, `table`, `key`, `uri`, `uri_title`, `submit_name`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
-('bx_albums_media', 'bx_albums', '_bx_albums_form_media', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_albums_files2albums', 'id', '', '', 'do_submit', '', 0, 1, '', '');
+('bx_albums_media', 'bx_albums', '_bx_albums_form_media', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_albums_files2albums', 'id', '', '', 'do_submit', '', 0, 1, 'BxAlbumsFormMedia', 'modules/boonex/albums/classes/BxAlbumsFormMedia.php');
 
 INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
-('bx_albums_media', 'bx_albums_media_edit', 'bx_albums', 0, '_bx_albums_form_media_display_edit');
+('bx_albums_media', 'bx_albums_media_edit', 'bx_albums', 0, '_bx_albums_form_media_display_edit'),
+('bx_albums_media', 'bx_albums_media_move', 'bx_albums', 0, '_bx_albums_form_media_display_move');
 
 INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES 
 ('bx_albums_media', 'bx_albums', 'title', '', '', 0, 'text', '_bx_albums_form_media_input_sys_title', '_bx_albums_form_media_input_title', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_albums_media', 'bx_albums', 'content_id', '', '', 0, 'select', '_bx_albums_form_media_input_sys_content_id', '_bx_albums_form_media_input_content_id', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
 ('bx_albums_media', 'bx_albums', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
 ('bx_albums_media', 'bx_albums', 'do_submit', '_bx_albums_form_media_input_do_submit', '', 0, 'submit', '_bx_albums_form_media_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
 ('bx_albums_media', 'bx_albums', 'do_cancel', '_bx_albums_form_media_input_do_cancel', '', 0, 'button', '_bx_albums_form_media_input_sys_do_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
@@ -458,7 +460,12 @@ INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_fo
 ('bx_albums_media_edit', 'title', 2147483647, 1, 1),
 ('bx_albums_media_edit', 'controls', 2147483647, 1, 2),
 ('bx_albums_media_edit', 'do_submit', 2147483647, 1, 3),
-('bx_albums_media_edit', 'do_cancel', 2147483647, 1, 4);
+('bx_albums_media_edit', 'do_cancel', 2147483647, 1, 4),
+
+('bx_albums_media_move', 'content_id', 2147483647, 1, 1),
+('bx_albums_media_move', 'controls', 2147483647, 1, 2),
+('bx_albums_media_move', 'do_submit', 2147483647, 1, 3),
+('bx_albums_media_move', 'do_cancel', 2147483647, 1, 4);
 
 
 -- COMMENTS

+ 42 - 0
modules/boonex/albums/js/main.js

@@ -59,6 +59,48 @@ BxAlbumsMain.prototype.onEditMedia = function(oData) {
         $('#' + this._oHtmlIds['subentry_votes'] + oData.content.subentry_id).html(oData.content.votes_formated);
 };
 
+BxAlbumsMain.prototype.deleteMedia = function(oButton, iId) {
+    var $this = this;
+
+    bx_confirm(_t('_Are_you_sure'), function() {
+        var oDate = new Date();
+        $this.loadingInButton(oButton, true);
+
+        $.get(
+            $this._sActionsUrl + 'delete_media/' + iId, 
+            {
+                _t: oDate.getTime()
+            },
+            function(oData) {
+                $this.loadingInButton(oButton, false);
+
+                processJsonData(oData);
+            },
+            'json'
+        );
+    });
+};
+
+BxAlbumsMain.prototype.moveMedia = function(oButton, iId) {
+    var $this = this;
+    var oDate = new Date();
+
+    this.loadingInButton(oButton, true);
+
+    $.get(
+        this._sActionsUrl + 'move_media/' + iId, 
+        {
+            _t: oDate.getTime()
+        },
+        function(oData) {
+            $this.loadingInButton(oButton, false);
+
+            processJsonData(oData);
+        },
+        'json'
+    );
+};
+
 BxAlbumsMain.prototype.loadingInButton = function(e, bShow) {
     if($(e).length)
         bx_loading_btn($(e), bShow);

+ 0 - 4
modules/boonex/albums/template/css/main.css

@@ -1,7 +1,3 @@
-
-@import url(../../../../base/text/template/css/main.css);
-
-
 /* flexbox */
 .bx-albums-medias-wrapper {
     display: -webkit-box;

+ 0 - 3
modules/boonex/albums/template/unit_gallery_private.html

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

+ 0 - 3
modules/boonex/albums/template/unit_live_search.html

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

+ 0 - 1
modules/boonex/albums/template/unit_meta_item.html

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

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно