fixed cron
This commit is contained in:
parent
6e989ff86c
commit
04c49956fe
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,3 +5,6 @@ main.js
|
|||||||
*.log
|
*.log
|
||||||
tls_key.pem
|
tls_key.pem
|
||||||
tls_cert.pem
|
tls_cert.pem
|
||||||
|
.DS_Store
|
||||||
|
._*
|
||||||
|
deploy.sh
|
||||||
37
app.js
37
app.js
@ -10,7 +10,6 @@ const config = require('./src/config/main');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
|
|
||||||
|
|
||||||
const swaggerOptions = {
|
const swaggerOptions = {
|
||||||
definition: {
|
definition: {
|
||||||
openapi: '3.1.0',
|
openapi: '3.1.0',
|
||||||
@ -68,35 +67,13 @@ app.get('/twitter-card.svg', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Schedule cleanup job
|
// Schedule cleanup job
|
||||||
// cron.schedule('*/10 * * * *', async () => {
|
cron.schedule('*/10 * * * *', async () => {
|
||||||
// try {
|
try {
|
||||||
// await MessageService.cleanup();
|
await MessageService.cleanup();
|
||||||
// console.log('Daily cleanup completed');
|
console.log('Daily cleanup completed');
|
||||||
// } catch (error) {
|
} catch (error) {
|
||||||
// console.error('Cleanup failed:', error);
|
console.error('Cleanup failed:', error);
|
||||||
// }
|
}
|
||||||
// });
|
|
||||||
|
|
||||||
|
|
||||||
app.get('/api/stats/total', (req, res) => {
|
|
||||||
// Replace this with your actual database query
|
|
||||||
res.json({
|
|
||||||
emailsCreated: 152847,
|
|
||||||
messagesReceived: 892365
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/api/stats/timeseries', (req, res) => {
|
|
||||||
// Replace this with your actual database query
|
|
||||||
res.json([
|
|
||||||
{ name: 'Mon', emails: 1240, messages: 5430 },
|
|
||||||
{ name: 'Tue', emails: 1580, messages: 6210 },
|
|
||||||
{ name: 'Wed', emails: 1890, messages: 7840 },
|
|
||||||
{ name: 'Thu', emails: 2090, messages: 8120 },
|
|
||||||
{ name: 'Fri', emails: 1870, messages: 6980 },
|
|
||||||
{ name: 'Sat', emails: 1450, messages: 5640 },
|
|
||||||
{ name: 'Sun', emails: 1320, messages: 4980 }
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(express.static(path.join(__dirname, 'client/build')));
|
app.use(express.static(path.join(__dirname, 'client/build')));
|
||||||
|
|||||||
164
src/db/seeds/test_cleanup.js
Normal file
164
src/db/seeds/test_cleanup.js
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
const { mysqlSafeTimestamp, generateUniqueName } = require('../../utils/functions');
|
||||||
|
const MessageService = require('../../email_server/services/MessageService');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param { import("knex").Knex } knex
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
|
exports.seed = async function(knex) {
|
||||||
|
try {
|
||||||
|
console.log('Starting cleanup test seeder...');
|
||||||
|
|
||||||
|
// Clean up existing test data first
|
||||||
|
await knex('messages').where('created_at', '<', mysqlSafeTimestamp()).delete();
|
||||||
|
await knex('temp_emails').where('created_at', '<', mysqlSafeTimestamp()).delete();
|
||||||
|
|
||||||
|
// Create or get test user
|
||||||
|
await knex('users')
|
||||||
|
.insert({
|
||||||
|
email: 'test@cleanup.com',
|
||||||
|
password: '$2b$10$abcdefghijklmnopqrstuvwxyz12345',
|
||||||
|
is_admin: false
|
||||||
|
})
|
||||||
|
.onConflict('email')
|
||||||
|
.merge();
|
||||||
|
|
||||||
|
const testUser = await knex('users')
|
||||||
|
.where('email', 'test@cleanup.com')
|
||||||
|
.first();
|
||||||
|
|
||||||
|
// Get a domain for test emails
|
||||||
|
const domain = await knex('domains').where('active', true).first();
|
||||||
|
if (!domain) throw new Error('No active domains found');
|
||||||
|
|
||||||
|
// Create temp emails that should be cleaned up (already expired)
|
||||||
|
const tempEmails = [];
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
// Created 15 days ago, expired yesterday
|
||||||
|
const createdAt = mysqlSafeTimestamp(false, -15);
|
||||||
|
const expiresAt = mysqlSafeTimestamp(false, -1); // Set to yesterday
|
||||||
|
|
||||||
|
console.log(`Creating expired email with created_at: ${createdAt}, expires_at: ${expiresAt}`);
|
||||||
|
|
||||||
|
const email = `${generateUniqueName()}@${domain.name}`;
|
||||||
|
await knex('temp_emails')
|
||||||
|
.insert({
|
||||||
|
email: email,
|
||||||
|
user_id: testUser.id,
|
||||||
|
expires_at: expiresAt,
|
||||||
|
created_at: createdAt,
|
||||||
|
updated_at: createdAt
|
||||||
|
});
|
||||||
|
|
||||||
|
const tempEmail = await knex('temp_emails')
|
||||||
|
.where('email', email)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
tempEmails.push(tempEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create messages for expired emails
|
||||||
|
for (const tempEmail of tempEmails) {
|
||||||
|
const messageCount = Math.floor(Math.random() * 3) + 1;
|
||||||
|
for (let i = 0; i < messageCount; i++) {
|
||||||
|
const messageDate = mysqlSafeTimestamp(false, -15);
|
||||||
|
await knex('messages').insert({
|
||||||
|
temp_email_id: tempEmail.id,
|
||||||
|
from: 'sender@example.com',
|
||||||
|
to: tempEmail.email,
|
||||||
|
subject: 'Old Test Message',
|
||||||
|
body: 'This is an old test message that should be cleaned up.',
|
||||||
|
headers: JSON.stringify({
|
||||||
|
'message-id': `<test-${Date.now()}@example.com>`,
|
||||||
|
'date': new Date().toISOString()
|
||||||
|
}),
|
||||||
|
created_at: messageDate,
|
||||||
|
updated_at: messageDate,
|
||||||
|
received_at: messageDate
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create control group - emails that should NOT be cleaned up
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
const createdAt = mysqlSafeTimestamp(false, -7); // 7 days ago
|
||||||
|
const expiresAt = mysqlSafeTimestamp(false, 7); // expires in 7 days
|
||||||
|
|
||||||
|
console.log(`Creating active email with created_at: ${createdAt}, expires_at: ${expiresAt}`);
|
||||||
|
|
||||||
|
const email = `${generateUniqueName()}@${domain.name}`;
|
||||||
|
await knex('temp_emails')
|
||||||
|
.insert({
|
||||||
|
email: email,
|
||||||
|
user_id: testUser.id,
|
||||||
|
expires_at: expiresAt,
|
||||||
|
created_at: createdAt,
|
||||||
|
updated_at: createdAt
|
||||||
|
});
|
||||||
|
|
||||||
|
const tempEmail = await knex('temp_emails')
|
||||||
|
.where('email', email)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
// Create recent messages
|
||||||
|
const messageCount = Math.floor(Math.random() * 2) + 1;
|
||||||
|
for (let j = 0; j < messageCount; j++) {
|
||||||
|
await knex('messages').insert({
|
||||||
|
temp_email_id: tempEmail.id,
|
||||||
|
from: 'sender@example.com',
|
||||||
|
to: tempEmail.email,
|
||||||
|
subject: 'Recent Test Message',
|
||||||
|
body: 'This is a recent test message that should NOT be cleaned up.',
|
||||||
|
headers: JSON.stringify({
|
||||||
|
'message-id': `<test-${Date.now()}@example.com>`,
|
||||||
|
'date': new Date().toISOString()
|
||||||
|
}),
|
||||||
|
created_at: mysqlSafeTimestamp(false, -7),
|
||||||
|
updated_at: mysqlSafeTimestamp(false, -7),
|
||||||
|
received_at: mysqlSafeTimestamp(false, -7)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query and display all temp emails
|
||||||
|
const emailDebug = await knex('temp_emails')
|
||||||
|
.select('id', 'email', 'created_at', 'expires_at')
|
||||||
|
.orderBy('created_at');
|
||||||
|
|
||||||
|
console.log('\nCurrent temp_emails in database:');
|
||||||
|
emailDebug.forEach(email => {
|
||||||
|
console.log(`ID: ${email.id}, Email: ${email.email}`);
|
||||||
|
console.log(`Created: ${email.created_at}, Expires: ${email.expires_at}\n`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Log counts and run cleanup
|
||||||
|
const beforeCounts = await getRecordCounts(knex);
|
||||||
|
console.log('\nBefore cleanup:', beforeCounts);
|
||||||
|
|
||||||
|
const cleanupResults = await MessageService.cleanup();
|
||||||
|
console.log('Cleanup results:', cleanupResults);
|
||||||
|
|
||||||
|
const afterCounts = await getRecordCounts(knex);
|
||||||
|
console.log('After cleanup:', afterCounts);
|
||||||
|
console.log('Records cleaned up:', {
|
||||||
|
tempEmails: beforeCounts.tempEmails - afterCounts.tempEmails,
|
||||||
|
messages: beforeCounts.messages - afterCounts.messages
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Seeder failed:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function getRecordCounts(knex) {
|
||||||
|
const [tempEmails, messages] = await Promise.all([
|
||||||
|
knex('temp_emails').count('* as count').first(),
|
||||||
|
knex('messages').count('* as count').first()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
tempEmails: parseInt(tempEmails.count),
|
||||||
|
messages: parseInt(messages.count)
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@ const Knex = require("knex");
|
|||||||
const knexConfig = require("../../config/database");
|
const knexConfig = require("../../config/database");
|
||||||
const knex = Knex(knexConfig.development);
|
const knex = Knex(knexConfig.development);
|
||||||
Model.knex(knex);
|
Model.knex(knex);
|
||||||
|
const { mysqlTimestampCompare, mysqlSafeTimestamp } = require("../../utils/functions");
|
||||||
|
|
||||||
class MessageService {
|
class MessageService {
|
||||||
static async isValidDomain(email) {
|
static async isValidDomain(email) {
|
||||||
@ -46,39 +47,52 @@ class MessageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async cleanup() {
|
static async cleanup() {
|
||||||
const now = new Date().toISOString();
|
const now = mysqlSafeTimestamp();
|
||||||
const cutoffDate = new Date();
|
console.log('Current time:', now);
|
||||||
cutoffDate.setDate(cutoffDate.getDate() - config.storage.retention);
|
|
||||||
|
|
||||||
|
// Find all expired temp emails
|
||||||
const expiredEmails = await TempEmail.query()
|
const expiredEmails = await TempEmail.query()
|
||||||
.where("expires_at", "<", now)
|
.select('id', 'created_at', 'expires_at')
|
||||||
.select("id");
|
.where('expires_at', '<', now);
|
||||||
|
|
||||||
const expiredEmailIds = expiredEmails.map((email) => email.id);
|
console.log('Found expired emails:', expiredEmails.length);
|
||||||
|
console.log('Expired emails:', expiredEmails);
|
||||||
|
|
||||||
if (expiredEmailIds.length > 0) {
|
if (expiredEmails.length > 0) {
|
||||||
console.log("Deleting messages for expired emails");
|
// Delete associated messages first
|
||||||
const deletedMessages = await Message.query()
|
const deletedMessages = await Message.query()
|
||||||
.whereIn("temp_email_id", expiredEmailIds)
|
.whereIn('temp_email_id', expiredEmails.map(email => email.id))
|
||||||
.delete();
|
.delete();
|
||||||
|
console.log('Deleted associated messages:', deletedMessages);
|
||||||
|
|
||||||
console.log("Deleting expired temp emails");
|
// Delete the expired temp emails
|
||||||
const deletedTempEmails = await TempEmail.query()
|
const deletedTempEmails = await TempEmail.query()
|
||||||
.whereIn("id", expiredEmailIds)
|
.whereIn('id', expiredEmails.map(email => email.id))
|
||||||
.delete();
|
.delete();
|
||||||
|
console.log('Deleted expired emails:', deletedTempEmails);
|
||||||
|
|
||||||
|
// Delete old messages (using created_at)
|
||||||
|
const cutoffDate = mysqlSafeTimestamp(false, -14); // 14 days ago
|
||||||
const expiredMessages = await Message.query()
|
const expiredMessages = await Message.query()
|
||||||
.where("created_at", "<", cutoffDate)
|
.where('created_at', '<', cutoffDate)
|
||||||
.delete();
|
.delete();
|
||||||
|
console.log('Deleted old messages:', expiredMessages);
|
||||||
|
|
||||||
console.log("Deleted messages:", deletedMessages + expiredMessages);
|
return {
|
||||||
console.log("Deleted emails:", deletedTempEmails);
|
deletedMessages: deletedMessages + expiredMessages,
|
||||||
return { deletedMessages, deletedTempEmails };
|
deletedTempEmails,
|
||||||
|
expiredEmailsFound: expiredEmails.length
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return { deletedMessages: 0, deletedTempEmails: 0 };
|
return {
|
||||||
|
deletedMessages: 0,
|
||||||
|
deletedTempEmails: 0,
|
||||||
|
expiredEmailsFound: 0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static async search(params) {
|
static async search(params) {
|
||||||
let query = Message.query()
|
let query = Message.query()
|
||||||
.joinRelated("temp_email")
|
.joinRelated("temp_email")
|
||||||
|
|||||||
@ -158,7 +158,7 @@ router.post('/generate', async (req, res) => {
|
|||||||
const tempEmail = await TempEmail.query().insert({
|
const tempEmail = await TempEmail.query().insert({
|
||||||
email: randomDomainName,
|
email: randomDomainName,
|
||||||
user_id: req.user.id,
|
user_id: req.user.id,
|
||||||
expires_at: mysqlSafeTimestamp(14)
|
expires_at: mysqlSafeTimestamp(false, 14)
|
||||||
});
|
});
|
||||||
|
|
||||||
await DailyStats.incrementEmailCount();
|
await DailyStats.incrementEmailCount();
|
||||||
|
|||||||
@ -2,23 +2,63 @@ const { uniqueNamesGenerator, adjectives, animals, colors, names, languages, sta
|
|||||||
const Domain = require('../db/models/Domain');
|
const Domain = require('../db/models/Domain');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
|
* @param {boolean} dateOnly - If true, return the date only
|
||||||
* @param {number} days - Number of days to add to the current date
|
* @param {number} days - Number of days to add to the current date
|
||||||
* @returns {string} - MySQL safe timestamp
|
* @returns {string} - MySQL safe timestamp
|
||||||
*/
|
*/
|
||||||
function mysqlSafeTimestamp(dateOnly = false, days) {
|
function mysqlSafeTimestamp(dateOnly = false, days = 0) {
|
||||||
if (dateOnly && days) {
|
const date = new Date();
|
||||||
return new Date(new Date().setDate(new Date().getDate() + days)).toISOString().split('T')[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (days) {
|
if (days) {
|
||||||
return new Date(new Date().setDate(new Date().getDate() + days)).toISOString().replace('T', ' ').replace(/\.\d{3}Z$/, '');
|
date.setDate(date.getDate() + days);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dateOnly) {
|
if (dateOnly) {
|
||||||
return new Date().toISOString().split('T')[0];
|
// Return YYYY-MM-DD format
|
||||||
|
return date.toISOString().split('T')[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Date().toISOString().replace('T', ' ').replace(/\.\d{3}Z$/, '');
|
// Return YYYY-MM-DD HH:mm:ss format
|
||||||
|
return date.toISOString()
|
||||||
|
.replace('T', ' ')
|
||||||
|
.replace(/\.\d{3}Z$/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} created_at - The created_at timestamp
|
||||||
|
* @param {string} expires_at - The expires_at timestamp
|
||||||
|
* @returns {boolean} - True if the expires_at is today and the difference between created_at and expires_at is 14 days
|
||||||
|
*/
|
||||||
|
function mysqlTimestampCompare(created_at, expires_at) {
|
||||||
|
if (!created_at || !expires_at) return false;
|
||||||
|
|
||||||
|
const parseDate = (mysqlDateTime) => {
|
||||||
|
if (mysqlDateTime instanceof Date) return mysqlDateTime;
|
||||||
|
if (typeof mysqlDateTime === 'string') {
|
||||||
|
// Handle MySQL datetime format: YYYY-MM-DD HH:mm:ss
|
||||||
|
const [datePart, timePart] = mysqlDateTime.split(' ');
|
||||||
|
return new Date(`${datePart}T${timePart}.000Z`);
|
||||||
|
}
|
||||||
|
return new Date(mysqlDateTime);
|
||||||
|
};
|
||||||
|
|
||||||
|
const createdDate = parseDate(created_at);
|
||||||
|
const expiresDate = parseDate(expires_at);
|
||||||
|
const today = new Date();
|
||||||
|
|
||||||
|
// Check if expires_at is today
|
||||||
|
const isExpiresToday = (
|
||||||
|
expiresDate.getFullYear() === today.getFullYear() &&
|
||||||
|
expiresDate.getMonth() === today.getMonth() &&
|
||||||
|
expiresDate.getDate() === today.getDate()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Calculate days difference
|
||||||
|
const diffTime = expiresDate - createdDate;
|
||||||
|
const diffDays = diffTime / (1000 * 60 * 60 * 24);
|
||||||
|
|
||||||
|
return isExpiresToday && Math.floor(diffDays) === 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateUniqueName() {
|
function generateUniqueName() {
|
||||||
@ -70,5 +110,6 @@ async function getRandomDomain(safeTLD = false) {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
mysqlSafeTimestamp,
|
mysqlSafeTimestamp,
|
||||||
generateUniqueName,
|
generateUniqueName,
|
||||||
getRandomDomain
|
getRandomDomain,
|
||||||
|
mysqlTimestampCompare
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user