Skip to content

Commit

Permalink
Merge pull request #73 from amosproj/dev
Browse files Browse the repository at this point in the history
Merge Dev into main
  • Loading branch information
engelharddirk authored Nov 20, 2024
2 parents 3508613 + ab2c021 commit e2b3ed5
Show file tree
Hide file tree
Showing 21 changed files with 3,868 additions and 734 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,8 @@ apps/*/.env
.angular

.cache/*

# Test results
apps/analyzer/.coverage
reports/*
coverage/*
18 changes: 15 additions & 3 deletions Documentation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ cd ./apps/analyzer/metadata_analyzer ; poetry install

- `npm ci`: dependency install

- copy `.env.example` file in backend and rename to `.env` (adjust database properties according to database setup if necessary)
- copy `.env.example` file in analyzer and rename to `.env` (adjust port properties according to backend setup if necessary)
- copy `.env.example` file in backend and rename to `.env` (adjust database properties according to database setup if
necessary)
- copy `.env.example` file in analyzer and rename to `.env` (adjust port properties according to backend setup if
necessary)
- To insert dummy data into table backupData you can use the SQL script `dummyData.sql` in `apps/backend/src/app/utils`

### Running the code locally:
Expand All @@ -27,10 +29,20 @@ cd ./apps/analyzer/metadata_analyzer ; poetry install
- the entity files need to be annotated with `@Entity(<table-name>)`
- append the entity file to the `entities` array in `db-config.service.ts`
- run the following command to generate a migration file:
- `nx run metadata-analyzer-backend:migrations:generate --name <migration-name>`
- `nx run metadata-analyzer-backend:migrations:generate --name <migration-name>`
- append the generated file to the `migrations` array in `db-config.service.ts`

### Running tests

- backend: `nx run metadata-analyzer-backend:test`
- frontend: `nx run metadata-analyzer-frontend:test`
- python: `nx run metadata-analyzer:test`

### Mailing

Fill the `.env` file with the mailing information
Hint: For gmail you have to generate an app password, which you have to use as password in the `.env` file
For changes in templates being used, you have to restart the backend

## Installing new dependencies

Expand Down
9 changes: 8 additions & 1 deletion apps/backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,11 @@ DATABASE_PORT=5433
DATABASE_USER="postgres"
DATABASE_PASSWORD="postgres"
DATABASE_DATABASE="postgres"
ANALYZER_URL="http://localhost:8000"
ANALYZER_URL="http://localhost:8000"
#Mailing
MAIL_HOST=smtp.example.com
MAIL_PORT=465
MAIL_USER=[email protected]
MAIL_PASSWORD=topsecret
MAIL_FROM=[email protected]
MAILING_LIST=[email protected],[email protected]
11 changes: 10 additions & 1 deletion apps/backend/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@
"main": "apps/backend/src/main.ts",
"outputPath": "dist/apps/backend",
"tsConfig": "apps/backend/tsconfig.app.json",
"assets": [],
"assets": [
"**/*.hbs"
],
"platform": "node",
"additionalEntryPoints": [
"{projectRoot}/src/migrations.main.ts"
Expand Down Expand Up @@ -81,6 +83,13 @@
"command": "npx typeorm-ts-node-esm -d dist/apps/backend/migrations.main.js migration:revert"
}
}
},
"test": {
"executor": "@nrwl/jest:jest",
"options": {
"jestConfig": "apps/backend/jest.config.ts",
"passWithNoTests": false
}
}
}
}
22 changes: 22 additions & 0 deletions apps/backend/src/app/alerting/alerting.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Body, Controller, Logger, Post } from '@nestjs/common';
import { ApiOperation } from '@nestjs/swagger';
import { AlertingService } from './alerting.service';
import { AlertingInformationDto } from './dto/alertingInformationDto';

@Controller('alerting')
export class AlertingController {
readonly logger = new Logger(AlertingController.name);

constructor(private readonly alertingService: AlertingService) {}

@Post()
@ApiOperation({ summary: 'Send an alert mail with the given informations.' })
async sendAlertMail(
@Body() alertingInformationDto: AlertingInformationDto
): Promise<void> {
await this.alertingService.triggerAlertMail(
alertingInformationDto.reason,
alertingInformationDto.description
);
}
}
11 changes: 11 additions & 0 deletions apps/backend/src/app/alerting/alerting.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { AlertingService } from './alerting.service';
import { MailModule } from '../utils/mail/mail.module';
import { AlertingController } from './alerting.controller';

@Module({
imports: [MailModule],
providers: [AlertingService],
controllers: [AlertingController],
})
export class AlertingModule {}
27 changes: 27 additions & 0 deletions apps/backend/src/app/alerting/alerting.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AlertingService } from './alerting.service';
import { MailService } from '../utils/mail/mail.service';

describe('AlertingService', () => {
let service: AlertingService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
AlertingService,
{
provide: MailService,
useValue: {
sendAlertMail: jest.fn(),
},
},
],
}).compile();

service = module.get(AlertingService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
11 changes: 11 additions & 0 deletions apps/backend/src/app/alerting/alerting.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Injectable } from '@nestjs/common';
import { MailService } from '../utils/mail/mail.service';

@Injectable()
export class AlertingService {
constructor(private mailService: MailService) {}

async triggerAlertMail(reason: string, description: string) {
await this.mailService.sendAlertMail(reason, description);
}
}
18 changes: 18 additions & 0 deletions apps/backend/src/app/alerting/dto/alertingInformationDto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';

export class AlertingInformationDto {
@ApiProperty({
description: 'Reason for the alert',
required: true,
})
@IsString()
reason!: string;

@ApiProperty({
description: 'Description of the alert',
required: true,
})
@IsString()
description!: string;
}
4 changes: 3 additions & 1 deletion apps/backend/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {TypeOrmModule} from '@nestjs/typeorm';
import {DbConfigService} from "./db-config.service";
import {DemoModule} from "./demo/demo.module";
import {BackupDataModule} from "./backupData/backupData.module";
import { AlertingModule } from './alerting/alerting.module';

@Module({
imports: [
Expand All @@ -18,7 +19,8 @@ import {BackupDataModule} from "./backupData/backupData.module";
useClass: DbConfigService,
}),
DemoModule,
BackupDataModule
BackupDataModule,
AlertingModule
],
controllers: [AppController],
providers: [AppService],
Expand Down
166 changes: 166 additions & 0 deletions apps/backend/src/app/backupData/backupData.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import request from 'supertest';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { BackupDataEntity } from './entity/backupData.entity';
import { CreateBackupDataDto } from './dto/createBackupData.dto';
import { BackupDataModule } from './backupData.module';

const mockBackupDataEntity: BackupDataEntity = {
id: '123e4567-e89b-12d3-a456-426614174062',
sizeMB: 100,
creationDate: new Date('2023-12-30 00:00:00.000000'),
bio: 'Test Bio',
};

const mockBackupDataRepository = {
save: jest
.fn()
.mockImplementation((backupData) => Promise.resolve(backupData)),
findOne: jest
.fn()
.mockImplementation(({ where: { id } }) =>
Promise.resolve({ ...mockBackupDataEntity, id })
),

findAndCount: jest
.fn()
.mockImplementation(() => Promise.resolve([[mockBackupDataEntity], 1])),
};

describe('BackupDataController (e2e)', () => {
let app: INestApplication;
let repository: Repository<BackupDataEntity>;

beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [BackupDataModule],
})
.overrideProvider(getRepositoryToken(BackupDataEntity))
.useValue(mockBackupDataRepository)
.compile();

repository = module.get(getRepositoryToken(BackupDataEntity));

app = module.createNestApplication();
await app.init();
});

afterAll(async () => {
await app.close();
});

it('/backupData (POST) should create new backup data entry', async () => {
const createBackupDataDto: CreateBackupDataDto = {
id: '1',
sizeMB: 100,
creationDate: new Date(),
bio: 'Test Bio 1',
};

const response = await request(app.getHttpServer())
.post('/backupData')
.send(createBackupDataDto)
.expect(201);

expect(response.body).toEqual({
id: createBackupDataDto.id,
sizeMB: createBackupDataDto.sizeMB,
creationDate: createBackupDataDto.creationDate.toISOString(),
bio: createBackupDataDto.bio,
});

expect(mockBackupDataRepository.save).toBeCalledWith({
...createBackupDataDto,
creationDate: createBackupDataDto.creationDate.toISOString(),
});
});
it('/backupData/:id (GET) should return a backup data entry by id', async () => {
const response = await request(app.getHttpServer())
.get(`/backupData/${mockBackupDataEntity.id}`)
.expect(200);

expect(response.body).toEqual({
...mockBackupDataEntity,
creationDate: mockBackupDataEntity.creationDate.toISOString(),
});

expect(mockBackupDataRepository.findOne).toBeCalledWith({
where: { id: mockBackupDataEntity.id },
});
});

it('/backupData (GET) with pagination should return paginated backup data entries', async () => {
const response = await request(app.getHttpServer())
.get('/backupData?offset=0&limit=1')
.expect(200);

expect(response.body).toEqual({
data: [
{
...mockBackupDataEntity,
creationDate: mockBackupDataEntity.creationDate.toISOString(),
},
],
paginationData: {
limit: '1',
offset: '0',
total: 1,
},
});

expect(mockBackupDataRepository.findAndCount).toBeCalledWith({
skip: '0',
take: '1',
order: { creationDate: 'DESC' },
where: {},
});
});

it('/backupData (GET) with filters should return filtered backup data entries', async () => {
const response = await request(app.getHttpServer())
.get('/backupData?bio=Test')
.expect(200);

expect(response.body).toEqual({
data: [
{
...mockBackupDataEntity,
creationDate: mockBackupDataEntity.creationDate.toISOString(),
},
],
paginationData: {
total: 1,
},
});

expect(mockBackupDataRepository.findAndCount).toBeCalledWith({
order: { creationDate: 'DESC' },
where: { bio: expect.any(Object) },
});
});

it('/backupData (GET) with date range should return backup data entries within date range', async () => {
const response = await request(app.getHttpServer())
.get('/backupData?fromDate=2023-12-01&toDate=2023-12-31')
.expect(200);

expect(response.body).toEqual({
data: [
{
...mockBackupDataEntity,
creationDate: mockBackupDataEntity.creationDate.toISOString(),
},
],
paginationData: {
total: 1,
},
});

expect(mockBackupDataRepository.findAndCount).toBeCalledWith({
order: { creationDate: 'DESC' },
where: { creationDate: expect.any(Object) },
});
});
});
1 change: 0 additions & 1 deletion apps/backend/src/app/demo/demo.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,4 @@ export class DemoController {
async createEntry(@Body() createEntryDto: CreateEntryDto): Promise<DemoDto> {
return await this.demoService.createEntry(createEntryDto.text);
}

}
2 changes: 0 additions & 2 deletions apps/backend/src/app/demo/demo.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { InjectRepository } from '@nestjs/typeorm';
import { DemoEntity } from './entity/demo.entity';
import { Repository } from 'typeorm';
import { AnalyzerServiceService } from '../analyzerService/analyzer-service.service';
import { firstValueFrom } from 'rxjs';

@Injectable()
export class DemoService {
Expand All @@ -30,5 +29,4 @@ export class DemoService {
entry.text = text;
return this.demoRepository.save(entry);
}

}
Loading

0 comments on commit e2b3ed5

Please sign in to comment.