[PHP-WEBMASTER] [web-analytics] main: Upgrade Matomo to 5.2.2

Author: Derick Rethans (derickr)
Date: 2025-01-28T10:43:23Z

Commit: Upgrade Matomo to 5.2.2 · php/web-analytics@295337b · GitHub
Raw diff: https://github.com/php/web-analytics/commit/295337bed842de426a08483bdd6779fc7ea8adb0.diff

Upgrade Matomo to 5.2.2

Changed paths:
  M www/core/Updates/5.2.0-b6.php
  M www/plugins/API/API.php
  M www/plugins/CoreAdminHome/OptOutManager.php
  M www/plugins/CorePluginsAdmin/SettingsMetadata.php
  M www/plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.js
  M www/plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.min.js
  M www/plugins/CorePluginsAdmin/vue/src/PluginSettings/PluginSettings.vue
  M www/plugins/Monolog/Formatter/LineMessageFormatter.php
  M www/plugins/Overlay/templates/startOverlaySession.twig
  M www/plugins/UsersManager/API.php
  M www/vendor/composer/InstalledVersions.php

Diff:

diff --git a/www/core/Updates/5.2.0-b6.php b/www/core/Updates/5.2.0-b6.php
index c2b8dba..4394792 100644
--- a/www/core/Updates/5.2.0-b6.php
+++ b/www/core/Updates/5.2.0-b6.php
@@ -31,17 +31,17 @@ public function __construct(MigrationFactory $factory)

     public function getMigrations(Updater $updater)
     {
- $startOfCurrentYear = Date::now()->toString('Y') . '-01-01';
+ $startOfCurrentMonth = Date::now()->toString('Y-m') . '-01';

         $commandToExecute = sprintf(
             './console core:invalidate-report-data --dates=%s,today --plugin=Actions.Actions_hits',
- $startOfCurrentYear
+ $startOfCurrentMonth
         );

         $migrations = [
- new CustomMigration(function () use ($startOfCurrentYear) {
+ new CustomMigration(function () use ($startOfCurrentMonth) {
                 $invalidator = StaticContainer::get(ArchiveInvalidator::class);
- $invalidator->scheduleReArchiving('all', 'Actions', 'Actions_hits', Date::factory($startOfCurrentYear));
+ $invalidator->scheduleReArchiving('all', 'Actions', 'Actions_hits', Date::factory($startOfCurrentMonth));
             }, $commandToExecute)
         ];

diff --git a/www/plugins/API/API.php b/www/plugins/API/API.php
index b2f4ec4..f8c7ada 100644
--- a/www/plugins/API/API.php
+++ b/www/plugins/API/API.php
@@ -525,7 +525,7 @@ public function getBulkRequest($urls)

             $params += $queryParameters;

- if (!empty($params['method']) && $params['method'] === 'API.getBulkRequest') {
+ if (!empty($params['method']) && is_string($params['method']) && trim($params['method']) === 'API.getBulkRequest') {
                 continue;
             }

diff --git a/www/plugins/CoreAdminHome/OptOutManager.php b/www/plugins/CoreAdminHome/OptOutManager.php
index 72154f7..81c1a4f 100644
--- a/www/plugins/CoreAdminHome/OptOutManager.php
+++ b/www/plugins/CoreAdminHome/OptOutManager.php
@@ -18,6 +18,7 @@
use Piwik\Request;
use Piwik\Tracker\IgnoreCookie;
use Piwik\Url;
+use Piwik\UrlHelper;
use Piwik\View;

/*
@@ -205,6 +206,20 @@ public function getOptOutJSEmbedCode(
         bool $applyStyling,
         bool $showIntro
     ): string {
+ $parsedUrl = parse_url($matomoUrl);
+
+ if (
+ (!empty($matomoUrl) && false === $parsedUrl)
+ || (!empty($parsedUrl['scheme']) && !in_array(strtolower($parsedUrl['scheme']), ['http', 'https']))
+ || (empty($parsedUrl['host']) || !Url::isValidHost($parsedUrl['host']))
+ ) {
+ throw new \Piwik\Exception\Exception('The provided URL is invalid.');
+ }
+
+ // We put together the url based on the parsed parameters manually to ensure it might not include unexpected values
+ // for protocol less urls starting with //, we need to prepend the double slash again
+ $matomoUrl = (strpos($matomoUrl, '//') === 0 ? '//' : '') . UrlHelper::getParseUrlReverse($parsedUrl);
+
         return '<div id="matomo-opt-out"></div>
<script src="' . rtrim($matomoUrl, '/') . '/index.php?module=CoreAdminHome&action=optOutJS&divId=matomo-opt-out&language=' . $language . ($applyStyling ? '&backgroundColor=' . $backgroundColor . '&fontColor=' . $fontColor . '&fontSize=' . $fontSize . '&fontFamily=' . $fontFamily : '') . '&showIntro=' . ($showIntro ? '1' : '0') . '"></script>';
     }
diff --git a/www/plugins/CorePluginsAdmin/SettingsMetadata.php b/www/plugins/CorePluginsAdmin/SettingsMetadata.php
index 96907b7..6afe240 100644
--- a/www/plugins/CorePluginsAdmin/SettingsMetadata.php
+++ b/www/plugins/CorePluginsAdmin/SettingsMetadata.php
@@ -20,6 +20,8 @@ class SettingsMetadata
{
     public const PASSWORD_PLACEHOLDER = '******';

+ public const EMPTY_ARRAY = '__empty__';
+
     /**
      * @param Settings $settingsInstances
      * @param array $settingValues array('pluginName' => array('settingName' => 'settingValue'))
@@ -34,6 +36,11 @@ public function setPluginSettings($settingsInstances, $settingValues)

                     $fieldConfig = $setting->configureField();

+ // empty arrays are sent as __empty__ value, so we need to convert it here back to an array
+ if ($setting->getType() === FieldConfig::TYPE_ARRAY && $value === self::EMPTY_ARRAY) {
+ $value = ;
+ }
+
                     if (
                         isset($value) && (
                         $fieldConfig->uiControl !== FieldConfig::UI_CONTROL_PASSWORD ||
diff --git a/www/plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.js b/www/plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.js
index de81481..8a5a535 100644
--- a/www/plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.js
+++ b/www/plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.js
@@ -17267,34 +17267,34 @@ var UI_CONTROLS_TO_TYPE = {
Fieldvue_type_script_lang_ts.render = Fieldvue_type_template_id_5f883444_render

/* harmony default export */ var Field = (Fieldvue_type_script_lang_ts);
-// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CorePluginsAdmin/vue/src/PluginSettings/PluginSettings.vue?vue&type=template&id=919e3cb4
+// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CorePluginsAdmin/vue/src/PluginSettings/PluginSettings.vue?vue&type=template&id=601e4fc6

-var PluginSettingsvue_type_template_id_919e3cb4_hoisted_1 = {
+var PluginSettingsvue_type_template_id_601e4fc6_hoisted_1 = {
   class: "pluginSettings",
   ref: "root"
};
-var PluginSettingsvue_type_template_id_919e3cb4_hoisted_2 = ["id"];
-var PluginSettingsvue_type_template_id_919e3cb4_hoisted_3 = {
+var PluginSettingsvue_type_template_id_601e4fc6_hoisted_2 = ["id"];
+var PluginSettingsvue_type_template_id_601e4fc6_hoisted_3 = {
   class: "card-content"
};
-var PluginSettingsvue_type_template_id_919e3cb4_hoisted_4 = ["id"];
-var PluginSettingsvue_type_template_id_919e3cb4_hoisted_5 = ["onClick", "disabled", "value"];
-function PluginSettingsvue_type_template_id_919e3cb4_render(_ctx, _cache, $props, $setup, $data, $options) {
+var PluginSettingsvue_type_template_id_601e4fc6_hoisted_4 = ["id"];
+var PluginSettingsvue_type_template_id_601e4fc6_hoisted_5 = ["onClick", "disabled", "value"];
+function PluginSettingsvue_type_template_id_601e4fc6_render(_ctx, _cache, $props, $setup, $data, $options) {
   var _component_GroupedSettings = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("GroupedSettings");

   var _component_ActivityIndicator = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("ActivityIndicator");

   var _component_PasswordConfirmation = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("PasswordConfirmation");

- return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", PluginSettingsvue_type_template_id_919e3cb4_hoisted_1, [(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.settingsPerPlugin, function (settings) {
+ return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", PluginSettingsvue_type_template_id_601e4fc6_hoisted_1, [(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.settingsPerPlugin, function (settings) {
     return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", {
       class: "card",
       id: "".concat(settings.pluginName, "PluginSettings"),
       key: "".concat(settings.pluginName, "PluginSettings")
- }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", PluginSettingsvue_type_template_id_919e3cb4_hoisted_3, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("h2", {
+ }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", PluginSettingsvue_type_template_id_601e4fc6_hoisted_3, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("h2", {
       class: "card-title",
       id: settings.pluginName
- }, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(settings.title), 9, PluginSettingsvue_type_template_id_919e3cb4_hoisted_4), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_GroupedSettings, {
+ }, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(settings.title), 9, PluginSettingsvue_type_template_id_601e4fc6_hoisted_4), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_GroupedSettings, {
       "group-name": settings.pluginName,
       settings: settings.settings,
       "all-setting-values": _ctx.settingValues,
@@ -17309,9 +17309,9 @@ function PluginSettingsvue_type_template_id_919e3cb4_render(_ctx, _cache, $props
       disabled: _ctx.isLoading,
       class: "pluginsSettingsSubmit btn",
       value: _ctx.translate('General_Save')
- }, null, 8, PluginSettingsvue_type_template_id_919e3cb4_hoisted_5), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_ActivityIndicator, {
+ }, null, 8, PluginSettingsvue_type_template_id_601e4fc6_hoisted_5), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_ActivityIndicator, {
       loading: _ctx.isLoading || _ctx.isSaving[settings.pluginName]
- }, null, 8, ["loading"])])], 8, PluginSettingsvue_type_template_id_919e3cb4_hoisted_2);
+ }, null, 8, ["loading"])])], 8, PluginSettingsvue_type_template_id_601e4fc6_hoisted_2);
   }), 128)), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_PasswordConfirmation, {
     modelValue: _ctx.showPasswordConfirmModal,
     "onUpdate:modelValue": _cache[0] || (_cache[0] = function ($event) {
@@ -17320,7 +17320,7 @@ function PluginSettingsvue_type_template_id_919e3cb4_render(_ctx, _cache, $props
     onConfirmed: _ctx.confirmPassword
   }, null, 8, ["modelValue", "onConfirmed"])], 512);
}
-// CONCATENATED MODULE: ./plugins/CorePluginsAdmin/vue/src/PluginSettings/PluginSettings.vue?vue&type=template&id=919e3cb4
+// CONCATENATED MODULE: ./plugins/CorePluginsAdmin/vue/src/PluginSettings/PluginSettings.vue?vue&type=template&id=601e4fc6

// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CorePluginsAdmin/vue/src/GroupedSettings/GroupedSettings.vue?vue&type=template&id=566a93cc

@@ -17807,6 +17807,10 @@ var PluginSettingsvue_type_script_lang_ts_window = window,
           postValue = '1';
         }

+ if (Array.isArray(postValue) && postValue.length === 0) {
+ postValue = '__empty__';
+ }
+
         values[pluginName].push({
           name: settingName,
           value: postValue
@@ -17822,7 +17826,7 @@ var PluginSettingsvue_type_script_lang_ts_window = window,

-PluginSettingsvue_type_script_lang_ts.render = PluginSettingsvue_type_template_id_919e3cb4_render
+PluginSettingsvue_type_script_lang_ts.render = PluginSettingsvue_type_template_id_601e4fc6_render

/* harmony default export */ var PluginSettings = (PluginSettingsvue_type_script_lang_ts);
// CONCATENATED MODULE: ./plugins/CorePluginsAdmin/vue/src/Plugins/PluginFilter.ts
diff --git a/www/plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.min.js b/www/plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.min.js
index 67cd177..e0380c6 100644
--- a/www/plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.min.js
+++ b/www/plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.min.js
@@ -4,7 +4,7 @@
  *
  * @link https://matomo.org
  * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */function Xs(e,t){if(!e)return;var n=;return Object.entries(e).forEach((function(e){var r=Ws(e,2),o=r[0],i=r[1];if(i&&"object"===zs(i)&&"undefined"!==typeof i.key)n.push(i);else{var a=o;"integer"===t&&"string"===typeof o&&(a=parseInt(a,10)),n.push({key:a,value:i})}})),n}function Qs(e){return Qs="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Qs(e)}var el=["password","url","search","email"],tl=["textarea","checkbox","text"],nl={checkbox:"FieldCheckbox","expandable-select":"FieldExpandableSelect","field-array":"FieldFieldArray",file:"FieldFile",hidden:"FieldHidden",multiselect:"FieldSelect",multituple:"FieldMultituple",number:"FieldNumber",radio:"FieldRadio",select:"FieldSelect",site:"FieldSite",text:"FieldText",textarea:"FieldTextarea"},rl={FieldSelect:ms,FieldCheckboxArray:Xs,FieldRadio:Xs,FieldExpandableSelect:oa},ol=Object(Oi["defineComponent"])({props:{modelValue:null,modelModifiers:Object,formField:{type:Object,required:!0}},emits:["update:modelValue"],components:{FieldCheckbox:Mi,FieldCheckboxArray:zi,FieldExpandableSelect:aa,FieldFieldArray:ua,FieldFile:ya,FieldHidden:wa,FieldMultituple:Ca,FieldNumber:Pa,FieldRadio:Fa,FieldSelect:bs,FieldSite:ws,FieldText:Cs,FieldTextArray:Ps,FieldTextarea:Fs,FieldTextareaArray:Rs},setup:function(e){var t=Object(Oi["ref"])(null),n=function(e){var n;e&&t.value&&"function"!==typeof e.render&&(n="string"===typeof e?0===e.indexOf("#")?window.$(e):window.vueSanitize(e):e,window.$(t.value).html("").append(n))};return Object(Oi["watch"])((function(){return e.formField.inlineHelp}),n),Object(Oi["onMounted"])((function(){n(e.formField.inlineHelp)})),{inlineHelp:t}},computed:{inlineHelpComponent:function(){var e=this.formField,t=e.inlineHelp;if(t&&"function"===typeof t.render)return e.inlineHelp},inlineHelpBind:function(){return this.inlineHelpComponent?this.formField.inlineHelpBind:void 0},childComponent:function(){var e=this.formField;if(e.component){var t=e.component;if(e.component.plugin){var n=e.component,r=n.plugin,o=n.name;if(!r||!o)throw new Error("Invalid component property given to FormField directive, must be {plugin: '...',name: '...'}");t=Object(Ci["useExternalPluginComponent"])(r,o)}return Object(Oi["markRaw"])(t)}var i=e.uiControl,a=nl[i];return-1!==el.indexOf(i)&&(a="FieldText"),"array"===this.formField.type&&-1!==tl.indexOf(i)&&(a="".concat(a,"Array")),a},extraChildComponentParams:function(){return"multiselect"===this.formField.uiControl?{multiple:!0}:{}},showFormHelp:function(){return this.formField.description||this.formField.inlineHelp||this.showDefaultValue||this.hasInlineHelpSlot},showDefaultValue:function(){return this.defaultValuePretty&&"checkbox"!==this.formField.uiControl&&"radio"!==this.formField.uiControl},processedModelValue:function(){var e=this.formField;if("boolean"===e.type){var t=this.modelValue&&this.modelValue>0&&"0"!==this.modelValue;if("checkbox"===e.uiControl)return t;if("radio"===e.uiControl)return t?"1":"0"}return this.modelValue},defaultValue:function(){var e=this.formField.defaultValue;return Array.isArray(e)?e.join(","):e},availableOptions:function(){var e=this.childComponent;if("string"!==typeof e)return null;var t=this.formField;return t.availableValues&&rl[e]?rl[e](t.availableValues,t.type,t.uiControlAttributes):null},defaultValuePretty:function(){var e=this.formField,t=e.defaultValue,n=this.availableOptions;if("string"===typeof t&&t){var r=null;try{r=JSON.parse(t)}catch(i){}if(null!==r&&"object"===Qs(r))return""}if(!Array.isArray(n))return Array.isArray(t)?"":t?"".concat(t):"";var o=;return Array.isArray(t)||(t=[t]),(n||).forEach((function(e){"undefined"!==typeof e.value&&-1!==t.indexOf(e.key)&&o.push(e.value)})),o.join(", ")},defaultValuePrettyTruncated:function(){return this.defaultValuePretty.substring(0,50)},hasInlineHelpSlot:function(){var e,t;if(!this.$slots["inline-help"])return!1;var n=this.$slots["inline-help"]();return!(null===n||void 0===n||null===(e=n[0])||void 0===e||null===(t=e.children)||void 0===t||!t.length)}},methods:{onChange:function(e){this.$emit("update:modelValue",e)}}});ol.render=Ei;var il=ol;function al(e,t,n,r,o,i){var a=Object(Oi["resolveComponent"])("FormField");return Object(Oi["openBlock"])(),Object(Oi["createBlock"])(a,{"form-field":e.field,"model-value":e.modelValue,"onUpdate:modelValue":t[0]||(t[0]=function(t){return e.onChange(t)}),"model-modifiers":e.modelModifiers},{"inline-help":Object(Oi["withCtx"])((function(){return[Object(Oi["renderSlot"])(e.$slots,"inline-help")]})),_:3},8,["form-field","model-value","model-modifiers"])}var sl={multiselect:"array",checkbox:"boolean",site:"object",number:"integer"},ll=Object(Oi["defineComponent"])({props:{modelValue:null,modelModifiers:Object,uicontrol:String,name:String,defaultValue:null,options:[Object,Array],description:String,introduction:String,title:String,inlineHelp:[String,Object],inlineHelpBind:Object,disabled:Boolean,uiControlAttributes:{type:Object,default:function(){return{}}},uiControlOptions:{type:Object,default:function(){return{}}},autocomplete:String,varType:String,autofocus:Boolean,tabindex:Number,fullWidth:Boolean,maxlength:Number,required:Boolean,placeholder:String,rows:Number,min:Number,max:Number,component:null},emits:["update:modelValue"],components:{FormField:il},computed:{type:function(){if(this.varType)return this.varType;var e=this.uicontrol;return e&&sl[e]?sl[e]:"string"},field:function(){return{uiControl:this.uicontrol,type:this.type,name:this.name,defaultValue:this.defaultValue,availableValues:this.options,description:this.description,introduction:this.introduction,inlineHelp:this.inlineHelp,inlineHelpBind:this.inlineHelpBind,title:this.title,component:this.component,uiControlAttributes:Object.assign(Object.assign({},this.uiControlAttributes),{},{disabled:this.disabled,autocomplete:this.autocomplete,tabindex:this.tabindex,autofocus:this.autofocus,rows:this.rows,required:this.required,maxlength:this.maxlength,placeholder:this.placeholder,min:this.min,max:this.max}),fullWidth:this.fullWidth,uiControlOptions:this.uiControlOptions}}},methods:{onChange:function(e){this.$emit("update:modelValue",e)}}});ll.render=al;var cl=ll,ul={class:"pluginSettings",ref:"root"},pl=["id"],dl={class:"card-content"},fl=["id"],ml=["onClick","disabled","value"];function hl(e,t,n,r,o,i){var a=Object(Oi["resolveComponent"])("GroupedSettings"),s=Object(Oi["resolveComponent"])("ActivityIndicator"),l=Object(Oi["resolveComponent"])("PasswordConfirmation");return Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("div",ul,[(Object(Oi["openBlock"])(!0),Object(Oi["createElementBlock"])(Oi["Fragment"],null,Object(Oi["renderList"])(e.settingsPerPlugin,(function(t){return Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("div",{class:"card",id:"".concat(t.pluginName,"PluginSettings"),key:"".concat(t.pluginName,"PluginSettings")},[Object(Oi["createElementVNode"])("div",dl,[Object(Oi["createElementVNode"])("h2",{class:"card-title",id:t.pluginName},Object(Oi["toDisplayString"])(t.title),9,fl),Object(Oi["createVNode"])(a,{"group-name":t.pluginName,settings:t.settings,"all-setting-values":e.settingValues,onChange:function(n){return e.settingValues["".concat(t.pluginName,".").concat(n.name)]=n.value}},null,8,["group-name","settings","all-setting-values","onChange"]),Object(Oi["createElementVNode"])("input",{type:"button",onClick:function(n){return e.saveSetting(t.pluginName)},disabled:e.isLoading,class:"pluginsSettingsSubmit btn",value:e.translate("General_Save")},null,8,ml),Object(Oi["createVNode"])(s,{loading:e.isLoading||e.isSaving[t.pluginName]},null,8,["loading"])])],8,pl)})),128)),Object(Oi["createVNode"])(l,{modelValue:e.showPasswordConfirmModal,"onUpdate:modelValue":t[0]||(t[0]=function(t){return e.showPasswordConfirmModal=t}),onConfirmed:e.confirmPassword},null,8,["modelValue","onConfirmed"])],512)}function gl(e,t,n,r,o,i){var a=Object(Oi["resolveComponent"])("GroupedSetting");return Object(Oi["openBlock"])(!0),Object(Oi["createElementBlock"])(Oi["Fragment"],null,Object(Oi["renderList"])(e.settings,(function(t){return Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("div",{key:"".concat(e.groupPrefix).concat(t.name)},[Object(Oi["createVNode"])(a,{"model-value":e.allSettingValues["".concat(e.groupPrefix).concat(t.name)],"onUpdate:modelValue":function(n){return e.$emit("change",{name:t.name,value:n})},setting:t,"condition-values":e.settingValues},null,8,["model-value","onUpdate:modelValue","setting","condition-values"])])})),128)}function bl(e,t,n,r,o,i){var a=Object(Oi["resolveComponent"])("FormField");return Object(Oi["withDirectives"])((Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("div",null,[Object(Oi["createVNode"])(a,{"model-value":e.modelValue,"onUpdate:modelValue":t[0]||(t[0]=function(t){return e.changeValue(t)}),"form-field":e.setting},null,8,["model-value","form-field"])],512)),[[Oi["vShow"],e.showField]])}var yl=Object(Oi["defineComponent"])({props:{setting:{type:Object,required:!0},modelValue:null,conditionValues:{type:Object,required:!0}},components:{FormField:il},emits:["update:modelValue"],computed:{showField:function(){var e=this.setting.condition;if(!e)return!0;e=e.replace(/&&/g," and "),e=e.replace(/\|\|/g," or "),e=e.replace(/!/g," not ");try{return vi.evaluate(e,this.conditionValues)}catch(t){return console.log("failed to parse setting condition '".concat(e,"': ").concat(t.message)),console.log(this.conditionValues),!1}}},methods:{changeValue:function(e){this.$emit("update:modelValue",e)}}});yl.render=bl;var vl=yl;function Ol(e,t){return kl(e)||xl(e,t)||wl(e,t)||jl()}function jl(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function wl(e,t){if(e){if("string"===typeof e)return Nl(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Nl(e,t):void 0}}function Nl(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function xl(e,t){var n=null==e?null:"undefined"!==typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,o,i=,a=!0,s=!1;try{for(n=n.call(e);!(a=(r=n.next()).done);a=!0)if(i.push(r.value),t&&i.length===t)break}catch(l){s=!0,o=l}finally{try{a||null==n["return"]||n["return"]()}finally{if(s)throw o}}return i}}function kl(e){if(Array.isArray(e))return e}var El=Object(Oi["defineComponent"])({props:{groupName:String,settings:{type:Array,required:!0},allSettingValues:{type:Object,required:!0}},emits:["change"],components:{GroupedSetting:vl},computed:{settingValues:function(){var e=this,t=Object.entries(this.allSettingValues).filter((function(t){var n=Ol(t,1),r=n[0];if(e.groupName){var o=r.split("."),i=Ol(o,1),a=i[0];if(a!==e.groupName)return!1}return!0})).map((function(t){var n=Ol(t,2),r=n[0],o=n[1];return e.groupName?[r.split(".")[1],o]:[r,o]}));return Object.fromEntries(t)},groupPrefix:function(){return this.groupName?"".concat(this.groupName,"."):""}}});El.render=gl;var Cl=El,Sl={class:"confirm-password-modal modal",ref:"root"},Al={class:"modal-content"},Vl={class:"modal-text"},Tl={ref:"content"},Pl={key:0},Ml={key:1},Bl={key:2},Dl={class:"modal-footer"},$l=["disabled"];function Fl(e,t,n,r,o,i){var a=Object(Oi["resolveComponent"])("Field");return Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("div",Sl,[Object(Oi["createElementVNode"])("div",Al,[Object(Oi["createElementVNode"])("div",Vl,[Object(Oi["createElementVNode"])("div",Tl,[Object(Oi["renderSlot"])(e.$slots,"default")],512),e.requiresPasswordConfirmation||e.slotHasContent?Object(Oi["createCommentVNode"])("",!0):(Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("h2",Pl,Object(Oi["toDisplayString"])(e.translate("UsersManager_ConfirmThisChange")),1)),e.requiresPasswordConfirmation&&!e.slotHasContent?(Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("h2",Ml,Object(Oi["toDisplayString"])(e.translate("UsersManager_ConfirmWithPassword")),1)):Object(Oi["createCommentVNode"])("",!0),e.requiresPasswordConfirmation&&e.slotHasContent?(Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("div",Bl,Object(Oi["toDisplayString"])(e.translate("UsersManager_ConfirmWithPassword")),1)):Object(Oi["createCommentVNode"])("",!0)]),Object(Oi["withDirectives"])(Object(Oi["createElementVNode"])("div",null,[Object(Oi["createVNode"])(a,{modelValue:e.passwordConfirmation,"onUpdate:modelValue":t[0]||(t[0]=function(t){return e.passwordConfirmation=t}),uicontrol:"password",disabled:e.requiresPasswordConfirmation?void 0:"disabled",name:"currentUserPassword",autocomplete:"off","full-width":!0,title:e.translate("UsersManager_YourCurrentPassword")},null,8,["modelValue","disabled","title"])],512),[[Oi["vShow"],e.requiresPasswordConfirmation]])]),Object(Oi["createElementVNode"])("div",Dl,[Object(Oi["createElementVNode"])("a",{href:"",class:"modal-action modal-close btn",disabled:e.requiresPasswordConfirmation&&!e.passwordConfirmation?"disabled":void 0,onClick:t[1]||(t[1]=function(t){return e.onClickConfirm(t)})},Object(Oi["toDisplayString"])(e.translate("General_Confirm")),9,$l),Object(Oi["createElementVNode"])("a",{href:"",class:"modal-action modal-close modal-no btn-flat",onClick:t[2]||(t[2]=function(t){return e.onClickCancel(t)})},Object(Oi["toDisplayString"])(e.translate("General_Cancel")),1)])],512)}var _l=window,Il=_l.$,Ll=Object(Oi["defineComponent"])({props:{modelValue:{type:Boolean,required:!0}},data:function(){return{passwordConfirmation:"",slotHasContent:!0}},emits:["confirmed","aborted","update:modelValue"],components:{Field:cl},activated:function(){this.$emit("update:modelValue",!1)},methods:{onClickConfirm:function(e){e.preventDefault(),this.$emit("confirmed",this.passwordConfirmation),this.passwordConfirmation=""},onClickCancel:function(e){e.preventDefault(),this.$emit("aborted"),this.passwordConfirmation=""},showPasswordConfirmModal:function(){var e=this;this.slotHasContent=!this.$refs.content.matches(":empty");var t=this.$refs.root,n=Il(t),r=function(t){var r=t.keyCode?t.keyCode:t.which;13===r&&(n.modal("close"),e.$emit("confirmed",e.passwordConfirmation),e.passwordConfirmation="")};n.modal({dismissible:!1,onOpenEnd:function(){var e=".modal.open #currentUserPassword";Il(e).focus(),Il(e).off("keypress").keypress(r)},onCloseEnd:function(){e.$emit("update:modelValue",!1)}}).modal("open")}},computed:{requiresPasswordConfirmation:function(){return!!Ci["Matomo"].requiresPasswordConfirmation}},watch:{modelValue:function(e){e&&this.showPasswordConfirmModal()}}});Ll.render=Fl;var Ul=Ll;function Hl(e,t){return Jl(e)||Wl(e,t)||Rl(e,t)||ql()}function ql(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function Rl(e,t){if(e){if("string"===typeof e)return zl(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?zl(e,t):void 0}}function zl(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function Wl(e,t){var n=null==e?null:"undefined"!==typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,o,i=,a=!0,s=!1;try{for(n=n.call(e);!(a=(r=n.next()).done);a=!0)if(i.push(r.value),t&&i.length===t)break}catch(l){s=!0,o=l}finally{try{a||null==n["return"]||n["return"]()}finally{if(s)throw o}}return i}}function Jl(e){if(Array.isArray(e))return e}var Gl=window,Kl=Gl.$,Yl=Object(Oi["defineComponent"])({props:{mode:String},components:{PasswordConfirmation:Ul,ActivityIndicator:Ci["ActivityIndicator"],GroupedSettings:Cl},data:function(){return{isLoading:!0,isSaving:{},showPasswordConfirmModal:!1,settingsToSave:null,settingsPerPlugin:,settingValues:{}}},created:function(){var e=this;Ci["AjaxHelper"].fetch({method:this.apiMethod}).then((function(t){e.isLoading=!1,e.settingsPerPlugin=t,t.forEach((function(t){t.settings.forEach((function(n){e.settingValues["".concat(t.pluginName,".").concat(n.name)]=n.value}))})),Object(Ci["scrollToAnchorInUrl"])(),e.addSectionsToTableOfContents()})).catch((function(){e.isLoading=!1}))},computed:{apiMethod:function(){return"admin"===this.mode?"CorePluginsAdmin.getSystemSettings":"CorePluginsAdmin.getUserSettings"},saveApiMethod:function(){return"admin"===this.mode?"CorePluginsAdmin.setSystemSettings":"CorePluginsAdmin.setUserSettings"}},methods:{addSectionsToTableOfContents:function(){var e=Kl("#generalSettingsTOC");if(e.length){var t=this.settingsPerPlugin;t.forEach((function(t){var n=t.pluginName,r=t.settings;n&&("CoreAdminHome"===n&&r?r.filter((function(e){return e.introduction})).forEach((function(t){e.append('<a href="#/'.concat(n,'PluginSettings">').concat(t.introduction,"</a> "))})):e.append('<a href="#/'.concat(n,'">').concat(n.replace(/([A-Z])/g," $1").trim(),"</a> ")))}))}},confirmPassword:function(e){this.showPasswordConfirmModal=!1,this.save(this.settingsToSave,e)},saveSetting:function(e){"admin"===this.mode?(this.settingsToSave=e,this.showPasswordConfirmModal=!0):this.save(e)},save:function(e,t){var n=this,r=this.saveApiMethod;this.isSaving[e]=!0;var o=this.getValuesForPlugin(e);Ci["AjaxHelper"].post({method:r},{settingValues:o,passwordConfirmation:t}).then((function(){n.isSaving[e]=!1;var t=Ci["NotificationsStore"].show({message:Object(Ci["translate"])("CoreAdminHome_PluginSettingsSaveSuccess"),id:"generalSettings",context:"success",type:"transient"});Ci["NotificationsStore"].scrollToNotification(t)})).catch((function(){n.isSaving[e]=!1})),this.settingsToSave=null},getValuesForPlugin:function(e){var t={};return t[e]||(t[e]=),Object.entries(this.settingValues).forEach((function(n){var r=Hl(n,2),o=r[0],i=r[1],a=o.split("."),s=Hl(a,2),l=s[0],c=s[1];if(l===e){var u=i;!1===u?u="0":!0===u&&(u="1"),t[l].push({name:c,value:u})}})),t}}});Yl.render=hl;var Zl=Yl,Xl=window,Ql=Xl.$;
+ */function Xs(e,t){if(!e)return;var n=;return Object.entries(e).forEach((function(e){var r=Ws(e,2),o=r[0],i=r[1];if(i&&"object"===zs(i)&&"undefined"!==typeof i.key)n.push(i);else{var a=o;"integer"===t&&"string"===typeof o&&(a=parseInt(a,10)),n.push({key:a,value:i})}})),n}function Qs(e){return Qs="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Qs(e)}var el=["password","url","search","email"],tl=["textarea","checkbox","text"],nl={checkbox:"FieldCheckbox","expandable-select":"FieldExpandableSelect","field-array":"FieldFieldArray",file:"FieldFile",hidden:"FieldHidden",multiselect:"FieldSelect",multituple:"FieldMultituple",number:"FieldNumber",radio:"FieldRadio",select:"FieldSelect",site:"FieldSite",text:"FieldText",textarea:"FieldTextarea"},rl={FieldSelect:ms,FieldCheckboxArray:Xs,FieldRadio:Xs,FieldExpandableSelect:oa},ol=Object(Oi["defineComponent"])({props:{modelValue:null,modelModifiers:Object,formField:{type:Object,required:!0}},emits:["update:modelValue"],components:{FieldCheckbox:Mi,FieldCheckboxArray:zi,FieldExpandableSelect:aa,FieldFieldArray:ua,FieldFile:ya,FieldHidden:wa,FieldMultituple:Ca,FieldNumber:Pa,FieldRadio:Fa,FieldSelect:bs,FieldSite:ws,FieldText:Cs,FieldTextArray:Ps,FieldTextarea:Fs,FieldTextareaArray:Rs},setup:function(e){var t=Object(Oi["ref"])(null),n=function(e){var n;e&&t.value&&"function"!==typeof e.render&&(n="string"===typeof e?0===e.indexOf("#")?window.$(e):window.vueSanitize(e):e,window.$(t.value).html("").append(n))};return Object(Oi["watch"])((function(){return e.formField.inlineHelp}),n),Object(Oi["onMounted"])((function(){n(e.formField.inlineHelp)})),{inlineHelp:t}},computed:{inlineHelpComponent:function(){var e=this.formField,t=e.inlineHelp;if(t&&"function"===typeof t.render)return e.inlineHelp},inlineHelpBind:function(){return this.inlineHelpComponent?this.formField.inlineHelpBind:void 0},childComponent:function(){var e=this.formField;if(e.component){var t=e.component;if(e.component.plugin){var n=e.component,r=n.plugin,o=n.name;if(!r||!o)throw new Error("Invalid component property given to FormField directive, must be {plugin: '...',name: '...'}");t=Object(Ci["useExternalPluginComponent"])(r,o)}return Object(Oi["markRaw"])(t)}var i=e.uiControl,a=nl[i];return-1!==el.indexOf(i)&&(a="FieldText"),"array"===this.formField.type&&-1!==tl.indexOf(i)&&(a="".concat(a,"Array")),a},extraChildComponentParams:function(){return"multiselect"===this.formField.uiControl?{multiple:!0}:{}},showFormHelp:function(){return this.formField.description||this.formField.inlineHelp||this.showDefaultValue||this.hasInlineHelpSlot},showDefaultValue:function(){return this.defaultValuePretty&&"checkbox"!==this.formField.uiControl&&"radio"!==this.formField.uiControl},processedModelValue:function(){var e=this.formField;if("boolean"===e.type){var t=this.modelValue&&this.modelValue>0&&"0"!==this.modelValue;if("checkbox"===e.uiControl)return t;if("radio"===e.uiControl)return t?"1":"0"}return this.modelValue},defaultValue:function(){var e=this.formField.defaultValue;return Array.isArray(e)?e.join(","):e},availableOptions:function(){var e=this.childComponent;if("string"!==typeof e)return null;var t=this.formField;return t.availableValues&&rl[e]?rl[e](t.availableValues,t.type,t.uiControlAttributes):null},defaultValuePretty:function(){var e=this.formField,t=e.defaultValue,n=this.availableOptions;if("string"===typeof t&&t){var r=null;try{r=JSON.parse(t)}catch(i){}if(null!==r&&"object"===Qs(r))return""}if(!Array.isArray(n))return Array.isArray(t)?"":t?"".concat(t):"";var o=;return Array.isArray(t)||(t=[t]),(n||).forEach((function(e){"undefined"!==typeof e.value&&-1!==t.indexOf(e.key)&&o.push(e.value)})),o.join(", ")},defaultValuePrettyTruncated:function(){return this.defaultValuePretty.substring(0,50)},hasInlineHelpSlot:function(){var e,t;if(!this.$slots["inline-help"])return!1;var n=this.$slots["inline-help"]();return!(null===n||void 0===n||null===(e=n[0])||void 0===e||null===(t=e.children)||void 0===t||!t.length)}},methods:{onChange:function(e){this.$emit("update:modelValue",e)}}});ol.render=Ei;var il=ol;function al(e,t,n,r,o,i){var a=Object(Oi["resolveComponent"])("FormField");return Object(Oi["openBlock"])(),Object(Oi["createBlock"])(a,{"form-field":e.field,"model-value":e.modelValue,"onUpdate:modelValue":t[0]||(t[0]=function(t){return e.onChange(t)}),"model-modifiers":e.modelModifiers},{"inline-help":Object(Oi["withCtx"])((function(){return[Object(Oi["renderSlot"])(e.$slots,"inline-help")]})),_:3},8,["form-field","model-value","model-modifiers"])}var sl={multiselect:"array",checkbox:"boolean",site:"object",number:"integer"},ll=Object(Oi["defineComponent"])({props:{modelValue:null,modelModifiers:Object,uicontrol:String,name:String,defaultValue:null,options:[Object,Array],description:String,introduction:String,title:String,inlineHelp:[String,Object],inlineHelpBind:Object,disabled:Boolean,uiControlAttributes:{type:Object,default:function(){return{}}},uiControlOptions:{type:Object,default:function(){return{}}},autocomplete:String,varType:String,autofocus:Boolean,tabindex:Number,fullWidth:Boolean,maxlength:Number,required:Boolean,placeholder:String,rows:Number,min:Number,max:Number,component:null},emits:["update:modelValue"],components:{FormField:il},computed:{type:function(){if(this.varType)return this.varType;var e=this.uicontrol;return e&&sl[e]?sl[e]:"string"},field:function(){return{uiControl:this.uicontrol,type:this.type,name:this.name,defaultValue:this.defaultValue,availableValues:this.options,description:this.description,introduction:this.introduction,inlineHelp:this.inlineHelp,inlineHelpBind:this.inlineHelpBind,title:this.title,component:this.component,uiControlAttributes:Object.assign(Object.assign({},this.uiControlAttributes),{},{disabled:this.disabled,autocomplete:this.autocomplete,tabindex:this.tabindex,autofocus:this.autofocus,rows:this.rows,required:this.required,maxlength:this.maxlength,placeholder:this.placeholder,min:this.min,max:this.max}),fullWidth:this.fullWidth,uiControlOptions:this.uiControlOptions}}},methods:{onChange:function(e){this.$emit("update:modelValue",e)}}});ll.render=al;var cl=ll,ul={class:"pluginSettings",ref:"root"},pl=["id"],dl={class:"card-content"},fl=["id"],ml=["onClick","disabled","value"];function hl(e,t,n,r,o,i){var a=Object(Oi["resolveComponent"])("GroupedSettings"),s=Object(Oi["resolveComponent"])("ActivityIndicator"),l=Object(Oi["resolveComponent"])("PasswordConfirmation");return Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("div",ul,[(Object(Oi["openBlock"])(!0),Object(Oi["createElementBlock"])(Oi["Fragment"],null,Object(Oi["renderList"])(e.settingsPerPlugin,(function(t){return Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("div",{class:"card",id:"".concat(t.pluginName,"PluginSettings"),key:"".concat(t.pluginName,"PluginSettings")},[Object(Oi["createElementVNode"])("div",dl,[Object(Oi["createElementVNode"])("h2",{class:"card-title",id:t.pluginName},Object(Oi["toDisplayString"])(t.title),9,fl),Object(Oi["createVNode"])(a,{"group-name":t.pluginName,settings:t.settings,"all-setting-values":e.settingValues,onChange:function(n){return e.settingValues["".concat(t.pluginName,".").concat(n.name)]=n.value}},null,8,["group-name","settings","all-setting-values","onChange"]),Object(Oi["createElementVNode"])("input",{type:"button",onClick:function(n){return e.saveSetting(t.pluginName)},disabled:e.isLoading,class:"pluginsSettingsSubmit btn",value:e.translate("General_Save")},null,8,ml),Object(Oi["createVNode"])(s,{loading:e.isLoading||e.isSaving[t.pluginName]},null,8,["loading"])])],8,pl)})),128)),Object(Oi["createVNode"])(l,{modelValue:e.showPasswordConfirmModal,"onUpdate:modelValue":t[0]||(t[0]=function(t){return e.showPasswordConfirmModal=t}),onConfirmed:e.confirmPassword},null,8,["modelValue","onConfirmed"])],512)}function gl(e,t,n,r,o,i){var a=Object(Oi["resolveComponent"])("GroupedSetting");return Object(Oi["openBlock"])(!0),Object(Oi["createElementBlock"])(Oi["Fragment"],null,Object(Oi["renderList"])(e.settings,(function(t){return Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("div",{key:"".concat(e.groupPrefix).concat(t.name)},[Object(Oi["createVNode"])(a,{"model-value":e.allSettingValues["".concat(e.groupPrefix).concat(t.name)],"onUpdate:modelValue":function(n){return e.$emit("change",{name:t.name,value:n})},setting:t,"condition-values":e.settingValues},null,8,["model-value","onUpdate:modelValue","setting","condition-values"])])})),128)}function bl(e,t,n,r,o,i){var a=Object(Oi["resolveComponent"])("FormField");return Object(Oi["withDirectives"])((Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("div",null,[Object(Oi["createVNode"])(a,{"model-value":e.modelValue,"onUpdate:modelValue":t[0]||(t[0]=function(t){return e.changeValue(t)}),"form-field":e.setting},null,8,["model-value","form-field"])],512)),[[Oi["vShow"],e.showField]])}var yl=Object(Oi["defineComponent"])({props:{setting:{type:Object,required:!0},modelValue:null,conditionValues:{type:Object,required:!0}},components:{FormField:il},emits:["update:modelValue"],computed:{showField:function(){var e=this.setting.condition;if(!e)return!0;e=e.replace(/&&/g," and "),e=e.replace(/\|\|/g," or "),e=e.replace(/!/g," not ");try{return vi.evaluate(e,this.conditionValues)}catch(t){return console.log("failed to parse setting condition '".concat(e,"': ").concat(t.message)),console.log(this.conditionValues),!1}}},methods:{changeValue:function(e){this.$emit("update:modelValue",e)}}});yl.render=bl;var vl=yl;function Ol(e,t){return kl(e)||xl(e,t)||wl(e,t)||jl()}function jl(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function wl(e,t){if(e){if("string"===typeof e)return Nl(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Nl(e,t):void 0}}function Nl(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function xl(e,t){var n=null==e?null:"undefined"!==typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,o,i=,a=!0,s=!1;try{for(n=n.call(e);!(a=(r=n.next()).done);a=!0)if(i.push(r.value),t&&i.length===t)break}catch(l){s=!0,o=l}finally{try{a||null==n["return"]||n["return"]()}finally{if(s)throw o}}return i}}function kl(e){if(Array.isArray(e))return e}var El=Object(Oi["defineComponent"])({props:{groupName:String,settings:{type:Array,required:!0},allSettingValues:{type:Object,required:!0}},emits:["change"],components:{GroupedSetting:vl},computed:{settingValues:function(){var e=this,t=Object.entries(this.allSettingValues).filter((function(t){var n=Ol(t,1),r=n[0];if(e.groupName){var o=r.split("."),i=Ol(o,1),a=i[0];if(a!==e.groupName)return!1}return!0})).map((function(t){var n=Ol(t,2),r=n[0],o=n[1];return e.groupName?[r.split(".")[1],o]:[r,o]}));return Object.fromEntries(t)},groupPrefix:function(){return this.groupName?"".concat(this.groupName,"."):""}}});El.render=gl;var Cl=El,Sl={class:"confirm-password-modal modal",ref:"root"},Al={class:"modal-content"},Vl={class:"modal-text"},Tl={ref:"content"},Pl={key:0},Ml={key:1},Bl={key:2},Dl={class:"modal-footer"},$l=["disabled"];function Fl(e,t,n,r,o,i){var a=Object(Oi["resolveComponent"])("Field");return Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("div",Sl,[Object(Oi["createElementVNode"])("div",Al,[Object(Oi["createElementVNode"])("div",Vl,[Object(Oi["createElementVNode"])("div",Tl,[Object(Oi["renderSlot"])(e.$slots,"default")],512),e.requiresPasswordConfirmation||e.slotHasContent?Object(Oi["createCommentVNode"])("",!0):(Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("h2",Pl,Object(Oi["toDisplayString"])(e.translate("UsersManager_ConfirmThisChange")),1)),e.requiresPasswordConfirmation&&!e.slotHasContent?(Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("h2",Ml,Object(Oi["toDisplayString"])(e.translate("UsersManager_ConfirmWithPassword")),1)):Object(Oi["createCommentVNode"])("",!0),e.requiresPasswordConfirmation&&e.slotHasContent?(Object(Oi["openBlock"])(),Object(Oi["createElementBlock"])("div",Bl,Object(Oi["toDisplayString"])(e.translate("UsersManager_ConfirmWithPassword")),1)):Object(Oi["createCommentVNode"])("",!0)]),Object(Oi["withDirectives"])(Object(Oi["createElementVNode"])("div",null,[Object(Oi["createVNode"])(a,{modelValue:e.passwordConfirmation,"onUpdate:modelValue":t[0]||(t[0]=function(t){return e.passwordConfirmation=t}),uicontrol:"password",disabled:e.requiresPasswordConfirmation?void 0:"disabled",name:"currentUserPassword",autocomplete:"off","full-width":!0,title:e.translate("UsersManager_YourCurrentPassword")},null,8,["modelValue","disabled","title"])],512),[[Oi["vShow"],e.requiresPasswordConfirmation]])]),Object(Oi["createElementVNode"])("div",Dl,[Object(Oi["createElementVNode"])("a",{href:"",class:"modal-action modal-close btn",disabled:e.requiresPasswordConfirmation&&!e.passwordConfirmation?"disabled":void 0,onClick:t[1]||(t[1]=function(t){return e.onClickConfirm(t)})},Object(Oi["toDisplayString"])(e.translate("General_Confirm")),9,$l),Object(Oi["createElementVNode"])("a",{href:"",class:"modal-action modal-close modal-no btn-flat",onClick:t[2]||(t[2]=function(t){return e.onClickCancel(t)})},Object(Oi["toDisplayString"])(e.translate("General_Cancel")),1)])],512)}var _l=window,Il=_l.$,Ll=Object(Oi["defineComponent"])({props:{modelValue:{type:Boolean,required:!0}},data:function(){return{passwordConfirmation:"",slotHasContent:!0}},emits:["confirmed","aborted","update:modelValue"],components:{Field:cl},activated:function(){this.$emit("update:modelValue",!1)},methods:{onClickConfirm:function(e){e.preventDefault(),this.$emit("confirmed",this.passwordConfirmation),this.passwordConfirmation=""},onClickCancel:function(e){e.preventDefault(),this.$emit("aborted"),this.passwordConfirmation=""},showPasswordConfirmModal:function(){var e=this;this.slotHasContent=!this.$refs.content.matches(":empty");var t=this.$refs.root,n=Il(t),r=function(t){var r=t.keyCode?t.keyCode:t.which;13===r&&(n.modal("close"),e.$emit("confirmed",e.passwordConfirmation),e.passwordConfirmation="")};n.modal({dismissible:!1,onOpenEnd:function(){var e=".modal.open #currentUserPassword";Il(e).focus(),Il(e).off("keypress").keypress(r)},onCloseEnd:function(){e.$emit("update:modelValue",!1)}}).modal("open")}},computed:{requiresPasswordConfirmation:function(){return!!Ci["Matomo"].requiresPasswordConfirmation}},watch:{modelValue:function(e){e&&this.showPasswordConfirmModal()}}});Ll.render=Fl;var Ul=Ll;function Hl(e,t){return Jl(e)||Wl(e,t)||Rl(e,t)||ql()}function ql(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function Rl(e,t){if(e){if("string"===typeof e)return zl(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?zl(e,t):void 0}}function zl(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function Wl(e,t){var n=null==e?null:"undefined"!==typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,o,i=,a=!0,s=!1;try{for(n=n.call(e);!(a=(r=n.next()).done);a=!0)if(i.push(r.value),t&&i.length===t)break}catch(l){s=!0,o=l}finally{try{a||null==n["return"]||n["return"]()}finally{if(s)throw o}}return i}}function Jl(e){if(Array.isArray(e))return e}var Gl=window,Kl=Gl.$,Yl=Object(Oi["defineComponent"])({props:{mode:String},components:{PasswordConfirmation:Ul,ActivityIndicator:Ci["ActivityIndicator"],GroupedSettings:Cl},data:function(){return{isLoading:!0,isSaving:{},showPasswordConfirmModal:!1,settingsToSave:null,settingsPerPlugin:,settingValues:{}}},created:function(){var e=this;Ci["AjaxHelper"].fetch({method:this.apiMethod}).then((function(t){e.isLoading=!1,e.settingsPerPlugin=t,t.forEach((function(t){t.settings.forEach((function(n){e.settingValues["".concat(t.pluginName,".").concat(n.name)]=n.value}))})),Object(Ci["scrollToAnchorInUrl"])(),e.addSectionsToTableOfContents()})).catch((function(){e.isLoading=!1}))},computed:{apiMethod:function(){return"admin"===this.mode?"CorePluginsAdmin.getSystemSettings":"CorePluginsAdmin.getUserSettings"},saveApiMethod:function(){return"admin"===this.mode?"CorePluginsAdmin.setSystemSettings":"CorePluginsAdmin.setUserSettings"}},methods:{addSectionsToTableOfContents:function(){var e=Kl("#generalSettingsTOC");if(e.length){var t=this.settingsPerPlugin;t.forEach((function(t){var n=t.pluginName,r=t.settings;n&&("CoreAdminHome"===n&&r?r.filter((function(e){return e.introduction})).forEach((function(t){e.append('<a href="#/'.concat(n,'PluginSettings">').concat(t.introduction,"</a> "))})):e.append('<a href="#/'.concat(n,'">').concat(n.replace(/([A-Z])/g," $1").trim(),"</a> ")))}))}},confirmPassword:function(e){this.showPasswordConfirmModal=!1,this.save(this.settingsToSave,e)},saveSetting:function(e){"admin"===this.mode?(this.settingsToSave=e,this.showPasswordConfirmModal=!0):this..save(e)},save:function(e,t){var n=this,r=this.saveApiMethod;this.isSaving[e]=!0;var o=this.getValuesForPlugin(e);Ci["AjaxHelper"].post({method:r},{settingValues:o,passwordConfirmation:t}).then((function(){n.isSaving[e]=!1;var t=Ci["NotificationsStore"].show({message:Object(Ci["translate"])("CoreAdminHome_PluginSettingsSaveSuccess"),id:"generalSettings",context:"success",type:"transient"});Ci["NotificationsStore"].scrollToNotification(t)})).catch((function(){n.isSaving[e]=!1})),this.settingsToSave=null},getValuesForPlugin:function(e){var t={};return t[e]||(t[e]=),Object.entries(this.settingValues).forEach((function(n){var r=Hl(n,2),o=r[0],i=r[1],a=o.split("."),s=Hl(a,2),l=s[0],c=s[1];if(l===e){var u=i;!1===u?u="0":!0===u&&(u="1"),Array.isArray(u)&&0===u.length&&(u="__empty__"),t[l].push({name:c,value:u})}})),t}}});Yl.render=hl;var Zl=Yl,Xl=window,Ql=Xl.$;
/*!
  * Matomo - free/libre analytics platform
  *
diff --git a/www/plugins/CorePluginsAdmin/vue/src/PluginSettings/PluginSettings.vue b/www/plugins/CorePluginsAdmin/vue/src/PluginSettings/PluginSettings.vue
index 0e47b71..914f68c 100644
--- a/www/plugins/CorePluginsAdmin/vue/src/PluginSettings/PluginSettings.vue
+++ b/www/plugins/CorePluginsAdmin/vue/src/PluginSettings/PluginSettings.vue
@@ -199,6 +199,10 @@ export default defineComponent({
           postValue = '1';
         }

+ if (Array.isArray(postValue) && postValue.length === 0) {
+ postValue = '__empty__';
+ }
+
         values[pluginName].push({
           name: settingName,
           value: postValue,
diff --git a/www/plugins/Monolog/Formatter/LineMessageFormatter.php b/www/plugins/Monolog/Formatter/LineMessageFormatter.php
index 6639b56..0468820 100644
--- a/www/plugins/Monolog/Formatter/LineMessageFormatter.php
+++ b/www/plugins/Monolog/Formatter/LineMessageFormatter.php
@@ -53,6 +53,8 @@ public function format(array $record)
         $total = '';

         foreach ($messages as $message) {
+ // escape control characters
+ $message = addcslashes($message, "\x00..\x09\x0B..\x1F\x7F");
             $message = $this->prefixMessageWithRequestId($record, $message);
             $total .= $this->formatMessage($class, $message, $date, $record);
         }
diff --git a/www/plugins/Overlay/templates/startOverlaySession.twig b/www/plugins/Overlay/templates/startOverlaySession.twig
index 7e8b4d5..ce1cfb3 100644
--- a/www/plugins/Overlay/templates/startOverlaySession.twig
+++ b/www/plugins/Overlay/templates/startOverlaySession.twig
@@ -16,22 +16,24 @@
         parser.href = urlToRedirect;
         var hostToRedirect = parser.hostname;

- var knownUrls = {{ knownUrls|raw }};
- for (var i = 0; i < knownUrls.length; i++) {
- parser.href = knownUrls[i];
- var testHost = parser.hostname;
- if (hostToRedirect === testHost && testHost) {
- match = true;
- if (navigator.appName == "Microsoft Internet Explorer") {
- // internet explorer loses the referrer if we use window.location.href=X
- var referLink = document.createElement("a");
- referLink.href = handleProtocol(urlToRedirect);
- document.body.appendChild(referLink);
- referLink.click();
- } else {
- window.location.href = handleProtocol(urlToRedirect);
+ if (parser.protocol === 'http:’ || parser.protocol === 'https:') {
+ var knownUrls = {{ knownUrls|raw }};
+ for (var i = 0; i < knownUrls.length; i++) {
+ parser.href = knownUrls[i];
+ var testHost = parser.hostname;
+ if (hostToRedirect === testHost && testHost) {
+ match = true;
+ if (navigator.appName == "Microsoft Internet Explorer") {
+ // internet explorer loses the referrer if we use window.location.href=X
+ var referLink = document.createElement("a");
+ referLink.href = handleProtocol(urlToRedirect);
+ document.body.appendChild(referLink);
+ referLink.click();
+ } else {
+ window.location.href = handleProtocol(urlToRedirect);
+ }
+ break;
                 }
- break;
             }
         }

diff --git a/www/plugins/UsersManager/API.php b/www/plugins/UsersManager/API.php
index 999604f..ae16801 100644
--- a/www/plugins/UsersManager/API.php
+++ b/www/plugins/UsersManager/API.php
@@ -16,6 +16,8 @@
use Piwik\Access\RolesProvider;
use Piwik\Auth\Password;
use Piwik\Common;
+use Piwik\Concurrency\Lock;
+use Piwik\Concurrency\LockBackend;
use Piwik\Config;
use Piwik\Container\StaticContainer;
use Piwik\Date;
@@ -825,33 +827,35 @@ public function inviteUser($userLogin, $email, $initialIdSite = null, $expiryInD
      */
     public function setSuperUserAccess($userLogin, $hasSuperUserAccess, $passwordConfirmation = null)
     {
- Piwik::checkUserHasSuperUserAccess();
- $this->checkUserIsNotAnonymous($userLogin);
- UsersManager::dieIfUsersAdminIsDisabled();
-
- $requirePasswordConfirmation = self::$SET_SUPERUSER_ACCESS_REQUIRE_PASSWORD_CONFIRMATION;
- self::$SET_SUPERUSER_ACCESS_REQUIRE_PASSWORD_CONFIRMATION = true;
-
- $isCliMode = Common::isPhpCliMode() && !(defined('PIWIK_TEST_MODE') && PIWIK_TEST_MODE);
- if (
- !$isCliMode
- && $requirePasswordConfirmation
- ) {
- $this->confirmCurrentUserPassword($passwordConfirmation);
- }
- $this->checkUserExists($userLogin);
+ $this->executeConcurrencySafe($userLogin, function () use ($userLogin, $hasSuperUserAccess, $passwordConfirmation) {
+ Piwik::checkUserHasSuperUserAccess();
+ $this->checkUserIsNotAnonymous($userLogin);
+ UsersManager::dieIfUsersAdminIsDisabled();
+
+ $requirePasswordConfirmation = self::$SET_SUPERUSER_ACCESS_REQUIRE_PASSWORD_CONFIRMATION;
+ self::$SET_SUPERUSER_ACCESS_REQUIRE_PASSWORD_CONFIRMATION = true;
+
+ $isCliMode = Common::isPhpCliMode() && !(defined('PIWIK_TEST_MODE') && PIWIK_TEST_MODE);
+ if (
+ !$isCliMode
+ && $requirePasswordConfirmation
+ ) {
+ $this->confirmCurrentUserPassword($passwordConfirmation);
+ }
+ $this->checkUserExists($userLogin);

- if (!$hasSuperUserAccess && $this->isUserTheOnlyUserHavingSuperUserAccess($userLogin)) {
- $message = Piwik::translate("UsersManager_ExceptionRemoveSuperUserAccessOnlySuperUser", $userLogin)
- . " "
- . Piwik::translate("UsersManager_ExceptionYouMustGrantSuperUserAccessFirst");
- throw new Exception($message);
- }
+ if (!$hasSuperUserAccess && $this->isUserTheOnlyUserHavingSuperUserAccess($userLogin)) {
+ $message = Piwik::translate("UsersManager_ExceptionRemoveSuperUserAccessOnlySuperUser", $userLogin)
+ . " "
+ . Piwik::translate("UsersManager_ExceptionYouMustGrantSuperUserAccessFirst");
+ throw new Exception($message);
+ }

- $this->model->deleteUserAccess($userLogin);
- $this->model->setSuperUserAccess($userLogin, $hasSuperUserAccess);
+ $this->model->deleteUserAccess($userLogin);
+ $this->model->setSuperUserAccess($userLogin, $hasSuperUserAccess);

- Cache::deleteTrackerCache();
+ Cache::deleteTrackerCache();
+ });
     }

     /**
@@ -1152,46 +1156,50 @@ public function setUserAccess($userLogin, $access, $idSites, $passwordConfirmati
         }

         $this->checkUserExist($userLogin);
- $this->checkUsersHasNotSuperUserAccess($userLogin);

- $this->model->deleteUserAccess($userLogin, $idSites);
+ $this->executeConcurrencySafe($userLogin, function () use ($userLogin, $access, $idSites, $roles, $capabilities) {
+ $idSites = $this->getIdSitesCheckAdminAccess($idSites);
+ $this->checkUsersHasNotSuperUserAccess($userLogin);

- if ($access === 'noaccess') {
- // if the access is noaccess then we don't save it as this is the default value
- // when no access are specified
- Piwik::postEvent('UsersManager.removeSiteAccess', [$userLogin, $idSites]);
- } else {
- $role = array_shift($roles);
- $this->model->addUserAccess($userLogin, $role, $idSites);
- }
+ $this->model->deleteUserAccess($userLogin, $idSites);

- if (!empty($capabilities)) {
- $this->addCapabilities($userLogin, $capabilities, $idSites);
- }
+ if ($access === 'noaccess') {
+ // if the access is noaccess then we don't save it as this is the default value
+ // when no access are specified
+ Piwik::postEvent('UsersManager.removeSiteAccess', [$userLogin, $idSites]);
+ } else {
+ $role = array_shift($roles);
+ $this->model->addUserAccess($userLogin, $role, $idSites);
+ }

- // Send notification to all super users if anonymous access is set for a site
- if ($userLogin === 'anonymous' && $access === 'view') {
- $container = StaticContainer::getContainer();
+ if (!empty($capabilities)) {
+ $this->addCapabilitesToUser($userLogin, $capabilities, $idSites);
+ }

- $siteNames = ;
+ // Send notification to all super users if anonymous access is set for a site
+ if ($userLogin === 'anonymous' && $access === 'view') {
+ $container = StaticContainer::getContainer();

- foreach ($idSites as $idSite) {
- $siteNames = Site::getNameFor($idSite);
- }
+ $siteNames = ;

- $superUsers = Piwik::getAllSuperUserAccessEmailAddresses();
- foreach ($superUsers as $login => $email) {
- $email = $container->make(AnonymousAccessEnabledEmail::class, array(
- 'login' => $login,
- 'emailAddress' => $email,
- 'siteName' => implode(', ', $siteNames)
- ));
- $email->safeSend();
+ foreach ($idSites as $idSite) {
+ $siteNames = Site::getNameFor($idSite);
+ }
+
+ $superUsers = Piwik::getAllSuperUserAccessEmailAddresses();
+ foreach ($superUsers as $login => $email) {
+ $email = $container->make(AnonymousAccessEnabledEmail::class, array(
+ 'login' => $login,
+ 'emailAddress' => $email,
+ 'siteName' => implode(', ', $siteNames)
+ ));
+ $email->safeSend();
+ }
             }
- }

- // we reload the access list which doesn't yet take in consideration this new user access
- $this->reloadPermissions();
+ // we reload the access list which doesn't yet take in consideration this new user access
+ $this->reloadPermissions();
+ });
     }

     /**
@@ -1208,28 +1216,40 @@ public function setUserAccess($userLogin, $access, $idSites, $passwordConfirmati
      */
     public function addCapabilities($userLogin, $capabilities, $idSites)
     {
- $idSites = $this->getIdSitesCheckAdminAccess($idSites);
+ $this->executeConcurrencySafe($userLogin, function () use ($userLogin, $capabilities, $idSites) {
+ $idSites = $this->getIdSitesCheckAdminAccess($idSites);

- if ($userLogin == 'anonymous') {
- throw new Exception(Piwik::translate("UsersManager_ExceptionAnonymousNoCapabilities"));
- }
+ if ($userLogin == 'anonymous') {
+ throw new Exception(Piwik::translate("UsersManager_ExceptionAnonymousNoCapabilities"));
+ }

- $this->checkUserExists($userLogin);
- $this->checkUsersHasNotSuperUserAccess([$userLogin]);
+ $this->checkUserExists($userLogin);
+ $this->checkUsersHasNotSuperUserAccess([$userLogin]);

- if (!is_array($capabilities)) {
- $capabilities = [$capabilities];
- }
+ if (!is_array($capabilities)) {
+ $capabilities = [$capabilities];
+ }

- foreach ($capabilities as $entry) {
- $this->capabilityProvider->checkValidCapability($entry);
- }
+ foreach ($capabilities as $entry) {
+ $this->capabilityProvider->checkValidCapability($entry);
+ }
+
+ $this->addCapabilitesToUser($userLogin, $capabilities, $idSites);

+ // we reload the access list which doesn't yet take in consideration this new user access
+ $this->reloadPermissions();
+ });
+ }
+
+ private function addCapabilitesToUser(string $userLogin, array $capabilities, $idSites)
+ {
         [$sitesIdWithRole, $sitesIdWithCapability] = $this->getRolesAndCapabilitiesForLogin($userLogin);

         foreach ($idSites as $idSite) {
             if (!array_key_exists($idSite, $sitesIdWithRole)) {
- throw new Exception(Piwik::translate('UsersManager_ExceptionNoCapabilitiesWithoutRole', [$userLogin, $idSite]));
+ throw new Exception(
+ Piwik::translate('UsersManager_ExceptionNoCapabilitiesWithoutRole', [$userLogin, $idSite])
+ );
             }
         }

@@ -1252,9 +1272,6 @@ public function addCapabilities($userLogin, $capabilities, $idSites)
                 }
             }
         }
-
- // we reload the access list which doesn't yet take in consideration this new user access
- $this->reloadPermissions();
     }

     private function getRolesAndCapabilitiesForLogin($userLogin)
@@ -1290,24 +1307,26 @@ private function getRolesAndCapabilitiesForLogin($userLogin)
      */
     public function removeCapabilities($userLogin, $capabilities, $idSites)
     {
- $idSites = $this->getIdSitesCheckAdminAccess($idSites);
+ $this->executeConcurrencySafe($userLogin, function () use ($userLogin, $capabilities, $idSites) {
+ $idSites = $this->getIdSitesCheckAdminAccess($idSites);

- $this->checkUserExists($userLogin);
+ $this->checkUserExists($userLogin);

- if (!is_array($capabilities)) {
- $capabilities = [$capabilities];
- }
+ if (!is_array($capabilities)) {
+ $capabilities = [$capabilities];
+ }

- foreach ($capabilities as $capability) {
- $this->capabilityProvider->checkValidCapability($capability);
- }
+ foreach ($capabilities as $capability) {
+ $this->capabilityProvider->checkValidCapability($capability);
+ }

- foreach ($capabilities as $capability) {
- $this->model->removeUserAccess($userLogin, $capability, $idSites);
- }
+ foreach ($capabilities as $capability) {
+ $this->model->removeUserAccess($userLogin, $capability, $idSites);
+ }

- // we reload the access list which doesn't yet take in consideration this removed capability
- $this->reloadPermissions();
+ // we reload the access list which doesn't yet take in consideration this removed capability
+ $this->reloadPermissions();
+ });
     }

     private function reloadPermissions()
@@ -1318,6 +1337,9 @@ private function reloadPermissions()

     private function getIdSitesCheckAdminAccess($idSites)
     {
+ // reload access to ensure we're not working with cached entries that might have been changed in between
+ Access::getInstance()->reloadAccess();
+
         if ($idSites === 'all') {
             // in case idSites is all we grant access to all the websites on which the current connected user has an 'admin' access
             $idSites = \Piwik\Plugins\SitesManager\API::getInstance()->getSitesIdWithAdminAccess();
@@ -1658,4 +1680,10 @@ public function generateInviteLink($userLogin, $expiryInDays = 7, $passwordConfi
                 'token' => $token,
             ]);
     }
+
+ private function executeConcurrencySafe(string $userLogin, callable $callback = null)
+ {
+ $lock = new Lock(StaticContainer::get(LockBackend::class), 'UsersManager.changePermissions');
+ $lock->execute($userLogin, $callback);
+ }
}
diff --git a/www/vendor/composer/InstalledVersions.php b/www/vendor/composer/InstalledVersions.php
index 07b32ed..6d29bff 100644
--- a/www/vendor/composer/InstalledVersions.php
+++ b/www/vendor/composer/InstalledVersions.php
@@ -32,6 +32,11 @@ class InstalledVersions
      */
     private static $installed;

+ /**
+ * @var bool
+ */
+ private static $installedIsLocalDir;
+
     /**
      * @var bool|null
      */
@@ -309,6 +314,12 @@ public static function reload($data)
     {
         self::$installed = $data;
         self::$installedByVendor = array();
+
+ // when using reload, we disable the duplicate protection to ensure that self::$installed data is
+ // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
+ // so we have to assume it does not, and that may result in duplicate data being returned when listing
+ // all installed packages for example
+ self::$installedIsLocalDir = false;
     }

     /**
@@ -325,7 +336,9 @@ private static function getInstalled()
         $copiedLocalDir = false;

         if (self::$canGetVendors) {
+ $selfDir = strtr(__DIR__, '\\', '/');
             foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+ $vendorDir = strtr($vendorDir, '\\', '/');
                 if (isset(self::$installedByVendor[$vendorDir])) {
                     $installed = self::$installedByVendor[$vendorDir];
                 } elseif (is_file($vendorDir.'/composer/installed.php')) {
@@ -333,11 +346,14 @@ private static function getInstalled()
                     $required = require $vendorDir.'/composer/installed.php';
                     self::$installedByVendor[$vendorDir] = $required;
                     $installed = $required;
- if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
+ if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
                         self::$installed = $required;
- $copiedLocalDir = true;
+ self::$installedIsLocalDir = true;
                     }
                 }
+ if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
+ $copiedLocalDir = true;
+ }
             }
         }