Skip to content

Commit

Permalink
Show install all plugins button on Manage Plugins and License key sec…
Browse files Browse the repository at this point in the history
…tion (#22615)

* Add code to show install all plugins button on Manage Plugins and License key section, #PG-3698

* Applied PR feedbacks and added UI tests

* Fixes for UI test

* Fixes failing UI test and handles some permission issue

* Updated method visibility to private

* Fixes for UI test

* Fixes for UI test

* Fixes for UI test

* Fixes UI test error

* UI test fix

* Updated UI test and UI screenshot

* Updated UI test

* Increased timeout

* Added reload

* UI test URL updated

* UI test fix:

* Updated UI screenshot

* Applied PR feedbacks

* Removed unwanted code

* some code cleanup

---------

Co-authored-by: sgiehl <[email protected]>
  • Loading branch information
AltamashShaikh and sgiehl authored Nov 25, 2024
1 parent 6379040 commit d616dba
Show file tree
Hide file tree
Showing 21 changed files with 391 additions and 275 deletions.
147 changes: 135 additions & 12 deletions plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.js

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions plugins/CorePluginsAdmin/vue/dist/CorePluginsAdmin.umd.min.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<!--
Matomo - free/libre analytics platform
@link https://matomo.org
@license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
-->

<template>
<div v-if="paidPluginsToInstallAtOnce.length">
<button
class="btn installAllPaidPluginsAtOnceButton"
@click.prevent="onInstallAllPaidPlugins()"
:disabled="disabled || loading"
>
<MatomoLoader v-if="loading"/>
{{ translate('Marketplace_InstallPurchasedPlugins') }}
</button>
<div
class="ui-confirm"
id="installAllPaidPluginsAtOnce"
ref="installAllPaidPluginsAtOnce"
>
<h2>{{ translate('Marketplace_InstallAllPurchasedPlugins') }}</h2>
<p>
{{ translate('Marketplace_InstallThesePlugins') }}
</p>
<ul>
<li v-for="pluginDisplayName in paidPluginsToInstallAtOnce" :key="pluginDisplayName">
{{ pluginDisplayName }}
</li>
</ul>
<p>
<input
role="install"
type="button"
:data-href="installAllPaidPluginsLink"
:value="translate(
'Marketplace_InstallAllPurchasedPluginsAction',
paidPluginsToInstallAtOnce.length,
)"
/>
<input
role="cancel"
type="button"
:value="translate('General_Cancel')"
/>
</p>
</div>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import {
Matomo, MatomoUrl, MatomoLoader, AjaxHelper,
} from 'CoreHome';
interface installAllPaidPluginsButton {
paidPluginsToInstallAtOnce: Array<string>;
installNonce: string;
loading: boolean;
}
export default defineComponent({
components: { MatomoLoader },
props: {
disabled: {
type: Boolean,
required: false,
default: false,
},
},
data(): installAllPaidPluginsButton {
return {
paidPluginsToInstallAtOnce: ([]) as Array<string>,
installNonce: '',
loading: false,
};
},
created() {
this.fetchPluginsToInstallAtOnce();
},
watch: {
disabled(newValue: boolean, oldValue: boolean) {
if (newValue === false && oldValue === true) {
this.fetchPluginsToInstallAtOnce();
}
},
},
methods: {
onInstallAllPaidPlugins() {
Matomo.helper.modalConfirm(this.$refs.installAllPaidPluginsAtOnce as HTMLElement);
},
fetchPluginsToInstallAtOnce() {
this.loading = true;
if (Matomo.hasSuperUserAccess) {
AjaxHelper.fetch({
module: 'Marketplace',
action: 'getPaidPluginsToInstallAtOnceParams',
}).then((response) => {
if (response) {
this.paidPluginsToInstallAtOnce = response.paidPluginsToInstallAtOnce ?? [];
this.installNonce = response.installAllPluginsNonce ?? '';
}
this.loading = false;
});
}
},
},
computed: {
installAllPaidPluginsLink() {
return `?${MatomoUrl.stringify({
...MatomoUrl.urlParsed.value,
module: 'Marketplace',
action: 'installAllPaidPlugins',
nonce: this.installNonce,
})}`;
},
},
});
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
<span v-html="$sanitize(changeLookByManageThemesText)"></span>
</p>
</div>
<InstallAllPaidPluginsButton
/>
</template>

<script lang="ts">
Expand All @@ -38,6 +40,8 @@ import {
translate,
MatomoUrl,
} from 'CoreHome';
import InstallAllPaidPluginsButton
from '../InstallAllPaidPluginsButton/InstallAllPaidPluginsButton.vue';
export default defineComponent({
props: {
Expand All @@ -47,6 +51,7 @@ export default defineComponent({
},
components: {
EnrichedHeadline,
InstallAllPaidPluginsButton,
},
directives: {
ContentIntro,
Expand Down
1 change: 1 addition & 0 deletions plugins/CorePluginsAdmin/vue/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ export { default as PluginName } from './Plugins/PluginName';
export { default as PluginsTable } from './PluginsTable/PluginsTable.vue';
export { default as PluginsTableWithUpdates } from './PluginsTable/PluginsTableWithUpdates.vue';
export { default as UploadPluginDialog } from './UploadPluginDialog/UploadPluginDialog.vue';
export { default as InstallAllPaidPluginsButton } from './InstallAllPaidPluginsButton/InstallAllPaidPluginsButton.vue';
36 changes: 34 additions & 2 deletions plugins/Marketplace/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,21 @@ public function manageLicenseKey()
));
}

public function getPaidPluginsToInstallAtOnceParams()
{
Piwik::checkUserHasSuperUserAccess();
Json::sendHeaderJSON();

if (!$this->isInstallAllPaidPluginsVisible()) {
return json_encode([]);
}

return json_encode([
'paidPluginsToInstallAtOnce' => $this->getAllPaidPluginsToInstallAtOnce(),
'installAllPluginsNonce' => Nonce::getNonce(self::INSTALL_NONCE),
], JSON_HEX_APOS);
}

private function getPrettyLongDate($date)
{
if (empty($date)) {
Expand Down Expand Up @@ -254,7 +269,7 @@ public function overview()
'premium' => count($paidPlugins),
];

$view->paidPluginsToInstallAtOnce = $this->getPaidPluginsToInstallAtOnceData($paidPlugins);
$view->paidPluginsToInstallAtOnce = $this->getAllPaidPluginsToInstallAtOnce();
$view->isValidConsumer = $this->consumer->isValidConsumer();
$view->pluginTypeOptions = array(
'plugins' => Piwik::translate('General_Plugins'),
Expand Down Expand Up @@ -292,7 +307,6 @@ public function updateOverview(): string
$paidPlugins = $this->plugins->getAllPaidPlugins();

$updateData = [
'paidPluginsToInstallAtOnce' => $this->getPaidPluginsToInstallAtOnceData($paidPlugins),
'isValidConsumer' => $this->consumer->isValidConsumer(),
];

Expand Down Expand Up @@ -571,4 +585,22 @@ protected function configureViewAndCheckPermission($template)

return $view;
}

private function isInstallAllPaidPluginsVisible(): bool
{
return (
$this->consumer->isValidConsumer() &&
Piwik::hasUserSuperUserAccess() &&
SettingsPiwik::isAutoUpdatePossible() &&
CorePluginsAdmin::isPluginsAdminEnabled() &&
count($this->getAllPaidPluginsToInstallAtOnce()) > 0
);
}

private function getAllPaidPluginsToInstallAtOnce()
{
$paidPlugins = $this->plugins->getAllPaidPlugins();

return $this->getPaidPluginsToInstallAtOnceData($paidPlugins);
}
}
1 change: 0 additions & 1 deletion plugins/Marketplace/templates/overview.twig
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
is-multi-server-environment="{{ isMultiServerEnvironment|default(false)|json_encode }}"
is-plugins-admin-enabled="{{ isPluginsAdminEnabled|default(false)|json_encode }}"
has-some-admin-access="{{ hasSomeAdminAccess|default(false)|json_encode }}"
paid-plugins-to-install-at-once="{{ paidPluginsToInstallAtOnce|default([])|json_encode }}"
install-nonce="{{ installNonce|default(null)|json_encode }}"
activate-nonce="{{ activateNonce|default(null)|json_encode }}"
deactivate-nonce="{{ deactivateNonce|default(null)|json_encode }}"
Expand Down
43 changes: 29 additions & 14 deletions plugins/Marketplace/tests/UI/Marketplace_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,26 +139,41 @@ describe("Marketplace", function () {
});

if (mode === 'superuser') {
it(mode + ' for a user with license key should be able to open install purchased plugins modal', async function () {
setEnvironment(mode, validLicense);
[paidPluginsUrl, '?module=Marketplace&action=manageLicenseKey&idSite=1&period=day&date=yesterday', '?module=CorePluginsAdmin&action=plugins&idSite=1&period=day&date=yesterday&activated=']
.forEach(function (url, index) {
it(mode + ' for a user with license key should be able to open paid plugins ' + index, async() => {
var indexArray = ['paidPluginsUrl', 'manageLicenseKeyUrl', 'managePluginsUrl'];
setEnvironment(mode, validLicense);

await page.goto('about:blank');
await page.goto(paidPluginsUrl);
await page.goto('about:blank');
await page.goto(url);

const elem = await page.jQuery(
'.installAllPaidPlugins button'
);
await captureSelector('paid_plugins_with_license_' + indexArray[index] + '_' + mode, '.pageWrap');
});

await elem.click();

// give it some time to fetch, animate, and render everything properly
await page.waitForNetworkIdle();
await page.waitForTimeout(500);
it(mode + ' for a user with license key should be able to open install purchased plugins modal for ' + index, async() => {
var indexArray = ['paidPluginsUrl', 'manageLicenseKeyUrl', 'managePluginsUrl'];
setEnvironment(mode, validLicense);

const selector = '.modal.open';
await page.screenshotSelector(selector);
await page.goto('about:blank');
await page.goto(url);
await page.waitForNetworkIdle();
await page.waitForTimeout(500);

expect(await page.screenshotSelector(selector)).to.matchImage('install_purchased_plugins_modal_' + mode);
const elem = await page.jQuery(
'.installAllPaidPluginsAtOnceButton.btn'
);

await elem.click();

// give it some time to fetch, animate, and render everything properly
await page.waitForNetworkIdle();
await page.waitForTimeout(500);

const pageElement = await page.$('.modal.open');
expect(await pageElement.screenshot()).to.matchImage('install_purchased_plugins_modal_' + indexArray[index] + '_' + mode);
});
});
}

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit d616dba

Please sign in to comment.