feat: rebrand Hemmelig to paste.es for cloudhost.es
- Set Spanish as default language with ephemeral/encrypted privacy focus - Translate all user-facing strings and legal pages to Spanish - Replace Norwegian flag with Spanish flag in footer - Remove Hemmelig/terces.cloud links, add cloudhost.es sponsorship - Rewrite PrivacyPage: zero data collection, ephemeral design emphasis - Rewrite TermsPage: Spanish law, RGPD, paste.es/CloudHost.es references - Update PWA manifest, HTML meta tags, package.json branding - Rename webhook headers to X-Paste-Event / X-Paste-Signature - Update API docs title and contact to paste.es / cloudhost.es Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
67
api/jobs/expired.ts
Normal file
67
api/jobs/expired.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { unlink } from 'fs/promises';
|
||||
import prisma from '../lib/db';
|
||||
|
||||
export const deleteExpiredSecrets = async () => {
|
||||
try {
|
||||
const now = new Date();
|
||||
await prisma.secrets.deleteMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
expiresAt: {
|
||||
lte: now,
|
||||
},
|
||||
},
|
||||
{
|
||||
views: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error deleting expired secrets:', error);
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteOrphanedFiles = async () => {
|
||||
try {
|
||||
// Find files that are not associated with any secret
|
||||
const orphanedFiles = await prisma.file.findMany({
|
||||
where: {
|
||||
secrets: {
|
||||
none: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (orphanedFiles.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete files from disk in parallel for better performance
|
||||
const deleteResults = await Promise.allSettled(
|
||||
orphanedFiles.map((file) => unlink(file.path))
|
||||
);
|
||||
|
||||
// Log any failures (file may already be deleted or inaccessible)
|
||||
deleteResults.forEach((result, index) => {
|
||||
if (result.status === 'rejected') {
|
||||
console.error(
|
||||
`Failed to delete file from disk: ${orphanedFiles[index].path}`,
|
||||
result.reason
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Delete orphaned file records from database
|
||||
await prisma.file.deleteMany({
|
||||
where: {
|
||||
id: {
|
||||
in: orphanedFiles.map((f) => f.id),
|
||||
},
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error deleting orphaned files:', error);
|
||||
}
|
||||
};
|
||||
14
api/jobs/index.ts
Normal file
14
api/jobs/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Cron } from 'croner';
|
||||
import { deleteExpiredSecrets, deleteOrphanedFiles } from './expired';
|
||||
|
||||
// https://crontab.guru
|
||||
export default function startJobs() {
|
||||
// This function can be used to start any other jobs in the future
|
||||
console.log('Job scheduler initialized.');
|
||||
|
||||
// Running every minute
|
||||
new Cron('* * * * *', async () => {
|
||||
await deleteExpiredSecrets();
|
||||
await deleteOrphanedFiles();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user