mirror of
https://github.com/wassname/talk.git
synced 2026-08-15 12:55:10 +08:00
[CORL-687] Webhooks (#2738)
* feat: initial webhook impl * feat: added support for key rotation * feat: harmonized fetcher * feat: added expired secrets cleaning * feat: event system refactor * feat: added story event * feat: simplfiied webhook handler * feat: added ref's to locations where user events can be added * feat: added UI to support webhooks * fix: renaming some Webhook -> WebhookEndpoint * fix: review comments to adjuist flow * feat: added localizations * fix: linting, updated snapshots * fix: adapted for new fluent * fix: rearranged folders * fix: linting * feat: added webhooks documentation * feat: improved toc generation * feat: added some tests to webhooks * fix: chain transition hooks * feat: added tests around webhook ui * fix: renamed events * fix: adjusted circle markdown linting * fix: adjusted doctoc script call * review: review fixes * review: review comments * review: adjusted signing secret confirmation * review: adjusted styles to harmonize button usage * fix: updated snapshots and tests * review: move form out of webhooks Moved the form out of the webhooks by relocating the layout used for the route associated with the configure routes. * fix: fixed bugs and snapshots with tests * feat: revised slack message format to use block api * fix: fixed a small text bug Co-authored-by: Vinh <vinh@vinh.tech> Co-authored-by: Kim Gardner <kgardnr@gmail.com>
This commit is contained in:
co-authored by
Vinh
Kim Gardner
parent
34ba2da88d
commit
e42c2b925d
@@ -86,7 +86,7 @@ export const storyModerationInputResolver = (
|
||||
*
|
||||
* @param source the source of the type, not used
|
||||
* @param args the args of the type, not used
|
||||
* @param ctx the TenantContext that will be used to get the shared counts
|
||||
* @param ctx the GraphContext that will be used to get the shared counts
|
||||
*/
|
||||
export const sharedModerationInputResolver = async (
|
||||
source: any,
|
||||
@@ -106,7 +106,7 @@ export const sharedModerationInputResolver = async (
|
||||
*
|
||||
* @param source the source of the payload, not used
|
||||
* @param args the args of the payload containing potentially a Story ID
|
||||
* @param ctx the TenantContext for which we can use to retrieve the shared data
|
||||
* @param ctx the GraphContext for which we can use to retrieve the shared data
|
||||
*/
|
||||
export const moderationQueuesResolver: QueryToModerationQueuesResolver = async (
|
||||
source,
|
||||
|
||||
@@ -33,9 +33,13 @@ export const Mutation: Required<GQLMutationTypeResolver<void>> = {
|
||||
user: await ctx.mutators.Users.updateNotificationSettings(input),
|
||||
clientMutationId,
|
||||
}),
|
||||
updateSettings: async (source, { input }, ctx) => ({
|
||||
updateSettings: async (
|
||||
source,
|
||||
{ input: { clientMutationId, ...input } },
|
||||
ctx
|
||||
) => ({
|
||||
settings: await ctx.mutators.Settings.update(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
clientMutationId,
|
||||
}),
|
||||
createCommentReaction: async (source, { input }, ctx) => ({
|
||||
comment: await ctx.mutators.Comments.createReaction(input),
|
||||
@@ -252,4 +256,52 @@ export const Mutation: Required<GQLMutationTypeResolver<void>> = {
|
||||
site: await ctx.mutators.Sites.update(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
createWebhookEndpoint: async (
|
||||
source,
|
||||
{ input: { clientMutationId, ...input } },
|
||||
ctx
|
||||
) => ({
|
||||
...(await ctx.mutators.Settings.createWebhookEndpoint(input)),
|
||||
clientMutationId,
|
||||
}),
|
||||
updateWebhookEndpoint: async (
|
||||
source,
|
||||
{ input: { clientMutationId, ...input } },
|
||||
ctx
|
||||
) => ({
|
||||
endpoint: await ctx.mutators.Settings.updateWebhookEndpoint(input),
|
||||
clientMutationId,
|
||||
}),
|
||||
disableWebhookEndpoint: async (
|
||||
source,
|
||||
{ input: { clientMutationId, ...input } },
|
||||
ctx
|
||||
) => ({
|
||||
endpoint: await ctx.mutators.Settings.disableWebhookEndpoint(input),
|
||||
clientMutationId,
|
||||
}),
|
||||
enableWebhookEndpoint: async (
|
||||
source,
|
||||
{ input: { clientMutationId, ...input } },
|
||||
ctx
|
||||
) => ({
|
||||
endpoint: await ctx.mutators.Settings.enableWebhookEndpoint(input),
|
||||
clientMutationId,
|
||||
}),
|
||||
deleteWebhookEndpoint: async (
|
||||
source,
|
||||
{ input: { clientMutationId, ...input } },
|
||||
ctx
|
||||
) => ({
|
||||
endpoint: await ctx.mutators.Settings.deleteWebhookEndpoint(input),
|
||||
clientMutationId,
|
||||
}),
|
||||
rotateWebhookEndpointSecret: async (
|
||||
source,
|
||||
{ input: { clientMutationId, ...input } },
|
||||
ctx
|
||||
) => ({
|
||||
endpoint: await ctx.mutators.Settings.rotateWebhookEndpointSecret(input),
|
||||
clientMutationId,
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { getWebhookEndpoint } from "coral-server/models/tenant";
|
||||
|
||||
import { GQLQueryTypeResolver } from "coral-server/graph/schema/__generated__/types";
|
||||
|
||||
import { moderationQueuesResolver } from "./ModerationQueues";
|
||||
@@ -25,4 +27,5 @@ export const Query: Required<GQLQueryTypeResolver<void>> = {
|
||||
ctx.loaders.Stories.activeStories(limit),
|
||||
sites: (source, args, ctx) => ctx.loaders.Sites.connection(args),
|
||||
site: (source, { id }, ctx) => (id ? ctx.loaders.Sites.site.load(id) : null),
|
||||
webhookEndpoint: (source, { id }, ctx) => getWebhookEndpoint(ctx.tenant, id),
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as settings from "coral-server/models/settings";
|
||||
|
||||
import { GQLSSOAuthIntegrationTypeResolver } from "coral-server/graph/schema/__generated__/types";
|
||||
|
||||
function getActiveSSOKey(keys: settings.SSOKey[]) {
|
||||
function getActiveSSOKey(keys: settings.Secret[]) {
|
||||
// Any key that has been rotated cannot be the active key.
|
||||
return keys.find(key => !key.rotatedAt);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
import {
|
||||
GQLFEATURE_FLAG,
|
||||
GQLSettingsTypeResolver,
|
||||
GQLWEBHOOK_EVENT_NAME,
|
||||
} from "coral-server/graph/schema/__generated__/types";
|
||||
|
||||
const filterValidFeatureFlags = () => {
|
||||
@@ -27,4 +28,5 @@ export const Settings: GQLSettingsTypeResolver<Tenant> = {
|
||||
const sites = await ctx.loaders.Sites.connection({});
|
||||
return sites.edges.length > 1;
|
||||
},
|
||||
webhookEvents: () => Object.values(GQLWEBHOOK_EVENT_NAME),
|
||||
};
|
||||
|
||||
@@ -17,3 +17,13 @@ export const Subscription: GQLSubscriptionTypeResolver = {
|
||||
commentFeatured,
|
||||
commentReleased,
|
||||
};
|
||||
|
||||
export { CommentFeaturedInput } from "./commentFeatured";
|
||||
export { CommentCreatedInput } from "./commentCreated";
|
||||
export {
|
||||
CommentEnteredModerationQueueInput,
|
||||
} from "./commentEnteredModerationQueue";
|
||||
export { CommentLeftModerationQueueInput } from "./commentLeftModerationQueue";
|
||||
export { CommentReleasedInput } from "./commentReleased";
|
||||
export { CommentReplyCreatedInput } from "./commentReplyCreated";
|
||||
export { CommentStatusUpdatedInput } from "./commentStatusUpdated";
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import * as tenant from "coral-server/models/tenant";
|
||||
|
||||
import { GQLWebhookEndpointTypeResolver } from "coral-server/graph/schema/__generated__/types";
|
||||
|
||||
export const WebhookEndpoint: GQLWebhookEndpointTypeResolver<
|
||||
tenant.Endpoint
|
||||
> = {
|
||||
signingSecret: ({ signingSecrets }) =>
|
||||
signingSecrets[signingSecrets.length - 1],
|
||||
};
|
||||
@@ -50,6 +50,7 @@ import { User } from "./User";
|
||||
import { UsernameHistory } from "./UsernameHistory";
|
||||
import { UsernameStatus } from "./UsernameStatus";
|
||||
import { UserStatus } from "./UserStatus";
|
||||
import { WebhookEndpoint } from "./WebhookEndpoint";
|
||||
|
||||
const Resolvers: GQLResolver = {
|
||||
ApproveCommentPayload,
|
||||
@@ -101,6 +102,7 @@ const Resolvers: GQLResolver = {
|
||||
UserStatus,
|
||||
Settings,
|
||||
SlackConfiguration,
|
||||
WebhookEndpoint,
|
||||
};
|
||||
|
||||
export default Resolvers;
|
||||
|
||||
Reference in New Issue
Block a user