From 56199d877f652b8cf2135b9f4d00d24142fba19f Mon Sep 17 00:00:00 2001 From: Sebastian Leidig Date: Wed, 14 Feb 2024 15:59:25 +0100 Subject: [PATCH] get module imports and dependencies aligned so that system starts --- .env | 4 +- src/couchdb/couch-db-client.service.ts | 13 ++-- src/notification/notification.module.ts | 1 + .../core/couchdb-report-changes.service.ts | 13 ++-- .../core/report-changes.service.ts | 1 - src/report-changes/report-changes.module.ts | 13 +++- ...couchdb-changes-repository.service.spec.ts | 33 ++++++++++ .../couchdb-changes-repository.service.ts | 60 +++++++++++++++++++ src/report/controller/report.controller.ts | 3 +- src/report/report.module.ts | 1 + 10 files changed, 125 insertions(+), 17 deletions(-) create mode 100644 src/report-changes/repository/couchdb-changes-repository.service.spec.ts create mode 100644 src/report-changes/repository/couchdb-changes-repository.service.ts diff --git a/.env b/.env index 462418b..5e64c44 100644 --- a/.env +++ b/.env @@ -1,7 +1,9 @@ SENTRY_DSN= PORT= DATABASE_URL=http://127.0.0.1:5984 -DATABASE_ADMIN=admin +DATABASE_USER=admin DATABASE_PASSWORD=admin QUERY_URL=http://127.0.0.1:4984 SCHEMA_CONFIG_ID=_design/sqlite:config +REPORT_DATABASE_URL=http://127.0.0.1:5984 +REPORT_DATABASE_NAME=app \ No newline at end of file diff --git a/src/couchdb/couch-db-client.service.ts b/src/couchdb/couch-db-client.service.ts index 7d1699b..1bb1483 100644 --- a/src/couchdb/couch-db-client.service.ts +++ b/src/couchdb/couch-db-client.service.ts @@ -2,14 +2,13 @@ import { Injectable, Logger } from '@nestjs/common'; import { catchError, map, Observable, of, switchMap } from 'rxjs'; import { HttpService } from '@nestjs/axios'; import { AxiosHeaders } from 'axios'; -import { CouchDbChangesResponse } from "./dtos"; +import { CouchDbChangesResponse } from './dtos'; -@Injectable() +@Injectable({}) export class CouchDbClient { private readonly logger = new Logger(CouchDbClient.name); - constructor(private httpService: HttpService) { - } + constructor(private httpService: HttpService) {} headDatabaseDocument( databaseUrl: string, @@ -121,14 +120,16 @@ export class CouchDbClient { this.logger.debug(err); } - changes( databaseUrl: string, databaseName: string, config?: any, ): Observable { return this.httpService - .get(`${databaseUrl}/${databaseName}/_changes`, config) + .get( + `${databaseUrl}/${databaseName}/_changes`, + config, + ) .pipe( map((response) => { return response.data; diff --git a/src/notification/notification.module.ts b/src/notification/notification.module.ts index 815726c..bafb43b 100644 --- a/src/notification/notification.module.ts +++ b/src/notification/notification.module.ts @@ -3,5 +3,6 @@ import { NotificationService } from './core/notification.service'; @Module({ providers: [NotificationService], + exports: [NotificationService], }) export class NotificationModule {} diff --git a/src/report-changes/core/couchdb-report-changes.service.ts b/src/report-changes/core/couchdb-report-changes.service.ts index 26789e8..43e7f0a 100644 --- a/src/report-changes/core/couchdb-report-changes.service.ts +++ b/src/report-changes/core/couchdb-report-changes.service.ts @@ -4,14 +4,14 @@ import { NotificationService } from '../../notification/core/notification.servic import { Reference } from '../../domain/reference'; import { ReportDataChangeEvent } from '../../domain/report-data-change-event'; import { ReportCalculation } from '../../domain/report-calculation'; -import { CouchDbClient } from '../../couchdb/couch-db-client.service'; import { CouchDbChangeResult, CouchDbChangesResponse, } from '../../couchdb/dtos'; import { Report } from '../../domain/report'; import { ReportChangesService } from './report-changes.service'; -import { ReportStorage } from '../../report/core/report-storage'; +import { CouchdbChangesRepositoryService } from '../repository/couchdb-changes-repository.service'; +import { DefaultReportStorage } from '../../report/storage/report-storage.service'; @Injectable() export class CouchdbReportChangesService implements ReportChangesService { @@ -19,12 +19,11 @@ export class CouchdbReportChangesService implements ReportChangesService { constructor( private notificationService: NotificationService, - private reportStorage: ReportStorage, - private couchDbClient: CouchDbClient, + private reportStorage: DefaultReportStorage, + private couchdbChangesRepository: CouchdbChangesRepositoryService, ) { - // (!) TODO: where to get databaseUrl and databaseName from? Can we centralize this ...? - this.couchDbClient - .changes('TODO', 'app') + this.couchdbChangesRepository + .fetchChanges() .subscribe((changes: CouchDbChangesResponse) => { // TODO: ensure continued fetching until all changes done // TODO: collect a batch of changes for a while before checking? diff --git a/src/report-changes/core/report-changes.service.ts b/src/report-changes/core/report-changes.service.ts index 74916b2..fe04cd1 100644 --- a/src/report-changes/core/report-changes.service.ts +++ b/src/report-changes/core/report-changes.service.ts @@ -1,5 +1,4 @@ /** * Monitor all changes to the application database and check if they affect any report's results. */ - export interface ReportChangesService {} diff --git a/src/report-changes/report-changes.module.ts b/src/report-changes/report-changes.module.ts index c45cc44..c698108 100644 --- a/src/report-changes/report-changes.module.ts +++ b/src/report-changes/report-changes.module.ts @@ -1,7 +1,18 @@ import { Module } from '@nestjs/common'; import { CouchdbReportChangesService } from './core/couchdb-report-changes.service'; +import { CouchdbChangesRepositoryService } from './repository/couchdb-changes-repository.service'; +import { NotificationModule } from '../notification/notification.module'; +import { ReportModule } from '../report/report.module'; +import { CouchDbClient } from '../couchdb/couch-db-client.service'; +import { HttpModule } from '@nestjs/axios'; @Module({ - providers: [CouchdbReportChangesService], + imports: [NotificationModule, ReportModule, HttpModule], + providers: [ + CouchdbReportChangesService, + CouchdbChangesRepositoryService, + CouchDbClient, // TODO: pack this into a CouchDbModule together with HttpModule import etc. + ], + exports: [CouchdbReportChangesService], }) export class ReportChangesModule {} diff --git a/src/report-changes/repository/couchdb-changes-repository.service.spec.ts b/src/report-changes/repository/couchdb-changes-repository.service.spec.ts new file mode 100644 index 0000000..e798329 --- /dev/null +++ b/src/report-changes/repository/couchdb-changes-repository.service.spec.ts @@ -0,0 +1,33 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { CouchdbChangesRepositoryService } from './couchdb-changes-repository.service'; +import { HttpModule } from '@nestjs/axios'; +import { ConfigService } from '@nestjs/config'; + +describe('CouchdbChangesRepositoryService', () => { + let service: CouchdbChangesRepositoryService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + imports: [HttpModule], + providers: [ + CouchdbChangesRepositoryService, + { + provide: ConfigService, + useValue: { + getOrThrow: jest.fn((key) => { + return 'foo'; + }), + }, + }, + ], + }).compile(); + + service = module.get( + CouchdbChangesRepositoryService, + ); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/report-changes/repository/couchdb-changes-repository.service.ts b/src/report-changes/repository/couchdb-changes-repository.service.ts new file mode 100644 index 0000000..3e1fbf9 --- /dev/null +++ b/src/report-changes/repository/couchdb-changes-repository.service.ts @@ -0,0 +1,60 @@ +import { + ForbiddenException, + Injectable, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { catchError, Observable } from 'rxjs'; +import { CouchDbClient } from '../../couchdb/couch-db-client.service'; +import { CouchDbChangesResponse } from '../../couchdb/dtos'; + +@Injectable() +export class CouchdbChangesRepositoryService { + // TODO: centralize this config by refactoring couchdbClient and providing configured clients through DI + // TODO: check if this is the correct db for our changes from app + private dbUrl: string = this.configService.getOrThrow('DATABASE_URL'); + private databaseName: string = 'app'; // TODO: move to config and clean up .env, clarifying different DBs there + private databaseUser: string = this.configService.getOrThrow('DATABASE_USER'); + private databasePassword: string = + this.configService.getOrThrow('DATABASE_PASSWORD'); + + private authHeaderValue: string; + + constructor( + private couchdbClient: CouchDbClient, + private configService: ConfigService, + ) { + const authHeader = Buffer.from( + `${this.databaseUser}:${this.databasePassword}`, + ).toString('base64'); + this.authHeaderValue = `Basic ${authHeader}`; + } + + fetchChanges(): Observable { + return this.couchdbClient + .changes(this.dbUrl, this.databaseName, { + headers: { + Authorization: this.authHeaderValue, + }, + }) + .pipe( + catchError((err, caught) => { + this.handleError(err); + throw caught; + }), + ); + } + + private handleError(err: any) { + if (err.response.status === 401) { + throw new UnauthorizedException(); + } + if (err.response.status === 403) { + throw new ForbiddenException(); + } + if (err.response.status === 404) { + throw new NotFoundException(); + } + } +} diff --git a/src/report/controller/report.controller.ts b/src/report/controller/report.controller.ts index d4eb668..2f8a47d 100644 --- a/src/report/controller/report.controller.ts +++ b/src/report/controller/report.controller.ts @@ -34,8 +34,9 @@ export class ReportController { ): Observable { return this.reportStorage .fetchReport(new Reference(reportId), token) - .pipe(switchMap((report) => this.getReportDto(report))); + .pipe(switchMap((report) => this.getReportDto(report as any))); // TODO: fix for undefined report } + private getReportDto(report: Report): Observable { return this.reportStorage .isCalculationOngoing(new Reference(report.id)) diff --git a/src/report/report.module.ts b/src/report/report.module.ts index 53cc2e0..5a68c0f 100644 --- a/src/report/report.module.ts +++ b/src/report/report.module.ts @@ -22,5 +22,6 @@ import { CouchDbClient } from '../couchdb/couch-db-client.service'; SqsReportCalculator, CouchDbClient, ], + exports: [DefaultReportStorage], }) export class ReportModule {}