mirror of
https://github.com/wassname/talk.git
synced 2026-09-12 13:01:11 +08:00
[CORL-183] Invite Users (#2349)
* feat: initial UI impl * feat: attach react devtools hook in development * feat: working mutations * feat: polished the invite modal with mutation Co-authored-by: Vinh <vinh@wikiwi.io> * feat: added check * feat: improve the invite server impl * feat: admin invite interface improvements * fix: update tests * feat: moved invite UI to admin * fix: include email enabled as condition for invite * feat: added admin tests * feat: added tests for invite complete flow * fix: review
This commit is contained in:
@@ -20,12 +20,14 @@ import {
|
||||
updateRole,
|
||||
updateUsername,
|
||||
} from "coral-server/services/users";
|
||||
import { invite } from "coral-server/services/users/auth/invite";
|
||||
|
||||
import {
|
||||
GQLBanUserInput,
|
||||
GQLCreateTokenInput,
|
||||
GQLDeactivateTokenInput,
|
||||
GQLIgnoreUserInput,
|
||||
GQLInviteUsersInput,
|
||||
GQLRemoveUserBanInput,
|
||||
GQLRemoveUserIgnoreInput,
|
||||
GQLRemoveUserSuspensionInput,
|
||||
@@ -41,6 +43,25 @@ import {
|
||||
} from "../schema/__generated__/types";
|
||||
|
||||
export const Users = (ctx: TenantContext) => ({
|
||||
invite: async ({ role, emails }: GQLInviteUsersInput) =>
|
||||
mapFieldsetToErrorCodes(
|
||||
invite(
|
||||
ctx.mongo,
|
||||
ctx.tenant,
|
||||
ctx.config,
|
||||
ctx.mailerQueue,
|
||||
ctx.signingConfig!,
|
||||
{ role, emails },
|
||||
ctx.user!,
|
||||
ctx.now
|
||||
),
|
||||
{
|
||||
"input.emails": [
|
||||
ERROR_CODES.EMAIL_INVALID_FORMAT,
|
||||
ERROR_CODES.EMAIL_EXCEEDS_MAX_LENGTH,
|
||||
],
|
||||
}
|
||||
),
|
||||
setUsername: async (
|
||||
input: GQLSetUsernameInput
|
||||
): Promise<Readonly<User> | null> =>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { GQLInviteTypeResolver } from "coral-server/graph/tenant/schema/__generated__/types";
|
||||
import * as invite from "coral-server/models/invite";
|
||||
|
||||
export const Invite: GQLInviteTypeResolver<invite.Invite> = {
|
||||
createdBy: ({ createdBy }, args, ctx) =>
|
||||
ctx.loaders.Users.user.load(createdBy),
|
||||
};
|
||||
@@ -107,6 +107,10 @@ export const Mutation: Required<GQLMutationTypeResolver<void>> = {
|
||||
comment: await ctx.mutators.Actions.rejectComment(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
inviteUsers: async (source, { input }, ctx) => ({
|
||||
invites: await ctx.mutators.Users.invite(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
setUsername: async (source, { input }, ctx) => ({
|
||||
user: await ctx.mutators.Users.setUsername(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
|
||||
@@ -16,6 +16,7 @@ import { FacebookAuthIntegration } from "./FacebookAuthIntegration";
|
||||
import { FeatureCommentPayload } from "./FeatureCommentPayload";
|
||||
import { Flag } from "./Flag";
|
||||
import { GoogleAuthIntegration } from "./GoogleAuthIntegration";
|
||||
import { Invite } from "./Invite";
|
||||
import { ModerationQueue } from "./ModerationQueue";
|
||||
import { ModerationQueues } from "./ModerationQueues";
|
||||
import { Mutation } from "./Mutation";
|
||||
@@ -48,6 +49,7 @@ const Resolvers: GQLResolver = {
|
||||
FeatureCommentPayload,
|
||||
Flag,
|
||||
GoogleAuthIntegration,
|
||||
Invite,
|
||||
ModerationQueue,
|
||||
ModerationQueues,
|
||||
Mutation,
|
||||
|
||||
@@ -881,7 +881,7 @@ type Email {
|
||||
"""
|
||||
smtpURI is the SMTP connection url to send emails on.
|
||||
"""
|
||||
smtpURI: String
|
||||
smtpURI: String @auth(roles: [ADMIN])
|
||||
|
||||
"""
|
||||
fromAddress is the email address that will be used to send emails from.
|
||||
@@ -1137,7 +1137,7 @@ type Settings {
|
||||
"""
|
||||
email is the set of credentials and settings associated with the organization.
|
||||
"""
|
||||
email: Email! @auth(roles: [ADMIN])
|
||||
email: Email! @auth(roles: [ADMIN, MODERATOR])
|
||||
|
||||
"""
|
||||
wordList will return a given list of words.
|
||||
@@ -1228,6 +1228,39 @@ type Token {
|
||||
createdAt: Time!
|
||||
}
|
||||
|
||||
"""
|
||||
Invite represents a given User that is pending registration that has been
|
||||
invited by an Administrator.
|
||||
"""
|
||||
type Invite {
|
||||
"""
|
||||
id is the identifier for the Invite.
|
||||
"""
|
||||
id: ID!
|
||||
|
||||
"""
|
||||
email is the email address that will be assigned and used for the
|
||||
invited User.
|
||||
"""
|
||||
email: String!
|
||||
|
||||
"""
|
||||
role is the USER_ROLE that the User will be assigned upon
|
||||
account creation.
|
||||
"""
|
||||
role: USER_ROLE!
|
||||
|
||||
"""
|
||||
createdBy is the User that created the Invite.
|
||||
"""
|
||||
createdBy: User!
|
||||
|
||||
"""
|
||||
createdAt is the time that the Invite was created on.
|
||||
"""
|
||||
createdAt: Time!
|
||||
}
|
||||
|
||||
"""
|
||||
BanStatusHistory is the list of all ban events against a specific User.
|
||||
"""
|
||||
@@ -3748,6 +3781,38 @@ type SetUsernamePayload {
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
##################
|
||||
# inviteUser
|
||||
##################
|
||||
|
||||
input InviteUsersInput {
|
||||
"""
|
||||
emails is the email addresses of the Users to be invited.
|
||||
"""
|
||||
emails: [String!]!
|
||||
|
||||
"""
|
||||
role is the designated role of the User being invited.
|
||||
"""
|
||||
role: USER_ROLE!
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
type InviteUsersPayload {
|
||||
"""
|
||||
invites is the references to the invited Users.
|
||||
"""
|
||||
invites: [Invite]!
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
##################
|
||||
# setEmail
|
||||
@@ -4362,6 +4427,13 @@ type Mutation {
|
||||
rejectComment(input: RejectCommentInput!): RejectCommentPayload!
|
||||
@auth(roles: [MODERATOR, ADMIN])
|
||||
|
||||
"""
|
||||
inviteUsers will send emails to the users with a new account at the designated
|
||||
role.
|
||||
"""
|
||||
inviteUsers(input: InviteUsersInput!): InviteUsersPayload!
|
||||
@auth(roles: [ADMIN])
|
||||
|
||||
"""
|
||||
setUsername will set the username on the current User if they have not set one
|
||||
before. This mutation will fail if the username is already set.
|
||||
|
||||
Reference in New Issue
Block a user