mirror of
https://github.com/wassname/talk.git
synced 2026-08-18 12:30:39 +08:00
[CORL-878] Upgrade dependencies (#2867)
* chore: upgrade fluent * chore: upgrade metascraper * chore: upgrade akismet-api * chore: upgrade apollo-server-express * chore: upgrade archiver * chore: upgrade bull * chore: upgrade express, cheerio, content-security-policy-builder * chore: upgrade convict * chore: upgrade cors, cron * chore: upgrade csv-stringify * chore: upgrade dompurify * chore: upgrade dotenv * chore: upgrade express-static-gzip * chore: upgrade fs-extra * chore: upgrade graphql-js * chore: upgrade graphql packages * chore: upgrade html-minifier * chore: upgrade html-to-text * chore: upgrade ioredis * chore: upgrade joi * chore: upgrade jsdom * chore: upgrade jsonwebtoken * chore: upgrade juice * chore: upgrade jwks-rsa ad linkifyjs * chore: upgrade lodash * chore: upgrade luxon * chore: upgrade metascraper * chore: upgrade mongodb * chore: upgrade ms * chore: upgrade node and node-fetch types * chore: upgrade nodemailer nunjucks and typescript-eslint * chore: Upgrade passport * upgrade: prom-client react-helmet source-map-support stack-utils * chore: upgrade uuid * chore: upgrade @babel packages * chore: upgrade types * chore: upgrade autoprefixer * chore: upgrade jest * chore: upgrade ts-jest * chore: remove linkify.d.ts * chore: upgrade bowser * chore: case-sensitive-paths-webpack-plugin * chore: upgrade classnames * chore: upgrade commander * chore: upgrade comment-json * chore: upgrade cross-spawn compression-webpack-plugin del * chore: upgrade build and watch related dependencies * chore: upgrade css-vars-ponyfill * chore: upgrade eslint and css-vars-ponyfill * chore: upgrade enzyme and eventemitter2 * fix: form bug * chore: upgrade farce * chore: upgrade final form * chore: upgrade react-popper * chore: upgrade flat and fork-ts-checker-webpack-plugin * chore: upgrade husky and gulp related, intersection observer * chore: upgrade lint-staged * chore: upgrade marked, loader-utils, mini-css-extract-plugin * chore: upgrade postcss-nested, proxy-polyfill, pstree.remy * chore: upgrade prettier * chore: fix prettier changes, upgrade react * chore: mute createFactory deprecated message * chore: upgrade react-copy-to-clipbard, react-axe, react-dom, react-test-renderer, react-timeago * chore: upgrade react-transistion-group, react-responsive * chore: upgrade types * chore: upgrade react-dev-utils, react-error-overlay regenerator-runtime * chore: upgrade types, sinon, sockjs-client, strip-ansi * chore: upgrade types, fonts * chore: upgrade nunjucks, ts-node, typescript-snapshot-plugin, wait-for-expect * chore: upgrade eslint packages * chore: upgrade fluent, types * chore: upgrade jsdom dep * chore: upgrade mongo * chore: upgrade deps * chore: upgrade typescript, recompose * chore: upgrade prettier * chore: remove obsolete prettier config * chore: upgrade jsdom types * chore: upgrade typescript-eslint * chore: upgrad deps * chore: upgrade deps * chore: upgrade relay related modules * chore: upgrade docz WIP * chore: upgrade docz * chore: add guard * chore: remove obsolete line * chore: comment * chore: refactors * fix: hook count change error
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { RedisPubSub } from "graphql-redis-subscriptions";
|
||||
import { Db } from "mongodb";
|
||||
import uuid from "uuid";
|
||||
import { v1 as uuid } from "uuid";
|
||||
|
||||
import { LanguageCode } from "coral-common/helpers/i18n/locales";
|
||||
import { Config } from "coral-server/config";
|
||||
@@ -81,7 +81,7 @@ export default class GraphContext {
|
||||
public readonly user?: User;
|
||||
|
||||
constructor(options: GraphContextOptions) {
|
||||
this.id = options.id || uuid.v1();
|
||||
this.id = options.id || uuid();
|
||||
this.now = options.now || new Date();
|
||||
this.lang = options.lang || options.i18n.getDefaultLang();
|
||||
this.disableCaching = options.disableCaching || false;
|
||||
|
||||
@@ -81,7 +81,7 @@ const auth: DirectiveResolverFn<
|
||||
(!permit && conditions.length > 0) ||
|
||||
// If the permit was specified, and some of the conditions for the user
|
||||
// aren't in the list of permitted conditions, then error.
|
||||
(permit && conditions.some(condition => !permit.includes(condition)))
|
||||
(permit && conditions.some((condition) => !permit.includes(condition)))
|
||||
) {
|
||||
// Compute the resource that the user was attempting to access.
|
||||
const resource = calculateLocationKey(info);
|
||||
|
||||
@@ -51,15 +51,9 @@ const rate: DirectiveResolverFn<
|
||||
const key = `${tenant.id}:rl:${user.id}:${info.operation.operation}.${resource}`;
|
||||
|
||||
// Perform the rate limiting check.
|
||||
const [[, tries]] = await redis
|
||||
.multi()
|
||||
.incr(key)
|
||||
.expire(key, seconds)
|
||||
.exec();
|
||||
const [[, tries]] = await redis.multi().incr(key).expire(key, seconds).exec();
|
||||
if (tries && tries > max) {
|
||||
const resetsAt = DateTime.fromJSDate(now)
|
||||
.plus({ seconds })
|
||||
.toJSDate();
|
||||
const resetsAt = DateTime.fromJSDate(now).plus({ seconds }).toJSDate();
|
||||
throw new RateLimitExceeded(key, max, resetsAt, tries);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function mapFieldsetToErrorCodes<T>(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (errorMap[param].some(code => err.code === code)) {
|
||||
if (errorMap[param].some((code) => err.code === code)) {
|
||||
err.param = param;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ApolloError } from "apollo-server-core";
|
||||
import { GraphQLError } from "graphql";
|
||||
import { GraphQLFormattedError } from "graphql";
|
||||
import { GraphQLExtension, GraphQLResponse } from "graphql-extensions";
|
||||
import { merge } from "lodash";
|
||||
|
||||
@@ -9,10 +9,14 @@ import {
|
||||
InternalError,
|
||||
} from "coral-server/errors";
|
||||
import GraphContext from "coral-server/graph/context";
|
||||
import { getOriginalError } from "./helpers";
|
||||
|
||||
function hoistCoralErrorExtensions(ctx: GraphContext, err: GraphQLError): void {
|
||||
function hoistCoralErrorExtensions(
|
||||
ctx: GraphContext,
|
||||
err: GraphQLFormattedError
|
||||
): void {
|
||||
// Grab or wrap the originalError so that it's a CoralError.
|
||||
const originalError = extractOriginalError(err, ctx);
|
||||
const originalError = getWrappedOriginalError(err, ctx);
|
||||
if (!originalError) {
|
||||
return;
|
||||
}
|
||||
@@ -25,7 +29,7 @@ function hoistCoralErrorExtensions(ctx: GraphContext, err: GraphQLError): void {
|
||||
|
||||
// Hoist the message from the original error into the message of the base
|
||||
// error.
|
||||
err.message = extensions.message;
|
||||
(err as any).message = extensions.message;
|
||||
|
||||
// Re-hoist the extensions.
|
||||
merge(err.extensions, extensions);
|
||||
@@ -39,8 +43,8 @@ function hoistCoralErrorExtensions(ctx: GraphContext, err: GraphQLError): void {
|
||||
* @param err the error to have their original error extracted from.
|
||||
* @param ctx the Context to extract the environment state.
|
||||
*/
|
||||
function extractOriginalError(
|
||||
err: GraphQLError,
|
||||
function getWrappedOriginalError(
|
||||
err: GraphQLFormattedError,
|
||||
ctx: GraphContext
|
||||
): CoralError | undefined {
|
||||
if (err instanceof ApolloError) {
|
||||
@@ -49,23 +53,25 @@ function extractOriginalError(
|
||||
return;
|
||||
}
|
||||
|
||||
if (!err.originalError) {
|
||||
const originalError = getOriginalError(err);
|
||||
|
||||
if (!originalError) {
|
||||
// Only errors that have an originalError need to be hoisted.
|
||||
return;
|
||||
}
|
||||
|
||||
if (err.originalError instanceof CoralError) {
|
||||
return err.originalError;
|
||||
if (originalError instanceof CoralError) {
|
||||
return originalError;
|
||||
}
|
||||
|
||||
if (ctx.config.get("env") !== "production") {
|
||||
return new InternalDevelopmentError(
|
||||
err.originalError,
|
||||
originalError,
|
||||
"wrapped internal development error"
|
||||
);
|
||||
}
|
||||
|
||||
return new InternalError(err.originalError, "wrapped internal error");
|
||||
return new InternalError(originalError, "wrapped internal error");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,8 +82,8 @@ function extractOriginalError(
|
||||
*/
|
||||
export function enrichError(
|
||||
ctx: GraphContext,
|
||||
err: GraphQLError
|
||||
): GraphQLError {
|
||||
err: GraphQLFormattedError
|
||||
): GraphQLFormattedError {
|
||||
if (err.extensions) {
|
||||
// Delete the exception field from the error extension, we never need to
|
||||
// provide that data.
|
||||
@@ -85,7 +91,7 @@ export function enrichError(
|
||||
delete err.extensions.exception;
|
||||
}
|
||||
|
||||
if (err.originalError) {
|
||||
if (getOriginalError(err)) {
|
||||
// Hoist the extensions onto the error.
|
||||
hoistCoralErrorExtensions(ctx, err);
|
||||
}
|
||||
@@ -104,7 +110,7 @@ export class ErrorWrappingExtension implements GraphQLExtension<GraphContext> {
|
||||
...o,
|
||||
graphqlResponse: {
|
||||
...o.graphqlResponse,
|
||||
errors: o.graphqlResponse.errors.map(err =>
|
||||
errors: o.graphqlResponse.errors.map((err) =>
|
||||
enrichError(o.context, err)
|
||||
),
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DocumentNode, ExecutionArgs, GraphQLError } from "graphql";
|
||||
import { DocumentNode, ExecutionArgs, GraphQLFormattedError } from "graphql";
|
||||
import {
|
||||
EndHandler,
|
||||
GraphQLExtension,
|
||||
@@ -11,7 +11,7 @@ import logger from "coral-server/logger";
|
||||
|
||||
import { getOperationMetadata, getPersistedQueryMetadata } from "./helpers";
|
||||
|
||||
export function logError(ctx: GraphContext, err: GraphQLError) {
|
||||
export function logError(ctx: GraphContext, err: GraphQLFormattedError) {
|
||||
ctx.logger.error({ err }, "graphql query error");
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ export class LoggerExtension implements GraphQLExtension<GraphContext> {
|
||||
context: GraphContext;
|
||||
}): void {
|
||||
if (response.graphqlResponse.errors) {
|
||||
response.graphqlResponse.errors.forEach(err =>
|
||||
response.graphqlResponse.errors.forEach((err) =>
|
||||
logError(response.context, err)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
DocumentNode,
|
||||
GraphQLFormattedError,
|
||||
OperationDefinitionNode,
|
||||
OperationTypeNode,
|
||||
} from "graphql";
|
||||
@@ -66,3 +67,16 @@ export const getPersistedQueryMetadata = ({
|
||||
operation,
|
||||
operationName,
|
||||
});
|
||||
|
||||
/**
|
||||
* getOriginalError tries to return the original error from a
|
||||
* formatted GraphQL error.
|
||||
*
|
||||
* @param err A GraphQL Formatted Error
|
||||
*/
|
||||
export const getOriginalError = (err: GraphQLFormattedError) => {
|
||||
if ((err as any).originalError) {
|
||||
return (err as any).originalError as Error;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
@@ -11,8 +11,8 @@ export default (ctx: GraphContext) => ({
|
||||
string,
|
||||
GQLDiscoveredOIDCConfiguration | null
|
||||
>(
|
||||
issuers =>
|
||||
Promise.all(issuers.map(issuer => discoverOIDCConfiguration(issuer))),
|
||||
(issuers) =>
|
||||
Promise.all(issuers.map((issuer) => discoverOIDCConfiguration(issuer))),
|
||||
{
|
||||
// Disable caching for the DataLoader if the Context is designed to be
|
||||
// long lived.
|
||||
|
||||
@@ -68,7 +68,7 @@ const primeCommentsFromConnection = (ctx: Context) => (
|
||||
) => {
|
||||
if (!ctx.disableCaching) {
|
||||
// For each of the nodes, prime the comment loader.
|
||||
connection.nodes.forEach(comment => {
|
||||
connection.nodes.forEach((comment) => {
|
||||
ctx.loaders.Comments.visible.prime(comment.id, comment);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { QueryToSitesArgs } from "coral-server/graph/schema/__generated__/types"
|
||||
|
||||
export default (ctx: TenantContext) => ({
|
||||
site: new DataLoader<string, Site | null>(
|
||||
ids => retrieveManySites(ctx.mongo, ctx.tenant.id, ids),
|
||||
(ids) => retrieveManySites(ctx.mongo, ctx.tenant.id, ids),
|
||||
{
|
||||
cache: !ctx.disableCaching,
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ const primeStoriesFromConnection = (ctx: GraphContext) => (
|
||||
) => {
|
||||
if (!ctx.disableCaching) {
|
||||
// For each of these nodes, prime the story loader.
|
||||
connection.nodes.forEach(story => {
|
||||
connection.nodes.forEach((story) => {
|
||||
ctx.loaders.Stories.story.prime(story.id, story);
|
||||
});
|
||||
}
|
||||
@@ -186,7 +186,7 @@ export default (ctx: GraphContext) => ({
|
||||
}
|
||||
),
|
||||
story: new DataLoader<string, Story | null>(
|
||||
ids => retrieveManyStories(ctx.mongo, ctx.tenant.id, ids),
|
||||
(ids) => retrieveManyStories(ctx.mongo, ctx.tenant.id, ids),
|
||||
{
|
||||
// Disable caching for the DataLoader if the Context is designed to be
|
||||
// long lived.
|
||||
|
||||
@@ -88,7 +88,7 @@ const primeUsersFromConnection = (ctx: Context) => (
|
||||
) => {
|
||||
if (!ctx.disableCaching) {
|
||||
// For each of the nodes, prime the user loader.
|
||||
connection.nodes.forEach(user => {
|
||||
connection.nodes.forEach((user) => {
|
||||
ctx.loaders.Users.user.prime(user.id, user);
|
||||
});
|
||||
}
|
||||
@@ -98,7 +98,7 @@ const primeUsersFromConnection = (ctx: Context) => (
|
||||
|
||||
export default (ctx: Context) => {
|
||||
const user = new DataLoader<string, User | null>(
|
||||
ids => retrieveManyUsers(ctx.mongo, ctx.tenant.id, ids),
|
||||
(ids) => retrieveManyUsers(ctx.mongo, ctx.tenant.id, ids),
|
||||
{
|
||||
// Disable caching for the DataLoader if the Context is designed to be
|
||||
// long lived.
|
||||
|
||||
@@ -27,7 +27,7 @@ export class SingletonResolver<T> {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
const promise = this.resolver().then(result => {
|
||||
const promise = this.resolver().then((result) => {
|
||||
return result;
|
||||
});
|
||||
|
||||
@@ -41,5 +41,6 @@ export class SingletonResolver<T> {
|
||||
export function createManyBatchLoadFn<U, V>(
|
||||
batchLoadFn: (input: U) => Promise<V>
|
||||
) {
|
||||
return (inputs: U[]) => Promise.all(inputs.map(input => batchLoadFn(input)));
|
||||
return (inputs: U[]) =>
|
||||
Promise.all(inputs.map((input) => batchLoadFn(input)));
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ export const Comments = (ctx: GraphContext) => ({
|
||||
GQLTAG.FEATURED,
|
||||
ctx.now
|
||||
)
|
||||
.then(comment =>
|
||||
.then((comment) =>
|
||||
comment.status !== GQLCOMMENT_STATUS.APPROVED
|
||||
? approveComment(
|
||||
ctx.mongo,
|
||||
@@ -182,7 +182,7 @@ export const Comments = (ctx: GraphContext) => ({
|
||||
)
|
||||
: comment
|
||||
)
|
||||
.then(comment => {
|
||||
.then((comment) => {
|
||||
// Publish that the comment was featured.
|
||||
publishCommentFeatured(ctx.broker, comment);
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { Omit } from "coral-common/types";
|
||||
|
||||
/**
|
||||
* validateMaximumLength will limit the value of an optional string to the
|
||||
* specified amount, otherwise will throw an error.
|
||||
|
||||
@@ -5,12 +5,10 @@ import {
|
||||
|
||||
const disabled = { enabled: false };
|
||||
|
||||
export const AuthIntegrations: GQLAuthIntegrationsTypeResolver<
|
||||
GQLAuthIntegrations
|
||||
> = {
|
||||
local: auth => auth.local || disabled,
|
||||
sso: auth => auth.sso || disabled,
|
||||
oidc: auth => auth.oidc || disabled,
|
||||
google: auth => auth.google || disabled,
|
||||
facebook: auth => auth.facebook || disabled,
|
||||
export const AuthIntegrations: GQLAuthIntegrationsTypeResolver<GQLAuthIntegrations> = {
|
||||
local: (auth) => auth.local || disabled,
|
||||
sso: (auth) => auth.sso || disabled,
|
||||
oidc: (auth) => auth.oidc || disabled,
|
||||
google: (auth) => auth.google || disabled,
|
||||
facebook: (auth) => auth.facebook || disabled,
|
||||
};
|
||||
|
||||
@@ -8,5 +8,5 @@ export type BanStatusInput = user.ConsolidatedBanStatus & {
|
||||
export const BanStatus: Required<GQLBanStatusTypeResolver<BanStatusInput>> = {
|
||||
active: ({ active }) => active,
|
||||
history: ({ history, userID }) =>
|
||||
history.map(status => ({ ...status, userID })),
|
||||
history.map((status) => ({ ...status, userID })),
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { GQLBanStatusHistoryTypeResolver } from "coral-server/graph/schema/__generated__/types";
|
||||
import * as user from "coral-server/models/user";
|
||||
|
||||
export const BanStatusHistory: Required<
|
||||
GQLBanStatusHistoryTypeResolver<user.BanStatusHistory>
|
||||
> = {
|
||||
export const BanStatusHistory: Required<GQLBanStatusHistoryTypeResolver<
|
||||
user.BanStatusHistory
|
||||
>> = {
|
||||
active: ({ active }) => active,
|
||||
createdBy: ({ createdBy }, input, ctx) => {
|
||||
if (createdBy) {
|
||||
|
||||
@@ -2,9 +2,7 @@ import { GQLCloseCommentingTypeResolver } from "coral-server/graph/schema/__gene
|
||||
import * as settings from "coral-server/models/settings";
|
||||
import { translate } from "coral-server/services/i18n";
|
||||
|
||||
export const CloseCommenting: GQLCloseCommentingTypeResolver<
|
||||
settings.CloseCommenting
|
||||
> = {
|
||||
export const CloseCommenting: GQLCloseCommentingTypeResolver<settings.CloseCommenting> = {
|
||||
message: (closeCommenting, input, ctx) => {
|
||||
if (closeCommenting.message) {
|
||||
return closeCommenting.message;
|
||||
|
||||
@@ -44,15 +44,16 @@ export const maybeLoadOnlyID = (
|
||||
};
|
||||
|
||||
export const Comment: GQLCommentTypeResolver<comment.Comment> = {
|
||||
body: c => (c.revisions.length > 0 ? getLatestRevision(c).body : null),
|
||||
body: (c) => (c.revisions.length > 0 ? getLatestRevision(c).body : null),
|
||||
// Send the whole comment back when you request revisions. This way, we get to
|
||||
// know the comment ID. The field mapping is handled by the CommentRevision
|
||||
// resolver.
|
||||
revision: c =>
|
||||
revision: (c) =>
|
||||
c.revisions.length > 0
|
||||
? { revision: getLatestRevision(c), comment: c }
|
||||
: null,
|
||||
revisionHistory: c => c.revisions.map(revision => ({ revision, comment: c })),
|
||||
revisionHistory: (c) =>
|
||||
c.revisions.map((revision) => ({ revision, comment: c })),
|
||||
editing: ({ revisions, createdAt }, input, ctx) => ({
|
||||
// When there is more than one body history, then the comment has been
|
||||
// edited.
|
||||
@@ -84,7 +85,7 @@ export const Comment: GQLCommentTypeResolver<comment.Comment> = {
|
||||
);
|
||||
},
|
||||
// Action Counts are encoded, decode them for use with the GraphQL system.
|
||||
actionCounts: c => decodeActionCounts(c.actionCounts),
|
||||
actionCounts: (c) => decodeActionCounts(c.actionCounts),
|
||||
flags: ({ id }, { first, after }, ctx) =>
|
||||
ctx.loaders.CommentActions.connection({
|
||||
first: defaultTo(first, 10),
|
||||
@@ -96,8 +97,8 @@ export const Comment: GQLCommentTypeResolver<comment.Comment> = {
|
||||
}),
|
||||
viewerActionPresence: (c, input, ctx) =>
|
||||
ctx.user ? ctx.loaders.Comments.retrieveMyActionPresence.load(c.id) : null,
|
||||
parentCount: c => (hasAncestors(c) ? c.ancestorIDs.length : 0),
|
||||
depth: c => (hasAncestors(c) ? c.ancestorIDs.length : 0),
|
||||
parentCount: (c) => (hasAncestors(c) ? c.ancestorIDs.length : 0),
|
||||
depth: (c) => (hasAncestors(c) ? c.ancestorIDs.length : 0),
|
||||
rootParent: (c, input, ctx, info) =>
|
||||
hasAncestors(c)
|
||||
? maybeLoadOnlyID(ctx, info, c.ancestorIDs[c.ancestorIDs.length - 1])
|
||||
|
||||
@@ -3,9 +3,7 @@ import { GQLCommentCreatedPayloadTypeResolver } from "coral-server/graph/schema/
|
||||
import { maybeLoadOnlyID } from "./Comment";
|
||||
import { CommentCreatedInput } from "./Subscription/commentCreated";
|
||||
|
||||
export const CommentCreatedPayload: GQLCommentCreatedPayloadTypeResolver<
|
||||
CommentCreatedInput
|
||||
> = {
|
||||
export const CommentCreatedPayload: GQLCommentCreatedPayloadTypeResolver<CommentCreatedInput> = {
|
||||
comment: ({ commentID }, args, ctx, info) =>
|
||||
maybeLoadOnlyID(ctx, info, commentID),
|
||||
};
|
||||
|
||||
@@ -3,9 +3,7 @@ import { GQLCommentEnteredModerationQueuePayloadTypeResolver } from "coral-serve
|
||||
import { maybeLoadOnlyID } from "./Comment";
|
||||
import { CommentEnteredModerationQueueInput } from "./Subscription/commentEnteredModerationQueue";
|
||||
|
||||
export const CommentEnteredModerationQueuePayload: GQLCommentEnteredModerationQueuePayloadTypeResolver<
|
||||
CommentEnteredModerationQueueInput
|
||||
> = {
|
||||
export const CommentEnteredModerationQueuePayload: GQLCommentEnteredModerationQueuePayloadTypeResolver<CommentEnteredModerationQueueInput> = {
|
||||
comment: ({ commentID }, args, ctx, info) =>
|
||||
maybeLoadOnlyID(ctx, info, commentID),
|
||||
};
|
||||
|
||||
@@ -3,9 +3,7 @@ import { GQLCommentLeftModerationQueuePayloadTypeResolver } from "coral-server/g
|
||||
import { maybeLoadOnlyID } from "./Comment";
|
||||
import { CommentLeftModerationQueueInput } from "./Subscription/commentLeftModerationQueue";
|
||||
|
||||
export const CommentLeftModerationQueuePayload: GQLCommentLeftModerationQueuePayloadTypeResolver<
|
||||
CommentLeftModerationQueueInput
|
||||
> = {
|
||||
export const CommentLeftModerationQueuePayload: GQLCommentLeftModerationQueuePayloadTypeResolver<CommentLeftModerationQueueInput> = {
|
||||
comment: ({ commentID }, args, ctx, info) =>
|
||||
maybeLoadOnlyID(ctx, info, commentID),
|
||||
};
|
||||
|
||||
@@ -2,9 +2,7 @@ import * as actions from "coral-server/models/action/moderation/comment";
|
||||
|
||||
import { GQLCommentModerationActionTypeResolver } from "../schema/__generated__/types";
|
||||
|
||||
export const CommentModerationAction: GQLCommentModerationActionTypeResolver<
|
||||
actions.CommentModerationAction
|
||||
> = {
|
||||
export const CommentModerationAction: GQLCommentModerationActionTypeResolver<actions.CommentModerationAction> = {
|
||||
revision: async (action, input, ctx) => {
|
||||
const comment = await ctx.loaders.Comments.visible.load(action.commentID);
|
||||
if (!comment) {
|
||||
|
||||
@@ -3,9 +3,7 @@ import { GQLCommentReleasedPayloadTypeResolver } from "coral-server/graph/schema
|
||||
import { maybeLoadOnlyID } from "./Comment";
|
||||
import { CommentReleasedInput } from "./Subscription/commentReleased";
|
||||
|
||||
export const CommentReleasedPayload: GQLCommentReleasedPayloadTypeResolver<
|
||||
CommentReleasedInput
|
||||
> = {
|
||||
export const CommentReleasedPayload: GQLCommentReleasedPayloadTypeResolver<CommentReleasedInput> = {
|
||||
comment: ({ commentID }, args, ctx, info) =>
|
||||
maybeLoadOnlyID(ctx, info, commentID),
|
||||
};
|
||||
|
||||
@@ -3,9 +3,7 @@ import { GQLCommentReplyCreatedPayloadTypeResolver } from "coral-server/graph/sc
|
||||
import { maybeLoadOnlyID } from "./Comment";
|
||||
import { CommentReplyCreatedInput } from "./Subscription/commentReplyCreated";
|
||||
|
||||
export const CommentReplyCreatedPayload: GQLCommentReplyCreatedPayloadTypeResolver<
|
||||
CommentReplyCreatedInput
|
||||
> = {
|
||||
export const CommentReplyCreatedPayload: GQLCommentReplyCreatedPayloadTypeResolver<CommentReplyCreatedInput> = {
|
||||
comment: ({ commentID }, args, ctx, info) =>
|
||||
maybeLoadOnlyID(ctx, info, commentID),
|
||||
};
|
||||
|
||||
@@ -7,14 +7,14 @@ export interface WrappedCommentRevision {
|
||||
comment: Comment;
|
||||
}
|
||||
|
||||
export const CommentRevision: Required<
|
||||
GQLCommentRevisionTypeResolver<WrappedCommentRevision>
|
||||
> = {
|
||||
id: w => w.revision.id,
|
||||
comment: w => w.comment,
|
||||
actionCounts: w => decodeActionCounts(w.revision.actionCounts),
|
||||
body: w => w.revision.body,
|
||||
export const CommentRevision: Required<GQLCommentRevisionTypeResolver<
|
||||
WrappedCommentRevision
|
||||
>> = {
|
||||
id: (w) => w.revision.id,
|
||||
comment: (w) => w.comment,
|
||||
actionCounts: (w) => decodeActionCounts(w.revision.actionCounts),
|
||||
body: (w) => w.revision.body,
|
||||
// Defaults to an empty object if not set on the revision.
|
||||
metadata: w => w.revision.metadata || {},
|
||||
createdAt: w => w.revision.createdAt,
|
||||
metadata: (w) => w.revision.metadata || {},
|
||||
createdAt: (w) => w.revision.createdAt,
|
||||
};
|
||||
|
||||
@@ -3,9 +3,7 @@ import { GQLCommentStatusUpdatedPayloadTypeResolver } from "coral-server/graph/s
|
||||
import { maybeLoadOnlyID } from "./Comment";
|
||||
import { CommentStatusUpdatedInput } from "./Subscription/commentStatusUpdated";
|
||||
|
||||
export const CommentStatusUpdatedPayload: GQLCommentStatusUpdatedPayloadTypeResolver<
|
||||
CommentStatusUpdatedInput
|
||||
> = {
|
||||
export const CommentStatusUpdatedPayload: GQLCommentStatusUpdatedPayloadTypeResolver<CommentStatusUpdatedInput> = {
|
||||
moderator: ({ moderatorID }, args, ctx) =>
|
||||
moderatorID ? ctx.loaders.Users.user.load(moderatorID) : null,
|
||||
comment: ({ commentID }, args, ctx, info) =>
|
||||
|
||||
@@ -2,9 +2,7 @@ import { GQLDisableCommentingTypeResolver } from "coral-server/graph/schema/__ge
|
||||
import * as settings from "coral-server/models/settings";
|
||||
import { translate } from "coral-server/services/i18n";
|
||||
|
||||
export const DisableCommenting: GQLDisableCommentingTypeResolver<
|
||||
settings.DisableCommenting
|
||||
> = {
|
||||
export const DisableCommenting: GQLDisableCommentingTypeResolver<settings.DisableCommenting> = {
|
||||
message: (disableCommenting, input, ctx) => {
|
||||
if (disableCommenting.message) {
|
||||
return disableCommenting.message;
|
||||
|
||||
@@ -5,9 +5,7 @@ import {
|
||||
|
||||
import { reconstructTenantURLResolver } from "./util";
|
||||
|
||||
export const FacebookAuthIntegration: GQLFacebookAuthIntegrationTypeResolver<
|
||||
GQLFacebookAuthIntegration
|
||||
> = {
|
||||
export const FacebookAuthIntegration: GQLFacebookAuthIntegrationTypeResolver<GQLFacebookAuthIntegration> = {
|
||||
callbackURL: reconstructTenantURLResolver("/api/auth/facebook/callback"),
|
||||
redirectURL: reconstructTenantURLResolver("/api/auth/facebook"),
|
||||
};
|
||||
|
||||
@@ -5,9 +5,7 @@ import {
|
||||
|
||||
import { reconstructTenantURLResolver } from "./util";
|
||||
|
||||
export const GoogleAuthIntegration: GQLGoogleAuthIntegrationTypeResolver<
|
||||
GQLGoogleAuthIntegration
|
||||
> = {
|
||||
export const GoogleAuthIntegration: GQLGoogleAuthIntegrationTypeResolver<GQLGoogleAuthIntegration> = {
|
||||
callbackURL: reconstructTenantURLResolver("/api/auth/google/callback"),
|
||||
redirectURL: reconstructTenantURLResolver("/api/auth/google"),
|
||||
};
|
||||
|
||||
@@ -5,9 +5,7 @@ import * as settings from "coral-server/models/settings";
|
||||
|
||||
export type LiveConfigurationInput = settings.LiveConfiguration;
|
||||
|
||||
export const LiveConfiguration: GQLLiveConfigurationTypeResolver<
|
||||
LiveConfigurationInput
|
||||
> = {
|
||||
export const LiveConfiguration: GQLLiveConfigurationTypeResolver<LiveConfigurationInput> = {
|
||||
configurable: (source, args, ctx) =>
|
||||
Boolean(!ctx.config.get("disable_live_updates")),
|
||||
enabled: (source, args, ctx) => {
|
||||
|
||||
@@ -15,9 +15,7 @@ export interface ModerationQueueInput {
|
||||
count: number | null;
|
||||
}
|
||||
|
||||
export const ModerationQueue: GQLModerationQueueTypeResolver<
|
||||
ModerationQueueInput
|
||||
> = {
|
||||
export const ModerationQueue: GQLModerationQueueTypeResolver<ModerationQueueInput> = {
|
||||
id: ({ selector, connection: { filter } }) => {
|
||||
// NOTE: (wyattjoh) when the queues change shape in the future, investigate adding more dynamicness to this id generation
|
||||
if (filter && filter.storyID) {
|
||||
|
||||
@@ -134,9 +134,7 @@ export const moderationQueuesResolver: QueryToModerationQueuesResolver = async (
|
||||
return sharedModerationInputResolver(source, args, ctx);
|
||||
};
|
||||
|
||||
export const ModerationQueues: GQLModerationQueuesTypeResolver<
|
||||
ModerationQueuesInput
|
||||
> = {
|
||||
export const ModerationQueues: GQLModerationQueuesTypeResolver<ModerationQueuesInput> = {
|
||||
unmoderated: mergeModerationInputFilters(
|
||||
{
|
||||
status: { $in: UNMODERATED_STATUSES },
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { GQLModeratorNoteTypeResolver } from "coral-server/graph/schema/__generated__/types";
|
||||
import * as user from "coral-server/models/user";
|
||||
|
||||
export const ModeratorNote: Required<
|
||||
GQLModeratorNoteTypeResolver<user.ModeratorNote>
|
||||
> = {
|
||||
export const ModeratorNote: Required<GQLModeratorNoteTypeResolver<
|
||||
user.ModeratorNote
|
||||
>> = {
|
||||
createdBy: ({ createdBy }, input, ctx) => {
|
||||
return ctx.loaders.Users.user.load(createdBy);
|
||||
},
|
||||
|
||||
@@ -5,9 +5,7 @@ import {
|
||||
|
||||
import { reconstructTenantURLResolver } from "./util";
|
||||
|
||||
export const OIDCAuthIntegration: GQLOIDCAuthIntegrationTypeResolver<
|
||||
GQLOIDCAuthIntegration
|
||||
> = {
|
||||
export const OIDCAuthIntegration: GQLOIDCAuthIntegrationTypeResolver<GQLOIDCAuthIntegration> = {
|
||||
callbackURL: reconstructTenantURLResolver("/api/auth/oidc/callback"),
|
||||
redirectURL: reconstructTenantURLResolver("/api/auth/oidc"),
|
||||
};
|
||||
|
||||
@@ -5,10 +5,10 @@ export type PremodStatusInput = user.ConsolidatedPremodStatus & {
|
||||
userID: string;
|
||||
};
|
||||
|
||||
export const PremodStatus: Required<
|
||||
GQLPremodStatusTypeResolver<PremodStatusInput>
|
||||
> = {
|
||||
export const PremodStatus: Required<GQLPremodStatusTypeResolver<
|
||||
PremodStatusInput
|
||||
>> = {
|
||||
active: ({ active }) => active,
|
||||
history: ({ history, userID }) =>
|
||||
history.map(status => ({ ...status, userID })),
|
||||
history.map((status) => ({ ...status, userID })),
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { GQLPremodStatusHistoryTypeResolver } from "coral-server/graph/schema/__generated__/types";
|
||||
import * as user from "coral-server/models/user";
|
||||
|
||||
export const PremodStatusHistory: Required<
|
||||
GQLPremodStatusHistoryTypeResolver<user.PremodStatusHistory>
|
||||
> = {
|
||||
export const PremodStatusHistory: Required<GQLPremodStatusHistoryTypeResolver<
|
||||
user.PremodStatusHistory
|
||||
>> = {
|
||||
active: ({ active }) => active,
|
||||
createdBy: ({ createdBy }, input, ctx) => {
|
||||
if (createdBy) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { GQLProfileTypeResolver } from "coral-server/graph/schema/__generated__/types";
|
||||
import * as user from "coral-server/models/user";
|
||||
|
||||
const resolveType: GQLProfileTypeResolver<user.Profile> = profile => {
|
||||
const resolveType: GQLProfileTypeResolver<user.Profile> = (profile) => {
|
||||
switch (profile.type) {
|
||||
case "local":
|
||||
return "LocalProfile";
|
||||
|
||||
@@ -8,5 +8,5 @@ export interface QueueInput {
|
||||
}
|
||||
|
||||
export const Queue: Required<GQLQueueTypeResolver<QueueInput>> = {
|
||||
counts: t => t.counts(),
|
||||
counts: (t) => t.counts(),
|
||||
};
|
||||
|
||||
@@ -15,9 +15,9 @@ const get = (fn: (ctx: GraphContext) => QueueInput) => (
|
||||
) => fn(ctx);
|
||||
|
||||
export const Queues: Required<GQLQueuesTypeResolver> = {
|
||||
mailer: get(ctx => ctx.mailerQueue),
|
||||
scraper: get(ctx => ctx.scraperQueue),
|
||||
notifier: get(ctx => ctx.notifierQueue),
|
||||
webhook: get(ctx => ctx.webhookQueue),
|
||||
rejector: get(ctx => ctx.rejectorQueue),
|
||||
mailer: get((ctx) => ctx.mailerQueue),
|
||||
scraper: get((ctx) => ctx.scraperQueue),
|
||||
notifier: get((ctx) => ctx.notifierQueue),
|
||||
webhook: get((ctx) => ctx.webhookQueue),
|
||||
rejector: get((ctx) => ctx.rejectorQueue),
|
||||
};
|
||||
|
||||
@@ -4,9 +4,9 @@ export interface RecentCommentHistoryInput {
|
||||
userID: string;
|
||||
}
|
||||
|
||||
export const RecentCommentHistory: Required<
|
||||
GQLRecentCommentHistoryTypeResolver<RecentCommentHistoryInput>
|
||||
> = {
|
||||
export const RecentCommentHistory: Required<GQLRecentCommentHistoryTypeResolver<
|
||||
RecentCommentHistoryInput
|
||||
>> = {
|
||||
statuses: ({ userID }, args, ctx) =>
|
||||
ctx.loaders.Comments.authorStatusCounts.load(userID),
|
||||
};
|
||||
|
||||
@@ -4,12 +4,10 @@ import { GQLSSOAuthIntegrationTypeResolver } from "coral-server/graph/schema/__g
|
||||
|
||||
function getActiveSSOKey(keys: settings.Secret[]) {
|
||||
// Any key that has been rotated cannot be the active key.
|
||||
return keys.find(key => !key.rotatedAt);
|
||||
return keys.find((key) => !key.rotatedAt);
|
||||
}
|
||||
|
||||
export const SSOAuthIntegration: GQLSSOAuthIntegrationTypeResolver<
|
||||
settings.SSOAuthIntegration
|
||||
> = {
|
||||
export const SSOAuthIntegration: GQLSSOAuthIntegrationTypeResolver<settings.SSOAuthIntegration> = {
|
||||
key: ({ keys }) => {
|
||||
const key = getActiveSSOKey(keys);
|
||||
if (key) {
|
||||
|
||||
@@ -3,9 +3,7 @@ import {
|
||||
GQLSlackConfigurationTypeResolver,
|
||||
} from "coral-server/graph/schema/__generated__/types";
|
||||
|
||||
export const SlackConfiguration: GQLSlackConfigurationTypeResolver<
|
||||
GQLSlackConfiguration
|
||||
> = {
|
||||
export const SlackConfiguration: GQLSlackConfigurationTypeResolver<GQLSlackConfiguration> = {
|
||||
// TODO: Remove this when we create a migration to generate slack channels on existing tenants
|
||||
channels: ({ channels = [] }) => channels,
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ export const Story: GQLStoryTypeResolver<story.Story> = {
|
||||
: GQLSTORY_STATUS.OPEN,
|
||||
isClosed: (s, input, ctx) => story.isStoryClosed(ctx.tenant, s, ctx.now),
|
||||
closedAt: (s, input, ctx) => story.getStoryClosedAt(ctx.tenant, s) || null,
|
||||
commentActionCounts: s => decodeActionCounts(s.commentCounts.action),
|
||||
commentActionCounts: (s) => decodeActionCounts(s.commentCounts.action),
|
||||
commentCounts: (s): CommentCountsInput => s,
|
||||
// Merge tenant settings into the story settings so we can easily inherit the
|
||||
// options if they exist.
|
||||
|
||||
@@ -7,14 +7,12 @@ import {
|
||||
GQLStorySettingsTypeResolver,
|
||||
} from "../schema/__generated__/types";
|
||||
|
||||
export const StorySettings: GQLStorySettingsTypeResolver<
|
||||
story.StorySettings
|
||||
> = {
|
||||
live: s => s.live || {},
|
||||
export const StorySettings: GQLStorySettingsTypeResolver<story.StorySettings> = {
|
||||
live: (s) => s.live || {},
|
||||
moderation: (s, input, ctx) => s.moderation || ctx.tenant.moderation,
|
||||
premodLinksEnable: (s, input, ctx) =>
|
||||
s.premodLinksEnable || ctx.tenant.premodLinksEnable,
|
||||
messageBox: s => {
|
||||
messageBox: (s) => {
|
||||
if (s.messageBox) {
|
||||
return s.messageBox;
|
||||
}
|
||||
|
||||
@@ -17,14 +17,15 @@ export type CommentCreatedSubscription = SubscriptionType<
|
||||
CommentCreatedInput
|
||||
>;
|
||||
|
||||
export const commentCreated: SubscriptionToCommentCreatedResolver<
|
||||
CommentCreatedInput
|
||||
> = createIterator(SUBSCRIPTION_CHANNELS.COMMENT_CREATED, {
|
||||
filter: (source, { storyID }) => {
|
||||
if (source.storyID !== storyID) {
|
||||
return false;
|
||||
}
|
||||
export const commentCreated: SubscriptionToCommentCreatedResolver<CommentCreatedInput> = createIterator(
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_CREATED,
|
||||
{
|
||||
filter: (source, { storyID }) => {
|
||||
if (source.storyID !== storyID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
return true;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -22,22 +22,23 @@ export type CommentEnteredModerationQueueSubscription = SubscriptionType<
|
||||
CommentEnteredModerationQueueInput
|
||||
>;
|
||||
|
||||
export const commentEnteredModerationQueue: SubscriptionToCommentEnteredModerationQueueResolver<
|
||||
CommentEnteredModerationQueueInput
|
||||
> = createIterator(SUBSCRIPTION_CHANNELS.COMMENT_ENTERED_MODERATION_QUEUE, {
|
||||
filter: (source, { storyID, queue }) => {
|
||||
// If we're filtering by storyID, then only send back comments with the
|
||||
// specific storyID.
|
||||
if (storyID && source.storyID !== storyID) {
|
||||
return false;
|
||||
}
|
||||
export const commentEnteredModerationQueue: SubscriptionToCommentEnteredModerationQueueResolver<CommentEnteredModerationQueueInput> = createIterator(
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_ENTERED_MODERATION_QUEUE,
|
||||
{
|
||||
filter: (source, { storyID, queue }) => {
|
||||
// If we're filtering by storyID, then only send back comments with the
|
||||
// specific storyID.
|
||||
if (storyID && source.storyID !== storyID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we're filtering by queue, then only send back comments from the
|
||||
// specific queue.
|
||||
if (queue && source.queue !== queue) {
|
||||
return false;
|
||||
}
|
||||
// If we're filtering by queue, then only send back comments from the
|
||||
// specific queue.
|
||||
if (queue && source.queue !== queue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
return true;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -17,14 +17,15 @@ export type CommentFeaturedSubscription = SubscriptionType<
|
||||
CommentFeaturedInput
|
||||
>;
|
||||
|
||||
export const commentFeatured: SubscriptionToCommentFeaturedResolver<
|
||||
CommentFeaturedInput
|
||||
> = createIterator(SUBSCRIPTION_CHANNELS.COMMENT_FEATURED, {
|
||||
filter: (source, { storyID }) => {
|
||||
if (source.storyID !== storyID) {
|
||||
return false;
|
||||
}
|
||||
export const commentFeatured: SubscriptionToCommentFeaturedResolver<CommentFeaturedInput> = createIterator(
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_FEATURED,
|
||||
{
|
||||
filter: (source, { storyID }) => {
|
||||
if (source.storyID !== storyID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
return true;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -21,22 +21,23 @@ export type CommentLeftModerationQueueSubscription = SubscriptionType<
|
||||
CommentLeftModerationQueueInput
|
||||
>;
|
||||
|
||||
export const commentLeftModerationQueue: SubscriptionToCommentLeftModerationQueueResolver<
|
||||
CommentLeftModerationQueueInput
|
||||
> = createIterator(SUBSCRIPTION_CHANNELS.COMMENT_LEFT_MODERATION_QUEUE, {
|
||||
filter: (source, { storyID, queue }) => {
|
||||
// If we're filtering by storyID, then only send back comments with the
|
||||
// specific storyID.
|
||||
if (storyID && source.storyID !== storyID) {
|
||||
return false;
|
||||
}
|
||||
export const commentLeftModerationQueue: SubscriptionToCommentLeftModerationQueueResolver<CommentLeftModerationQueueInput> = createIterator(
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_LEFT_MODERATION_QUEUE,
|
||||
{
|
||||
filter: (source, { storyID, queue }) => {
|
||||
// If we're filtering by storyID, then only send back comments with the
|
||||
// specific storyID.
|
||||
if (storyID && source.storyID !== storyID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we're filtering by queue, then only send back comments from the
|
||||
// specific queue.
|
||||
if (queue && source.queue !== queue) {
|
||||
return false;
|
||||
}
|
||||
// If we're filtering by queue, then only send back comments from the
|
||||
// specific queue.
|
||||
if (queue && source.queue !== queue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
return true;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -17,14 +17,15 @@ export type CommentReleasedSubscription = SubscriptionType<
|
||||
CommentReleasedInput
|
||||
>;
|
||||
|
||||
export const commentReleased: SubscriptionToCommentReleasedResolver<
|
||||
CommentReleasedInput
|
||||
> = createIterator(SUBSCRIPTION_CHANNELS.COMMENT_RELEASED, {
|
||||
filter: (source, { storyID }) => {
|
||||
if (source.storyID !== storyID) {
|
||||
return false;
|
||||
}
|
||||
export const commentReleased: SubscriptionToCommentReleasedResolver<CommentReleasedInput> = createIterator(
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_RELEASED,
|
||||
{
|
||||
filter: (source, { storyID }) => {
|
||||
if (source.storyID !== storyID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
return true;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -17,14 +17,15 @@ export type CommentReplyCreatedSubscription = SubscriptionType<
|
||||
CommentReplyCreatedInput
|
||||
>;
|
||||
|
||||
export const commentReplyCreated: SubscriptionToCommentReplyCreatedResolver<
|
||||
CommentReplyCreatedInput
|
||||
> = createIterator(SUBSCRIPTION_CHANNELS.COMMENT_REPLY_CREATED, {
|
||||
filter: (source, { ancestorID }) => {
|
||||
if (!source.ancestorIDs.includes(ancestorID)) {
|
||||
return false;
|
||||
}
|
||||
export const commentReplyCreated: SubscriptionToCommentReplyCreatedResolver<CommentReplyCreatedInput> = createIterator(
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_REPLY_CREATED,
|
||||
{
|
||||
filter: (source, { ancestorID }) => {
|
||||
if (!source.ancestorIDs.includes(ancestorID)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
return true;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -23,16 +23,17 @@ export type CommentStatusUpdatedSubscription = SubscriptionType<
|
||||
CommentStatusUpdatedInput
|
||||
>;
|
||||
|
||||
export const commentStatusUpdated: SubscriptionToCommentStatusUpdatedResolver<
|
||||
CommentStatusUpdatedInput
|
||||
> = createIterator(SUBSCRIPTION_CHANNELS.COMMENT_STATUS_UPDATED, {
|
||||
filter: (source, { id }) => {
|
||||
// If we're filtering by id, then only send back updates for the specified
|
||||
// comment.
|
||||
if (id && source.commentID !== id) {
|
||||
return false;
|
||||
}
|
||||
export const commentStatusUpdated: SubscriptionToCommentStatusUpdatedResolver<CommentStatusUpdatedInput> = createIterator(
|
||||
SUBSCRIPTION_CHANNELS.COMMENT_STATUS_UPDATED,
|
||||
{
|
||||
filter: (source, { id }) => {
|
||||
// If we're filtering by id, then only send back updates for the specified
|
||||
// comment.
|
||||
if (id && source.commentID !== id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
return true;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -102,6 +102,6 @@ export function createIterator<
|
||||
createTenantAsyncIterator(channel),
|
||||
createFilterFn(filter)
|
||||
),
|
||||
resolve: payload => payload,
|
||||
resolve: (payload) => payload,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,9 +20,7 @@ export const Subscription: GQLSubscriptionTypeResolver = {
|
||||
|
||||
export { CommentFeaturedInput } from "./commentFeatured";
|
||||
export { CommentCreatedInput } from "./commentCreated";
|
||||
export {
|
||||
CommentEnteredModerationQueueInput,
|
||||
} from "./commentEnteredModerationQueue";
|
||||
export { CommentEnteredModerationQueueInput } from "./commentEnteredModerationQueue";
|
||||
export { CommentLeftModerationQueueInput } from "./commentLeftModerationQueue";
|
||||
export { CommentReleasedInput } from "./commentReleased";
|
||||
export { CommentReplyCreatedInput } from "./commentReplyCreated";
|
||||
|
||||
@@ -5,11 +5,11 @@ export type SuspensionStatusInput = user.ConsolidatedSuspensionStatus & {
|
||||
userID: string;
|
||||
};
|
||||
|
||||
export const SuspensionStatus: Required<
|
||||
GQLSuspensionStatusTypeResolver<SuspensionStatusInput>
|
||||
> = {
|
||||
export const SuspensionStatus: Required<GQLSuspensionStatusTypeResolver<
|
||||
SuspensionStatusInput
|
||||
>> = {
|
||||
active: ({ active }) => active,
|
||||
until: ({ until }) => until,
|
||||
history: ({ history, userID }) =>
|
||||
history.map(status => ({ ...status, userID })),
|
||||
history.map((status) => ({ ...status, userID })),
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { GQLSuspensionStatusHistoryTypeResolver } from "coral-server/graph/schema/__generated__/types";
|
||||
import * as user from "coral-server/models/user";
|
||||
|
||||
export const SuspensionStatusHistory: Required<
|
||||
GQLSuspensionStatusHistoryTypeResolver<user.SuspensionStatusHistory>
|
||||
> = {
|
||||
export const SuspensionStatusHistory: Required<GQLSuspensionStatusHistoryTypeResolver<
|
||||
user.SuspensionStatusHistory
|
||||
>> = {
|
||||
active: ({ from }, input, ctx) =>
|
||||
from.start <= ctx.now && from.finish > ctx.now,
|
||||
from: ({ from }) => from,
|
||||
|
||||
@@ -13,9 +13,9 @@ export type UserStatusInput = user.UserStatus & {
|
||||
userID: string;
|
||||
};
|
||||
|
||||
export const UserStatus: Required<
|
||||
GQLUserStatusTypeResolver<UserStatusInput>
|
||||
> = {
|
||||
export const UserStatus: Required<GQLUserStatusTypeResolver<
|
||||
UserStatusInput
|
||||
>> = {
|
||||
current: (status, input, ctx) => {
|
||||
const consolidatedStatus = user.consolidateUserStatus(status, ctx.now);
|
||||
const statuses: GQLUSER_STATUS[] = [];
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { GQLUsernameHistoryTypeResolver } from "coral-server/graph/schema/__generated__/types";
|
||||
import * as user from "coral-server/models/user";
|
||||
|
||||
export const UsernameHistory: Required<
|
||||
GQLUsernameHistoryTypeResolver<user.UsernameHistory>
|
||||
> = {
|
||||
export const UsernameHistory: Required<GQLUsernameHistoryTypeResolver<
|
||||
user.UsernameHistory
|
||||
>> = {
|
||||
createdBy: ({ createdBy }, input, ctx) => {
|
||||
if (createdBy) {
|
||||
return ctx.loaders.Users.user.load(createdBy);
|
||||
|
||||
@@ -5,9 +5,9 @@ export type UsernameStatusInput = user.ConsolidatedUsernameStatus & {
|
||||
userID: string;
|
||||
};
|
||||
|
||||
export const UsernameStatus: Required<
|
||||
GQLUsernameStatusTypeResolver<UsernameStatusInput>
|
||||
> = {
|
||||
export const UsernameStatus: Required<GQLUsernameStatusTypeResolver<
|
||||
UsernameStatusInput
|
||||
>> = {
|
||||
history: ({ history, userID }) =>
|
||||
history.map(status => ({ ...status, userID })),
|
||||
history.map((status) => ({ ...status, userID })),
|
||||
};
|
||||
|
||||
@@ -2,9 +2,7 @@ import * as tenant from "coral-server/models/tenant";
|
||||
|
||||
import { GQLWebhookEndpointTypeResolver } from "coral-server/graph/schema/__generated__/types";
|
||||
|
||||
export const WebhookEndpoint: GQLWebhookEndpointTypeResolver<
|
||||
tenant.Endpoint
|
||||
> = {
|
||||
export const WebhookEndpoint: GQLWebhookEndpointTypeResolver<tenant.Endpoint> = {
|
||||
signingSecret: ({ signingSecrets }) =>
|
||||
signingSecrets[signingSecrets.length - 1],
|
||||
};
|
||||
|
||||
@@ -6,86 +6,119 @@ import Cursor from "./cursor";
|
||||
describe("parseLiteral", () => {
|
||||
it("parses a date from a string", () => {
|
||||
expect(
|
||||
Cursor.parseLiteral({
|
||||
kind: Kind.STRING,
|
||||
value: "2018-07-16T18:34:26.744Z",
|
||||
})
|
||||
Cursor.parseLiteral(
|
||||
{
|
||||
kind: Kind.STRING,
|
||||
value: "2018-07-16T18:34:26.744Z",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toBeInstanceOf(Date);
|
||||
|
||||
expect(
|
||||
Cursor.parseLiteral({
|
||||
kind: Kind.STRING,
|
||||
value: "this-should-fail",
|
||||
})
|
||||
Cursor.parseLiteral(
|
||||
{
|
||||
kind: Kind.STRING,
|
||||
value: "this-should-fail",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toEqual(null);
|
||||
|
||||
expect(
|
||||
Cursor.parseLiteral({
|
||||
kind: Kind.STRING,
|
||||
value: "",
|
||||
})
|
||||
Cursor.parseLiteral(
|
||||
{
|
||||
kind: Kind.STRING,
|
||||
value: "",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toEqual(null);
|
||||
});
|
||||
|
||||
it("parses a number from a string", () => {
|
||||
expect(
|
||||
Cursor.parseLiteral({
|
||||
kind: Kind.STRING,
|
||||
value: "20",
|
||||
})
|
||||
Cursor.parseLiteral(
|
||||
{
|
||||
kind: Kind.STRING,
|
||||
value: "20",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toEqual(20);
|
||||
|
||||
expect(
|
||||
Cursor.parseLiteral({
|
||||
kind: Kind.STRING,
|
||||
value: "0",
|
||||
})
|
||||
Cursor.parseLiteral(
|
||||
{
|
||||
kind: Kind.STRING,
|
||||
value: "0",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toEqual(0);
|
||||
|
||||
expect(
|
||||
Cursor.parseLiteral({
|
||||
kind: Kind.STRING,
|
||||
value: "null",
|
||||
})
|
||||
Cursor.parseLiteral(
|
||||
{
|
||||
kind: Kind.STRING,
|
||||
value: "null",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toEqual(null);
|
||||
|
||||
expect(
|
||||
Cursor.parseLiteral({
|
||||
kind: Kind.STRING,
|
||||
value: "0",
|
||||
})
|
||||
Cursor.parseLiteral(
|
||||
{
|
||||
kind: Kind.STRING,
|
||||
value: "0",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toEqual(0);
|
||||
});
|
||||
|
||||
it("parses a number from a number", () => {
|
||||
expect(
|
||||
Cursor.parseLiteral({
|
||||
kind: Kind.INT,
|
||||
value: "20",
|
||||
})
|
||||
Cursor.parseLiteral(
|
||||
{
|
||||
kind: Kind.INT,
|
||||
value: "20",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toEqual(20);
|
||||
|
||||
expect(
|
||||
Cursor.parseLiteral({
|
||||
kind: Kind.INT,
|
||||
value: "0",
|
||||
})
|
||||
Cursor.parseLiteral(
|
||||
{
|
||||
kind: Kind.INT,
|
||||
value: "0",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toEqual(0);
|
||||
|
||||
expect(
|
||||
Cursor.parseLiteral({
|
||||
kind: Kind.INT,
|
||||
value: "",
|
||||
})
|
||||
Cursor.parseLiteral(
|
||||
{
|
||||
kind: Kind.INT,
|
||||
value: "",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toEqual(null);
|
||||
});
|
||||
|
||||
it("does not parse unknown kinds", () => {
|
||||
expect(
|
||||
Cursor.parseLiteral({
|
||||
kind: Kind.FLOAT,
|
||||
value: "0.0",
|
||||
})
|
||||
Cursor.parseLiteral(
|
||||
{
|
||||
kind: Kind.FLOAT,
|
||||
value: "0.0",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,27 +5,36 @@ import Locale from "./locale";
|
||||
describe("parseLiteral", () => {
|
||||
it("parses a valid locale from a string", () => {
|
||||
expect(
|
||||
Locale.parseLiteral({
|
||||
kind: Kind.STRING,
|
||||
value: "en-US",
|
||||
})
|
||||
Locale.parseLiteral(
|
||||
{
|
||||
kind: Kind.STRING,
|
||||
value: "en-US",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toBe("en-US");
|
||||
});
|
||||
it("parses an unsupported locale from a string", () => {
|
||||
expect(() =>
|
||||
Locale.parseLiteral({
|
||||
kind: Kind.STRING,
|
||||
value: "xyz",
|
||||
})
|
||||
Locale.parseLiteral(
|
||||
{
|
||||
kind: Kind.STRING,
|
||||
value: "xyz",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
it("throws when not a string", () => {
|
||||
expect(() =>
|
||||
Locale.parseLiteral({
|
||||
kind: Kind.INT,
|
||||
value: "4",
|
||||
})
|
||||
Locale.parseLiteral(
|
||||
{
|
||||
kind: Kind.INT,
|
||||
value: "4",
|
||||
},
|
||||
null
|
||||
)
|
||||
).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from "subscriptions-transport-ws";
|
||||
|
||||
import { ACCESS_TOKEN_PARAM, CLIENT_ID_PARAM } from "coral-common/constants";
|
||||
import { Omit, RequireProperty } from "coral-common/types";
|
||||
import { RequireProperty } from "coral-common/types";
|
||||
import { AppOptions } from "coral-server/app";
|
||||
import { getHostname } from "coral-server/app/helpers/hostname";
|
||||
import {
|
||||
@@ -195,7 +195,7 @@ export function formatResponse(
|
||||
if (value.errors && value.errors.length > 0) {
|
||||
return {
|
||||
...value,
|
||||
errors: value.errors.map(err => {
|
||||
errors: value.errors.map((err) => {
|
||||
const enriched = enrichError(context, err);
|
||||
|
||||
// Log the error out.
|
||||
|
||||
Reference in New Issue
Block a user