Skip to content

Commit dba54c2

Browse files
feat: update bot send mail
1 parent 7a4d347 commit dba54c2

File tree

9 files changed

+84
-17
lines changed

9 files changed

+84
-17
lines changed

client/src/components/forms/channel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { useQuery } from '@tanstack/react-query';
2222
import { queryChannelTypesOption } from '@/lib/query-options/channel';
2323
import { zodResolver } from '@hookform/resolvers/zod';
2424
import { ChannelType } from '@/types/channel';
25-
import { useEffect, useMemo } from 'react';
25+
import { useMemo } from 'react';
2626
import { useDidUpdate } from '@/hooks/use-did-update';
2727

2828
type Props = {

client/src/components/pages/channels/data-toolbar.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import ChannelForm from '@/components/forms/channel';
22
import {
33
Button,
4-
Input,
54
Sheet,
6-
SheetClose,
75
SheetContent,
86
SheetDescription,
97
SheetFooter,
@@ -13,14 +11,10 @@ import {
1311
} from '@/components/ui';
1412
import { useCreateChannel } from '@/hooks/channel';
1513
import { useSearch } from '@/hooks/use-search';
16-
import React, { useState } from 'react';
14+
import { useState } from 'react';
1715
import { Trans, useTranslation } from 'react-i18next';
1816
import { Link } from 'react-router-dom';
1917

20-
type Props = {
21-
table: any;
22-
};
23-
2418
export const DataToolbar = () => {
2519
const { renderInput } = useSearch();
2620
const { t } = useTranslation(['common', 'channel']);

client/src/components/pages/channels/row-action.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { useBodyOverflow } from '@/hooks/use-body-overflow';
1919
import { TChannelWithChannelType } from '@/types/channel';
2020
import { Row } from '@tanstack/react-table';
2121
import { Link, MoreHorizontal } from 'lucide-react';
22-
import { useEffect, useState } from 'react';
22+
import { useState } from 'react';
2323
import { Trans, useTranslation } from 'react-i18next';
2424

2525
type Props = {

client/src/pages/channels.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const Channels = () => {
3030
<DataTable
3131
columns={cols}
3232
data={data.items || []}
33-
renderToolbar={(table) => <DataToolbar />}
33+
renderToolbar={() => <DataToolbar />}
3434
opts={{
3535
state: {
3636
sorting,

server/src/config/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,6 @@ export const {
3030
SIGNATURE_SECRET,
3131
PUBLIC_DOMAIN,
3232
BOT_ENDPOINT,
33+
MAIL_USER,
34+
MAIL_PASS,
3335
} = process.env;

server/src/dtos/bot-mail.dto.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { TTemplate } from '@/mail/send-mail';
2+
import { IsEmail, IsNotEmpty, IsObject, IsString } from 'class-validator';
3+
4+
export class BotMailDto {
5+
@IsString()
6+
@IsEmail()
7+
@IsNotEmpty()
8+
to: string;
9+
10+
@IsString()
11+
@IsNotEmpty()
12+
subject: string;
13+
14+
@IsString()
15+
@IsNotEmpty()
16+
@IsString()
17+
from: string;
18+
19+
@IsString()
20+
@IsNotEmpty()
21+
template: TTemplate;
22+
23+
@IsObject()
24+
variables: Record<string, any>;
25+
}

server/src/mail/send-mail.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { render } from '@react-email/render';
22
import nodemailer from 'nodemailer';
33
import { logger } from '../utils/logger';
44
import { ForgotPassword, ForgotPasswordProps } from './templates';
5+
import { MAIL_PASS, MAIL_USER } from '@/config';
56

67
interface TemplateProps {
78
'forgot-password': ForgotPasswordProps;
@@ -16,17 +17,25 @@ const MAP_TEMPLATES: TMapTemplates = {
1617
'verify-email': () => '',
1718
};
1819

20+
export type TTemplate = keyof TemplateProps;
1921

2022
export const sendMail = async <T extends keyof TemplateProps>(opts: {
2123
to: string;
2224
subject: string;
2325
template: T;
2426
props: TemplateProps[T];
25-
user?: string
26-
pass?: string
27+
from?: string;
28+
user?: string;
29+
pass?: string;
2730
}) => {
28-
const { to, subject, template, props, pass
29-
= process.env.MAIL_PASS, user = process.env.MAIL_USER
31+
const {
32+
to,
33+
subject,
34+
template,
35+
props,
36+
pass = MAIL_PASS,
37+
user = MAIL_USER,
38+
from = MAIL_USER,
3039
} = opts;
3140
try {
3241
const html = MAP_TEMPLATES[template](props);
@@ -42,9 +51,8 @@ export const sendMail = async <T extends keyof TemplateProps>(opts: {
4251
},
4352
});
4453

45-
4654
await transporter.sendMail({
47-
from: process.env.MAIL_FROM,
55+
from,
4856
to,
4957
subject,
5058
html,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { BotMailDto } from '@/dtos/bot-mail.dto';
2+
import { SendMailQueue } from '@/queues/mail.queue';
3+
import { Service } from 'typedi';
4+
import { db } from '@/database/db';
5+
import { settings } from '@/database/schema';
6+
import { eq } from 'drizzle-orm';
7+
8+
@Service()
9+
export class BotMailService {
10+
constructor(private readonly sendMailQueue: SendMailQueue) {}
11+
12+
async sendMail(fields: BotMailDto) {
13+
const { from, subject, template, to, variables } = fields;
14+
15+
const userId = '1';
16+
17+
const [user] = await db
18+
.select()
19+
.from(settings)
20+
.where(eq(settings.userId, userId));
21+
22+
if (!user) {
23+
return;
24+
}
25+
26+
const { email, password } = user.email;
27+
28+
await this.sendMailQueue.addJob({
29+
from,
30+
to,
31+
props: variables,
32+
subject,
33+
template,
34+
pass: password,
35+
user: email,
36+
});
37+
}
38+
}

server/src/services/setting.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Service } from 'typedi';
66
import { decrypt, encrypt } from '@/utils/crypto';
77
@Service()
88
export class SettingService {
9-
async findByUserId(userId: string) {
9+
async findByUserId(userId: string): Promise<string> {
1010
const [setting] = await db
1111
.select()
1212
.from(settings)

0 commit comments

Comments
 (0)