diff --git a/src/controllers/timer-controllers.js b/src/controllers/timer-controllers.js index f34b258..e242543 100644 --- a/src/controllers/timer-controllers.js +++ b/src/controllers/timer-controllers.js @@ -28,6 +28,7 @@ class TimerControllers { this.backupUsageInterval = 60000 * 10 // 10 minutes this.newSmAccountsInterval = 60000 * 60 // 60 minutes this.updateSmAccountsInterval = 60000 * 10 // 10 minutes + this.removeOlderDeletedChatsAndPostsInterval = 60000 * 60 * 1 // 1 hour // Encapsulate dependencies this.config = config @@ -42,7 +43,7 @@ class TimerControllers { this.backupUsage = this.backupUsage.bind(this) this.newSmAccounts = this.newSmAccounts.bind(this) this.updateSmAccounts = this.updateSmAccounts.bind(this) - + this.removeOlderDeletedChatsAndPosts = this.removeOlderDeletedChatsAndPosts.bind(this) // State this.gcOrdersInt = null this.gcOffersInt = null @@ -50,6 +51,7 @@ class TimerControllers { this.loadOffersInt = null this.newSmAccountsInt = null this.updateSmAccountsInt = null + this.removeOlderDeletedChatsAndPostsInt = null } // Start all the time-based controllers. @@ -62,6 +64,7 @@ class TimerControllers { this.backupUsageHandle = setInterval(this.backupUsage, this.backupUsageInterval) this.newSmAccountsInt = setInterval(this.newSmAccounts, this.newSmAccountsInterval) this.updateSmAccountsInt = setInterval(this.updateSmAccounts, this.updateSmAccountsInterval) + this.removeOlderDeletedChatsAndPostsInt = setInterval(this.removeOlderDeletedChatsAndPosts, this.removeOlderDeletedChatsAndPostsInterval) return true } @@ -74,6 +77,7 @@ class TimerControllers { clearInterval(this.backupUsageHandle) clearInterval(this.newSmAccountsInt) clearInterval(this.updateSmAccountsInt) + clearInterval(this.removeOlderDeletedChatsAndPostsInt) } // Garbage Collect the Orders. @@ -194,6 +198,22 @@ class TimerControllers { return false } } + + // Remove older deleted chats and posts. + async removeOlderDeletedChatsAndPosts () { + try { + //console.log('removeOlderDeletedChatsAndPosts() Timer Controller executing at ', new Date().toLocaleString()) + clearInterval(this.removeOlderDeletedChatsAndPostsInt) + await this.useCases.nostr.removeOlderDeletedChats() + await this.useCases.nostr.removeOlderDeletedPosts() + this.removeOlderDeletedChatsAndPostsInt = setInterval(this.removeOlderDeletedChatsAndPosts, this.removeOlderDeletedChatsAndPostsInterval) + return true + } catch (err) { + console.error('Error in time-controller.js/removeOlderDeletedChatsAndPosts(): ', err) + this.removeOlderDeletedChatsAndPostsInt = setInterval(this.removeOlderDeletedChatsAndPosts, this.removeOlderDeletedChatsAndPostsInterval) + return false + } + } } export default TimerControllers diff --git a/src/use-cases/nostr-use-cases.js b/src/use-cases/nostr-use-cases.js index 3026b76..73fd8ec 100644 --- a/src/use-cases/nostr-use-cases.js +++ b/src/use-cases/nostr-use-cases.js @@ -25,6 +25,8 @@ class NostrUseCases { this.getDeletedChats = this.getDeletedChats.bind(this) this.createDeletedPost = this.createDeletedPost.bind(this) this.getDeletedPosts = this.getDeletedPosts.bind(this) + this.removeOlderDeletedChats = this.removeOlderDeletedChats.bind(this) + this.removeOlderDeletedPosts = this.removeOlderDeletedPosts.bind(this) } // Create a new deleted chat model and add it to the Mongo database. @@ -87,6 +89,42 @@ class NostrUseCases { throw err } } + + // Remove deleted chats that are older than 3 months. + async removeOlderDeletedChats () { + try { + const deletedChats = await this.DeletedChatModel.find({}) + const threeMonthsAgo = new Date() + threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3) + for (let i = 0; i < deletedChats.length; i++) { + const deletedChat = deletedChats[i] + if (deletedChat.createdAt.getTime() < threeMonthsAgo.getTime()) { + await deletedChat.remove() + } + } + } catch (err) { + wlogger.error('Error in lib/users.js/removeOlderDeletedChats()') + throw err + } + } + + // Remove deleted posts that are older than 3 months. + async removeOlderDeletedPosts () { + try { + const deletedPosts = await this.DeletedPostModel.find({}) + const threeMonthsAgo = new Date() + threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3) + for (let i = 0; i < deletedPosts.length; i++) { + const deletedPost = deletedPosts[i] + if (deletedPost.createdAt.getTime() < threeMonthsAgo.getTime()) { + await deletedPost.remove() + } + } + } catch (err) { + wlogger.error('Error in lib/users.js/removeOlderDeletedPosts()') + throw err + } + } } export default NostrUseCases diff --git a/test/unit/controllers/timer-controllers.unit.js b/test/unit/controllers/timer-controllers.unit.js index ca46d99..9bdc3da 100644 --- a/test/unit/controllers/timer-controllers.unit.js +++ b/test/unit/controllers/timer-controllers.unit.js @@ -187,4 +187,20 @@ describe('#Timer-Controllers', () => { assert.equal(result, false) }) }) + describe('#removeOlderDeletedChatsAndPosts', () => { + it('should kick off the Use Cases and return true', async () => { + sandbox.stub(uut.useCases.nostr, 'removeOlderDeletedChats').resolves() + sandbox.stub(uut.useCases.nostr, 'removeOlderDeletedPosts').resolves() + const result = await uut.removeOlderDeletedChatsAndPosts() + + assert.equal(result, true) + }) + }) + it('should kick off the Use Cases and return false on error', async () => { + sandbox.stub(uut.useCases.nostr, 'removeOlderDeletedChats').throws(new Error('test error')) + sandbox.stub(uut.useCases.nostr, 'removeOlderDeletedPosts').throws(new Error('test error')) + const result = await uut.removeOlderDeletedChatsAndPosts() + + assert.equal(result, false) + }) }) diff --git a/test/unit/mocks/use-cases/index.js b/test/unit/mocks/use-cases/index.js index f4dead8..91a088e 100644 --- a/test/unit/mocks/use-cases/index.js +++ b/test/unit/mocks/use-cases/index.js @@ -148,7 +148,12 @@ class NostrUseCasesMock { async getDeletedPosts() { return [] } - + async removeOlderDeletedChats() { + return true + } + async removeOlderDeletedPosts() { + return true + } } class UseCasesMock { diff --git a/test/unit/use-cases/nostr.use-case.unit.js b/test/unit/use-cases/nostr.use-case.unit.js index 5d50099..eaf21e6 100644 --- a/test/unit/use-cases/nostr.use-case.unit.js +++ b/test/unit/use-cases/nostr.use-case.unit.js @@ -210,4 +210,78 @@ describe('#nostr-use-cases', () => { assert.include(err.message, 'test error') } }) + describe('#removeOlderDeletedChats', () => { + it('should remove older deleted chats from the database', async () => { + const threeMonthsAgo = new Date() + threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3) // 3 months ago + threeMonthsAgo.setDate(threeMonthsAgo.getDate() - 1) // 1 day ago + const spy = sinon.spy() + const deletedChatsMock = [ + // Newer deleted chat + { + eventId: 'note19e93faw4ffqepsqsrwrnstd3ee00nmzakwwuyfjm43dankgummfqms4p6q', + createdAt: new Date(), + remove: spy + }, + // Older deleted chat + { + eventId: 'note19e93faw4ffqepsqsrwrnstd3ee00nmzakwwuyfjm43dankgummfqms4p6q', + createdAt: threeMonthsAgo, + remove: spy + } + ] + sandbox.stub(uut.DeletedChatModel, 'find').resolves(deletedChatsMock) + await uut.removeOlderDeletedChats() + assert.equal(spy.callCount, 1, 'Expected to be called once.') + }) + it('should handle error', async () => { + try { + // Force an error. + sandbox.stub(uut.DeletedChatModel, 'find').throws(new Error('test error')) + + await uut.removeOlderDeletedChats() + + assert.fail('Unexpected code path') + } catch (err) { + assert.include(err.message, 'test error') + } + }) + }) + describe('#removeOlderDeletedPosts', () => { + it('should remove older deleted posts from the database', async () => { + const threeMonthsAgo = new Date() + threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3) // 3 months ago + threeMonthsAgo.setDate(threeMonthsAgo.getDate() - 1) // 1 day ago + const spy = sinon.spy() + const deletedPostsMock = [ + // Newer deleted post + { + eventId: 'note19e93faw4ffqepsqsrwrnstd3ee00nmzakwwuyfjm43dankgummfqms4p6q', + createdAt: new Date(), + remove: spy + }, + // Older deleted post + { + eventId: 'note19e93faw4ffqepsqsrwrnstd3ee00nmzakwwuyfjm43dankgummfqms4p6q', + createdAt: threeMonthsAgo, + remove: spy + } + ] + sandbox.stub(uut.DeletedPostModel, 'find').resolves(deletedPostsMock) + await uut.removeOlderDeletedPosts() + assert.equal(spy.callCount, 1, 'Expected to be called once.') + }) + it('should handle error', async () => { + try { + // Force an error. + sandbox.stub(uut.DeletedPostModel, 'find').throws(new Error('test error')) + + await uut.removeOlderDeletedPosts() + + assert.fail('Unexpected code path') + } catch (err) { + assert.include(err.message, 'test error') + } + }) + }) })