Skip to content

Commit

Permalink
Merge pull request #232 from mobeigi/fix-unsubscribe-when-admin-email…
Browse files Browse the repository at this point in the history
…-in-children

Fix bug where unsubscription fails due to admin comment in children c…
  • Loading branch information
mobeigi authored Feb 3, 2025
2 parents 91e796d + 8f6e2d8 commit 499bb84
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { NextResponse } from 'next/server';
import { getPayload } from 'payload';
import config from '@payload-config';
import { createPayloadHmac256 } from '@/utils/crypto/hmac256';
import { headers } from 'next/headers';

export const GET = async (request: Request, { params: paramsPromise }: { params: Promise<{ commentId: string }> }) => {
try {
Expand Down Expand Up @@ -41,17 +40,18 @@ export const GET = async (request: Request, { params: paramsPromise }: { params:
return NextResponse.json({ error: 'You have already unsubscribed from this comment.' }, { status: 400 });
}

const headerList = await headers();
const result = await payload.auth({ headers: headerList });

await payload.update({
collection: 'comments',
id: commentId,
data: {
notifyOnReply: false,
},
overrideAccess: true,
user: result.user,
context: {
// Avoid performing unnecessary validation since we are only updating the 'notifyOnReply'
bypassUserValidation: true,
bypassSpamValidation: true,
},
});

return NextResponse.json({ message: 'You have successfully unsubscribed from this comment.' }, { status: 200 });
Expand Down
178 changes: 93 additions & 85 deletions app/src/payload/collections/Comments/hooks/validationHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { BASE_URL } from '@/constants/app';
import { requireEnvVar } from '@/utils/env';
import { Author, Blog, CheckResult, Client, Comment, CommentType } from '@cedx/akismet';

export const validationHook: CollectionBeforeValidateHook = async ({ data, req, operation }) => {
export const validationHook: CollectionBeforeValidateHook = async ({ data, req, operation, context }) => {
if (!data) {
throw new ValidationError({
collection: 'comments',
Expand Down Expand Up @@ -49,46 +49,48 @@ export const validationHook: CollectionBeforeValidateHook = async ({ data, req,
}

// Authenticated comment path where the comment email belongs to a Payload user
const userBeingImpersonatedDocs = await req.payload.find({
collection: 'users',
where: {
email: {
equals: comment.email,
if (context.bypassUserValidation !== true) {
const userBeingImpersonatedDocs = await req.payload.find({
collection: 'users',
where: {
email: {
equals: comment.email,
},
},
},
limit: 1,
});

if (userBeingImpersonatedDocs.docs.length) {
const userBeingImpersonated = userBeingImpersonatedDocs.docs[0];

if (!signedInUser) {
throw new ValidationError({
collection: 'comments',
errors: [
{
path: 'email',
message: 'You must be signed in to submit a comment using this email address.',
},
],
});
}
limit: 1,
});

if (signedInUser.id !== userBeingImpersonated.id) {
throw new ValidationError({
collection: 'comments',
errors: [
{
path: 'email',
message:
'The email address provided does not match your authenticated account. Please use your account email to submit a comment.',
},
],
});
if (userBeingImpersonatedDocs.docs.length) {
const userBeingImpersonated = userBeingImpersonatedDocs.docs[0];

if (!signedInUser) {
throw new ValidationError({
collection: 'comments',
errors: [
{
path: 'email',
message: 'You must be signed in to submit a comment using this email address.',
},
],
});
}

if (signedInUser.id !== userBeingImpersonated.id) {
throw new ValidationError({
collection: 'comments',
errors: [
{
path: 'email',
message:
'The email address provided does not match your authenticated account. Please use your account email to submit a comment.',
},
],
});
}

// Set author to signed in user
comment.author = signedInUser.id;
}

// Set author to signed in user
comment.author = signedInUser.id;
}

if (!comment.ipAddress) {
Expand Down Expand Up @@ -126,57 +128,63 @@ export const validationHook: CollectionBeforeValidateHook = async ({ data, req,
}

// Akismet spam check for anonymous comments
if (!signedInUser) {
if (!comment.content) {
throw new ValidationError({
collection: 'comments',
errors: [{ path: 'content', message: 'Content is required to submit a comment.' }],
if (context.bypassSpamValidation !== true) {
if (!signedInUser) {
if (!comment.content) {
throw new ValidationError({
collection: 'comments',
errors: [{ path: 'content', message: 'Content is required to submit a comment.' }],
});
}
const commentTextContent = extractTextContent(comment.content) || '';

const akismetWebsite = new Blog({
charset: 'UTF-8',
languages: ['en'],
url: BASE_URL,
});
}
const commentTextContent = extractTextContent(comment.content) || '';

const akismetWebsite = new Blog({
charset: 'UTF-8',
languages: ['en'],
url: BASE_URL,
});
const akismetClient = new Client(requireEnvVar(process.env.AKISMET_API_KEY, 'AKISMET_API_KEY'), akismetWebsite, {
userAgent: 'Node.js | Akismet/1.0',
});

const akismetAuthor = new Author({
email: comment.email,
ipAddress: comment.ipAddress,
name: comment.displayName,
role: 'guest',
userAgent: comment.userAgent,
});

const akismetComment = new Comment({
author: akismetAuthor,
date: comment.createdAt ? new Date(comment.createdAt) : null,
content: commentTextContent,
type: CommentType.comment,
});

let akismetCheckResult;
try {
akismetCheckResult = await akismetClient.checkComment(akismetComment);
} catch (error) {
console.warn('Unable to perform spam check.', error);
throw new ValidationError({
collection: 'comments',
errors: [],
global: 'Unable to perform spam check. Please try again later.',
const akismetClient = new Client(
requireEnvVar(process.env.AKISMET_API_KEY, 'AKISMET_API_KEY'),
akismetWebsite,
{
userAgent: 'Node.js | Akismet/1.0',
},
);

const akismetAuthor = new Author({
email: comment.email,
ipAddress: comment.ipAddress,
name: comment.displayName,
role: 'guest',
userAgent: comment.userAgent,
});
}

if (akismetCheckResult === CheckResult.spam) {
throw new ValidationError({
collection: 'comments',
errors: [],
global: 'Your comment was flagged as spam and could not be submitted.',
const akismetComment = new Comment({
author: akismetAuthor,
date: comment.createdAt ? new Date(comment.createdAt) : null,
content: commentTextContent,
type: CommentType.comment,
});

let akismetCheckResult;
try {
akismetCheckResult = await akismetClient.checkComment(akismetComment);
} catch (error) {
console.warn('Unable to perform spam check.', error);
throw new ValidationError({
collection: 'comments',
errors: [],
global: 'Unable to perform spam check. Please try again later.',
});
}

if (akismetCheckResult === CheckResult.spam) {
throw new ValidationError({
collection: 'comments',
errors: [],
global: 'Your comment was flagged as spam and could not be submitted.',
});
}
}
}
}
Expand Down

0 comments on commit 499bb84

Please sign in to comment.