Skip to content

Commit

Permalink
Merge pull request #106 from Samagra-Anamaya/ste
Browse files Browse the repository at this point in the history
feat: add scheme transaction APIs
  • Loading branch information
singhalkarun authored Dec 4, 2023
2 parents bb92250 + d2b8fdb commit 61ab021
Show file tree
Hide file tree
Showing 13 changed files with 662 additions and 0 deletions.
37 changes: 37 additions & 0 deletions packages/bff/prisma/migrations/20231204115049_ste/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
-- CreateTable
CREATE TABLE "scheme_transaction" (
"id" SERIAL NOT NULL,
"scheme_code" TEXT NOT NULL,
"aadhaar_number" VARCHAR(12) NOT NULL,
"aadhaar_reference_number" VARCHAR(13) NOT NULL,
"unique_beneficiary_id" VARCHAR(127) NOT NULL,
"financial_year" VARCHAR(15) NOT NULL,
"transaction_type" VARCHAR(127) NOT NULL,
"transaction_amount" INTEGER NOT NULL,
"in_kind_benefit_detail" VARCHAR(127) NOT NULL,
"transaction_date" VARCHAR(15) NOT NULL,
"remarks" TEXT,
"department_data" JSONB,
"user_id" UUID NOT NULL,

CONSTRAINT "scheme_transaction_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "transaction_history_table" (
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
"request_body" JSONB[],
"total_records" INTEGER NOT NULL,
"valid_records" INTEGER NOT NULL,
"invalid_records" INTEGER NOT NULL,
"contain_errors" BOOLEAN NOT NULL DEFAULT false,
"valid_records_saved" BOOLEAN NOT NULL DEFAULT false,
"errors" JSONB NOT NULL,
"user_id" UUID NOT NULL,
"transaction_start_time" TIMESTAMP(3) NOT NULL,
"transaction_end_time" TIMESTAMP(3) NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,

CONSTRAINT "transaction_history_table_pkey" PRIMARY KEY ("id")
);
32 changes: 32 additions & 0 deletions packages/bff/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,35 @@ model VillageData {
submissions Json?
status VillageDataStatus @default(UNASSIGNED)
}

model scheme_transaction {
id Int @id @default(autoincrement())
scheme_code String
aadhaar_number String @db.VarChar(12)
aadhaar_reference_number String @db.VarChar(13)
unique_beneficiary_id String @db.VarChar(127)
financial_year String @db.VarChar(15)
transaction_type String @db.VarChar(127)
transaction_amount Int
in_kind_benefit_detail String @db.VarChar(127)
transaction_date String @db.VarChar(15)
remarks String?
department_data Json?
user_id String @db.Uuid
}

model transaction_history_table {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
request_body Json[]
total_records Int
valid_records Int
invalid_records Int
contain_errors Boolean @default(false)
valid_records_saved Boolean @default(false)
errors Json
user_id String @db.Uuid
transaction_start_time DateTime
transaction_end_time DateTime
created_at DateTime @default(now())
updated_at DateTime @updatedAt
}
6 changes: 6 additions & 0 deletions packages/bff/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import { MinioHealthIndicator } from './minio/minio.health';
import { HealthController } from './health/health.controller';
import { HealthService } from './health/health.service';
import { HttpModule } from '@nestjs/axios';
import { SteService } from './ste/ste.service';
import { SteController } from './ste/ste.controller';
import { SteModule } from './ste/ste.module';
@Module({
imports: [
ConfigModule.forRoot({
Expand Down Expand Up @@ -53,12 +56,14 @@ import { HttpModule } from '@nestjs/axios';
}),
SubmissionModule,
MinioModule,
SteModule,
],
controllers: [
AppController,
SubmissionController,
UploadController,
HealthController,
SteController,
],
providers: [
{
Expand All @@ -75,6 +80,7 @@ import { HttpModule } from '@nestjs/axios';
UploadService,
MinioHealthIndicator,
HealthService,
SteService,
],
})
export class AppModule {}
3 changes: 3 additions & 0 deletions packages/bff/src/common/public.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { SetMetadata } from '@nestjs/common';

export const Public = () => SetMetadata('isPublic', true);
70 changes: 70 additions & 0 deletions packages/bff/src/common/ste.auth-guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {
CanActivate,
ExecutionContext,
Injectable,
Scope,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import * as jwt from 'jsonwebtoken';
import * as jwksClient from 'jwks-rsa';
import { Reflector } from '@nestjs/core';

@Injectable({ scope: Scope.DEFAULT })
export class SteAuthGuard implements CanActivate {
private client: jwksClient.JwksClient;
private getKey: any;

constructor(private readonly reflector: Reflector) {
this.client = jwksClient({
jwksUri: process.env.JWKS_URI,
requestHeaders: {}, // Optional
timeout: 30000, // Defaults to 30s
});

this.getKey = (header: jwt.JwtHeader, callback: any) => {
this.client.getSigningKey(header.kid, (err, key: any) => {
if (err) {
console.log(`Error fetching signing key: ${err}`);
callback(err);
} else {
const signingKey = key.publicKey || key.rsaPublicKey;
callback(null, signingKey);
}
});
};
}

canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const isPublic = this.reflector.get<boolean>(
'isPublic',
context.getHandler(),
);
if (isPublic) return true;
const request = context.switchToHttp().getRequest();

const bearerToken = request.headers.authorization?.split(' ')[1];

if (!bearerToken) {
return false;
}

return new Promise<boolean>((resolve) => {
jwt.verify(bearerToken, this.getKey, (err, decoded) => {
if (err) {
console.log('JWT verification error:', err);
resolve(false);
} else {
if (!decoded['roles'].includes('department')) {
resolve(false);
}
request.headers.userId = decoded.sub;
request.headers.username = decoded['preferred_username'];
request.headers.roles = decoded['roles'];
resolve(true);
}
});
});
}
}
9 changes: 9 additions & 0 deletions packages/bff/src/ste/dto/auth.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ApiProperty } from '@nestjs/swagger';

export class AuthDto {
@ApiProperty()
username: string;

@ApiProperty()
password: string;
}
78 changes: 78 additions & 0 deletions packages/bff/src/ste/dto/scheme.transaction.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { ApiProperty } from '@nestjs/swagger';
import { JsonArray } from '@prisma/client/runtime/library';

export class SchemeTransactionEvent {
@ApiProperty({
example: 'CULC8',
})
schemeCode: string;

@ApiProperty({
example: '123412341234',
description: '12 Digit Aadhaar Number',
})
aadhaarNumber: string;

@ApiProperty({
example: '1234123412345',
description: '13 Digit Aadhaar Reference Number',
})
aadhaarReferenceNumber: string;

@ApiProperty({
example: '123456',
})
uniqueBeneficiaryId: string;

@ApiProperty({
example: '2022-23',
description: 'Financial year in YYYY-YY format',
})
financialYear: string;

@ApiProperty({
example: 'Cash',
})
transactionType: string;

@ApiProperty({
example: 5000,
description: 'Transaction Amount',
})
transactionAmount: number;

@ApiProperty({
example: 'Training',
})
inKindBenefitDetail: string;

@ApiProperty({
example: '12-05-2023',
description: 'Transaction date in DD-MM-YYYY format',
})
transactionDate: string;

@ApiProperty({
type: String,
})
remarks = '';

@ApiProperty({
type: [],
example: [
{
marker: 'Date of Birth',
value: '21-01-1999',
},
],
description: 'These are department specific marker-value pairs',
})
departmentData: JsonArray = [];
}

export class SchemeTransactionEventDto {
@ApiProperty({
type: [SchemeTransactionEvent],
})
data: SchemeTransactionEvent[];
}
18 changes: 18 additions & 0 deletions packages/bff/src/ste/ste.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { SteController } from './ste.controller';

describe('SteController', () => {
let controller: SteController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [SteController],
}).compile();

controller = module.get<SteController>(SteController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
59 changes: 59 additions & 0 deletions packages/bff/src/ste/ste.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
Body,
Controller,
Get,
Param,
Post,
Req,
UseGuards,
} from '@nestjs/common';
import { SteService } from './ste.service';
import { SchemeTransactionEventDto } from './dto/scheme.transaction.dto';
import { Public } from 'src/common/public.decorator';
import { Request } from 'express';
import { SteAuthGuard } from 'src/common/ste.auth-guard';
import { AuthDto } from './dto/auth.dto';

@UseGuards(SteAuthGuard)
@Controller('ste')
export class SteController {
constructor(private readonly steService: SteService) {}

@Public()
@Post('/authenticate')
async authenticate(@Body() authDto: AuthDto) {
return await this.steService.authenticate(
authDto.username,
authDto.password,
);
}

@Post('/saveSchemeTransaction')
async saveSchemeTransaction(
@Body() schemeTransactionDetail: SchemeTransactionEventDto,
@Req() request: Request,
) {
const userIdHeader = request.headers.userId;
const userId: string = Array.isArray(userIdHeader)
? userIdHeader[0]
: userIdHeader;
return await this.steService.saveSchemeTransaction(
schemeTransactionDetail.data,
userId,
);
}

@Get('/transactionHistory/:id')
async getTransactionHistory(@Param('id') transactionHistoryid: string) {
return await this.steService.getTransactionHistory(transactionHistoryid);
}

@Get('/progress')
async getProgress(@Req() request: Request) {
const userIdHeader = request.headers.userId;
const userId: string = Array.isArray(userIdHeader)
? userIdHeader[0]
: userIdHeader;
return await this.steService.getProgress(userId);
}
}
4 changes: 4 additions & 0 deletions packages/bff/src/ste/ste.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Module } from '@nestjs/common';

@Module({})
export class SteModule {}
18 changes: 18 additions & 0 deletions packages/bff/src/ste/ste.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { SteService } from './ste.service';

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

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [SteService],
}).compile();

service = module.get<SteService>(SteService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
Loading

0 comments on commit 61ab021

Please sign in to comment.