11const Imap = require ( "imap" ) ;
2+ var EmailReplyParser = require ( "email-reply-parser" ) ;
3+
4+ import { GoogleAuth } from "google-auth-library" ;
25import { prisma } from "../prisma" ;
36
47const { simpleParser } = require ( "mailparser" ) ;
@@ -14,19 +17,103 @@ const year = date.getFullYear();
1417//@ts -ignore
1518const d = new Date ( [ year , month , today ] ) ;
1619
20+ // Function to get or refresh the access token
21+ async function getValidAccessToken ( queue : any ) {
22+ const {
23+ clientId,
24+ clientSecret,
25+ refreshToken,
26+ accessToken,
27+ expiresIn,
28+ username,
29+ } = queue ;
30+
31+ // Check if token is still valid
32+ const now = Math . floor ( Date . now ( ) / 1000 ) ;
33+ if ( accessToken && expiresIn && now < expiresIn ) {
34+ return accessToken ;
35+ }
36+
37+ // Initialize GoogleAuth client
38+ const auth = new GoogleAuth ( {
39+ clientOptions : {
40+ clientId : clientId ,
41+ clientSecret : clientSecret ,
42+ } ,
43+ } ) ;
44+
45+ const oauth2Client = auth . fromJSON ( {
46+ client_id : clientId ,
47+ client_secret : clientSecret ,
48+ refresh_token : refreshToken ,
49+ } ) ;
50+
51+ // Refresh the token if expired
52+ const tokenInfo = await oauth2Client . getAccessToken ( ) ;
53+
54+ const expiryDate = queue . expiresIn + 3600 ;
55+
56+ if ( tokenInfo . token ) {
57+ await prisma . emailQueue . update ( {
58+ where : { id : queue . id } ,
59+ data : {
60+ accessToken : tokenInfo . token ,
61+ expiresIn : expiryDate ,
62+ } ,
63+ } ) ;
64+ return tokenInfo . token ;
65+ } else {
66+ throw new Error ( "Unable to refresh access token." ) ;
67+ }
68+ }
69+
70+ // Function to generate XOAUTH2 string
71+ function generateXOAuth2Token ( user : string , accessToken : string ) {
72+ const authString = [
73+ "user=" + user ,
74+ "auth=Bearer " + accessToken ,
75+ "" ,
76+ "" ,
77+ ] . join ( "\x01" ) ;
78+ return Buffer . from ( authString ) . toString ( "base64" ) ;
79+ }
80+
81+ async function returnImapConfig ( queue : any ) {
82+ switch ( queue . serviceType ) {
83+ case "gmail" :
84+ const validatedAccessToken = await getValidAccessToken ( queue ) ;
85+ return {
86+ user : queue . username ,
87+ host : queue . hostname ,
88+ port : 993 ,
89+ tls : true ,
90+ xoauth2 : generateXOAuth2Token ( queue . username , validatedAccessToken ) ,
91+ tlsOptions : { rejectUnauthorized : false , servername : queue . hostname } ,
92+ } ;
93+ case "other" :
94+ return {
95+ user : queue . username ,
96+ password : queue . password ,
97+ host : queue . hostname ,
98+ port : queue . tls ? 993 : 143 ,
99+ tls : queue . tls ,
100+ tlsOptions : { rejectUnauthorized : false , servername : queue . hostname } ,
101+ } ;
102+ default :
103+ throw new Error ( "Unsupported service type" ) ;
104+ }
105+ }
106+
17107export const getEmails = async ( ) => {
18108 try {
19109 const queues = await client . emailQueue . findMany ( { } ) ;
20110
21111 for ( let i = 0 ; i < queues . length ; i ++ ) {
22- var imapConfig = {
23- user : queues [ i ] . username ,
24- password : queues [ i ] . password ,
25- host : queues [ i ] . hostname ,
26- port : queues [ i ] . tls ? 993 : 110 ,
27- tls : queues [ i ] . tls ,
28- tlsOptions : { servername : queues [ i ] . hostname } ,
29- } ;
112+ var imapConfig = await returnImapConfig ( queues [ i ] ) ;
113+
114+ if ( ! imapConfig ) {
115+ continue ;
116+ }
30117
31118 const imap = new Imap ( imapConfig ) ;
32119 imap . connect ( ) ;
@@ -53,9 +140,9 @@ export const getEmails = async () => {
53140 simpleParser ( stream , async ( err : any , parsed : any ) => {
54141 const { from, subject, textAsHtml, text, html } = parsed ;
55142
56- // Handle reply emails
143+ var reply_text = new EmailReplyParser ( ) . read ( text ) ;
144+
57145 if ( subject ?. includes ( "Re:" ) ) {
58- // Extract ticket number from subject (e.g., "Re: Ticket #123")
59146 const ticketIdMatch = subject . match ( / # ( \d + ) / ) ;
60147 if ( ! ticketIdMatch ) {
61148 console . log (
@@ -67,17 +154,28 @@ export const getEmails = async () => {
67154
68155 const ticketId = ticketIdMatch [ 1 ] ;
69156
70- // Create comment with the reply
71- return await client . comment . create ( {
72- data : {
73- text : text ? text : "No Body" ,
74- userId : null ,
75- ticketId : ticketId ,
76- reply : true ,
77- replyEmail : from . value [ 0 ] . address ,
78- public : true ,
157+ const find = await client . ticket . findFirst ( {
158+ where : {
159+ Number : Number ( ticketId ) ,
79160 } ,
80161 } ) ;
162+
163+ if ( find ) {
164+ return await client . comment . create ( {
165+ data : {
166+ text : text
167+ ? reply_text . fragments [ 0 ] . _content
168+ : "No Body" ,
169+ userId : null ,
170+ ticketId : find . id ,
171+ reply : true ,
172+ replyEmail : from . value [ 0 ] . address ,
173+ public : true ,
174+ } ,
175+ } ) ;
176+ } else {
177+ console . log ( "Ticket not found" ) ;
178+ }
81179 } else {
82180 const imap = await client . imap_Email . create ( {
83181 data : {
0 commit comments