diff options
author | Kate Butler <kate@innocraft.com> | 2019-08-14 02:48:36 +0300 |
---|---|---|
committer | Thomas Steur <tsteur@users.noreply.github.com> | 2019-08-14 02:48:36 +0300 |
commit | 5f96a27e860de0da9cc86db8736e08a9573fbec8 (patch) | |
tree | 488de6bbcbc5dbe2ec735e3a27d968dc08a95e1b /plugins/UsersManager | |
parent | 85932196aa30e93cc0c28d4445b081b7f710c8ae (diff) |
Add newsletter signup button to user settings page (#14466)
* Add newsletter signup button to user settings page
* UI tests for newsletter signup on user settings page
* Move UI tests for user settings out of UIIntegrationTest
* Fix screenshots for UI tests
* Move newsletter signup logic out of API
* PR changes
* Require token to sign users up to newsletter
* Add privacy notice and checkbox to newsletter signup
* Update UI tests
* Fix UI test
* do things the angular way
* Update userSettings.twig
* PR changes
* Update reference screenshots
* Fix UI test to work with new piwik form elements; remove duplicate test
* Capture notification container in screenshot
* fix ui tests
Diffstat (limited to 'plugins/UsersManager')
15 files changed, 232 insertions, 3 deletions
diff --git a/plugins/UsersManager/API.php b/plugins/UsersManager/API.php index b25a1d6f79..fac5b6178d 100644 --- a/plugins/UsersManager/API.php +++ b/plugins/UsersManager/API.php @@ -969,6 +969,7 @@ class API extends \Piwik\Plugin\API } $this->model->deleteUserOnly($userLogin); + $this->model->deleteUserOptions($userLogin); $this->model->deleteUserAccess($userLogin); Cache::deleteTrackerCache(); @@ -1362,6 +1363,18 @@ class API extends \Piwik\Plugin\API return $user['token_auth']; } + public function newsletterSignup() + { + Piwik::checkUserIsNotAnonymous(); + + $userLogin = Piwik::getCurrentUserLogin(); + $email = Piwik::getCurrentUserEmail(); + + $success = NewsletterSignup::signupForNewsletter($userLogin, $email, true); + $result = $success ? array('success' => true) : array('error' => true); + return $result; + } + private function isUserHasAdminAccessTo($idSite) { try { diff --git a/plugins/UsersManager/Controller.php b/plugins/UsersManager/Controller.php index 9b0c9b475a..a9e2ffcf5b 100644 --- a/plugins/UsersManager/Controller.php +++ b/plugins/UsersManager/Controller.php @@ -13,6 +13,7 @@ use Piwik\API\Request; use Piwik\API\ResponseBuilder; use Piwik\Common; use Piwik\Container\StaticContainer; +use Piwik\Option; use Piwik\Piwik; use Piwik\Plugin\ControllerAdmin; use Piwik\Plugins\LanguagesManager\API as APILanguagesManager; @@ -183,6 +184,10 @@ class Controller extends ControllerAdmin $view->userTokenAuth = Piwik::getCurrentUserTokenAuth(); $view->ignoreSalt = $this->getIgnoreCookieSalt(); + $newsletterSignupOptionKey = NewsletterSignup::NEWSLETTER_SIGNUP_OPTION . $userLogin; + $view->showNewsletterSignup = Option::get($newsletterSignupOptionKey) === false + && SettingsPiwik::isInternetEnabled(); + $userPreferences = new UserPreferences(); $defaultReport = $userPreferences->getDefaultReport(); diff --git a/plugins/UsersManager/Model.php b/plugins/UsersManager/Model.php index 22d7413ccb..839fdbd578 100644 --- a/plugins/UsersManager/Model.php +++ b/plugins/UsersManager/Model.php @@ -12,6 +12,7 @@ use Piwik\Auth\Password; use Piwik\Common; use Piwik\Date; use Piwik\Db; +use Piwik\Option; use Piwik\Piwik; use Piwik\Plugins\SitesManager\SitesManager; use Piwik\Plugins\UsersManager\Sql\SiteAccessFilter; @@ -392,6 +393,11 @@ class Model Piwik::postEvent('UsersManager.deleteUser', array($userLogin)); } + public function deleteUserOptions($userLogin) + { + Option::deleteLike('UsersManager.%.' . $userLogin); + } + /** * @param string $userLogin */ diff --git a/plugins/UsersManager/NewsletterSignup.php b/plugins/UsersManager/NewsletterSignup.php new file mode 100644 index 0000000000..af489f5562 --- /dev/null +++ b/plugins/UsersManager/NewsletterSignup.php @@ -0,0 +1,53 @@ +<?php + +/** + * Matomo - free/libre analytics platform + * + * @link http://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Plugins\UsersManager; + +use Exception; +use Piwik\Config; +use Piwik\Container\StaticContainer; +use Piwik\Http; +use Piwik\Option; +use Piwik\SettingsPiwik; +use Piwik\Url; + +class NewsletterSignup +{ + const NEWSLETTER_SIGNUP_OPTION = 'UsersManager.newsletterSignup.'; + + public static function signupForNewsletter($userLogin, $email, $matomoOrg = false, $professionalServices = false) + { + // Don't bother if they aren't signing up for at least one newsletter, or if we don't have internet access + $doSignup = ($matomoOrg || $professionalServices) && SettingsPiwik::isInternetEnabled(); + if (!$doSignup) { + return false; + } + + $url = Config::getInstance()->General['api_service_url']; + $url .= '/1.0/subscribeNewsletter/'; + + $params = array( + 'email' => $email, + 'piwikorg' => (int)$matomoOrg, + 'piwikpro' => (int)$professionalServices, + 'url' => Url::getCurrentUrlWithoutQueryString(), + 'language' => StaticContainer::get('Piwik\Translation\Translator')->getCurrentLanguage(), + ); + + $url .= '?' . Http::buildQuery($params); + try { + Http::sendHttpRequest($url, $timeout = 2); + $optionKey = self::NEWSLETTER_SIGNUP_OPTION . $userLogin; + Option::set($optionKey, 1); + return true; + } catch (Exception $e) { + return false; + } + } +}
\ No newline at end of file diff --git a/plugins/UsersManager/UsersManager.php b/plugins/UsersManager/UsersManager.php index a844aee258..7e3f6de428 100644 --- a/plugins/UsersManager/UsersManager.php +++ b/plugins/UsersManager/UsersManager.php @@ -239,6 +239,7 @@ class UsersManager extends \Piwik\Plugin $translationKeys[] = "General_Save"; $translationKeys[] = "General_Done"; $translationKeys[] = "General_Pagination"; + $translationKeys[] = "General_PleaseTryAgain"; $translationKeys[] = "UsersManager_DeleteConfirm"; $translationKeys[] = "UsersManager_ConfirmGrantSuperUserAccess"; $translationKeys[] = "UsersManager_ConfirmProhibitOtherUsersSuperUserAccess"; @@ -314,6 +315,7 @@ class UsersManager extends \Piwik\Plugin $translationKeys[] = 'General_Warning'; $translationKeys[] = 'General_Add'; $translationKeys[] = 'General_Note'; + $translationKeys[] = 'General_Yes'; $translationKeys[] = 'UsersManager_FilterByWebsite'; $translationKeys[] = 'UsersManager_GiveAccessToAll'; $translationKeys[] = 'UsersManager_OrManageIndividually'; @@ -324,5 +326,7 @@ class UsersManager extends \Piwik\Plugin $translationKeys[] = 'UsersManager_AreYouSureAddCapability'; $translationKeys[] = 'UsersManager_AreYouSureRemoveCapability'; $translationKeys[] = 'UsersManager_IncludedInUsersRole'; + $translationKeys[] = 'UsersManager_NewsletterSignupFailureMessage'; + $translationKeys[] = 'UsersManager_NewsletterSignupSuccessMessage'; } } diff --git a/plugins/UsersManager/angularjs/personal-settings/personal-settings.controller.js b/plugins/UsersManager/angularjs/personal-settings/personal-settings.controller.js index 31f9f02f7e..635d6e93db 100644 --- a/plugins/UsersManager/angularjs/personal-settings/personal-settings.controller.js +++ b/plugins/UsersManager/angularjs/personal-settings/personal-settings.controller.js @@ -7,14 +7,18 @@ (function () { angular.module('piwikApp').controller('PersonalSettingsController', PersonalSettingsController); - PersonalSettingsController.$inject = ['piwikApi', '$window', 'piwik']; + PersonalSettingsController.$inject = ['piwikApi', '$filter', '$window', 'piwik']; - function PersonalSettingsController(piwikApi, $window, piwik) { + function PersonalSettingsController(piwikApi, $filter, $window, piwik) { // remember to keep controller very simple. Create a service/factory (model) if needed + var translate = $filter('translate'); + var self = this; + this.newsletterSignupButtonTitle = translate('General_Save'); this.doesRequirePasswordConfirmation = false; + this.showNewsletterSignup = true; function updateSettings(postParams) { @@ -43,6 +47,33 @@ this.doesRequirePasswordConfirmation = true; }; + this.signupForNewsletter = function () { + var signupBtn = $('#newsletterSignupBtn'); + signupBtn.html(translate('General_Loading')); + this.isProcessingNewsletterSignup = true; + + piwikApi.withTokenInUrl(); + piwikApi.fetch({module: 'API', method: 'UsersManager.newsletterSignup'}).then(function () { + self.isProcessingNewsletterSignup = false; + self.showNewsletterSignup = false; + + var UI = require('piwik/UI'); + var notification = new UI.Notification(); + notification.show(translate('UsersManager_NewsletterSignupSuccessMessage'), { id: 'newslettersignup', context: 'success'}); + notification.scrollToNotification(); + + }, function () { + self.isProcessingNewsletterSignup = false; + + var UI = require('piwik/UI'); + var notification = new UI.Notification(); + notification.show(translate('UsersManager_NewsletterSignupFailureMessage'), { id: 'newslettersignup', context: 'error' }); + notification.scrollToNotification(); + + self.newsletterSignupButtonTitle = translate('General_PleaseTryAgain'); + }); + }; + this.regenerateTokenAuth = function () { var parameters = { userLogin: piwik.userLogin }; diff --git a/plugins/UsersManager/lang/en.json b/plugins/UsersManager/lang/en.json index 866b52567a..c8f7e4de47 100644 --- a/plugins/UsersManager/lang/en.json +++ b/plugins/UsersManager/lang/en.json @@ -161,6 +161,10 @@ "EmailChangedEmail2": "This change was initiated from the following device: %1$s (IP address = %2$s).", "IfThisWasYouIgnoreIfNot": "If this was you, feel free to ignore this email. If this was not you, please login, correct your email address, change your password and contact your Matomo administrator.", "PasswordChangeNotificationSubject": "Your Matomo account's password has just been changed", - "PasswordChangedEmail": "Your password has just been changed. The change was initiated from the following device: %1$s (IP address = %2$s)." + "PasswordChangedEmail": "Your password has just been changed. The change was initiated from the following device: %1$s (IP address = %2$s).", + "NewsletterSignupTitle": "Newsletter Signup", + "NewsletterSignupMessage": "Subscribe to our newsletter to receive regular information about Matomo. You can unsubscribe from it any time. This service uses MadMimi. Learn more about it on our %1$sPrivacy Policy page%2$s.", + "NewsletterSignupFailureMessage": "Whoops, something went wrong. We weren't able to sign you up for the newsletter.", + "NewsletterSignupSuccessMessage": "Super, you're all signed up! We'll be in touch soon." } } diff --git a/plugins/UsersManager/templates/userSettings.twig b/plugins/UsersManager/templates/userSettings.twig index 72ac592a29..567cac4984 100644 --- a/plugins/UsersManager/templates/userSettings.twig +++ b/plugins/UsersManager/templates/userSettings.twig @@ -120,6 +120,29 @@ </form> </div> +{% if showNewsletterSignup %} +<div ng-controller="PersonalSettingsController as personalSettings"> + <div piwik-content-block id="newsletterSignup" + ng-show="personalSettings.showNewsletterSignup" + content-title="{{ 'UsersManager_NewsletterSignupTitle'|translate|e('html_attr') }}"> + + <div piwik-field uicontrol="checkbox" name="newsletterSignupCheckbox" + ng-model="personalSettings.newsletterSignupCheckbox" + full-width="true" + data-title="{{ 'UsersManager_NewsletterSignupMessage'|translate('<a href="https://matomo.org/privacy-policy/" target="_blank">', '</a>')|e('html_attr') }}" + > + </div> + + <div piwik-save-button id="newsletterSignupBtn" + onconfirm="personalSettings.signupForNewsletter()" + data-disabled="!personalSettings.newsletterSignupCheckbox" + value="{{ '{{ personalSettings.newsletterSignupButtonTitle }}'|raw }}" + saving="personalSettings.isProcessingNewsletterSignup"> + </div> + </div> +</div> +{% endif %} + <div piwik-content-block content-title="{{ 'UsersManager_TokenAuth'|translate|e('html_attr') }}"> <pre piwik-select-on-focus id="token_auth_user" piwik-show-sensitive-data="{{ userTokenAuth }}"></pre> diff --git a/plugins/UsersManager/tests/Integration/UsersManagerTest.php b/plugins/UsersManager/tests/Integration/UsersManagerTest.php index 2d6fc410f7..15f2124ab6 100644 --- a/plugins/UsersManager/tests/Integration/UsersManagerTest.php +++ b/plugins/UsersManager/tests/Integration/UsersManagerTest.php @@ -11,9 +11,11 @@ namespace Piwik\Plugins\UsersManager\tests\Integration; use Piwik\Access; use Piwik\Auth\Password; use Piwik\Common; +use Piwik\Option; use Piwik\Plugins\SitesManager\API as APISitesManager; use Piwik\Plugins\UsersManager\API; use Piwik\Plugins\UsersManager\Model; +use Piwik\Plugins\UsersManager\NewsletterSignup; use Piwik\Plugins\UsersManager\UsersManager; use Piwik\Plugins\UsersManager\UserUpdater; use Piwik\Tests\Framework\Fixture; @@ -425,6 +427,18 @@ class UsersManagerTest extends IntegrationTestCase $this->assertEquals(array(), $this->api->getSitesAccessFromUser("geggeqgeqag")); } + public function testDeleteUser_deletesUserOptions() + { + Fixture::createSuperUser(); + $this->api->addUser("geggeqgeqag", "geqgeagae", "test@test.com", "alias"); + Option::set(NewsletterSignup::NEWSLETTER_SIGNUP_OPTION . 'geggeqgeqag', 'yes'); + + $this->api->deleteUser("geggeqgeqag"); + + $option = Option::get(NewsletterSignup::NEWSLETTER_SIGNUP_OPTION . 'geggeqgeqag'); + $this->assertFalse($option); + } + /** * @expectedException \Exception * @expectedExceptionMessage UsersManager_ExceptionUserDoesNotExist diff --git a/plugins/UsersManager/tests/UI/UserSettings_spec.js b/plugins/UsersManager/tests/UI/UserSettings_spec.js new file mode 100644 index 0000000000..190673c6ca --- /dev/null +++ b/plugins/UsersManager/tests/UI/UserSettings_spec.js @@ -0,0 +1,61 @@ +/*! + * Matomo - free/libre analytics platform + * + * UsersManager screenshot tests. + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +describe("UserSettings", function () { + this.timeout(0); + this.fixture = "Piwik\\Plugins\\UsersManager\\tests\\Fixtures\\ManyUsers"; + + var url = "?module=UsersManager&action=userSettings"; + + before(async function() { + await page.webpage.setViewport({ + width: 1250, + height: 768 + }); + }); + + it('should show user settings page', async function () { + await page.goto(url); + expect(await page.screenshotSelector('.admin')).to.matchImage('load'); + }); + + it('should allow user to subscribe to newsletter', async function () { + await page.click('#newsletterSignup label'); + await page.click('#newsletterSignupBtn input'); + await page.waitForNetworkIdle(); + expect(await page.screenshotSelector('.pageWrap')).to.matchImage('signup_success'); + }); + + it('should not prompt user to subscribe to newsletter again', async function () { + // Assumes previous test has clicked on the signup button - so we shouldn't see it this time + await page.goto(url); + expect(await page.screenshotSelector('.admin')).to.matchImage('already_signed_up'); + }); + + it('should ask for password confirmation when changing email', async function () { + await page.evaluate(function () { + $('#userSettingsTable input#email').val('testlogin123@example.com').change(); + }); + await page.click('#userSettingsTable [piwik-save-button] .btn'); + await page.waitFor(500); // wait for animation + + let pageWrap = await page.$('.modal.open'); + expect(await pageWrap.screenshot()).to.matchImage('asks_confirmation'); + }); + + it('should load error when wrong password specified', async function () { + await page.type('.modal.open #currentPassword', 'foobartest123'); + btnNo = await page.jQuery('.modal.open .modal-action:not(.modal-no)'); + await btnNo.click(); + await page.waitForNetworkIdle(); + + let pageWrap = await page.$('#notificationContainer'); + expect(await pageWrap.screenshot()).to.matchImage('wrong_password_confirmed'); + }); +});
\ No newline at end of file diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_already_signed_up.png b/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_already_signed_up.png new file mode 100644 index 0000000000..c80c406a1d --- /dev/null +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_already_signed_up.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c72e030a905a1d12b9a7f37a7ba55b4c8af795605e0dfe2b6f5720bf22b2e38 +size 256833 diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_asks_confirmation.png b/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_asks_confirmation.png new file mode 100644 index 0000000000..9463f3d49a --- /dev/null +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_asks_confirmation.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a7d52fd49c0ec3236a9f30599d30ca50df02faabd60d7fee95cb03565b69863 +size 15729 diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_load.png b/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_load.png new file mode 100644 index 0000000000..3c36a8c9c4 --- /dev/null +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_load.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:471e81890434001d43d046898ffbfa54538ab874c97edcdc71254268f5226e68 +size 281276 diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_signup_success.png b/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_signup_success.png new file mode 100644 index 0000000000..0f182e8e02 --- /dev/null +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_signup_success.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:faf42e67b73481c4cb2cad9cb54bf5fb4c5e99009e7caa1f5503e48d70bf61c3 +size 269494 diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_wrong_password_confirmed.png b/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_wrong_password_confirmed.png new file mode 100644 index 0000000000..59aee17129 --- /dev/null +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UserSettings_wrong_password_confirmed.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d553f29ce6bf59c9368d9496286bbfc720ecab6125560fe3fbf36051b9622bf1 +size 6092 |