mirror of
https://github.com/wassname/talk.git
synced 2026-07-11 23:43:20 +08:00
feat: added moderation email notifications (#2525)
This commit is contained in:
@@ -107,6 +107,20 @@ email-template-notificationOnStaffReply =
|
||||
{ $organizationName } - <a data-l10n-name="storyLink">{ $storyTitle }</a><br /><br/>
|
||||
{ $authorUsername } works for { $organizationName } and has replied to your comment: <a data-l10n-name="commentPermalink">View comment</a>
|
||||
|
||||
## On Comment Approved
|
||||
|
||||
email-subject-notificationOnCommentApproved = Your comment on { $organizationName } has been published
|
||||
email-template-notificationOnCommentApproved =
|
||||
{ $organizationName }<br /><br/>
|
||||
Thank you for submitting your comment. Your comment has now been published: <a data-l10n-name="commentPermalink">View comment</a>
|
||||
|
||||
## On Comment Rejected
|
||||
|
||||
email-subject-notificationOnCommentRejected = Your comment on { $organizationName } was not published
|
||||
email-template-notificationOnCommentRejected =
|
||||
{ $organizationName }<br /><br/>
|
||||
The language used in one of your comments did not comply with our community guidelines, and so the comment has been removed.
|
||||
|
||||
# Notification Digest
|
||||
|
||||
email-subject-notificationDigest = Your latest comment activity at { $organizationName }
|
||||
|
||||
@@ -8,3 +8,8 @@ export const PUBLISHED_STATUSES = [
|
||||
GQLCOMMENT_STATUS.NONE,
|
||||
GQLCOMMENT_STATUS.APPROVED,
|
||||
];
|
||||
|
||||
export const MODERATOR_STATUSES = [
|
||||
GQLCOMMENT_STATUS.PREMOD,
|
||||
GQLCOMMENT_STATUS.SYSTEM_WITHHELD,
|
||||
];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { GQLCOMMENT_STATUS } from "coral-server/graph/tenant/schema/__generated__/types";
|
||||
|
||||
import { Comment } from "./comment";
|
||||
import { PUBLISHED_STATUSES } from "./constants";
|
||||
import { MODERATOR_STATUSES, PUBLISHED_STATUSES } from "./constants";
|
||||
import { Revision } from "./revision";
|
||||
|
||||
/**
|
||||
@@ -25,6 +25,10 @@ export function hasPublishedStatus(comment: Pick<Comment, "status">): boolean {
|
||||
return PUBLISHED_STATUSES.includes(comment.status);
|
||||
}
|
||||
|
||||
export function hasModeratorStatus(comment: Pick<Comment, "status">): boolean {
|
||||
return MODERATOR_STATUSES.includes(comment.status);
|
||||
}
|
||||
|
||||
/**
|
||||
* getLatestRevision will get the latest revision from a Comment.
|
||||
*
|
||||
|
||||
@@ -45,10 +45,24 @@ export type OnFeaturedTemplate = NotificationContext<
|
||||
}
|
||||
>;
|
||||
|
||||
export type OnCommentRejectedTemplate = NotificationContext<
|
||||
"notification/on-comment-rejected",
|
||||
{}
|
||||
>;
|
||||
|
||||
export type OnCommentApprovedTemplate = NotificationContext<
|
||||
"notification/on-comment-approved",
|
||||
{
|
||||
commentPermalink: string;
|
||||
}
|
||||
>;
|
||||
|
||||
export type DigestibleTemplate =
|
||||
| OnReplyTemplate
|
||||
| OnStaffReplyTemplate
|
||||
| OnFeaturedTemplate;
|
||||
| OnFeaturedTemplate
|
||||
| OnCommentRejectedTemplate
|
||||
| OnCommentApprovedTemplate;
|
||||
|
||||
type DigestTemplate = NotificationContext<
|
||||
"notification/digest",
|
||||
@@ -187,6 +201,8 @@ type Templates =
|
||||
| OnReplyTemplate
|
||||
| OnStaffReplyTemplate
|
||||
| OnFeaturedTemplate
|
||||
| DigestTemplate;
|
||||
| DigestTemplate
|
||||
| OnCommentRejectedTemplate
|
||||
| OnCommentApprovedTemplate;
|
||||
|
||||
export { Templates as EmailTemplate };
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{% extends "layouts/notification.html" %}
|
||||
@@ -0,0 +1 @@
|
||||
{% extends "layouts/notification.html" %}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
<div data-l10n-id="email-template-notificationOnCommentApproved" data-l10n-args="{{ context | dump }}">
|
||||
{{ context.organizationName }}<br /><br/>
|
||||
Thank you for submitting your comment. Your comment has now been published: <a data-l10n-name="commentPermalink" href="{{ context.commentPermalink }}">View comment</a>
|
||||
</div>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
<div data-l10n-id="email-template-notificationOnCommentRejected" data-l10n-args="{{ context | dump }}">
|
||||
{{ context.organizationName }}<br /><br/>
|
||||
The language used in one of your comments did not comply with our community guidelines, and so the comment has been removed.
|
||||
</div>
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NotificationCategory } from "./category";
|
||||
import { featured } from "./featured";
|
||||
import { moderation } from "./moderation";
|
||||
import { reply } from "./reply";
|
||||
import { staffReply } from "./staffReply";
|
||||
|
||||
@@ -10,6 +11,7 @@ const categories: NotificationCategory[] = [
|
||||
...reply,
|
||||
...staffReply,
|
||||
...featured,
|
||||
...moderation,
|
||||
];
|
||||
|
||||
export default categories;
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import { CommentStatusUpdatedInput } from "coral-server/graph/tenant/resolvers/Subscription/commentStatusUpdated";
|
||||
import { SUBSCRIPTION_CHANNELS } from "coral-server/graph/tenant/resolvers/Subscription/types";
|
||||
import { hasModeratorStatus } from "coral-server/models/comment";
|
||||
|
||||
import { GQLCOMMENT_STATUS } from "coral-server/graph/tenant/schema/__generated__/types";
|
||||
import { getURLWithCommentID } from "coral-server/models/story";
|
||||
import NotificationContext from "../context";
|
||||
import { Notification } from "../notification";
|
||||
import { NotificationCategory } from "./category";
|
||||
|
||||
async function processor(
|
||||
ctx: NotificationContext,
|
||||
input: CommentStatusUpdatedInput
|
||||
): Promise<Notification | null> {
|
||||
// Check to see if this comment was previously in a moderation status.
|
||||
if (!hasModeratorStatus({ status: input.oldStatus })) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Load the comment in question.
|
||||
const comment = await ctx.comments.load(input.commentID);
|
||||
if (!comment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the comment author.
|
||||
const author = await ctx.users.load(comment.authorID);
|
||||
if (!author) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check to see if this user has notifications enabled.
|
||||
if (!author.notifications.onModeration) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Generate the unsubscribe URL.
|
||||
const unsubscribeURL = await ctx.generateUnsubscribeURL(author);
|
||||
|
||||
// Check to see which template we should use.
|
||||
if (comment.status === GQLCOMMENT_STATUS.APPROVED) {
|
||||
// Get the story that this was written on.
|
||||
const story = await ctx.stories.load(comment.storyID);
|
||||
if (!story) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
userID: author.id,
|
||||
template: {
|
||||
name: "notification/on-comment-approved",
|
||||
context: {
|
||||
commentPermalink: getURLWithCommentID(story.url, comment.id),
|
||||
organizationName: ctx.tenant.organization.name,
|
||||
organizationURL: ctx.tenant.organization.url,
|
||||
unsubscribeURL,
|
||||
},
|
||||
},
|
||||
};
|
||||
} else if (comment.status === GQLCOMMENT_STATUS.REJECTED) {
|
||||
return {
|
||||
userID: author.id,
|
||||
template: {
|
||||
name: "notification/on-comment-rejected",
|
||||
context: {
|
||||
organizationName: ctx.tenant.organization.name,
|
||||
organizationURL: ctx.tenant.organization.url,
|
||||
unsubscribeURL,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export const moderation: NotificationCategory[] = [
|
||||
{
|
||||
name: "moderation",
|
||||
process: processor,
|
||||
event: SUBSCRIPTION_CHANNELS.COMMENT_STATUS_UPDATED,
|
||||
digestOrder: 30,
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user