Author: Derick Rethans (derickr) Date: 2025-01-28T10:43:23Z Commit: https://github.com/php/web-analytics/commit/295337bed842de426a08483bdd6779fc7ea8adb0 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; + } } }