From bf859c38ee415eb55df57cf4bf9344f02ab95395 Mon Sep 17 00:00:00 2001
From: Simon Backx <simon@ghost.org>
Date: Fri, 3 Nov 2023 16:02:46 +0100
Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Fixed=20showing=20recommendation?=
 =?UTF-8?q?s=20on=20custom=20welcome=20pages=20(#18864)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

no issue

When a custom welcome page is set for a tier, the recommendations modal
didn't show. If recommendations were disabled, there was also no toast
to confirm the sign up.

To fix this, we'll need to set the success and action query parameters
on the welcome page, but only if it is not an external site.
---
 .../server/services/members/middleware.js     |  8 +++
 .../core/test/e2e-api/members/signin.test.js  | 49 ++++++++++++++-----
 2 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/ghost/core/core/server/services/members/middleware.js b/ghost/core/core/server/services/members/middleware.js
index 23451c2ecd..a3ad49a4fb 100644
--- a/ghost/core/core/server/services/members/middleware.js
+++ b/ghost/core/core/server/services/members/middleware.js
@@ -265,8 +265,16 @@ const createSessionFromMagicLink = async function createSessionFromMagicLink(req
                 const ensureEndsWith = (string, endsWith) => (string.endsWith(endsWith) ? string : string + endsWith);
                 const removeLeadingSlash = string => string.replace(/^\//, '');
 
+                // Add query parameters so the frontend can detect that the signup went fine
+
                 const redirectUrl = new URL(removeLeadingSlash(ensureEndsWith(customRedirect, '/')), ensureEndsWith(baseUrl, '/'));
 
+                if (urlUtils.isSiteUrl(redirectUrl)) {
+                    // Add only for non-external URLs
+                    redirectUrl.searchParams.set('success', 'true');
+                    redirectUrl.searchParams.set('action', 'signup');
+                }
+
                 return res.redirect(redirectUrl.href);
             }
         }
diff --git a/ghost/core/test/e2e-api/members/signin.test.js b/ghost/core/test/e2e-api/members/signin.test.js
index 7ef02f0e30..aaa238bbec 100644
--- a/ghost/core/test/e2e-api/members/signin.test.js
+++ b/ghost/core/test/e2e-api/members/signin.test.js
@@ -3,6 +3,7 @@ const models = require('../../../core/server/models');
 const assert = require('assert/strict');
 require('should');
 const sinon = require('sinon');
+const members = require('../../../core/server/services/members');
 
 let membersAgent, membersService;
 
@@ -64,7 +65,7 @@ describe('Members Signin', function () {
 
         await membersAgent.get(`/?token=${token}&action=signup`)
             .expectStatus(302)
-            .expectHeader('Location', /\/welcome-free\/$/)
+            .expectHeader('Location', /\/welcome-free\/\?success=true&action=signup$/)
             .expectHeader('Set-Cookie', /members-ssr.*/);
     });
 
@@ -75,7 +76,7 @@ describe('Members Signin', function () {
 
         await membersAgent.get(`/?token=${token}&action=signup-paid`)
             .expectStatus(302)
-            .expectHeader('Location', /\/welcome-paid\/$/)
+            .expectHeader('Location', /\/welcome-paid\/\?success=true&action=signup$/)
             .expectHeader('Set-Cookie', /members-ssr.*/);
     });
 
@@ -86,10 +87,36 @@ describe('Members Signin', function () {
 
         await membersAgent.get(`/?token=${token}&action=subscribe`)
             .expectStatus(302)
-            .expectHeader('Location', /\/welcome-free\/$/)
+            .expectHeader('Location', /\/welcome-free\/\?success=true&action=signup$/)
             .expectHeader('Set-Cookie', /members-ssr.*/);
     });
 
+    it('Will redirect to an external welcome page for subscribe', async function () {
+        // Alter the product welcome page to an external URL
+        const freeProduct = await members.api.productRepository.get({slug: 'free'});
+        await members.api.productRepository.update({
+            id: freeProduct.id,
+            welcome_page_url: 'https://externalsite.ghost/welcome/'
+        });
+
+        try {
+            const magicLink = await membersService.api.getMagicLink('member1@test.com', 'signup');
+            const magicLinkUrl = new URL(magicLink);
+            const token = magicLinkUrl.searchParams.get('token');
+
+            await membersAgent.get(`/?token=${token}&action=subscribe`)
+                .expectStatus(302)
+                .expectHeader('Location', 'https://externalsite.ghost/welcome/') // no query params added
+                .expectHeader('Set-Cookie', /members-ssr.*/);
+        } finally {
+            // Change it back
+            await members.api.productRepository.update({
+                id: freeProduct.id,
+                welcome_page_url: freeProduct.get('welcome_page_url')
+            });
+        }
+    });
+
     it('Will create a new member on signup', async function () {
         const email = 'not-existent-member@test.com';
         const magicLink = await membersService.api.getMagicLink(email, 'signup');
@@ -98,7 +125,7 @@ describe('Members Signin', function () {
 
         await membersAgent.get(`/?token=${token}&action=signup`)
             .expectStatus(302)
-            .expectHeader('Location', /\/welcome-free\/$/)
+            .expectHeader('Location', /\/welcome-free\/\?success=true&action=signup$/)
             .expectHeader('Set-Cookie', /members-ssr.*/);
 
         const member = await getMemberByEmail(email);
@@ -129,7 +156,7 @@ describe('Members Signin', function () {
 
         await membersAgent.get(`/?token=${token}&action=signup`)
             .expectStatus(302)
-            .expectHeader('Location', /\/welcome-free\/$/)
+            .expectHeader('Location', /\/welcome-free\/\?success=true&action=signup$/)
             .expectHeader('Set-Cookie', /members-ssr.*/);
     });
 
@@ -173,7 +200,7 @@ describe('Members Signin', function () {
             // Use a first time
             await membersAgent.get(`/?token=${token}&action=signup`)
                 .expectStatus(302)
-                .expectHeader('Location', /\/welcome-free\/$/)
+                .expectHeader('Location', /\/welcome-free\/\?success=true&action=signup$/)
                 .expectHeader('Set-Cookie', /members-ssr.*/);
 
             // Fetch token in the database
@@ -189,7 +216,7 @@ describe('Members Signin', function () {
 
             await membersAgent.get(`/?token=${token}&action=signup`)
                 .expectStatus(302)
-                .expectHeader('Location', /\/welcome-free\/$/)
+                .expectHeader('Location', /\/welcome-free\/\?success=true&action=signup$/)
                 .expectHeader('Set-Cookie', /members-ssr.*/);
 
             await model.refresh();
@@ -226,17 +253,17 @@ describe('Members Signin', function () {
             // Use a first time
             await membersAgent.get(`/?token=${token}&action=signup`)
                 .expectStatus(302)
-                .expectHeader('Location', /\/welcome-free\/$/)
+                .expectHeader('Location', /\/welcome-free\/\?success=true&action=signup$/)
                 .expectHeader('Set-Cookie', /members-ssr.*/);
 
             await membersAgent.get(`/?token=${token}&action=signup`)
                 .expectStatus(302)
-                .expectHeader('Location', /\/welcome-free\/$/)
+                .expectHeader('Location', /\/welcome-free\/\?success=true&action=signup$/)
                 .expectHeader('Set-Cookie', /members-ssr.*/);
 
             await membersAgent.get(`/?token=${token}&action=signup`)
                 .expectStatus(302)
-                .expectHeader('Location', /\/welcome-free\/$/)
+                .expectHeader('Location', /\/welcome-free\/\?success=true&action=signup$/)
                 .expectHeader('Set-Cookie', /members-ssr.*/);
 
             // Fetch token in the database
@@ -534,7 +561,7 @@ describe('Members Signin', function () {
 
             await membersAgent.get(`/?token=${token}&action=signup`)
                 .expectStatus(302)
-                .expectHeader('Location', /\/welcome-free\/$/)
+                .expectHeader('Location', /\/welcome-free\/\?success=true&action=signup$/)
                 .expectHeader('Set-Cookie', /members-ssr.*/);
 
             const member = await getMemberByEmail(email);