diff --git a/backend/package.json b/backend/package.json index 2eb5884..4a9af59 100644 --- a/backend/package.json +++ b/backend/package.json @@ -28,6 +28,7 @@ "@nestjs/jwt": "^10.2.0", "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", + "@nestjs/schedule": "^4.0.2", "bcrypt": "^5.1.1", "drizzle-orm": "^0.30.9", "passport": "^0.7.0", diff --git a/backend/pnpm-lock.yaml b/backend/pnpm-lock.yaml index 122c50e..4f5bda4 100644 --- a/backend/pnpm-lock.yaml +++ b/backend/pnpm-lock.yaml @@ -20,6 +20,9 @@ dependencies: '@nestjs/platform-express': specifier: ^10.0.0 version: 10.3.8(@nestjs/common@10.3.8)(@nestjs/core@10.3.8) + '@nestjs/schedule': + specifier: ^4.0.2 + version: 4.0.2(@nestjs/common@10.3.8)(@nestjs/core@10.3.8) bcrypt: specifier: ^5.1.1 version: 5.1.1 @@ -1452,6 +1455,18 @@ packages: transitivePeerDependencies: - supports-color + /@nestjs/schedule@4.0.2(@nestjs/common@10.3.8)(@nestjs/core@10.3.8): + resolution: {integrity: sha512-po9oauE7fO0CjhDKvVC2tzEgjOUwhxYoIsXIVkgfu+xaDMmzzpmXY2s1LT4oP90Z+PaTtPoAHmhslnYmo4mSZg==} + peerDependencies: + '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 + '@nestjs/core': ^8.0.0 || ^9.0.0 || ^10.0.0 + dependencies: + '@nestjs/common': 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.3.8(@nestjs/common@10.3.8)(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1) + cron: 3.1.7 + uuid: 9.0.1 + dev: false + /@nestjs/schematics@10.1.1(chokidar@3.6.0)(typescript@5.3.3): resolution: {integrity: sha512-o4lfCnEeIkfJhGBbLZxTuVWcGuqDCFwg5OrvpgRUBM7vI/vONvKKiB5riVNpO+JqXoH0I42NNeDb0m4V5RREig==} peerDependencies: @@ -1707,6 +1722,10 @@ packages: dependencies: '@types/node': 20.12.7 + /@types/luxon@3.4.2: + resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==} + dev: false + /@types/methods@1.1.4: resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} dev: true @@ -2740,6 +2759,13 @@ packages: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} dev: true + /cron@3.1.7: + resolution: {integrity: sha512-tlBg7ARsAMQLzgwqVxy8AZl/qlTc5nibqYwtNGoCrd+cV+ugI+tvZC1oT/8dFH8W455YrywGykx/KMmAqOr7Jw==} + dependencies: + '@types/luxon': 3.4.2 + luxon: 3.4.4 + dev: false + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -4774,6 +4800,11 @@ packages: es5-ext: 0.10.64 dev: true + /luxon@3.4.4: + resolution: {integrity: sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==} + engines: {node: '>=12'} + dev: false + /magic-string@0.30.5: resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} engines: {node: '>=12'} @@ -6258,6 +6289,11 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} + /uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + dev: false + /v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} dev: true diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index 50ad833..75054d9 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -6,9 +6,11 @@ import { AuthController } from './auth/auth.controller'; import { APP_GUARD } from '@nestjs/core'; import { JwtAuthGuard } from './auth/jwt-auth.guard'; import { TaskGroupController } from './task-group.controller'; +import { ScheduleModule } from '@nestjs/schedule'; +import { AssignmentsModule } from './assignment.module'; @Module({ - imports: [AuthModule], + imports: [AuthModule, ScheduleModule.forRoot(), AssignmentsModule], controllers: [ TasksController, AssignmentController, diff --git a/backend/src/assignment-scheduler.service.ts b/backend/src/assignment-scheduler.service.ts new file mode 100644 index 0000000..8821415 --- /dev/null +++ b/backend/src/assignment-scheduler.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@nestjs/common'; +import { Cron, CronExpression } from '@nestjs/schedule'; +import { + dbGetTaskGroupUsers, + dbGetTaskGroupsToCreateForCurrentInterval, +} from './db/functions/task-group'; +import { dbGetAssignmentsForTaskGroup } from './db/functions/assignment-task-group'; + +@Injectable() +export class AssignmentSchedulerService { + @Cron(CronExpression.EVERY_5_SECONDS) + async handleCron() { + const taskGroupsToCreateAssignmentsFor = + await dbGetTaskGroupsToCreateForCurrentInterval(); + for (const { taskGroupId } of taskGroupsToCreateAssignmentsFor) { + const users = await dbGetTaskGroupUsers(taskGroupId); + const assignments = await dbGetAssignmentsForTaskGroup( + taskGroupId, + users.length, + ); + console.log({ assignments }); + } + } +} diff --git a/backend/src/assignment.module.ts b/backend/src/assignment.module.ts new file mode 100644 index 0000000..3889c3f --- /dev/null +++ b/backend/src/assignment.module.ts @@ -0,0 +1,7 @@ +import { Module } from '@nestjs/common'; +import { AssignmentSchedulerService } from './assignment-scheduler.service'; + +@Module({ + providers: [AssignmentSchedulerService], +}) +export class AssignmentsModule {} diff --git a/backend/src/db/functions/assignment-task-group.ts b/backend/src/db/functions/assignment-task-group.ts new file mode 100644 index 0000000..94d18ff --- /dev/null +++ b/backend/src/db/functions/assignment-task-group.ts @@ -0,0 +1,18 @@ +import { desc, eq } from 'drizzle-orm'; +import { db } from '..'; +import { taskGroupAssignmentTable } from '../schema'; + +export async function dbGetAssignmentsForTaskGroup( + taskGroupId: number, + limit?: number, +) { + const result = db + .select() + .from(taskGroupAssignmentTable) + .where(eq(taskGroupAssignmentTable.taskGroupId, taskGroupId)) + .orderBy(desc(taskGroupAssignmentTable.createdAt)); + if (limit === undefined) { + return await result; + } + return await result.limit(limit); +} diff --git a/backend/src/db/functions/task-group.ts b/backend/src/db/functions/task-group.ts index 04bf395..c31c4a6 100644 --- a/backend/src/db/functions/task-group.ts +++ b/backend/src/db/functions/task-group.ts @@ -55,10 +55,10 @@ export async function dbGetTaskGroupsToCreateForCurrentInterval() { taskGroupAssignmentTable, eq(taskGroupTable.id, taskGroupAssignmentTable.taskGroupId), ) - .groupBy(taskGroupTable.id) - .having( - sql` MAX(${taskGroupAssignmentTable.createdAt}) < (NOW() - ${taskGroupTable.interval})`, - ); + .groupBy(taskGroupTable.id); + // .having( + // sql`MAX(${taskGroupAssignmentTable.createdAt}) < (NOW() - ${taskGroupTable.interval})`, + // ); return taskGroupIdsToCreateAssignmentsFor; } catch (error) { console.error({ error });