@@ -12,7 +12,7 @@ const parser = require('mongodb-query-parser');
1212const { boolean } = require ( 'boolean' ) ;
1313const _ = require ( '#helpers/lodash' ) ;
1414
15- const { Users } = require ( '#models' ) ;
15+ const { Users, Emails } = require ( '#models' ) ;
1616const config = require ( '#config' ) ;
1717
1818const REGEX_BYTES = new RE2 ( / ^ ( ( - | \+ ) ? ( \d + (?: \. \d + ) ? ) ) * ( k b | m b | g b | t b | p b ) $ / i) ;
@@ -52,29 +52,91 @@ async function list(ctx) {
5252 }
5353 }
5454
55- const [ users , itemCount ] = await Promise . all ( [
55+ const now = new Date ( ) ;
56+ const oneHourAgo = new Date ( now - 60 * 60 * 1000 ) ;
57+ const twentyFourHoursAgo = new Date ( now - 24 * 60 * 60 * 1000 ) ;
58+ const seventyTwoHoursAgo = new Date ( now - 72 * 60 * 60 * 1000 ) ;
59+
60+ const [ users , itemCount , emailCounts ] = await Promise . all ( [
5661 // eslint-disable-next-line unicorn/no-array-callback-reference
5762 Users . find ( query )
5863 . limit ( ctx . query . limit )
5964 . skip ( ctx . paginate . skip )
6065 . lean ( )
6166 . sort ( ctx . query . sort || '-created_at' )
6267 . exec ( ) ,
63- Users . countDocuments ( query )
68+ Users . countDocuments ( query ) ,
69+ // Get SMTP outbound email counts per user with time-based breakdowns
70+ Emails . aggregate ( [
71+ {
72+ $match : {
73+ // Only count delivered/sent emails (not failed/bounced)
74+ status : { $in : [ 'delivered' , 'deferred' , 'sent' ] }
75+ }
76+ } ,
77+ {
78+ $group : {
79+ _id : '$user' ,
80+ totalEmails : { $sum : 1 } ,
81+ lastEmailAt : { $max : '$created_at' } ,
82+ // Count emails within time periods
83+ emailsLast1Hour : {
84+ $sum : {
85+ $cond : [ { $gte : [ '$created_at' , oneHourAgo ] } , 1 , 0 ]
86+ }
87+ } ,
88+ emailsLast24Hours : {
89+ $sum : {
90+ $cond : [ { $gte : [ '$created_at' , twentyFourHoursAgo ] } , 1 , 0 ]
91+ }
92+ } ,
93+ emailsLast72Hours : {
94+ $sum : {
95+ $cond : [ { $gte : [ '$created_at' , seventyTwoHoursAgo ] } , 1 , 0 ]
96+ }
97+ }
98+ }
99+ }
100+ ] )
64101 ] ) ;
65102
103+ // Create a map for quick lookup of email counts
104+ const emailCountMap = new Map ( ) ;
105+ for ( const count of emailCounts ) {
106+ emailCountMap . set ( count . _id . toString ( ) , {
107+ totalEmails : count . totalEmails ,
108+ lastEmailAt : count . lastEmailAt ,
109+ emailsLast1Hour : count . emailsLast1Hour ,
110+ emailsLast24Hours : count . emailsLast24Hours ,
111+ emailsLast72Hours : count . emailsLast72Hours
112+ } ) ;
113+ }
114+
115+ // Add email counts to each user
116+ const usersWithEmailCounts = users . map ( ( user ) => ( {
117+ ...user ,
118+ totalEmails : emailCountMap . get ( user . _id . toString ( ) ) ?. totalEmails || 0 ,
119+ lastEmailAt : emailCountMap . get ( user . _id . toString ( ) ) ?. lastEmailAt || null ,
120+ emailsLast1Hour :
121+ emailCountMap . get ( user . _id . toString ( ) ) ?. emailsLast1Hour || 0 ,
122+ emailsLast24Hours :
123+ emailCountMap . get ( user . _id . toString ( ) ) ?. emailsLast24Hours || 0 ,
124+ emailsLast72Hours :
125+ emailCountMap . get ( user . _id . toString ( ) ) ?. emailsLast72Hours || 0
126+ } ) ) ;
127+
66128 const pageCount = Math . ceil ( itemCount / ctx . query . limit ) ;
67129
68130 if ( ctx . accepts ( 'html' ) )
69131 return ctx . render ( 'admin/users' , {
70- users,
132+ users : usersWithEmailCounts ,
71133 pageCount,
72134 itemCount,
73135 pages : paginate . getArrayPages ( ctx ) ( 6 , pageCount , ctx . query . page )
74136 } ) ;
75137
76138 const table = await ctx . render ( 'admin/users/_table' , {
77- users,
139+ users : usersWithEmailCounts ,
78140 pageCount,
79141 itemCount,
80142 pages : paginate . getArrayPages ( ctx ) ( 6 , pageCount , ctx . query . page )
0 commit comments