diff --git a/listify-api/package-lock.json b/listify-api/package-lock.json index ff1f66b..316496b 100644 --- a/listify-api/package-lock.json +++ b/listify-api/package-lock.json @@ -17,6 +17,7 @@ "@nestjs/event-emitter": "^3.1.0", "@nestjs/jwt": "^11.0.2", "@nestjs/platform-express": "^11.0.1", + "@nestjs/schedule": "^6.1.3", "@nestjs/typeorm": "^11.0.1", "@types/web-push": "^3.6.4", "handlebars": "^4.7.9", @@ -2853,6 +2854,19 @@ "@nestjs/core": "^11.0.0" } }, + "node_modules/@nestjs/schedule": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-6.1.3.tgz", + "integrity": "sha512-RflMFOpR16Dwd1jAUbeB4mfGTCh65fvEdL4mSjQPJChpkRGRjIXjb+6YQcK2faQrVT60c9DmLmoVR7/ONCtuYQ==", + "license": "MIT", + "dependencies": { + "cron": "4.4.0" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "@nestjs/core": "^10.0.0 || ^11.0.0" + } + }, "node_modules/@nestjs/schematics": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-11.1.0.tgz", @@ -3294,6 +3308,12 @@ "@types/node": "*" } }, + "node_modules/@types/luxon": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.7.2.tgz", + "integrity": "sha512-gW+Oib+vUtGJBtNC8V9Reww0oIpusw+4m81uncg9REGZAJfqOQHfo/nkabnc7w0QReXyPqjrbWMJk6NuAkiX3Q==", + "license": "MIT" + }, "node_modules/@types/methods": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", @@ -5569,6 +5589,23 @@ "devOptional": true, "license": "MIT" }, + "node_modules/cron": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cron/-/cron-4.4.0.tgz", + "integrity": "sha512-fkdfq+b+AHI4cKdhZlppHveI/mgz2qpiYxcm+t5E5TsxX7QrLS1VE0+7GENEk9z0EeGPcpSciGv6ez24duWhwQ==", + "license": "MIT", + "dependencies": { + "@types/luxon": "~3.7.0", + "luxon": "~3.7.0" + }, + "engines": { + "node": ">=18.x" + }, + "funding": { + "type": "ko-fi", + "url": "https://ko-fi.com/intcreator" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -9611,6 +9648,15 @@ "url": "https://github.com/sponsors/wellwelwel" } }, + "node_modules/luxon": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", + "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", diff --git a/listify-api/package.json b/listify-api/package.json index 3f8f0f2..5b164d0 100644 --- a/listify-api/package.json +++ b/listify-api/package.json @@ -32,6 +32,7 @@ "@nestjs/event-emitter": "^3.1.0", "@nestjs/jwt": "^11.0.2", "@nestjs/platform-express": "^11.0.1", + "@nestjs/schedule": "^6.1.3", "@nestjs/typeorm": "^11.0.1", "@types/web-push": "^3.6.4", "handlebars": "^4.7.9", diff --git a/listify-api/src/app.module.ts b/listify-api/src/app.module.ts index 4457d5e..0c55c41 100644 --- a/listify-api/src/app.module.ts +++ b/listify-api/src/app.module.ts @@ -12,6 +12,7 @@ import { ListTemplatesModule } from './list-templates/list-templates.module'; import { ListsModule } from './lists/lists.module'; import { MailModule } from './mail/mail.module'; import { McpModule } from './mcp/mcp.module'; +import { NotificationsModule } from './notifications/notifications.module'; import { TasksModule } from './tasks/tasks.module'; import { databaseLoggerOptionsFromEnv, @@ -66,6 +67,7 @@ import { DatabaseLogger } from './database/database.logger'; ListsModule, ListTemplatesModule, TasksModule, + NotificationsModule, McpModule, ], controllers: [AppController], diff --git a/listify-api/src/lists/list-reminder.service.ts b/listify-api/src/lists/list-reminder.service.ts index 5ec305d..6ec51c8 100644 --- a/listify-api/src/lists/list-reminder.service.ts +++ b/listify-api/src/lists/list-reminder.service.ts @@ -1,9 +1,4 @@ -import { - Injectable, - Logger, - OnModuleDestroy, - OnModuleInit, -} from '@nestjs/common'; +import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { InjectRepository } from '@nestjs/typeorm'; import { IsNull, LessThanOrEqual, Repository } from 'typeorm'; @@ -12,9 +7,8 @@ import { UserListEntity } from './user-list.entity'; import { ListsService } from './lists.service'; @Injectable() -export class ListReminderService implements OnModuleInit, OnModuleDestroy { +export class ListReminderService { private readonly logger = new Logger(ListReminderService.name); - private timer?: NodeJS.Timeout; private processing = false; constructor( @@ -25,29 +19,6 @@ export class ListReminderService implements OnModuleInit, OnModuleDestroy { private readonly listsService: ListsService, ) {} - onModuleInit(): void { - if (process.env.NODE_ENV === 'test') { - return; - } - - const intervalMs = Number( - this.configService.get('LIST_REMINDER_POLL_INTERVAL_MS', '60000'), - ); - - this.timer = setInterval( - () => void this.processDueReminders(), - Number.isFinite(intervalMs) && intervalMs > 0 ? intervalMs : 60000, - ); - void this.processDueReminders(); - } - - onModuleDestroy(): void { - if (this.timer) { - clearInterval(this.timer); - this.timer = undefined; - } - } - async processDueReminders(now = new Date()): Promise { if (this.processing) { return; diff --git a/listify-api/src/lists/lists.module.ts b/listify-api/src/lists/lists.module.ts index d848f2a..0b5175b 100644 --- a/listify-api/src/lists/lists.module.ts +++ b/listify-api/src/lists/lists.module.ts @@ -30,6 +30,6 @@ import { UserListShareEntity } from './user-list-share.entity'; ], controllers: [ListsController], providers: [ListRealtimeService, ListReminderService, ListsService], - exports: [ListRealtimeService, ListsService], + exports: [ListRealtimeService, ListReminderService, ListsService], }) export class ListsModule {} diff --git a/listify-api/src/mail/mail.service.ts b/listify-api/src/mail/mail.service.ts index de4868d..5014db8 100644 --- a/listify-api/src/mail/mail.service.ts +++ b/listify-api/src/mail/mail.service.ts @@ -191,8 +191,8 @@ export class MailService { displayName: payload.displayName, slotLabel: payload.slot === 'morning' - ? 'Morgenuebersicht' - : 'Nachmittagsuebersicht', + ? 'Morgenübersicht' + : 'Nachmittagsübersicht', dateLabel: this.formatDay(payload.date), tasksUrl: payload.tasksUrl, todayTasks: payload.todayTasks, diff --git a/listify-api/src/mail/templates/list-reminder.hbs b/listify-api/src/mail/templates/list-reminder.hbs index 7501344..b5abca9 100644 --- a/listify-api/src/mail/templates/list-reminder.hbs +++ b/listify-api/src/mail/templates/list-reminder.hbs @@ -13,7 +13,7 @@
{{appName}}
-

Erinnerung fuer {{listName}}

+

Erinnerung für {{listName}}

@@ -37,7 +37,7 @@ - Liste oeffnen + Liste öffnen diff --git a/listify-api/src/mail/templates/task-digest.hbs b/listify-api/src/mail/templates/task-digest.hbs index 03f9e90..696a7f9 100644 --- a/listify-api/src/mail/templates/task-digest.hbs +++ b/listify-api/src/mail/templates/task-digest.hbs @@ -13,23 +13,23 @@
{{appName}}
-

{{slotLabel}} fuer deine Tasks

+

{{slotLabel}} für deine Tasks

- {{#if displayName}}Hallo {{displayName}}, {{/if}}du hast {{taskCount}} offene Tasks fuer {{dateLabel}} oder frueher. + {{#if displayName}}Hallo {{displayName}}, {{/if}}du hast {{taskCount}} offene Tasks für {{dateLabel}} oder früher.

{{#if overdueTaskCount}} -

Ueberfaellig

+

Überfällig