@@ -10,6 +10,7 @@ const expect = chai.expect;
1010chai . config . includeStack = true ;
1111const config = require ( '@zone-eu/wild-config' ) ;
1212const { ObjectId } = require ( 'mongodb' ) ;
13+ const { ImapFlow } = require ( 'imapflow' ) ;
1314const { parseSearchQuery, getMongoDBQuery } = require ( '../../lib/search-query' ) ;
1415
1516const server = supertest . agent ( `http://127.0.0.1:${ config . api . port } ` ) ;
@@ -259,6 +260,7 @@ describe('Messages tests', function () {
259260 let queryAttachmentMessageId ;
260261 let queryFlaggedSeenAttachmentMessageId ;
261262 let queryAltMailboxMessageId ;
263+ let testUsername ;
262264 let testAddress ;
263265
264266 const queryFixture = {
@@ -335,7 +337,7 @@ describe('Messages tests', function () {
335337
336338 before ( async ( ) => {
337339 const testUserTag = Date . now ( ) . toString ( 36 ) ;
338- const testUsername = `messagestestsuser-${ testUserTag } ` ;
340+ testUsername = `messagestestsuser-${ testUserTag } ` ;
339341 testAddress = `${ testUsername } @web.zone.test` ;
340342 queryFixture . fromAddress = testAddress ;
341343
@@ -1065,6 +1067,97 @@ describe('Messages tests', function () {
10651067 expect ( archivedRoot ) . to . not . have . property ( 'hasDrafts' ) ;
10661068 } ) ;
10671069
1070+ it ( 'should GET /users/:user/search expect success / IMAP APPEND draft hasDrafts matches only the direct parent' , async ( ) => {
1071+ const mailboxPath = `imap-draft-reference-${ Date . now ( ) . toString ( 36 ) } ` ;
1072+ const mailboxResponse = await server
1073+ . post ( `/users/${ user } /mailboxes` )
1074+ . send ( { path : `/${ mailboxPath } ` , hidden : false , retention : 10000 } )
1075+ . expect ( 200 ) ;
1076+ const mailbox = mailboxResponse . body . id ;
1077+
1078+ const root = await server
1079+ . post ( `/users/${ user } /mailboxes/${ mailbox } /messages` )
1080+ . send ( {
1081+ to : [ { address : 'imap-draft@example.com' } ] ,
1082+ subject : 'IMAP Draft Thread' ,
1083+ text : 'Root message'
1084+ } )
1085+ . expect ( 200 ) ;
1086+
1087+ const reply = await server
1088+ . post ( `/users/${ user } /mailboxes/${ mailbox } /messages` )
1089+ . send ( {
1090+ to : [ { address : 'imap-draft@example.com' } ] ,
1091+ text : 'Intermediate reply' ,
1092+ reference : {
1093+ mailbox,
1094+ id : root . body . message . id ,
1095+ action : 'reply'
1096+ }
1097+ } )
1098+ . expect ( 200 ) ;
1099+
1100+ await server . put ( `/users/${ user } /mailboxes/${ mailbox } /messages/${ reply . body . message . id } ` ) . send ( { draft : false } ) . expect ( 200 ) ;
1101+
1102+ const rootData = await server . get ( `/users/${ user } /mailboxes/${ mailbox } /messages/${ root . body . message . id } ` ) . send ( { } ) . expect ( 200 ) ;
1103+ const replyData = await server . get ( `/users/${ user } /mailboxes/${ mailbox } /messages/${ reply . body . message . id } ` ) . send ( { } ) . expect ( 200 ) ;
1104+ const rawDraft = [
1105+ `From: ${ testAddress } ` ,
1106+ 'To: imap-draft@example.com' ,
1107+ 'Subject: Re: IMAP Draft Thread' ,
1108+ `Message-ID: <imap-draft-${ Date . now ( ) . toString ( 36 ) } @web.zone.test>` ,
1109+ `In-Reply-To: ${ replyData . body . messageId } ` ,
1110+ `References: ${ rootData . body . messageId } ${ replyData . body . messageId } ` ,
1111+ 'MIME-Version: 1.0' ,
1112+ 'Content-Type: text/plain; charset=utf-8' ,
1113+ '' ,
1114+ 'Draft uploaded with IMAP APPEND'
1115+ ] . join ( '\r\n' ) ;
1116+
1117+ const client = new ImapFlow ( {
1118+ host : '127.0.0.1' ,
1119+ port : config . imap . port ,
1120+ secure : true ,
1121+ auth : {
1122+ user : testUsername ,
1123+ pass : 'secretpassword'
1124+ } ,
1125+ tls : {
1126+ rejectUnauthorized : false
1127+ } ,
1128+ logger : false
1129+ } ) ;
1130+
1131+ let appendResult ;
1132+ try {
1133+ await client . connect ( ) ;
1134+ appendResult = await client . append ( mailboxPath , rawDraft , [ '\\Draft' ] ) ;
1135+ } finally {
1136+ if ( client . usable ) {
1137+ await client . logout ( ) ;
1138+ } else {
1139+ client . close ( ) ;
1140+ }
1141+ }
1142+
1143+ expect ( appendResult . uid ) . to . be . a ( 'number' ) ;
1144+
1145+ const appendedDraft = await server . get ( `/users/${ user } /mailboxes/${ mailbox } /messages/${ appendResult . uid } ` ) . send ( { } ) . expect ( 200 ) ;
1146+ expect ( appendedDraft . body ) . to . not . have . property ( 'reference' ) ;
1147+
1148+ const expandedThread = await server
1149+ . get ( `/users/${ user } /search?thread=${ rootData . body . thread } &includeHasDrafts=true&limit=3` )
1150+ . send ( { } )
1151+ . expect ( 200 ) ;
1152+
1153+ expect ( expandedThread . body . results . map ( entry => entry . id ) ) . to . deep . equal ( [
1154+ appendResult . uid ,
1155+ reply . body . message . id ,
1156+ root . body . message . id
1157+ ] ) ;
1158+ expect ( expandedThread . body . results . map ( entry => entry . hasDrafts ) ) . to . deep . equal ( [ false , true , false ] ) ;
1159+ } ) ;
1160+
10681161 it ( 'should GET /users/:user/search expect success / q supports subject and in keywords' , async ( ) => {
10691162 const q = `subject:"${ queryFixture . subjectKeyword } " in:${ queryMailbox } ` ;
10701163 const search = await searchQ ( q ) ;
0 commit comments