2
1
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2023-12-13 21:00:40 +01:00

Restored newsletter email verification flow (#18548)

refs https://github.com/TryGhost/Product/issues/3832

---

<!-- Leave the line below if you'd like GitHub Copilot to generate a
summary from your commit -->
<!--
copilot:summary
-->
### <samp>🤖 Generated by Copilot at 8a40cbc</samp>

This pull request adds a feature to verify the sender email address for
a newsletter in the admin settings app. It implements a UI component, a
custom hook, and a server-side service to handle the verification
process. It also fixes a minor typo and a navigation issue in the
newsletters module.
This commit is contained in:
Jono M 2023-10-10 07:34:48 +01:00 committed by GitHub
parent 7f2dc6e5fa
commit 4b07de885a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 4 deletions

View file

@ -97,3 +97,15 @@ export const useEditNewsletter = createMutation<NewslettersEditResponseType, New
update: updateQueryCache('newsletters')
}
});
export const useVerifyNewsletterEmail = createMutation<NewslettersResponseType, {token: string}>({
method: 'PUT',
path: () => '/newsletters/verifications/',
body: ({token}) => ({token}),
defaultSearchParams: {include: 'count.active_members,count.posts'},
updateQueries: {
dataType,
emberUpdateType: 'createOrUpdate',
update: updateQueryCache('newsletters')
}
});

View file

@ -1,12 +1,27 @@
import Button from '../../../admin-x-ds/global/Button';
import ConfirmationModal from '../../../admin-x-ds/global/modal/ConfirmationModal';
import NewslettersList from './newsletters/NewslettersList';
import React, {useState} from 'react';
import NiceModal, {useModal} from '@ebay/nice-modal-react';
import React, {ReactNode, useEffect, useState} from 'react';
import SettingGroup from '../../../admin-x-ds/settings/SettingGroup';
import TabView from '../../../admin-x-ds/global/TabView';
import useHandleError from '../../../utils/api/handleError';
import useQueryParams from '../../../hooks/useQueryParams';
import useRouting from '../../../hooks/useRouting';
import {useBrowseNewsletters} from '../../../api/newsletters';
import {APIError} from '../../../utils/errors';
import {useBrowseNewsletters, useVerifyNewsletterEmail} from '../../../api/newsletters';
import {withErrorBoundary} from '../../../admin-x-ds/global/ErrorBoundary';
const NavigateToNewsletter = ({id, children}: {id: string; children: ReactNode}) => {
const modal = useModal();
const {updateRoute} = useRouting();
return <button className="text-green" type="button" onClick={() => {
updateRoute(`newsletters/${id}`);
modal.remove();
}}>{children}</button>;
};
const Newsletters: React.FC<{ keywords: string[] }> = ({keywords}) => {
const {updateRoute} = useRouting();
const openNewsletterModal = () => {
@ -15,6 +30,45 @@ const Newsletters: React.FC<{ keywords: string[] }> = ({keywords}) => {
const [selectedTab, setSelectedTab] = useState('active-newsletters');
const {data: {newsletters, meta, isEnd} = {}, fetchNextPage} = useBrowseNewsletters();
const verifyEmailToken = useQueryParams().getParam('verifyEmail');
const {mutateAsync: verifyEmail} = useVerifyNewsletterEmail();
const handleError = useHandleError();
useEffect(() => {
if (!verifyEmailToken) {
return;
}
const verify = async () => {
try {
const {newsletters: [updatedNewsletter]} = await verifyEmail({token: verifyEmailToken});
NiceModal.show(ConfirmationModal, {
title: 'Email address verified',
prompt: <>Success! From address for newsletter <NavigateToNewsletter id={updatedNewsletter.id}>{updatedNewsletter.name}</NavigateToNewsletter> changed to <strong>{updatedNewsletter.sender_email}</strong></>,
okLabel: 'Close',
cancelLabel: '',
onOk: confirmModal => confirmModal?.remove()
});
} catch (e) {
let prompt = 'There was an error verifying your email address. Please try again.';
if (e instanceof APIError && e.message === 'Token expired') {
prompt = 'The verification link has expired. Please try again.';
}
NiceModal.show(ConfirmationModal, {
title: 'Error verifying email address',
prompt: prompt,
okLabel: 'Close',
cancelLabel: '',
onOk: confirmModal => confirmModal?.remove()
});
handleError(e, {withToast: false});
}
};
verify();
}, [verifyEmailToken, handleError, verifyEmail]);
const buttons = (
<Button color='green' label='Add newsletter' link linkWithPadding onClick={() => {
openNewsletterModal();

View file

@ -455,6 +455,7 @@ const NewsletterDetailModalContent: React.FC<{newsletter: Newsletter; onlyOne: b
onOk: (confirmModal) => {
confirmModal?.remove();
modal.remove();
updateRoute('newsletters');
}
});
}

View file

@ -199,7 +199,7 @@ class NewslettersService {
}
let updatedNewsletter;
try {
updatedNewsletter = await this.NewsletterModel.edit(cleanedAttrs, options);
} catch (error) {
@ -215,7 +215,7 @@ class NewslettersService {
// Load relations correctly in the response
updatedNewsletter = await this.NewsletterModel.findOne({id: updatedNewsletter.id}, {...options, require: true});
await this.respondWithEmailVerification(updatedNewsletter, emailsToVerify);
return updatedNewsletter;
}