-
Notifications
You must be signed in to change notification settings - Fork 4
user invite #244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
user invite #244
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| export const EMAIL_DELIVERY_STATUS = { | ||
| PENDING: 'pending', | ||
| RECEIVED: 'received', | ||
| ALL: ['pending', 'received'], | ||
| }; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,19 @@ | ||||||||||||||||||||||||||
| import { mongooseStringRandomId } from 'erxes-api-shared/utils'; | ||||||||||||||||||||||||||
| import { Schema } from 'mongoose'; | ||||||||||||||||||||||||||
| import { EMAIL_DELIVERY_STATUS } from '~/modules/organization/team-member/constants'; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export const emailDeliveriesSchema = new Schema({ | ||||||||||||||||||||||||||
| _id: mongooseStringRandomId, | ||||||||||||||||||||||||||
| subject: { type: String }, | ||||||||||||||||||||||||||
| body: { type: String }, | ||||||||||||||||||||||||||
| to: { type: [String] }, | ||||||||||||||||||||||||||
| cc: { type: [String], optional: true }, | ||||||||||||||||||||||||||
| bcc: { type: [String], optional: true }, | ||||||||||||||||||||||||||
|
Comment on lines
+10
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: The 'optional' property is not a standard Mongoose schema option. Remove 'optional: true' from the schema fields, as Mongoose ignores this property. Fields are optional by default unless 'required: true' is specified.
Suggested change
Comment on lines
+10
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix non-standard Mongoose optional field syntax. The - cc: { type: [String], optional: true },
- bcc: { type: [String], optional: true },
+ cc: { type: [String] },
+ bcc: { type: [String] },Alternatively, if you want to be explicit about optional fields: - cc: { type: [String], optional: true },
- bcc: { type: [String], optional: true },
+ cc: { type: [String], required: false },
+ bcc: { type: [String], required: false },📝 Committable suggestion
Suggested change
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| attachments: { type: [Object] }, | ||||||||||||||||||||||||||
| from: { type: String }, | ||||||||||||||||||||||||||
| kind: { type: String }, | ||||||||||||||||||||||||||
| customerId: { type: String }, | ||||||||||||||||||||||||||
| userId: { type: String }, | ||||||||||||||||||||||||||
| createdAt: { type: Date, default: Date.now }, | ||||||||||||||||||||||||||
| status: { type: String, enum: EMAIL_DELIVERY_STATUS.ALL }, | ||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: Consider setting a default value for 'status'. Setting a default value like 'pending' for 'status' can help prevent missing or inconsistent values. Suggested implementation: status: { type: String, enum: EMAIL_DELIVERY_STATUS.ALL, default: 'pending' },If default: EMAIL_DELIVERY_STATUS.PENDING |
||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import { Model } from 'mongoose'; | ||
| import { IModels } from '~/connectionResolvers'; | ||
| import { emailDeliveriesSchema } from '~/modules/organization/team-member/db/definitions/emailDeliveries'; | ||
| import { | ||
| IEmailDeliveries, | ||
| IEmailDeliveriesDocument, | ||
| } from '~/modules/organization/team-member/types'; | ||
|
|
||
| export interface IEmailDeliveryModel extends Model<IEmailDeliveriesDocument> { | ||
| createEmailDelivery(doc: IEmailDeliveries): Promise<IEmailDeliveriesDocument>; | ||
| updateEmailDeliveryStatus(_id: string, status: string): Promise<void>; | ||
| } | ||
|
|
||
| export const loadEmailDeliveryClass = (models: IModels) => { | ||
| class EmailDelivery { | ||
| /** | ||
| * Create an EmailDelivery document | ||
| */ | ||
| public static async createEmailDelivery(doc: IEmailDeliveries) { | ||
| return models.EmailDeliveries.create({ | ||
| ...doc, | ||
| }); | ||
| } | ||
|
|
||
| public static async updateEmailDeliveryStatus(_id: string, status: string) { | ||
| return models.EmailDeliveries.updateOne({ _id }, { $set: { status } }); | ||
| } | ||
| } | ||
|
|
||
| emailDeliveriesSchema.loadClass(EmailDelivery); | ||
|
|
||
| return emailDeliveriesSchema; | ||
| }; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,10 +1,13 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { IContext } from '~/connectionResolvers'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||
| IUser, | ||||||||||||||||||||||||||||||||||||||||||||||||
| IDetail, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ILink, | ||||||||||||||||||||||||||||||||||||||||||||||||
| IEmailSignature, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ILink, | ||||||||||||||||||||||||||||||||||||||||||||||||
| IUser, | ||||||||||||||||||||||||||||||||||||||||||||||||
| } from 'erxes-api-shared/core-types'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { isEnabled, sendTRPCMessage } from 'erxes-api-shared/utils'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { IContext } from '~/connectionResolvers'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { sendInvitationEmail } from '~/modules/organization/team-member/utils'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { resetPermissionsCache } from '~/modules/permissions/utils'; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| export interface IUsersEdit extends IUser { | ||||||||||||||||||||||||||||||||||||||||||||||||
| channelIds?: string[]; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -198,7 +201,7 @@ export const userMutations = { | |||||||||||||||||||||||||||||||||||||||||||||||
| departmentId?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||
| }>; | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { models }: IContext, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { models, subdomain }: IContext, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| for (const entry of entries) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| await models.Users.checkDuplication({ email: entry.email }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -210,6 +213,8 @@ export const userMutations = { | |||||||||||||||||||||||||||||||||||||||||||||||
| if (docModified?.scopeBrandIds?.length) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| doc.brandIds = docModified.scopeBrandIds; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const token = await models.Users.invite(doc); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const createdUser = await models.Users.findOne({ email: entry.email }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (entry.branchId) { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -229,7 +234,21 @@ export const userMutations = { | |||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (entry.channelIds && (await isEnabled('frontline'))) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| sendTRPCMessage({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| pluginName: 'frontline', | ||||||||||||||||||||||||||||||||||||||||||||||||
| method: 'mutation', | ||||||||||||||||||||||||||||||||||||||||||||||||
| module: 'inbox', | ||||||||||||||||||||||||||||||||||||||||||||||||
| action: 'updateUserChannels', | ||||||||||||||||||||||||||||||||||||||||||||||||
| input: { channelIds: entry.channelIds, userId: createdUser?._id }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+238
to
+246
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling for TRPC message sending. The TRPC message is sent without error handling. If the frontline service is unavailable or the operation fails, it could cause the entire user invitation process to fail silently or throw an unhandled error. if (entry.channelIds && (await isEnabled('frontline'))) {
- sendTRPCMessage({
- pluginName: 'frontline',
- method: 'mutation',
- module: 'inbox',
- action: 'updateUserChannels',
- input: { channelIds: entry.channelIds, userId: createdUser?._id },
- });
+ try {
+ await sendTRPCMessage({
+ pluginName: 'frontline',
+ method: 'mutation',
+ module: 'inbox',
+ action: 'updateUserChannels',
+ input: { channelIds: entry.channelIds, userId: createdUser?._id },
+ });
+ } catch (error) {
+ console.error('Failed to update user channels:', error);
+ // Continue with invitation process even if channel update fails
+ }
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| sendInvitationEmail(models, subdomain, { email: entry.email, token }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question (bug_risk): sendInvitationEmail is called without awaiting its result. If you need to handle errors or ensure the email is sent before continuing, use 'await'. If fire-and-forget is intentional, please document this choice. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling for invitation email sending. The - sendInvitationEmail(models, subdomain, { email: entry.email, token });
+ try {
+ await sendInvitationEmail(models, subdomain, { email: entry.email, token });
+ } catch (error) {
+ console.error('Failed to send invitation email:', error);
+ // Consider whether to continue or throw based on business requirements
+ }🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| await resetPermissionsCache(models); | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import { Document } from 'mongoose'; | ||
|
|
||
| export interface IAttachmentParams { | ||
| data: string; | ||
| filename: string; | ||
| size: number; | ||
| mimeType: string; | ||
| } | ||
|
|
||
| export interface IEmailDeliveries { | ||
| subject: string; | ||
| body: string; | ||
| to: string[]; | ||
| cc?: string[]; | ||
| bcc?: string[]; | ||
| attachments?: IAttachmentParams[]; | ||
| from: string; | ||
| kind: string; | ||
| userId?: string; | ||
| customerId?: string; | ||
| status?: string; | ||
| } | ||
|
|
||
| export interface IEmailDeliveriesDocument extends IEmailDeliveries, Document { | ||
| id: string; | ||
| } | ||
|
|
||
| export interface IEmailParams { | ||
| toEmails?: string[]; | ||
| fromEmail?: string; | ||
| title?: string; | ||
| customHtml?: string; | ||
| customHtmlData?: any; | ||
| template?: { name?: string; data?: any }; | ||
| attachments?: object[]; | ||
| modifier?: (data: any, email: string) => void; | ||
| transportMethod?: string; | ||
| getOrganizationDetail?: ({ subdomain }: { subdomain: string }) => any; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The schema for 'cc' (and similarly 'bcc') uses 'optional: true'. In Mongoose the standard option is 'required: false'. Verify that the intended optional behavior is achieved.