mirror of
https://github.com/wassname/talk.git
synced 2026-07-27 11:28:12 +08:00
[CORL-498, CORL-495, CORL-539, CORL-496, CORL-494] Email Notifications Support & Framework (#2498)
* chore: renamed old templates * feat: initial notifications support * feat: email enhancements * fix: linting * feat: initial digesting beheviour * feat: added notification configuration * feat: added unsubscribe routes * fix: fixed failing snapshots/tests bc random ids * feat: adjusted the save beheviour, added tests * feat: added tests * feat: added staff replies * feat: renamed E-Mail to Email * feat: enhanced cron processing * fix: linting + updating tests * feat: enhanced cron context * fix: added staff replies back in
This commit is contained in:
@@ -9,6 +9,7 @@ import logger from "coral-server/logger";
|
||||
import { Tenant } from "coral-server/models/tenant";
|
||||
import { User } from "coral-server/models/user";
|
||||
import { MailerQueue } from "coral-server/queue/tasks/mailer";
|
||||
import { NotifierQueue } from "coral-server/queue/tasks/notifier";
|
||||
import { ScraperQueue } from "coral-server/queue/tasks/scraper";
|
||||
import { JWTSigningConfig } from "coral-server/services/jwt";
|
||||
import TenantCache from "coral-server/services/tenant/cache";
|
||||
@@ -20,6 +21,7 @@ export interface TenantContextOptions extends CommonContextOptions {
|
||||
tenant: Tenant;
|
||||
tenantCache: TenantCache;
|
||||
mailerQueue: MailerQueue;
|
||||
notifierQueue: NotifierQueue;
|
||||
scraperQueue: ScraperQueue;
|
||||
signingConfig?: JWTSigningConfig;
|
||||
clientID?: string;
|
||||
@@ -41,6 +43,7 @@ export default class TenantContext extends CommonContext {
|
||||
constructor({
|
||||
tenant,
|
||||
logger: log = logger,
|
||||
notifierQueue,
|
||||
...options
|
||||
}: TenantContextOptions) {
|
||||
super({
|
||||
@@ -57,6 +60,7 @@ export default class TenantContext extends CommonContext {
|
||||
this.clientID = options.clientID;
|
||||
this.publisher = createPublisher(
|
||||
this.pubsub,
|
||||
notifierQueue,
|
||||
this.tenant.id,
|
||||
this.clientID
|
||||
);
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
updateAvatar,
|
||||
updateEmail,
|
||||
updateEmailByID,
|
||||
updateNotificationSettings,
|
||||
updatePassword,
|
||||
updateRole,
|
||||
updateUsername,
|
||||
@@ -46,6 +47,7 @@ import {
|
||||
GQLSetUsernameInput,
|
||||
GQLSuspendUserInput,
|
||||
GQLUpdateEmailInput,
|
||||
GQLUpdateNotificationSettingsInput,
|
||||
GQLUpdatePasswordInput,
|
||||
GQLUpdateUserAvatarInput,
|
||||
GQLUpdateUserEmailInput,
|
||||
@@ -53,6 +55,7 @@ import {
|
||||
GQLUpdateUserRoleInput,
|
||||
GQLUpdateUserUsernameInput,
|
||||
} from "../schema/__generated__/types";
|
||||
import { WithoutMutationID } from "./util";
|
||||
|
||||
export const Users = (ctx: TenantContext) => ({
|
||||
invite: async ({ role, emails }: GQLInviteUsersInput) =>
|
||||
@@ -178,6 +181,9 @@ export const Users = (ctx: TenantContext) => ({
|
||||
input.email,
|
||||
input.password
|
||||
),
|
||||
updateNotificationSettings: async (
|
||||
input: WithoutMutationID<GQLUpdateNotificationSettingsInput>
|
||||
) => updateNotificationSettings(ctx.mongo, ctx.tenant, ctx.user!, input),
|
||||
updateUserAvatar: async (input: GQLUpdateUserAvatarInput) =>
|
||||
updateAvatar(ctx.mongo, ctx.tenant, input.userID, input.avatar),
|
||||
updateUserRole: async (input: GQLUpdateUserRoleInput) =>
|
||||
|
||||
@@ -17,10 +17,10 @@ import {
|
||||
hasPublishedStatus,
|
||||
} from "coral-server/models/comment/helpers";
|
||||
import { createConnection } from "coral-server/models/helpers";
|
||||
import { getURLWithCommentID } from "coral-server/models/story";
|
||||
import { getCommentEditableUntilDate } from "coral-server/services/comments";
|
||||
|
||||
import TenantContext from "../context";
|
||||
import { getURLWithCommentID } from "./util";
|
||||
|
||||
export const maybeLoadOnlyID = (
|
||||
ctx: TenantContext,
|
||||
|
||||
@@ -25,6 +25,14 @@ export const Mutation: Required<GQLMutationTypeResolver<void>> = {
|
||||
},
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
updateNotificationSettings: async (
|
||||
source,
|
||||
{ input: { clientMutationId, ...input } },
|
||||
ctx
|
||||
) => ({
|
||||
user: await ctx.mutators.Users.updateNotificationSettings(input),
|
||||
clientMutationId,
|
||||
}),
|
||||
updateSettings: async (source, { input }, ctx) => ({
|
||||
settings: await ctx.mutators.Settings.update(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import { SubscriptionToCommentCreatedResolver } from "coral-server/graph/tenant/schema/__generated__/types";
|
||||
|
||||
import { createIterator } from "./helpers";
|
||||
import { SUBSCRIPTION_CHANNELS, SubscriptionPayload } from "./types";
|
||||
import {
|
||||
SUBSCRIPTION_CHANNELS,
|
||||
SubscriptionPayload,
|
||||
SubscriptionType,
|
||||
} from "./types";
|
||||
|
||||
export interface CommentCreatedInput extends SubscriptionPayload {
|
||||
storyID: string;
|
||||
commentID: string;
|
||||
}
|
||||
|
||||
export type CommentCreatedSubscription = SubscriptionType<
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_CREATED,
|
||||
CommentCreatedInput
|
||||
>;
|
||||
|
||||
export const commentCreated: SubscriptionToCommentCreatedResolver<
|
||||
CommentCreatedInput
|
||||
> = createIterator(SUBSCRIPTION_CHANNELS.COMMENT_CREATED, {
|
||||
|
||||
+10
-1
@@ -4,7 +4,11 @@ import {
|
||||
} from "coral-server/graph/tenant/schema/__generated__/types";
|
||||
|
||||
import { createIterator } from "./helpers";
|
||||
import { SUBSCRIPTION_CHANNELS, SubscriptionPayload } from "./types";
|
||||
import {
|
||||
SUBSCRIPTION_CHANNELS,
|
||||
SubscriptionPayload,
|
||||
SubscriptionType,
|
||||
} from "./types";
|
||||
|
||||
export interface CommentEnteredModerationQueueInput
|
||||
extends SubscriptionPayload {
|
||||
@@ -13,6 +17,11 @@ export interface CommentEnteredModerationQueueInput
|
||||
storyID: string;
|
||||
}
|
||||
|
||||
export type CommentEnteredModerationQueueSubscription = SubscriptionType<
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_ENTERED_MODERATION_QUEUE,
|
||||
CommentEnteredModerationQueueInput
|
||||
>;
|
||||
|
||||
export const commentEnteredModerationQueue: SubscriptionToCommentEnteredModerationQueueResolver<
|
||||
CommentEnteredModerationQueueInput
|
||||
> = createIterator(SUBSCRIPTION_CHANNELS.COMMENT_ENTERED_MODERATION_QUEUE, {
|
||||
|
||||
@@ -4,7 +4,11 @@ import {
|
||||
} from "coral-server/graph/tenant/schema/__generated__/types";
|
||||
|
||||
import { createIterator } from "./helpers";
|
||||
import { SUBSCRIPTION_CHANNELS, SubscriptionPayload } from "./types";
|
||||
import {
|
||||
SUBSCRIPTION_CHANNELS,
|
||||
SubscriptionPayload,
|
||||
SubscriptionType,
|
||||
} from "./types";
|
||||
|
||||
export interface CommentLeftModerationQueueInput extends SubscriptionPayload {
|
||||
queue: GQLMODERATION_QUEUE;
|
||||
@@ -12,6 +16,11 @@ export interface CommentLeftModerationQueueInput extends SubscriptionPayload {
|
||||
storyID: string;
|
||||
}
|
||||
|
||||
export type CommentLeftModerationQueueSubscription = SubscriptionType<
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_LEFT_MODERATION_QUEUE,
|
||||
CommentLeftModerationQueueInput
|
||||
>;
|
||||
|
||||
export const commentLeftModerationQueue: SubscriptionToCommentLeftModerationQueueResolver<
|
||||
CommentLeftModerationQueueInput
|
||||
> = createIterator(SUBSCRIPTION_CHANNELS.COMMENT_LEFT_MODERATION_QUEUE, {
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import { SubscriptionToCommentReplyCreatedResolver } from "coral-server/graph/tenant/schema/__generated__/types";
|
||||
|
||||
import { createIterator } from "./helpers";
|
||||
import { SUBSCRIPTION_CHANNELS, SubscriptionPayload } from "./types";
|
||||
import {
|
||||
SUBSCRIPTION_CHANNELS,
|
||||
SubscriptionPayload,
|
||||
SubscriptionType,
|
||||
} from "./types";
|
||||
|
||||
export interface CommentReplyCreatedInput extends SubscriptionPayload {
|
||||
ancestorIDs: string[];
|
||||
commentID: string;
|
||||
}
|
||||
|
||||
export type CommentReplyCreatedSubscription = SubscriptionType<
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_REPLY_CREATED,
|
||||
CommentReplyCreatedInput
|
||||
>;
|
||||
|
||||
export const commentReplyCreated: SubscriptionToCommentReplyCreatedResolver<
|
||||
CommentReplyCreatedInput
|
||||
> = createIterator(SUBSCRIPTION_CHANNELS.COMMENT_REPLY_CREATED, {
|
||||
|
||||
@@ -4,7 +4,11 @@ import {
|
||||
} from "coral-server/graph/tenant/schema/__generated__/types";
|
||||
|
||||
import { createIterator } from "./helpers";
|
||||
import { SUBSCRIPTION_CHANNELS, SubscriptionPayload } from "./types";
|
||||
import {
|
||||
SUBSCRIPTION_CHANNELS,
|
||||
SubscriptionPayload,
|
||||
SubscriptionType,
|
||||
} from "./types";
|
||||
|
||||
export interface CommentStatusUpdatedInput extends SubscriptionPayload {
|
||||
newStatus: GQLCOMMENT_STATUS;
|
||||
@@ -13,6 +17,11 @@ export interface CommentStatusUpdatedInput extends SubscriptionPayload {
|
||||
commentID: string;
|
||||
}
|
||||
|
||||
export type CommentStatusUpdatedSubscription = SubscriptionType<
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_STATUS_UPDATED,
|
||||
CommentStatusUpdatedInput
|
||||
>;
|
||||
|
||||
export const commentStatusUpdated: SubscriptionToCommentStatusUpdatedResolver<
|
||||
CommentStatusUpdatedInput
|
||||
> = createIterator(SUBSCRIPTION_CHANNELS.COMMENT_STATUS_UPDATED, {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { CommentCreatedInput } from "./commentCreated";
|
||||
import { CommentEnteredModerationQueueInput } from "./commentEnteredModerationQueue";
|
||||
import { CommentLeftModerationQueueInput } from "./commentLeftModerationQueue";
|
||||
import { CommentReplyCreatedInput } from "./commentReplyCreated";
|
||||
import { CommentStatusUpdatedInput } from "./commentStatusUpdated";
|
||||
import { CommentCreatedSubscription } from "./commentCreated";
|
||||
import { CommentEnteredModerationQueueSubscription } from "./commentEnteredModerationQueue";
|
||||
import { CommentLeftModerationQueueSubscription } from "./commentLeftModerationQueue";
|
||||
import { CommentReplyCreatedSubscription } from "./commentReplyCreated";
|
||||
import { CommentStatusUpdatedSubscription } from "./commentStatusUpdated";
|
||||
|
||||
export enum SUBSCRIPTION_CHANNELS {
|
||||
COMMENT_ENTERED_MODERATION_QUEUE = "COMMENT_ENTERED_MODERATION_QUEUE",
|
||||
@@ -25,23 +25,8 @@ export interface SubscriptionType<
|
||||
}
|
||||
|
||||
export type SUBSCRIPTION_INPUT =
|
||||
| SubscriptionType<
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_ENTERED_MODERATION_QUEUE,
|
||||
CommentEnteredModerationQueueInput
|
||||
>
|
||||
| SubscriptionType<
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_LEFT_MODERATION_QUEUE,
|
||||
CommentLeftModerationQueueInput
|
||||
>
|
||||
| SubscriptionType<
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_STATUS_UPDATED,
|
||||
CommentStatusUpdatedInput
|
||||
>
|
||||
| SubscriptionType<
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_REPLY_CREATED,
|
||||
CommentReplyCreatedInput
|
||||
>
|
||||
| SubscriptionType<
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_CREATED,
|
||||
CommentCreatedInput
|
||||
>;
|
||||
| CommentEnteredModerationQueueSubscription
|
||||
| CommentLeftModerationQueueSubscription
|
||||
| CommentStatusUpdatedSubscription
|
||||
| CommentReplyCreatedSubscription
|
||||
| CommentCreatedSubscription;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { GraphQLResolveInfo } from "graphql";
|
||||
import graphqlFields from "graphql-fields";
|
||||
import { pull } from "lodash";
|
||||
import { URL } from "url";
|
||||
|
||||
import { parseQuery, stringifyQuery } from "coral-common/utils";
|
||||
import { constructTenantURL, reconstructURL } from "coral-server/app/url";
|
||||
|
||||
import TenantContext from "../context";
|
||||
@@ -17,20 +15,6 @@ export function getRequestedFields<T>(info: GraphQLResolveInfo) {
|
||||
return pull(Object.keys(graphqlFields<T>(info)), "__typename");
|
||||
}
|
||||
|
||||
/**
|
||||
* getURLWithCommentID returns the url with the comment id.
|
||||
*
|
||||
* @param storyURL url of the story
|
||||
* @param commentID id of the comment
|
||||
*/
|
||||
export function getURLWithCommentID(storyURL: string, commentID?: string) {
|
||||
const url = new URL(storyURL);
|
||||
const query = parseQuery(url.search);
|
||||
url.search = stringifyQuery({ ...query, commentID });
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
export function reconstructTenantURLResolver<T = any>(path: string) {
|
||||
return (parent: T, args: {}, ctx: TenantContext) => {
|
||||
// If the request is available, then prefer it over building from the tenant
|
||||
|
||||
@@ -1088,11 +1088,11 @@ type CommenterAccountFeatures {
|
||||
"""
|
||||
changeUsername: Boolean!
|
||||
"""
|
||||
downloadComments when true, user may download their comment history
|
||||
downloadComments when true, user may download their comment history
|
||||
"""
|
||||
downloadComments: Boolean!
|
||||
"""
|
||||
deleteAccount when true, non-sso user may permanently delete their account
|
||||
deleteAccount when true, non-sso user may permanently delete their account
|
||||
"""
|
||||
deleteAccount: Boolean!
|
||||
}
|
||||
@@ -1535,6 +1535,60 @@ enum USER_STATUS {
|
||||
SUSPENDED
|
||||
}
|
||||
|
||||
enum DIGEST_FREQUENCY {
|
||||
"""
|
||||
NONE will have the notifications send immediatly rather than bundling for digesting.
|
||||
"""
|
||||
NONE
|
||||
|
||||
"""
|
||||
DAILY will queue up the notifications and send them daily.
|
||||
"""
|
||||
DAILY
|
||||
|
||||
"""
|
||||
HOURLY will queue up the notifications and send them hourly.
|
||||
"""
|
||||
HOURLY
|
||||
}
|
||||
|
||||
"""
|
||||
UserNotificationSettings stores the notification settings for a given User.
|
||||
"""
|
||||
type UserNotificationSettings {
|
||||
"""
|
||||
onReply, when true, will enable notifications to be sent to users that have
|
||||
replies to their comments.
|
||||
"""
|
||||
onReply: Boolean!
|
||||
|
||||
"""
|
||||
onFeatured, when true, will enable notifications to be sent to users that have
|
||||
their comment's featured.
|
||||
"""
|
||||
onFeatured: Boolean!
|
||||
|
||||
"""
|
||||
onStaffReplies when true, will enable notifications to be sent to users that
|
||||
have a staff member reply to their comments. These notifications will
|
||||
supercede notifications that would have been sent for a basic reply
|
||||
notification.
|
||||
"""
|
||||
onStaffReplies: Boolean!
|
||||
|
||||
"""
|
||||
onModeration when true, will enable notifications to be sent to users when a
|
||||
comment that they wrote that was previously unpublished, becomes published due
|
||||
to a moderator action.
|
||||
"""
|
||||
onModeration: Boolean!
|
||||
|
||||
"""
|
||||
digestFrequency is the frequency to send notifications.
|
||||
"""
|
||||
digestFrequency: DIGEST_FREQUENCY!
|
||||
}
|
||||
|
||||
"""
|
||||
User is someone that leaves Comments, and logs in.
|
||||
"""
|
||||
@@ -1655,7 +1709,11 @@ type User {
|
||||
tokens lists the access tokens associated with the account.
|
||||
"""
|
||||
tokens: [Token!]!
|
||||
@auth(roles: [ADMIN], userIDField: "id", permit: [SUSPENDED, BANNED, PENDING_DELETION])
|
||||
@auth(
|
||||
roles: [ADMIN]
|
||||
userIDField: "id"
|
||||
permit: [SUSPENDED, BANNED, PENDING_DELETION]
|
||||
)
|
||||
|
||||
"""
|
||||
ignoredUsers will return the list of ignored users.
|
||||
@@ -1667,6 +1725,12 @@ type User {
|
||||
permit: [SUSPENDED, BANNED, PENDING_DELETION]
|
||||
)
|
||||
|
||||
"""
|
||||
notifications stores the notification settings for the given User.
|
||||
"""
|
||||
notifications: UserNotificationSettings!
|
||||
@auth(userIDField: "id", permit: [SUSPENDED, BANNED])
|
||||
|
||||
"""
|
||||
createdAt is the time that the User was created at.
|
||||
"""
|
||||
@@ -2503,6 +2567,61 @@ type Query {
|
||||
## Mutations
|
||||
################################################################################
|
||||
|
||||
##################
|
||||
## updateNotificationSettings
|
||||
##################
|
||||
|
||||
input UpdateNotificationSettingsInput {
|
||||
"""
|
||||
onReply, when true, will enable notifications to be sent to users that have
|
||||
replies to their comments.
|
||||
"""
|
||||
onReply: Boolean
|
||||
|
||||
"""
|
||||
onFeatured, when true, will enable notifications to be sent to users that have
|
||||
their comment's featured.
|
||||
"""
|
||||
onFeatured: Boolean
|
||||
|
||||
"""
|
||||
onStaffReplies when true, will enable notifications to be sent to users that
|
||||
have a staff member reply to their comments. These notifications will
|
||||
supercede notifications that would have been sent for a basic reply
|
||||
notification.
|
||||
"""
|
||||
onStaffReplies: Boolean
|
||||
|
||||
"""
|
||||
onModeration when true, will enable notifications to be sent to users when a
|
||||
comment that they wrote that was previously unpublished, becomes published due
|
||||
to a moderator action.
|
||||
"""
|
||||
onModeration: Boolean
|
||||
|
||||
"""
|
||||
digestFrequency is the frequency to send notifications.
|
||||
"""
|
||||
digestFrequency: DIGEST_FREQUENCY
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
type UpdateNotificationSettingsPayload {
|
||||
"""
|
||||
user is the possibly modified User.
|
||||
"""
|
||||
user: User!
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
##################
|
||||
## createComment
|
||||
##################
|
||||
@@ -3140,11 +3259,11 @@ input CommenterAccountFeaturesInput {
|
||||
"""
|
||||
changeUsername: Boolean
|
||||
"""
|
||||
downloadComments when true, user may download their comment history
|
||||
downloadComments when true, user may download their comment history
|
||||
"""
|
||||
downloadComments: Boolean
|
||||
"""
|
||||
deleteAccount when true, non-sso user may permanently delete their account
|
||||
deleteAccount when true, non-sso user may permanently delete their account
|
||||
"""
|
||||
deleteAccount: Boolean
|
||||
}
|
||||
@@ -4887,7 +5006,9 @@ type Mutation {
|
||||
before. This mutation will fail if the username is already set.
|
||||
"""
|
||||
setUsername(input: SetUsernameInput!): SetUsernamePayload!
|
||||
@auth(permit: [MISSING_NAME, MISSING_EMAIL, SUSPENDED, BANNED, PENDING_DELETION])
|
||||
@auth(
|
||||
permit: [MISSING_NAME, MISSING_EMAIL, SUSPENDED, BANNED, PENDING_DELETION]
|
||||
)
|
||||
|
||||
"""
|
||||
updateUsername will set the username on the current User if they have not set one
|
||||
@@ -4959,6 +5080,14 @@ type Mutation {
|
||||
"""
|
||||
updateEmail(input: UpdateEmailInput!): UpdateEmailPayload! @auth
|
||||
|
||||
"""
|
||||
updateNotificationSettings can be used to update the notification settings for
|
||||
the current logged in user.
|
||||
"""
|
||||
updateNotificationSettings(
|
||||
input: UpdateNotificationSettingsInput!
|
||||
): UpdateNotificationSettingsPayload! @auth
|
||||
|
||||
"""
|
||||
updateUserEmail allows administrators to update a given User's email address
|
||||
to the one provided.
|
||||
@@ -5023,7 +5152,8 @@ type Mutation {
|
||||
"""
|
||||
requestCommentsDownload(
|
||||
input: RequestCommentsDownloadInput!
|
||||
): RequestCommentsDownloadPayload! @auth(permit: [SUSPENDED, BANNED, PENDING_DELETION])
|
||||
): RequestCommentsDownloadPayload!
|
||||
@auth(permit: [SUSPENDED, BANNED, PENDING_DELETION])
|
||||
|
||||
"""
|
||||
requestUserCommentsDownload allows a user to request to download their comments.
|
||||
|
||||
@@ -3,12 +3,13 @@ import { RedisPubSub } from "graphql-redis-subscriptions";
|
||||
import { createSubscriptionChannelName } from "coral-server/graph/tenant/resolvers/Subscription/helpers";
|
||||
import { SUBSCRIPTION_INPUT } from "coral-server/graph/tenant/resolvers/Subscription/types";
|
||||
import logger from "coral-server/logger";
|
||||
import { NotifierQueue } from "coral-server/queue/tasks/notifier";
|
||||
|
||||
export type Publisher = (input: SUBSCRIPTION_INPUT) => Promise<void>;
|
||||
|
||||
/**
|
||||
* createPublisher will create a new Publisher that can be used to send events
|
||||
* over the pubsub broker to facilitate live updates.
|
||||
* over the pubsub broker to facilitate live updates and notifications.
|
||||
*
|
||||
* @param pubsub the pubsub broker to be used to facilitate the publish action
|
||||
* @param tenantID the ID of the Tenant where the event will be published with
|
||||
@@ -16,13 +17,23 @@ export type Publisher = (input: SUBSCRIPTION_INPUT) => Promise<void>;
|
||||
*/
|
||||
export const createPublisher = (
|
||||
pubsub: RedisPubSub,
|
||||
notifier: NotifierQueue,
|
||||
tenantID: string,
|
||||
clientID?: string
|
||||
): Publisher => async ({ channel, payload }) => {
|
||||
): Publisher => async input => {
|
||||
const { channel, payload } = input;
|
||||
|
||||
logger.trace({ channel, tenantID, clientID }, "publishing event");
|
||||
|
||||
return pubsub.publish(createSubscriptionChannelName(tenantID, channel), {
|
||||
...payload,
|
||||
clientID,
|
||||
});
|
||||
// Start the publishing operation out to all affected subscribers.
|
||||
await Promise.all([
|
||||
// Publish to the underlying pubsub system for subscriptions.
|
||||
pubsub.publish(createSubscriptionChannelName(tenantID, channel), {
|
||||
...payload,
|
||||
clientID,
|
||||
}),
|
||||
// Notify the notifications queue so we can offload notification processing
|
||||
// to it.
|
||||
notifier.add({ tenantID, input }),
|
||||
]);
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@ import { getOperationMetadata } from "coral-server/graph/common/extensions/helpe
|
||||
import { getPersistedQuery } from "coral-server/graph/tenant/persisted";
|
||||
import { GQLUSER_ROLE } from "coral-server/graph/tenant/schema/__generated__/types";
|
||||
import logger from "coral-server/logger";
|
||||
import { userIsStaff } from "coral-server/models/user/helpers";
|
||||
import { hasStaffRole } from "coral-server/models/user/helpers";
|
||||
import { extractTokenFromRequest } from "coral-server/services/jwt";
|
||||
|
||||
import TenantContext, { TenantContextOptions } from "../context";
|
||||
@@ -133,7 +133,7 @@ export function onConnect(options: OnConnectOptions): OnConnectFn {
|
||||
// TODO: (wyattjoh) if the story settings can only disable, and not
|
||||
// enable live updates (as it takes precedence over global settings)
|
||||
// then we can add a check for `!tenant.live.enabled` here too.
|
||||
if (!opts.user || !userIsStaff(opts.user)) {
|
||||
if (!opts.user || !hasStaffRole(opts.user)) {
|
||||
throw new LiveUpdatesDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user