From 6a59ba29431e6bc6b035d49d9995bf08d6d9f07a Mon Sep 17 00:00:00 2001 From: Yuriy Bakhtin Date: Mon, 11 Dec 2023 11:44:33 +0100 Subject: [PATCH] Refactor auto start tour for new user (#6685) * Refactor auto start tour for new user * Revert "Auxiliary commit to revert individual files from b63f530b8626802c66e10a241ba4ddfa670f8c65" This reverts commit c9ebfdc71d1dd2f1d2dd3927ae464ff3f2f0b939. * Activate test for auto tour * Fix test * Fix test * Refactor displaying of dashboard sidebar tour widget * Refactor auto start tour for new registered user * Don't use session for displaying of dashboard sidebar tour widget * Fix auto tour test * Don't redirect after init auto start tour * Update deprecated actions --------- Co-authored-by: Lucas Bartholemy --- .github/workflows/php-test.yml | 8 +- CHANGELOG.md | 1 + protected/humhub/modules/tour/Events.php | 49 +++++++++ protected/humhub/modules/tour/Module.php | 71 +++---------- protected/humhub/modules/tour/config.php | 5 +- .../tests/codeception/acceptance.suite.yml | 3 + .../codeception/acceptance/AutoTourCest.php | 1 - .../humhub/modules/tour/widgets/Dashboard.php | 18 +++- .../humhub/modules/tour/widgets/Tour.php | 99 ++++++++++++++----- .../tests/codeception/fixtures/data/user.php | 16 +-- 10 files changed, 173 insertions(+), 98 deletions(-) create mode 100644 protected/humhub/modules/tour/Events.php diff --git a/.github/workflows/php-test.yml b/.github/workflows/php-test.yml index e9831d60a0..8e28287ff6 100644 --- a/.github/workflows/php-test.yml +++ b/.github/workflows/php-test.yml @@ -59,8 +59,8 @@ jobs: run: | docker run --detach --net=host --shm-size="2g" selenium/standalone-chrome - - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 # - name: Setup cache environment # id: cache-env @@ -71,7 +71,7 @@ jobs: # key: ${{ env.key }} # - name: Cache extensions -# uses: actions/cache@v1 +# uses: actions/cache@v3 # with: # path: ${{ steps.cache-env.outputs.dir }} # key: ${{ steps.cache-env.outputs.key }} @@ -92,7 +92,7 @@ jobs: run: composer validate - name: Cache dependencies installed with composer - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: ${{ env.COMPOSER_CACHE_DIR }} key: php${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.json') }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 797326ea6b..1032ed0304 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ HumHub Changelog - Fix #6674: Fix visibility of draft and scheduled content on dashboard - Fix #6679: On the space invitation by link page, the language chooser doesn't save the selected language - Fix #6677: Do not check mobile push module in requirements check on installation +- Fix #6678: Refactor auto start tour for new user - Fix #6694: Remove the "Offline" tooltip when my own "Online" status is not displayed - Fix #6700: Reload theme variable `@baseTheme` after flushing cache diff --git a/protected/humhub/modules/tour/Events.php b/protected/humhub/modules/tour/Events.php new file mode 100644 index 0000000000..91fcddf347 --- /dev/null +++ b/protected/humhub/modules/tour/Events.php @@ -0,0 +1,49 @@ +user->isGuest) { + return; + } + + if (DashboardWidget::isVisible()) { + /* @var Sidebar $sidebar */ + $sidebar = $event->sender; + $sidebar->addWidget(DashboardWidget::class, [], ['sortOrder' => 100]); + } + } + + public static function onUserBeforeLogin($event) + { + if ($event->identity instanceof User && self::shouldStartWelcomeTour($event->identity)) { + Tour::enableAutoStart('dashboard', $event->identity); + } + } + + private static function shouldStartWelcomeTour(?User $user = null): bool + { + return $user->last_login === null && // Force auto start only for new created user who is logged in first time after registration + DashboardWidget::isVisible($user) && // Start it only when the dashboard sidebar widget is visible for the user + !Yii::$app->getModule('tour')->showWelcomeWindow($user); // No need auto start because it will be done by dashboard widget + } +} diff --git a/protected/humhub/modules/tour/Module.php b/protected/humhub/modules/tour/Module.php index 7951b70d8e..4d2fdaed7d 100644 --- a/protected/humhub/modules/tour/Module.php +++ b/protected/humhub/modules/tour/Module.php @@ -2,9 +2,8 @@ namespace humhub\modules\tour; -use Yii; -use humhub\modules\tour\widgets\Dashboard; use humhub\modules\user\models\User; +use Yii; /** * This module shows an introduction tour for new users @@ -25,68 +24,20 @@ class Module extends \humhub\components\Module public $isCoreModule = true; /** - * @var bool enable auto-start tour for new accounts - * @since 1.15 - */ - public $autoStartOnNewAccounts = false; - - /** - * Check is first login - * @since 1.15 + * Check if the welcome tour window should be displayed automatically * - * @param User $user + * @param User|null $user * @return bool */ - private function getIsFirstLogin(User $user): bool + public function showWelcomeWindow(?User $user = null): bool { - $settings = Yii::$app->getModule('tour')->settings; - $showWelcome = ( - $user->id == 1 && + if ($user === null && !Yii::$app->user->isGuest) { + $user = Yii::$app->user->identity; + } + + return $user instanceof User && + $user->id === 1 && Yii::$app->getModule('installer')->settings->get('sampleData') != 1 && - $settings->user()->get('welcome') != 1 - ); - - return ( - !$showWelcome && - $user->updated_by === null && - $user->created_at === $user->updated_at - ); - } - - /** - * Set updated_by for current user - * @since 1.15 - * - * @param User $user - * @return void - */ - private function setFirstLoginDone(User $user) - { - $user->updateAttributes(['updated_by' => $user->id]); - } - - /** - * Event Callback - */ - public static function onDashboardSidebarInit($event) - { - if (Yii::$app->user->isGuest) { - return; - } - - /** @var Module $module */ - $module = Yii::$app->getModule('tour'); - $settings = $module->settings; - - if ($settings->get('enable') == 1 && $settings->user()->get("hideTourPanel") != 1) { - $module->autoStartOnNewAccounts = $module->getIsFirstLogin(Yii::$app->user->identity); - if ($module->autoStartOnNewAccounts) { - $module->setFirstLoginDone(Yii::$app->user->identity); - - Yii::$app->getResponse()->redirect(['/dashboard/dashboard', 'tour' => true]); - } else { - $event->sender->addWidget(Dashboard::class, [], ['sortOrder' => 100]); - } - } + $this->settings->user($user)->get('welcome') != 1; } } diff --git a/protected/humhub/modules/tour/config.php b/protected/humhub/modules/tour/config.php index 2b03e2b6f9..f1fde46b07 100644 --- a/protected/humhub/modules/tour/config.php +++ b/protected/humhub/modules/tour/config.php @@ -1,13 +1,16 @@ 'tour', 'class' => Module::class, 'isCoreModule' => true, 'events' => [ - ['class' => Sidebar::class, 'event' => Sidebar::EVENT_INIT, 'callback' => [Module::class, 'onDashboardSidebarInit']], + [Sidebar::class, Sidebar::EVENT_INIT, [Events::class, 'onDashboardSidebarInit']], + [User::class, User::EVENT_BEFORE_LOGIN, [Events::class, 'onUserBeforeLogin']], ], ]; diff --git a/protected/humhub/modules/tour/tests/codeception/acceptance.suite.yml b/protected/humhub/modules/tour/tests/codeception/acceptance.suite.yml index f29f91900a..453f7b8d83 100644 --- a/protected/humhub/modules/tour/tests/codeception/acceptance.suite.yml +++ b/protected/humhub/modules/tour/tests/codeception/acceptance.suite.yml @@ -20,3 +20,6 @@ modules: browser: chrome port: 4444 window_size: 1600x900 + capabilities: + chromeOptions: + args: ["--lang=en-US"] diff --git a/protected/humhub/modules/tour/tests/codeception/acceptance/AutoTourCest.php b/protected/humhub/modules/tour/tests/codeception/acceptance/AutoTourCest.php index 4b6d80377c..deefb95fd7 100644 --- a/protected/humhub/modules/tour/tests/codeception/acceptance/AutoTourCest.php +++ b/protected/humhub/modules/tour/tests/codeception/acceptance/AutoTourCest.php @@ -14,7 +14,6 @@ use Yii; class AutoTourCest { /** - * @skip * @param AcceptanceTester $I * @throws \Exception */ diff --git a/protected/humhub/modules/tour/widgets/Dashboard.php b/protected/humhub/modules/tour/widgets/Dashboard.php index eea14f5e04..e0a8c098db 100644 --- a/protected/humhub/modules/tour/widgets/Dashboard.php +++ b/protected/humhub/modules/tour/widgets/Dashboard.php @@ -20,6 +20,9 @@ namespace humhub\modules\tour\widgets; +use humhub\components\SettingsManager; +use humhub\modules\tour\Module; +use humhub\modules\user\models\User; use Yii; use yii\base\Widget; @@ -30,14 +33,25 @@ class Dashboard extends Widget { public function run() { - $settingsManager = Yii::$app->getModule('tour')->settings->user(); + /* @var Module $module */ + $module = Yii::$app->getModule('tour'); + $settingsManager = $module->settings->user(); return $this->render('tourPanel', [ 'interface' => $settingsManager->get("interface"), 'spaces' => $settingsManager->get("spaces"), 'profile' => $settingsManager->get("profile"), 'administration' => $settingsManager->get("administration"), - 'showWelcome' => (Yii::$app->user->id == 1 && Yii::$app->getModule('installer')->settings->get('sampleData') != 1 && $settingsManager->get('welcome') != 1) + 'showWelcome' => $module->showWelcomeWindow() ]); } + + public static function isVisible(?User $user = null): bool + { + /* @var SettingsManager $settings */ + $settings = Yii::$app->getModule('tour')->settings; + + return $settings->get('enable') == 1 && + $settings->user($user)->get('hideTourPanel') != 1; + } } diff --git a/protected/humhub/modules/tour/widgets/Tour.php b/protected/humhub/modules/tour/widgets/Tour.php index 4f52207fbc..11d7f7244d 100644 --- a/protected/humhub/modules/tour/widgets/Tour.php +++ b/protected/humhub/modules/tour/widgets/Tour.php @@ -2,7 +2,15 @@ namespace humhub\modules\tour\widgets; +use humhub\components\SettingsManager; +use humhub\components\Widget; +use humhub\modules\admin\controllers\ModuleController; +use humhub\modules\dashboard\controllers\DashboardController; +use humhub\modules\space\controllers\SpaceController; use humhub\modules\tour\assets\TourAsset; +use humhub\modules\tour\widgets\Dashboard as DashboardWidget; +use humhub\modules\user\controllers\ProfileController; +use humhub\modules\user\models\User; use Yii; /** @@ -12,48 +20,53 @@ use Yii; * @since 0.5 * @author andystrobel */ -class Tour extends \humhub\components\Widget +class Tour extends Widget { + private static function getTypes(): array + { + return [ + 'dashboard' => ['view' => 'guide_interface', 'controller' => DashboardController::class], + 'space' => ['view' => 'guide_spaces', 'controller' => SpaceController::class], + 'user' => ['view' => 'guide_profile', 'controller' => ProfileController::class], + 'admin' => ['view' => 'guide_administration', 'controller' => ModuleController::class] + ]; + } + /** * Executes the widgets */ public function run() { if (Yii::$app->user->isGuest) { - return; + return ''; } - // Active tour flag not set - if (!isset($_GET['tour'])) { - return; + // Active tour flag is not set and auto start is not enabled + if (!Yii::$app->request->get('tour') && !self::isEnabledAutoStart()) { + return ''; } // Tour only possible when we are in a module if (Yii::$app->controller->module === null) { - return; + return ''; } // Check if tour is activated by admin and users - $settings = Yii::$app->getModule('tour')->settings; - if ($settings->get('enable') == 0 && $settings->user()->get("hideTourPanel") == 1) { - return; + if (!DashboardWidget::isVisible()) { + return ''; } + $type = self::getCurrentType(); + + if ($type === null) { + return ''; + } + + self::disableAutoStart($type['type']); + TourAsset::register($this->view); - // save current module and controller id's - $currentModuleId = Yii::$app->controller->module->id; - $currentControllerId = Yii::$app->controller->id; - - if ($currentModuleId == "dashboard" && $currentControllerId == "dashboard") { - return $this->render('guide_interface'); - } elseif ($currentModuleId == "space" && $currentControllerId == "space") { - return $this->render('guide_spaces', []); - } elseif ($currentModuleId == "user" && $currentControllerId == "profile") { - return $this->render('guide_profile', []); - } elseif ($currentModuleId == "marketplace" && $currentControllerId == "browse") { - return $this->render('guide_administration', []); - } + return $this->render($type['view']); } /** @@ -63,4 +76,46 @@ class Tour extends \humhub\components\Widget { // Dummy for old template version } + + private static function getSettings(): SettingsManager + { + return Yii::$app->getModule('tour')->settings; + } + + public static function isEnabledAutoStart(?string $type = null, ?User $user = null): bool + { + if ($type === null) { + $type = self::getCurrentType(); + if ($type === null) { + return false; + } + $type = $type['type']; + } + + return (bool) self::getSettings()->user($user)->get('autoStartTour.' . $type, false); + } + + public static function enableAutoStart(string $type, ?User $user = null) + { + self::getSettings()->user($user)->set('autoStartTour.' . $type, true); + } + + public static function disableAutoStart(string $type, ?User $user = null) + { + if (self::isEnabledAutoStart($type)) { + self::getSettings()->user($user)->delete('autoStartTour.' . $type); + } + } + + private static function getCurrentType(): ?array + { + foreach (self::getTypes() as $type => $tour) { + if (Yii::$app->controller instanceof $tour['controller']) { + $tour['type'] = $type; + return $tour; + } + } + + return null; + } } diff --git a/protected/humhub/modules/user/tests/codeception/fixtures/data/user.php b/protected/humhub/modules/user/tests/codeception/fixtures/data/user.php index 051e1b5bc7..8bd6cae2e6 100644 --- a/protected/humhub/modules/user/tests/codeception/fixtures/data/user.php +++ b/protected/humhub/modules/user/tests/codeception/fixtures/data/user.php @@ -20,12 +20,12 @@ return [ // Working Users - ['id' => 1, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f5839c', 'status' => '1','username' => 'Admin', 'email' => 'admin@example.com', 'contentcontainer_id' => 1, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-05 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-05 05:36:19', 'updated_by' => '1', 'last_login' => '2014-08-05 05:36:16'], - ['id' => 2, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f5839d', 'status' => '1','username' => 'User1', 'email' => 'user1@example.com', 'contentcontainer_id' => 2, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-07 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-07 05:36:02', 'updated_by' => null, 'last_login' => '2014-08-07 05:36:16'], - ['id' => 3, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f5839e', 'status' => '1','username' => 'User2', 'email' => 'user2@example.com', 'contentcontainer_id' => 3, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-08 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-08 05:36:02', 'updated_by' => null, 'last_login' => '2014-08-08 05:36:16'], - ['id' => 4, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f5839f', 'status' => '1','username' => 'User3', 'email' => 'user3@example.com', 'contentcontainer_id' => 8, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-08 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-08 05:36:19', 'updated_by' => '1', 'last_login' => '2014-08-08 05:36:16'], - ['id' => 5, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f58399', 'status' => '0','username' => 'DisabledUser', 'email' => 'disabled@example.com', 'contentcontainer_id' => 9, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-08 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-08 05:36:19', 'updated_by' => '1', 'last_login' => '2014-08-07 05:36:16'], - ['id' => 6, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f58390', 'status' => '2','username' => 'UnapprovedUser', 'email' => 'unnapproved@example.com', 'contentcontainer_id' => 10, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-08 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-08 05:36:19', 'updated_by' => '1', 'last_login' => '2014-08-07 05:36:16'], - ['id' => 7, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f58391', 'status' => '2','username' => 'UnapprovedNoGroup', 'email' => 'unnapprovedNoGroup@example.com', 'contentcontainer_id' => 11, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-08 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-08 05:36:19', 'updated_by' => '1', 'last_login' => '2014-08-07 05:36:16'], - ['id' => 8, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f58393', 'status' => '1','username' => 'AdminNotMember', 'email' => 'adminnotmember@example.com', 'contentcontainer_id' => 13, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-08 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-08 05:36:19', 'updated_by' => '1', 'last_login' => '2014-08-05 05:36:16'], + ['id' => 1, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f5839c', 'status' => '1','username' => 'Admin', 'email' => 'admin@example.com', 'contentcontainer_id' => 1, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-05 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-05 05:36:19', 'updated_by' => '1', 'last_login' => null], + ['id' => 2, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f5839d', 'status' => '1','username' => 'User1', 'email' => 'user1@example.com', 'contentcontainer_id' => 2, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-07 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-07 05:36:02', 'updated_by' => null, 'last_login' => null], + ['id' => 3, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f5839e', 'status' => '1','username' => 'User2', 'email' => 'user2@example.com', 'contentcontainer_id' => 3, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-08 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-08 05:36:02', 'updated_by' => null, 'last_login' => null], + ['id' => 4, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f5839f', 'status' => '1','username' => 'User3', 'email' => 'user3@example.com', 'contentcontainer_id' => 8, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-08 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-08 05:36:19', 'updated_by' => '1', 'last_login' => null], + ['id' => 5, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f58399', 'status' => '0','username' => 'DisabledUser', 'email' => 'disabled@example.com', 'contentcontainer_id' => 9, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-08 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-08 05:36:19', 'updated_by' => '1', 'last_login' => null], + ['id' => 6, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f58390', 'status' => '2','username' => 'UnapprovedUser', 'email' => 'unnapproved@example.com', 'contentcontainer_id' => 10, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-08 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-08 05:36:19', 'updated_by' => '1', 'last_login' => null], + ['id' => 7, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f58391', 'status' => '2','username' => 'UnapprovedNoGroup', 'email' => 'unnapprovedNoGroup@example.com', 'contentcontainer_id' => 11, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-08 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-08 05:36:19', 'updated_by' => '1', 'last_login' => null], + ['id' => 8, 'guid' => '01e50e0d-82cd-41fc-8b0c-552392f58393', 'status' => '1','username' => 'AdminNotMember', 'email' => 'adminnotmember@example.com', 'contentcontainer_id' => 13, 'auth_mode' => 'local', 'language' => 'en-US', 'created_at' => '2014-08-08 05:36:02', 'created_by' => null, 'updated_at' => '2014-08-08 05:36:19', 'updated_by' => '1', 'last_login' => null], ];