mirror of
https://github.com/wassname/talk.git
synced 2026-08-11 11:27:10 +08:00
Merge branch 'next' into permalink
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
import { User } from "talk-server/models/user";
|
||||
import { Request } from "talk-server/types/express";
|
||||
|
||||
export interface CommonContextOptions {
|
||||
user?: User;
|
||||
req?: Request;
|
||||
}
|
||||
|
||||
export default class CommonContext {
|
||||
public user?: User;
|
||||
public req?: Request;
|
||||
|
||||
constructor({ user }: CommonContextOptions) {
|
||||
constructor({ user, req }: CommonContextOptions) {
|
||||
this.user = user;
|
||||
this.req = req;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
GraphQLOptions,
|
||||
} from "apollo-server-express";
|
||||
import { FieldDefinitionNode, GraphQLError, ValidationContext } from "graphql";
|
||||
import { Config } from "talk-server/config";
|
||||
import { Config } from "talk-common/config";
|
||||
|
||||
// Sourced from: https://github.com/apollographql/apollo-server/blob/958846887598491fadea57b3f9373d129300f250/packages/apollo-server-core/src/ApolloServer.ts#L46-L57
|
||||
const NoIntrospection = (context: ValidationContext) => ({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { RedisPubSub } from "graphql-redis-subscriptions";
|
||||
import { Config } from "talk-server/config";
|
||||
import { Config } from "talk-common/config";
|
||||
import { createRedisClient } from "talk-server/services/redis";
|
||||
|
||||
export async function createPubSub(config: Config): Promise<RedisPubSub> {
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import { Db } from "mongodb";
|
||||
|
||||
import CommonContext from "talk-server/graph/common/context";
|
||||
import { Request } from "talk-server/types/express";
|
||||
|
||||
export interface ManagementContextOptions {
|
||||
db: Db;
|
||||
mongo: Db;
|
||||
req?: Request;
|
||||
}
|
||||
|
||||
export default class ManagementContext extends CommonContext {
|
||||
public db: Db;
|
||||
public mongo: Db;
|
||||
|
||||
constructor({ db }: ManagementContextOptions) {
|
||||
super({});
|
||||
constructor({ req, mongo }: ManagementContextOptions) {
|
||||
super({ req });
|
||||
|
||||
this.db = db;
|
||||
this.mongo = mongo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { GraphQLSchema } from "graphql";
|
||||
import { Db } from "mongodb";
|
||||
|
||||
import { Config } from "talk-server/config";
|
||||
import { Config } from "talk-common/config";
|
||||
import { graphqlMiddleware } from "talk-server/graph/common/middleware";
|
||||
import { Request } from "talk-server/types/express";
|
||||
|
||||
import Context from "./context";
|
||||
import ManagementContext from "./context";
|
||||
|
||||
export default (schema: GraphQLSchema, config: Config, db: Db) =>
|
||||
graphqlMiddleware(config, async () => ({
|
||||
export default (schema: GraphQLSchema, config: Config, mongo: Db) =>
|
||||
graphqlMiddleware(config, async (req: Request) => ({
|
||||
schema,
|
||||
context: new Context({ db }),
|
||||
context: new ManagementContext({ req, mongo }),
|
||||
}));
|
||||
|
||||
@@ -1,30 +1,49 @@
|
||||
import { Redis } from "ioredis";
|
||||
import { Db } from "mongodb";
|
||||
|
||||
import CommonContext from "talk-server/graph/common/context";
|
||||
import { Tenant } from "talk-server/models/tenant";
|
||||
import { User } from "talk-server/models/user";
|
||||
import TenantCache from "talk-server/services/tenant/cache";
|
||||
import { Request } from "talk-server/types/express";
|
||||
|
||||
import loaders from "./loaders";
|
||||
import mutators from "./mutators";
|
||||
|
||||
export interface TenantContextOptions {
|
||||
db: Db;
|
||||
mongo: Db;
|
||||
redis: Redis;
|
||||
tenant: Tenant;
|
||||
tenantCache: TenantCache;
|
||||
req?: Request;
|
||||
user?: User;
|
||||
}
|
||||
|
||||
export default class TenantContext extends CommonContext {
|
||||
public loaders: ReturnType<typeof loaders>;
|
||||
public mutators: ReturnType<typeof mutators>;
|
||||
public db: Db;
|
||||
public mongo: Db;
|
||||
public redis: Redis;
|
||||
public user?: User;
|
||||
public tenant: Tenant;
|
||||
public tenantCache: TenantCache;
|
||||
|
||||
constructor({ user, tenant, db }: TenantContextOptions) {
|
||||
super({ user });
|
||||
constructor({
|
||||
req,
|
||||
user,
|
||||
tenant,
|
||||
mongo,
|
||||
redis,
|
||||
tenantCache,
|
||||
}: TenantContextOptions) {
|
||||
super({ user, req });
|
||||
|
||||
this.tenant = tenant;
|
||||
this.tenantCache = tenantCache;
|
||||
this.user = user;
|
||||
this.mongo = mongo;
|
||||
this.redis = redis;
|
||||
this.loaders = loaders(this);
|
||||
this.mutators = mutators(this);
|
||||
this.db = db;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ import { findOrCreate } from "talk-server/services/assets";
|
||||
|
||||
export default (ctx: TenantContext) => ({
|
||||
findOrCreate: (input: FindOrCreateAssetInput) =>
|
||||
findOrCreate(ctx.db, ctx.tenant, input),
|
||||
findOrCreate(ctx.mongo, ctx.tenant, input),
|
||||
asset: new DataLoader<string, Asset | null>(ids =>
|
||||
retrieveManyAssets(ctx.db, ctx.tenant.id, ids)
|
||||
retrieveManyAssets(ctx.mongo, ctx.tenant.id, ids)
|
||||
),
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
|
||||
export default (ctx: Context) => ({
|
||||
comment: new DataLoader((ids: string[]) =>
|
||||
retrieveManyComments(ctx.db, ctx.tenant.id, ids)
|
||||
retrieveManyComments(ctx.mongo, ctx.tenant.id, ids)
|
||||
),
|
||||
forAsset: (
|
||||
assetID: string,
|
||||
@@ -25,7 +25,7 @@ export default (ctx: Context) => ({
|
||||
after,
|
||||
}: AssetToCommentsArgs
|
||||
) =>
|
||||
retrieveCommentAssetConnection(ctx.db, ctx.tenant.id, assetID, {
|
||||
retrieveCommentAssetConnection(ctx.mongo, ctx.tenant.id, assetID, {
|
||||
first,
|
||||
orderBy,
|
||||
after,
|
||||
@@ -40,9 +40,15 @@ export default (ctx: Context) => ({
|
||||
after,
|
||||
}: CommentToRepliesArgs
|
||||
) =>
|
||||
retrieveCommentRepliesConnection(ctx.db, ctx.tenant.id, assetID, parentID, {
|
||||
first,
|
||||
orderBy,
|
||||
after,
|
||||
}),
|
||||
retrieveCommentRepliesConnection(
|
||||
ctx.mongo,
|
||||
ctx.tenant.id,
|
||||
assetID,
|
||||
parentID,
|
||||
{
|
||||
first,
|
||||
orderBy,
|
||||
after,
|
||||
}
|
||||
),
|
||||
});
|
||||
|
||||
@@ -4,6 +4,6 @@ import { retrieveManyUsers, User } from "talk-server/models/user";
|
||||
|
||||
export default (ctx: Context) => ({
|
||||
user: new DataLoader<string, User | null>(ids =>
|
||||
retrieveManyUsers(ctx.db, ctx.tenant.id, ids)
|
||||
retrieveManyUsers(ctx.mongo, ctx.tenant.id, ids)
|
||||
),
|
||||
});
|
||||
|
||||
@@ -1,21 +1,41 @@
|
||||
import { GraphQLSchema } from "graphql";
|
||||
import { Redis } from "ioredis";
|
||||
import { Db } from "mongodb";
|
||||
|
||||
import { Config } from "talk-server/config";
|
||||
import { Config } from "talk-common/config";
|
||||
import { graphqlMiddleware } from "talk-server/graph/common/middleware";
|
||||
import { Request } from "talk-server/types/express";
|
||||
|
||||
import TenantContext from "./context";
|
||||
|
||||
export default async (schema: GraphQLSchema, config: Config, db: Db) => {
|
||||
export interface TenantGraphQLMiddlewareOptions {
|
||||
schema: GraphQLSchema;
|
||||
config: Config;
|
||||
mongo: Db;
|
||||
redis: Redis;
|
||||
}
|
||||
|
||||
export default async ({
|
||||
schema,
|
||||
config,
|
||||
mongo,
|
||||
redis,
|
||||
}: TenantGraphQLMiddlewareOptions) => {
|
||||
return graphqlMiddleware(config, async (req: Request) => {
|
||||
// Load the tenant and user from the request.
|
||||
const { tenant, user } = req;
|
||||
const { tenant, user, tenantCache } = req;
|
||||
|
||||
// Return the graph options.
|
||||
return {
|
||||
schema,
|
||||
context: new TenantContext({ db, tenant: tenant!, user }),
|
||||
context: new TenantContext({
|
||||
req,
|
||||
mongo,
|
||||
redis,
|
||||
tenant: tenant!,
|
||||
user,
|
||||
tenantCache,
|
||||
}),
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -5,12 +5,17 @@ import { create } from "talk-server/services/comments";
|
||||
|
||||
export default (ctx: TenantContext) => ({
|
||||
create: (input: GQLCreateCommentInput): Promise<Comment> => {
|
||||
// FIXME: remove tenant + user !
|
||||
return create(ctx.db, ctx.tenant, {
|
||||
author_id: ctx.user!.id,
|
||||
asset_id: input.assetID,
|
||||
body: input.body,
|
||||
parent_id: input.parentID,
|
||||
});
|
||||
return create(
|
||||
ctx.mongo,
|
||||
ctx.tenant,
|
||||
ctx.user!,
|
||||
{
|
||||
author_id: ctx.user!.id,
|
||||
asset_id: input.assetID,
|
||||
body: input.body,
|
||||
parent_id: input.parentID,
|
||||
},
|
||||
ctx.req
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import TenantContext from "talk-server/graph/tenant/context";
|
||||
|
||||
import Comment from "./comment";
|
||||
import Settings from "./settings";
|
||||
|
||||
export default (ctx: TenantContext) => ({
|
||||
Comment: Comment(ctx),
|
||||
Settings: Settings(ctx),
|
||||
});
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { isNull, omitBy } from "lodash";
|
||||
|
||||
import TenantContext from "talk-server/graph/tenant/context";
|
||||
import { GQLSettingsInput } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { Tenant } from "talk-server/models/tenant";
|
||||
import { update } from "talk-server/services/tenant";
|
||||
|
||||
export default ({ mongo, redis, tenantCache, tenant }: TenantContext) => ({
|
||||
update: (input: GQLSettingsInput): Promise<Tenant | null> =>
|
||||
update(mongo, redis, tenantCache, tenant, omitBy(input, isNull)),
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { GQLAuthIntegrationsTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { AuthIntegration, AuthIntegrations } from "talk-server/models/tenant";
|
||||
import { AuthIntegration, AuthIntegrations } from "talk-server/models/settings";
|
||||
|
||||
const disabled: AuthIntegration = { enabled: false };
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { GQLAuthSettingsTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { Auth } from "talk-server/models/tenant";
|
||||
import { Auth } from "talk-server/models/settings";
|
||||
|
||||
const AuthSettings: GQLAuthSettingsTypeResolver<Auth> = {
|
||||
integrations: auth => auth.integrations,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { GQLFacebookAuthIntegrationTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { FacebookAuthIntegration } from "talk-server/models/tenant";
|
||||
import { FacebookAuthIntegration } from "talk-server/models/settings";
|
||||
|
||||
const FacebookAuthIntegration: GQLFacebookAuthIntegrationTypeResolver<
|
||||
FacebookAuthIntegration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { GQLGoogleAuthIntegrationTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { GoogleAuthIntegration } from "talk-server/models/tenant";
|
||||
import { GoogleAuthIntegration } from "talk-server/models/settings";
|
||||
|
||||
const GoogleAuthIntegration: GQLGoogleAuthIntegrationTypeResolver<
|
||||
GoogleAuthIntegration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { GQLLocalAuthIntegrationTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { LocalAuthIntegration } from "talk-server/models/tenant";
|
||||
import { LocalAuthIntegration } from "talk-server/models/settings";
|
||||
|
||||
const LocalAuthIntegration: GQLLocalAuthIntegrationTypeResolver<
|
||||
LocalAuthIntegration
|
||||
|
||||
@@ -5,6 +5,10 @@ const Mutation: GQLMutationTypeResolver<void> = {
|
||||
comment: await ctx.mutators.Comment.create(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
updateSettings: async (source, { input }, ctx) => ({
|
||||
settings: await ctx.mutators.Settings.update(input.settings),
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
};
|
||||
|
||||
export default Mutation;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { GQLOIDCAuthIntegrationTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { OIDCAuthIntegration } from "talk-server/models/tenant";
|
||||
import { OIDCAuthIntegration } from "talk-server/models/settings";
|
||||
|
||||
const OIDCAuthIntegration: GQLOIDCAuthIntegrationTypeResolver<
|
||||
OIDCAuthIntegration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { GQLSSOAuthIntegrationTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { SSOAuthIntegration } from "talk-server/models/tenant";
|
||||
import { SSOAuthIntegration } from "talk-server/models/settings";
|
||||
|
||||
const SSOAuthIntegration: GQLSSOAuthIntegrationTypeResolver<
|
||||
SSOAuthIntegration
|
||||
|
||||
@@ -25,6 +25,19 @@ Cursor represents a paginating cursor.
|
||||
"""
|
||||
scalar Cursor
|
||||
|
||||
################################################################################
|
||||
## Actions
|
||||
################################################################################
|
||||
|
||||
enum ACTION_TYPE {
|
||||
FLAG
|
||||
DONTAGREE
|
||||
}
|
||||
|
||||
enum ACTION_ITEM_TYPE {
|
||||
COMMENTS
|
||||
}
|
||||
|
||||
################################################################################
|
||||
## Settings
|
||||
################################################################################
|
||||
@@ -287,7 +300,7 @@ type Settings {
|
||||
"""
|
||||
domains will return a given list of whitelisted domains.
|
||||
"""
|
||||
domains: [String!] @auth(roles: [ADMIN]) @auth(roles: [ADMIN])
|
||||
domains: [String!] @auth(roles: [ADMIN])
|
||||
|
||||
"""
|
||||
auth contains all the settings related to authentication and authorization.
|
||||
@@ -301,6 +314,7 @@ type Settings {
|
||||
|
||||
enum USER_ROLE {
|
||||
COMMENTER
|
||||
STAFF
|
||||
MODERATOR
|
||||
ADMIN
|
||||
}
|
||||
@@ -390,8 +404,34 @@ type User {
|
||||
################################################################################
|
||||
|
||||
enum COMMENT_STATUS {
|
||||
"""
|
||||
The comment is not PREMOD, but was not applied a moderation status by a
|
||||
moderator.
|
||||
"""
|
||||
NONE
|
||||
|
||||
"""
|
||||
The comment has been accepted by a moderator.
|
||||
"""
|
||||
ACCEPTED
|
||||
|
||||
"""
|
||||
The comment has been rejected by a moderator.
|
||||
"""
|
||||
REJECTED
|
||||
|
||||
"""
|
||||
The comment was created while the asset's premoderation option was on, and
|
||||
new comments that haven't been moderated yet are referred to as
|
||||
"premoderated" or "premod" comments.
|
||||
"""
|
||||
PREMOD
|
||||
|
||||
"""
|
||||
SYSTEM_WITHHELD represents a comment that was withheld by the system because
|
||||
it was flagged by an internal process for further review.
|
||||
"""
|
||||
SYSTEM_WITHHELD
|
||||
}
|
||||
|
||||
"""
|
||||
@@ -661,6 +701,66 @@ type CreateCommentPayload {
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
##################
|
||||
## updateSettings
|
||||
##################
|
||||
|
||||
"""
|
||||
SettingsInput is the partial type of the Settings type for performing mutations.
|
||||
"""
|
||||
input SettingsInput {
|
||||
moderation: MODERATION_MODE
|
||||
requireEmailConfirmation: Boolean
|
||||
infoBoxEnable: Boolean
|
||||
infoBoxContent: String
|
||||
questionBoxEnable: Boolean
|
||||
questionBoxContent: String
|
||||
questionBoxIcon: String
|
||||
premodLinksEnable: Boolean
|
||||
autoCloseStream: Boolean
|
||||
customCssUrl: String
|
||||
closedTimeout: Int
|
||||
closedMessage: String
|
||||
disableCommenting: Boolean
|
||||
disableCommentingMessage: String
|
||||
editCommentWindowLength: Int
|
||||
charCountEnable: Boolean
|
||||
charCount: Int
|
||||
organizationName: String
|
||||
organizationContactEmail: String
|
||||
# wordlist: WordlistSettings @auth(roles: [ADMIN, MODERATOR])
|
||||
domains: [String!]
|
||||
# auth: AuthSettings!
|
||||
}
|
||||
|
||||
"""
|
||||
UpdateSettingsInput provides the input for the updateSettings Mutation.
|
||||
"""
|
||||
input UpdateSettingsInput {
|
||||
settings: SettingsInput!
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
"""
|
||||
UpdateSettingsPayload contains the updated Settings after the updateSettings
|
||||
mutation.
|
||||
"""
|
||||
type UpdateSettingsPayload {
|
||||
"""
|
||||
settings is the updated Settings.
|
||||
"""
|
||||
settings: Settings
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
##################
|
||||
## Mutation
|
||||
##################
|
||||
@@ -670,6 +770,11 @@ type Mutation {
|
||||
createComment will create a Comment as the current logged in User.
|
||||
"""
|
||||
createComment(input: CreateCommentInput!): CreateCommentPayload @auth
|
||||
|
||||
"""
|
||||
updateSettings will update the Settings for the given Tenant.
|
||||
"""
|
||||
updateSettings(input: UpdateSettingsInput!): UpdateSettingsPayload @auth(roles: [ADMIN])
|
||||
}
|
||||
|
||||
################################################################################
|
||||
|
||||
Reference in New Issue
Block a user