mirror of
https://github.com/Crazyco-xyz/48hr.email.git
synced 2026-01-09 19:29:34 +01:00
[Feat]: Show total and historical email count in UI
Enhances user interface by displaying both the current number of emails and the largest UID seen, offering better visibility into historical mailbox activity. Updates backend logic and view templates to support this change, and improves maintainability by centralizing count formatting.
This commit is contained in:
parent
1cf35f76f0
commit
83a4fac4ab
8 changed files with 43 additions and 3 deletions
|
|
@ -71,7 +71,7 @@ User=user
|
||||||
Group=user
|
Group=user
|
||||||
|
|
||||||
WorkingDirectory=/opt/48hr-email
|
WorkingDirectory=/opt/48hr-email
|
||||||
ExecStart=npm run prod
|
ExecStart=npm run start
|
||||||
|
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
TimeoutStartSec=0
|
TimeoutStartSec=0
|
||||||
|
|
|
||||||
3
app.js
3
app.js
|
|
@ -56,6 +56,9 @@ imapService.on(ImapService.EVENT_ERROR, error => {
|
||||||
|
|
||||||
app.set('mailProcessingService', mailProcessingService)
|
app.set('mailProcessingService', mailProcessingService)
|
||||||
|
|
||||||
|
app.locals.imapService = imapService
|
||||||
|
app.locals.mailProcessingService = mailProcessingService
|
||||||
|
|
||||||
debug('Starting IMAP connection and message loading')
|
debug('Starting IMAP connection and message loading')
|
||||||
imapService.connectAndLoadMessages().catch(error => {
|
imapService.connectAndLoadMessages().catch(error => {
|
||||||
debug('Failed to connect to IMAP:', error.message)
|
debug('Failed to connect to IMAP:', error.message)
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,17 @@ class Helper {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getLargestUid(imapService) {
|
||||||
|
return await imapService.getLargestUid();
|
||||||
|
}
|
||||||
|
|
||||||
|
countElementBuilder(count = 0, largestUid = 0) {
|
||||||
|
const handling = `<label title="Historically managed ${largestUid} email${largestUid === 1 ? '' : 's'}">
|
||||||
|
<h4 style="display: inline;"><u><i>${count}</i></u> mail${count === 1 ? '' : 's'}</h4>
|
||||||
|
</label>`
|
||||||
|
return handling
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Helper
|
module.exports = Helper
|
||||||
|
|
@ -421,8 +421,18 @@ class ImapService extends EventEmitter {
|
||||||
]
|
]
|
||||||
return this.connection.search(searchCriteria, fetchOptions)
|
return this.connection.search(searchCriteria, fetchOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the largest UID from all messages in the mailbox.
|
||||||
|
*/
|
||||||
|
async getLargestUid() {
|
||||||
|
const uids = await this._getAllUids();
|
||||||
|
return uids.length > 0 ? Math.max(...uids) : null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Consumers should use these constants:
|
// Consumers should use these constants:
|
||||||
ImapService.EVENT_NEW_MAIL = 'mail'
|
ImapService.EVENT_NEW_MAIL = 'mail'
|
||||||
ImapService.EVENT_DELETED_MAIL = 'mailDeleted'
|
ImapService.EVENT_DELETED_MAIL = 'mailDeleted'
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ router.get('/:address/:errorCode', async(req, res, next) => {
|
||||||
}
|
}
|
||||||
debug(`Error page requested: ${req.params.errorCode} for ${req.params.address}`)
|
debug(`Error page requested: ${req.params.errorCode} for ${req.params.address}`)
|
||||||
const count = await mailProcessingService.getCount()
|
const count = await mailProcessingService.getCount()
|
||||||
|
const largestUid = await req.app.locals.imapService.getLargestUid()
|
||||||
|
const totalcount = helper.countElementBuilder(count, largestUid)
|
||||||
const errorCode = parseInt(req.params.errorCode) || 404
|
const errorCode = parseInt(req.params.errorCode) || 404
|
||||||
const message = req.query.message || (req.session && req.session.errorMessage) || 'An error occurred'
|
const message = req.query.message || (req.session && req.session.errorMessage) || 'An error occurred'
|
||||||
|
|
||||||
|
|
@ -26,6 +28,7 @@ router.get('/:address/:errorCode', async(req, res, next) => {
|
||||||
purgeTime: purgeTime,
|
purgeTime: purgeTime,
|
||||||
address: req.params.address,
|
address: req.params.address,
|
||||||
count: count,
|
count: count,
|
||||||
|
totalcount: totalcount,
|
||||||
message: message,
|
message: message,
|
||||||
status: errorCode,
|
status: errorCode,
|
||||||
branding: config.http.branding
|
branding: config.http.branding
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ const helper = new(Helper)
|
||||||
|
|
||||||
const purgeTime = helper.purgeTimeElemetBuilder()
|
const purgeTime = helper.purgeTimeElemetBuilder()
|
||||||
|
|
||||||
|
|
||||||
const sanitizeAddress = param('address').customSanitizer(
|
const sanitizeAddress = param('address').customSanitizer(
|
||||||
(value, { req }) => {
|
(value, { req }) => {
|
||||||
return req.params.address
|
return req.params.address
|
||||||
|
|
@ -25,12 +26,15 @@ router.get('^/:address([^@/]+@[^@/]+)', sanitizeAddress, async(req, res, next) =
|
||||||
}
|
}
|
||||||
debug(`Inbox request for ${req.params.address}`)
|
debug(`Inbox request for ${req.params.address}`)
|
||||||
const count = await mailProcessingService.getCount()
|
const count = await mailProcessingService.getCount()
|
||||||
|
const largestUid = await req.app.locals.imapService.getLargestUid()
|
||||||
|
const totalcount = helper.countElementBuilder(count, largestUid)
|
||||||
debug(`Rendering inbox with ${count} total mails`)
|
debug(`Rendering inbox with ${count} total mails`)
|
||||||
res.render('inbox', {
|
res.render('inbox', {
|
||||||
title: `${config.http.branding[0]} | ` + req.params.address,
|
title: `${config.http.branding[0]} | ` + req.params.address,
|
||||||
purgeTime: purgeTime,
|
purgeTime: purgeTime,
|
||||||
address: req.params.address,
|
address: req.params.address,
|
||||||
count: count,
|
count: count,
|
||||||
|
totalcount: totalcount,
|
||||||
mailSummaries: mailProcessingService.getMailSummaries(req.params.address),
|
mailSummaries: mailProcessingService.getMailSummaries(req.params.address),
|
||||||
branding: config.http.branding,
|
branding: config.http.branding,
|
||||||
})
|
})
|
||||||
|
|
@ -49,6 +53,8 @@ router.get(
|
||||||
const mailProcessingService = req.app.get('mailProcessingService')
|
const mailProcessingService = req.app.get('mailProcessingService')
|
||||||
debug(`Viewing email ${req.params.uid} for ${req.params.address}`)
|
debug(`Viewing email ${req.params.uid} for ${req.params.address}`)
|
||||||
const count = await mailProcessingService.getCount()
|
const count = await mailProcessingService.getCount()
|
||||||
|
const largestUid = await req.app.locals.imapService.getLargestUid()
|
||||||
|
const totalcount = helper.countElementBuilder(count, largestUid)
|
||||||
const mail = await mailProcessingService.getOneFullMail(
|
const mail = await mailProcessingService.getOneFullMail(
|
||||||
req.params.address,
|
req.params.address,
|
||||||
req.params.uid
|
req.params.uid
|
||||||
|
|
@ -67,6 +73,7 @@ router.get(
|
||||||
purgeTime: purgeTime,
|
purgeTime: purgeTime,
|
||||||
address: req.params.address,
|
address: req.params.address,
|
||||||
count: count,
|
count: count,
|
||||||
|
totalcount: totalcount,
|
||||||
mail,
|
mail,
|
||||||
uid: req.params.uid,
|
uid: req.params.uid,
|
||||||
branding: config.http.branding,
|
branding: config.http.branding,
|
||||||
|
|
@ -194,6 +201,8 @@ router.get(
|
||||||
debug(`Fetching raw email ${req.params.uid} for ${req.params.address}`)
|
debug(`Fetching raw email ${req.params.uid} for ${req.params.address}`)
|
||||||
const uid = parseInt(req.params.uid, 10)
|
const uid = parseInt(req.params.uid, 10)
|
||||||
const count = await mailProcessingService.getCount()
|
const count = await mailProcessingService.getCount()
|
||||||
|
const largestUid = await req.app.locals.imapService.getLargestUid()
|
||||||
|
const totalcount = helper.countElementBuilder(count, largestUid)
|
||||||
|
|
||||||
// Validate UID is a valid integer
|
// Validate UID is a valid integer
|
||||||
if (isNaN(uid) || uid <= 0) {
|
if (isNaN(uid) || uid <= 0) {
|
||||||
|
|
@ -214,7 +223,8 @@ router.get(
|
||||||
debug(`Rendering raw email view for UID ${req.params.uid}`)
|
debug(`Rendering raw email view for UID ${req.params.uid}`)
|
||||||
res.render('raw', {
|
res.render('raw', {
|
||||||
title: req.params.uid + " | raw | " + req.params.address,
|
title: req.params.uid + " | raw | " + req.params.address,
|
||||||
mail
|
mail,
|
||||||
|
totalcount: totalcount
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
debug(`Raw email ${uid} not found for ${req.params.address}`)
|
debug(`Raw email ${uid} not found for ${req.params.address}`)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ router.get('/', async(req, res, next) => {
|
||||||
}
|
}
|
||||||
debug('Login page requested')
|
debug('Login page requested')
|
||||||
const count = await mailProcessingService.getCount()
|
const count = await mailProcessingService.getCount()
|
||||||
|
const largestUid = await req.app.locals.imapService.getLargestUid()
|
||||||
|
const totalcount = helper.countElementBuilder(count, largestUid)
|
||||||
debug(`Rendering login page with ${count} total mails`)
|
debug(`Rendering login page with ${count} total mails`)
|
||||||
res.render('login', {
|
res.render('login', {
|
||||||
title: `${config.http.branding[0]} | Your temporary Inbox`,
|
title: `${config.http.branding[0]} | Your temporary Inbox`,
|
||||||
|
|
@ -25,6 +27,7 @@ router.get('/', async(req, res, next) => {
|
||||||
purgeTime: purgeTime,
|
purgeTime: purgeTime,
|
||||||
domains: helper.getDomains(),
|
domains: helper.getDomains(),
|
||||||
count: count,
|
count: count,
|
||||||
|
totalcount: totalcount,
|
||||||
branding: config.http.branding,
|
branding: config.http.branding,
|
||||||
example: config.email.examples.account,
|
example: config.email.examples.account,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
{% block footer %}
|
{% block footer %}
|
||||||
<section class="container footer">
|
<section class="container footer">
|
||||||
<hr>
|
<hr>
|
||||||
<h4>{{ branding[0] }} offered by <a href="{{ branding[2] }}" style="text-decoration:underline" target="_blank">{{ branding[1] }}</a> | All Emails will be deleted after {{ purgeTime | raw }} | Currently handling <u><i>{{ count }}</i></u> Emails</h4>
|
<h4>{{ branding[0] }} offered by <a href="{{ branding[2] }}" style="text-decoration:underline" target="_blank">{{ branding[1] }}</a> | All Emails will be deleted after {{ purgeTime | raw }} | Currently handling {{ totalcount | raw }}</h4>
|
||||||
<h4 class="container footer-two"> This project is <a href="https://github.com/crazyco-xyz/48hr.email" style="text-decoration:underline" target="_blank">open-source ♥</a></h4>
|
<h4 class="container footer-two"> This project is <a href="https://github.com/crazyco-xyz/48hr.email" style="text-decoration:underline" target="_blank">open-source ♥</a></h4>
|
||||||
</section>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue