fix it
This commit is contained in:
parent
d2d1ab493c
commit
2e2724c7a6
1
.gitignore
vendored
1
.gitignore
vendored
@ -0,0 +1 @@
|
||||
/node_modules
|
||||
5
.prettierrc
Normal file
5
.prettierrc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"singleQuote": false,
|
||||
"trailingComma": "none",
|
||||
"semi": true
|
||||
}
|
||||
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@ -0,0 +1,13 @@
|
||||
# Dockerfile
|
||||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 3001
|
||||
|
||||
CMD ["npm", "run", "start:dev"]
|
||||
99
README.md
Normal file
99
README.md
Normal file
@ -0,0 +1,99 @@
|
||||
<p align="center">
|
||||
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
|
||||
</p>
|
||||
|
||||
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
||||
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
||||
|
||||
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
|
||||
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
|
||||
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
|
||||
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
|
||||
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
|
||||
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
|
||||
</p>
|
||||
<!--[](https://opencollective.com/nest#backer)
|
||||
[](https://opencollective.com/nest#sponsor)-->
|
||||
|
||||
## Description
|
||||
|
||||
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
|
||||
|
||||
## Project setup
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
```
|
||||
|
||||
## Compile and run the project
|
||||
|
||||
```bash
|
||||
# development
|
||||
$ npm run start
|
||||
|
||||
# watch mode
|
||||
$ npm run start:dev
|
||||
|
||||
# production mode
|
||||
$ npm run start:prod
|
||||
```
|
||||
|
||||
## Run tests
|
||||
|
||||
```bash
|
||||
# unit tests
|
||||
$ npm run test
|
||||
|
||||
# e2e tests
|
||||
$ npm run test:e2e
|
||||
|
||||
# test coverage
|
||||
$ npm run test:cov
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
|
||||
|
||||
If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
|
||||
|
||||
```bash
|
||||
$ npm install -g mau
|
||||
$ mau deploy
|
||||
```
|
||||
|
||||
With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
|
||||
|
||||
## Resources
|
||||
|
||||
Check out a few resources that may come in handy when working with NestJS:
|
||||
|
||||
- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
|
||||
- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
|
||||
- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
|
||||
- Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
|
||||
- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
|
||||
- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
|
||||
- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
|
||||
- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
|
||||
|
||||
## Support
|
||||
|
||||
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||
|
||||
## Stay in touch
|
||||
|
||||
- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
|
||||
- Website - [https://nestjs.com](https://nestjs.com/)
|
||||
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||
|
||||
## License
|
||||
|
||||
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
|
||||
4
dist/app.module.d.ts
vendored
Normal file
4
dist/app.module.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import { MiddlewareConsumer, NestModule } from '@nestjs/common';
|
||||
export declare class AppModule implements NestModule {
|
||||
configure(consumer: MiddlewareConsumer): void;
|
||||
}
|
||||
39
dist/app.module.js
vendored
Normal file
39
dist/app.module.js
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AppModule = void 0;
|
||||
const app_service_1 = require("./app.service");
|
||||
const common_1 = require("@nestjs/common");
|
||||
const auth_controller_1 = require("./controllers/auth.controller");
|
||||
const subscription_controller_1 = require("./controllers/subscription.controller");
|
||||
const billing_controller_1 = require("./controllers/billing.controller");
|
||||
const sms_controller_1 = require("./controllers/sms.controller");
|
||||
const otp_controller_1 = require("./controllers/otp.controller");
|
||||
const mock_data_service_1 = require("./services/mock-data.service");
|
||||
const token_service_1 = require("./services/token.service");
|
||||
const auth_middleware_1 = require("./middleware/auth.middleware");
|
||||
let AppModule = class AppModule {
|
||||
configure(consumer) {
|
||||
consumer.apply(auth_middleware_1.AuthMiddleware).exclude('/oauth/v3/token').forRoutes('*');
|
||||
}
|
||||
};
|
||||
exports.AppModule = AppModule;
|
||||
exports.AppModule = AppModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [],
|
||||
controllers: [
|
||||
auth_controller_1.AuthController,
|
||||
subscription_controller_1.SubscriptionController,
|
||||
billing_controller_1.BillingController,
|
||||
sms_controller_1.SmsController,
|
||||
otp_controller_1.OtpController,
|
||||
],
|
||||
providers: [app_service_1.AppService, mock_data_service_1.MockDataService, token_service_1.TokenService],
|
||||
})
|
||||
], AppModule);
|
||||
//# sourceMappingURL=app.module.js.map
|
||||
1
dist/app.module.js.map
vendored
Normal file
1
dist/app.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,+CAA2C;AAE3C,2CAAwE;AACxE,mEAA+D;AAC/D,mFAA+E;AAC/E,yEAAqE;AACrE,iEAA6D;AAC7D,iEAA6D;AAC7D,oEAA+D;AAC/D,4DAAwD;AACxD,kEAA8D;AAavD,IAAM,SAAS,GAAf,MAAM,SAAS;IACpB,SAAS,CAAC,QAA4B;QACpC,QAAQ,CAAC,KAAK,CAAC,gCAAc,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC3E,CAAC;CACF,CAAA;AAJY,8BAAS;oBAAT,SAAS;IAXrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,EAAE;QACX,WAAW,EAAE;YACX,gCAAc;YACd,gDAAsB;YACtB,sCAAiB;YACjB,8BAAa;YACb,8BAAa;SACd;QACD,SAAS,EAAE,CAAC,wBAAU,EAAE,mCAAe,EAAE,4BAAY,CAAC;KACvD,CAAC;GACW,SAAS,CAIrB"}
|
||||
3
dist/app.service.d.ts
vendored
Normal file
3
dist/app.service.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
export declare class AppService {
|
||||
getHello(): string;
|
||||
}
|
||||
20
dist/app.service.js
vendored
Normal file
20
dist/app.service.js
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AppService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
let AppService = class AppService {
|
||||
getHello() {
|
||||
return 'Hello World!';
|
||||
}
|
||||
};
|
||||
exports.AppService = AppService;
|
||||
exports.AppService = AppService = __decorate([
|
||||
(0, common_1.Injectable)()
|
||||
], AppService);
|
||||
//# sourceMappingURL=app.service.js.map
|
||||
1
dist/app.service.js.map
vendored
Normal file
1
dist/app.service.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.service.js","sourceRoot":"","sources":["../src/app.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAGrC,IAAM,UAAU,GAAhB,MAAM,UAAU;IACrB,QAAQ;QACN,OAAO,cAAc,CAAC;IACxB,CAAC;CACF,CAAA;AAJY,gCAAU;qBAAV,UAAU;IADtB,IAAA,mBAAU,GAAE;GACA,UAAU,CAItB"}
|
||||
18
dist/controllers/auth.controller.d.ts
vendored
Normal file
18
dist/controllers/auth.controller.d.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
import { TokenService } from '../services/token.service';
|
||||
export declare class AuthController {
|
||||
private tokenService;
|
||||
constructor(tokenService: TokenService);
|
||||
generateToken(authHeader: string, grantType: string): {
|
||||
error: string;
|
||||
error_description: string;
|
||||
token_type?: undefined;
|
||||
access_token?: undefined;
|
||||
expires_in?: undefined;
|
||||
} | {
|
||||
token_type: string;
|
||||
access_token: string;
|
||||
expires_in: number;
|
||||
error?: undefined;
|
||||
error_description?: undefined;
|
||||
};
|
||||
}
|
||||
56
dist/controllers/auth.controller.js
vendored
Normal file
56
dist/controllers/auth.controller.js
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AuthController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const token_service_1 = require("../services/token.service");
|
||||
let AuthController = class AuthController {
|
||||
constructor(tokenService) {
|
||||
this.tokenService = tokenService;
|
||||
}
|
||||
generateToken(authHeader, grantType) {
|
||||
if (!authHeader || !authHeader.startsWith('Basic ')) {
|
||||
return {
|
||||
error: 'invalid_client',
|
||||
error_description: 'Invalid authentication credentials',
|
||||
};
|
||||
}
|
||||
if (grantType !== 'client_credentials') {
|
||||
return {
|
||||
error: 'unsupported_grant_type',
|
||||
error_description: 'Only client_credentials is supported',
|
||||
};
|
||||
}
|
||||
const token = this.tokenService.generateToken();
|
||||
return {
|
||||
token_type: 'Bearer',
|
||||
access_token: token,
|
||||
expires_in: 3600,
|
||||
};
|
||||
}
|
||||
};
|
||||
exports.AuthController = AuthController;
|
||||
__decorate([
|
||||
(0, common_1.Post)('token'),
|
||||
__param(0, (0, common_1.Headers)('authorization')),
|
||||
__param(1, (0, common_1.Body)('grant_type')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], AuthController.prototype, "generateToken", null);
|
||||
exports.AuthController = AuthController = __decorate([
|
||||
(0, common_1.Controller)('oauth/v3'),
|
||||
__metadata("design:paramtypes", [token_service_1.TokenService])
|
||||
], AuthController);
|
||||
//# sourceMappingURL=auth.controller.js.map
|
||||
1
dist/controllers/auth.controller.js.map
vendored
Normal file
1
dist/controllers/auth.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.controller.js","sourceRoot":"","sources":["../../src/controllers/auth.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AACA,2CAAiE;AACjE,6DAAyD;AAGlD,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB,YAAoB,YAA0B;QAA1B,iBAAY,GAAZ,YAAY,CAAc;IAAG,CAAC;IAElD,aAAa,CACe,UAAkB,EACxB,SAAiB;QAGrC,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpD,OAAO;gBACL,KAAK,EAAE,gBAAgB;gBACvB,iBAAiB,EAAE,oCAAoC;aACxD,CAAC;QACJ,CAAC;QACD,IAAI,SAAS,KAAK,oBAAoB,EAAE,CAAC;YACvC,OAAO;gBACL,KAAK,EAAE,wBAAwB;gBAC/B,iBAAiB,EAAE,sCAAsC;aAC1D,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC;QAChD,OAAO;YACL,UAAU,EAAE,QAAQ;YACpB,YAAY,EAAE,KAAK;YACnB,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;CACF,CAAA;AA5BY,wCAAc;AAGzB;IADC,IAAA,aAAI,EAAC,OAAO,CAAC;IAEX,WAAA,IAAA,gBAAO,EAAC,eAAe,CAAC,CAAA;IACxB,WAAA,IAAA,aAAI,EAAC,YAAY,CAAC,CAAA;;;;mDAsBpB;yBA3BU,cAAc;IAD1B,IAAA,mBAAU,EAAC,UAAU,CAAC;qCAEa,4BAAY;GADnC,cAAc,CA4B1B"}
|
||||
8
dist/controllers/billing.controller.d.ts
vendored
Normal file
8
dist/controllers/billing.controller.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
import { MockDataService } from '../services/mock-data.service';
|
||||
export declare class BillingController {
|
||||
private mockData;
|
||||
constructor(mockData: MockDataService);
|
||||
chargeUser(ise2: string, mco: string, body: any): {
|
||||
amountTransaction: any;
|
||||
};
|
||||
}
|
||||
75
dist/controllers/billing.controller.js
vendored
Normal file
75
dist/controllers/billing.controller.js
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.BillingController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const mock_data_service_1 = require("../services/mock-data.service");
|
||||
let BillingController = class BillingController {
|
||||
constructor(mockData) {
|
||||
this.mockData = mockData;
|
||||
}
|
||||
chargeUser(ise2, mco, body) {
|
||||
console.log('[MOCK] Charge request:', { ise2, mco, body });
|
||||
const { amountTransaction } = body;
|
||||
if (!amountTransaction) {
|
||||
throw new common_1.HttpException({
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: 'SVC0002',
|
||||
text: 'Invalid input value for message part amountTransaction'
|
||||
}
|
||||
}
|
||||
}, common_1.HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
const amount = parseFloat(amountTransaction.paymentAmount.chargingInformation.amount);
|
||||
const result = this.mockData.createTransaction({
|
||||
endUserId: ise2,
|
||||
amount,
|
||||
...amountTransaction,
|
||||
});
|
||||
if (!result.success) {
|
||||
throw new common_1.HttpException({
|
||||
requestError: {
|
||||
policyException: {
|
||||
messageId: result.error.code,
|
||||
text: result.error.message
|
||||
}
|
||||
}
|
||||
}, common_1.HttpStatus.FORBIDDEN);
|
||||
}
|
||||
return {
|
||||
amountTransaction: {
|
||||
...amountTransaction,
|
||||
serverReferenceCode: result.transaction.serverReferenceCode,
|
||||
transactionOperationStatus: 'Charged',
|
||||
resourceURL: `http://localhost:3001/payment/mea/v1/transactions/${result.transaction.serverReferenceCode}`
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
exports.BillingController = BillingController;
|
||||
__decorate([
|
||||
(0, common_1.Post)('acr:X-Orange-ISE2/transactions/amount'),
|
||||
__param(0, (0, common_1.Headers)('x-orange-ise2')),
|
||||
__param(1, (0, common_1.Headers)('x-orange-mco')),
|
||||
__param(2, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, String, Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], BillingController.prototype, "chargeUser", null);
|
||||
exports.BillingController = BillingController = __decorate([
|
||||
(0, common_1.Controller)('payment/mea/v1'),
|
||||
__metadata("design:paramtypes", [mock_data_service_1.MockDataService])
|
||||
], BillingController);
|
||||
//# sourceMappingURL=billing.controller.js.map
|
||||
1
dist/controllers/billing.controller.js.map
vendored
Normal file
1
dist/controllers/billing.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"billing.controller.js","sourceRoot":"","sources":["../../src/controllers/billing.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AACA,2CAA4F;AAC5F,qEAAgE;AAGzD,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAC5B,YAAoB,QAAyB;QAAzB,aAAQ,GAAR,QAAQ,CAAiB;IAAG,CAAC;IAGjD,UAAU,CACkB,IAAY,EACb,GAAW,EAC5B,IAAS;QAEjB,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAE3D,MAAM,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC;QAEnC,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvB,MAAM,IAAI,sBAAa,CAAC;gBACtB,YAAY,EAAE;oBACZ,gBAAgB,EAAE;wBAChB,SAAS,EAAE,SAAS;wBACpB,IAAI,EAAE,wDAAwD;qBAC/D;iBACF;aACF,EAAE,mBAAU,CAAC,WAAW,CAAC,CAAC;QAC7B,CAAC;QAED,MAAM,MAAM,GAAG,UAAU,CAAC,iBAAiB,CAAC,aAAa,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAGtF,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YAC7C,SAAS,EAAE,IAAI;YACf,MAAM;YACN,GAAG,iBAAiB;SACrB,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,sBAAa,CAAC;gBACtB,YAAY,EAAE;oBACZ,eAAe,EAAE;wBACf,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;wBAC5B,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO;qBAC3B;iBACF;aACF,EAAE,mBAAU,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;QAED,OAAO;YACL,iBAAiB,EAAE;gBACjB,GAAG,iBAAiB;gBACpB,mBAAmB,EAAE,MAAM,CAAC,WAAW,CAAC,mBAAmB;gBAC3D,0BAA0B,EAAE,SAAS;gBACrC,WAAW,EAAE,qDAAqD,MAAM,CAAC,WAAW,CAAC,mBAAmB,EAAE;aAC3G;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AArDY,8CAAiB;AAI5B;IADC,IAAA,aAAI,EAAC,uCAAuC,CAAC;IAE3C,WAAA,IAAA,gBAAO,EAAC,eAAe,CAAC,CAAA;IACxB,WAAA,IAAA,gBAAO,EAAC,cAAc,CAAC,CAAA;IACvB,WAAA,IAAA,aAAI,GAAE,CAAA;;;;mDA6CR;4BApDU,iBAAiB;IAD7B,IAAA,mBAAU,EAAC,gBAAgB,CAAC;qCAEG,mCAAe;GADlC,iBAAiB,CAqD7B"}
|
||||
12
dist/controllers/otp.controller.d.ts
vendored
Normal file
12
dist/controllers/otp.controller.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
import { MockDataService } from '../services/mock-data.service';
|
||||
export declare class OtpController {
|
||||
private mockData;
|
||||
constructor(mockData: MockDataService);
|
||||
createChallenge(body: any): {
|
||||
challenge: any;
|
||||
location: string;
|
||||
};
|
||||
validateChallenge(challengeId: string, body: any): {
|
||||
challenge: any;
|
||||
};
|
||||
}
|
||||
109
dist/controllers/otp.controller.js
vendored
Normal file
109
dist/controllers/otp.controller.js
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.OtpController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const mock_data_service_1 = require("../services/mock-data.service");
|
||||
let OtpController = class OtpController {
|
||||
constructor(mockData) {
|
||||
this.mockData = mockData;
|
||||
}
|
||||
createChallenge(body) {
|
||||
console.log('[MOCK] OTP Challenge creation:', body);
|
||||
const { challenge } = body;
|
||||
if (!challenge || challenge.method !== 'OTP-SMS-AUTH') {
|
||||
throw new common_1.HttpException({
|
||||
error: {
|
||||
code: 232740003,
|
||||
message: 'Invalid input value',
|
||||
description: 'Invalid challenge method'
|
||||
}
|
||||
}, common_1.HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
const msisdnInput = challenge.inputs.find(i => i.type === 'MSISDN');
|
||||
if (!msisdnInput) {
|
||||
throw new common_1.HttpException({
|
||||
error: {
|
||||
code: 232740000,
|
||||
message: 'Missing input',
|
||||
description: 'MSISDN is required'
|
||||
}
|
||||
}, common_1.HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
const challengeId = this.mockData.createOtpChallenge(msisdnInput.value, challenge.country);
|
||||
return {
|
||||
challenge: {
|
||||
...challenge,
|
||||
result: []
|
||||
},
|
||||
location: `/challenge/v1/challenges/${challengeId}`
|
||||
};
|
||||
}
|
||||
validateChallenge(challengeId, body) {
|
||||
console.log('[MOCK] OTP Challenge validation:', { challengeId, body });
|
||||
const { challenge } = body;
|
||||
const otpInput = challenge.inputs.find(i => i.type === 'confirmationCode');
|
||||
if (!otpInput || !otpInput.value) {
|
||||
throw new common_1.HttpException({
|
||||
error: {
|
||||
code: 232740203,
|
||||
message: 'Invalid challenge inputs',
|
||||
description: 'OTP code is required'
|
||||
}
|
||||
}, common_1.HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
const result = this.mockData.validateOtp(challengeId, otpInput.value);
|
||||
if (!result.success) {
|
||||
throw new common_1.HttpException({
|
||||
error: {
|
||||
code: 232740201,
|
||||
message: 'Authorization denied',
|
||||
description: result.error
|
||||
}
|
||||
}, common_1.HttpStatus.FORBIDDEN);
|
||||
}
|
||||
return {
|
||||
challenge: {
|
||||
...challenge,
|
||||
result: [
|
||||
{
|
||||
type: 'ise2',
|
||||
value: result.ise2
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
exports.OtpController = OtpController;
|
||||
__decorate([
|
||||
(0, common_1.Post)('challenges'),
|
||||
__param(0, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], OtpController.prototype, "createChallenge", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('challenges/:id'),
|
||||
__param(0, (0, common_1.Param)('id')),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], OtpController.prototype, "validateChallenge", null);
|
||||
exports.OtpController = OtpController = __decorate([
|
||||
(0, common_1.Controller)('challenge/v1'),
|
||||
__metadata("design:paramtypes", [mock_data_service_1.MockDataService])
|
||||
], OtpController);
|
||||
//# sourceMappingURL=otp.controller.js.map
|
||||
1
dist/controllers/otp.controller.js.map
vendored
Normal file
1
dist/controllers/otp.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"otp.controller.js","sourceRoot":"","sources":["../../src/controllers/otp.controller.ts"],"names":[],"mappings":"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"}
|
||||
8
dist/controllers/sms.controller.d.ts
vendored
Normal file
8
dist/controllers/sms.controller.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
import { MockDataService } from '../services/mock-data.service';
|
||||
export declare class SmsController {
|
||||
private mockData;
|
||||
constructor(mockData: MockDataService);
|
||||
sendSms(ise2: string, mco: string, body: any): {
|
||||
outboundSMSMessageRequest: any;
|
||||
};
|
||||
}
|
||||
59
dist/controllers/sms.controller.js
vendored
Normal file
59
dist/controllers/sms.controller.js
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SmsController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const mock_data_service_1 = require("../services/mock-data.service");
|
||||
let SmsController = class SmsController {
|
||||
constructor(mockData) {
|
||||
this.mockData = mockData;
|
||||
}
|
||||
sendSms(ise2, mco, body) {
|
||||
console.log('[MOCK] SMS MT request:', { ise2, mco, body });
|
||||
const { outboundSMSMessageRequest } = body;
|
||||
if (!outboundSMSMessageRequest) {
|
||||
throw new common_1.HttpException({
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: 'SVC0002',
|
||||
text: 'Invalid request format',
|
||||
},
|
||||
},
|
||||
}, common_1.HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
const messageId = `SMS-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
||||
return {
|
||||
outboundSMSMessageRequest: {
|
||||
...outboundSMSMessageRequest,
|
||||
clientCorrelator: messageId,
|
||||
resourceURL: `http://localhost:3001/smsmessaging/v1/outbound/requests/${messageId}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
exports.SmsController = SmsController;
|
||||
__decorate([
|
||||
(0, common_1.Post)('/outbound/tel:msisdn/requests'),
|
||||
__param(0, (0, common_1.Headers)('x-orange-ise2')),
|
||||
__param(1, (0, common_1.Headers)('x-orange-mco')),
|
||||
__param(2, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, String, Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], SmsController.prototype, "sendSms", null);
|
||||
exports.SmsController = SmsController = __decorate([
|
||||
(0, common_1.Controller)('smsmessaging/service/mea/v1'),
|
||||
__metadata("design:paramtypes", [mock_data_service_1.MockDataService])
|
||||
], SmsController);
|
||||
//# sourceMappingURL=sms.controller.js.map
|
||||
1
dist/controllers/sms.controller.js.map
vendored
Normal file
1
dist/controllers/sms.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"sms.controller.js","sourceRoot":"","sources":["../../src/controllers/sms.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AACA,2CAOwB;AACxB,qEAAgE;AAGzD,IAAM,aAAa,GAAnB,MAAM,aAAa;IACxB,YAAoB,QAAyB;QAAzB,aAAQ,GAAR,QAAQ,CAAiB;IAAG,CAAC;IAIjD,OAAO,CACqB,IAAY,EACb,GAAW,EAC5B,IAAS;QAEjB,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAE3D,MAAM,EAAE,yBAAyB,EAAE,GAAG,IAAI,CAAC;QAE3C,IAAI,CAAC,yBAAyB,EAAE,CAAC;YAC/B,MAAM,IAAI,sBAAa,CACrB;gBACE,YAAY,EAAE;oBACZ,gBAAgB,EAAE;wBAChB,SAAS,EAAE,SAAS;wBACpB,IAAI,EAAE,wBAAwB;qBAC/B;iBACF;aACF,EACD,mBAAU,CAAC,WAAW,CACvB,CAAC;QACJ,CAAC;QAGD,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QAEjF,OAAO;YACL,yBAAyB,EAAE;gBACzB,GAAG,yBAAyB;gBAC5B,gBAAgB,EAAE,SAAS;gBAC3B,WAAW,EAAE,2DAA2D,SAAS,EAAE;aACpF;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAvCY,sCAAa;AAKxB;IADA,IAAA,aAAI,EAAC,+BAA+B,CAAC;IAElC,WAAA,IAAA,gBAAO,EAAC,eAAe,CAAC,CAAA;IACxB,WAAA,IAAA,gBAAO,EAAC,cAAc,CAAC,CAAA;IACvB,WAAA,IAAA,aAAI,GAAE,CAAA;;;;4CA8BR;wBAtCU,aAAa;IADzB,IAAA,mBAAU,EAAC,6BAA6B,CAAC;qCAEV,mCAAe;GADlC,aAAa,CAuCzB"}
|
||||
9
dist/controllers/subscription.controller.d.ts
vendored
Normal file
9
dist/controllers/subscription.controller.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
import { MockDataService } from '../services/mock-data.service';
|
||||
export declare class SubscriptionController {
|
||||
private mockData;
|
||||
constructor(mockData: MockDataService);
|
||||
createSubscription(ise2: string, mco: string, body: any): any;
|
||||
getSubscription(id: string): any;
|
||||
deleteSubscription(id: string): string;
|
||||
private sendSubscriptionNotification;
|
||||
}
|
||||
113
dist/controllers/subscription.controller.js
vendored
Normal file
113
dist/controllers/subscription.controller.js
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SubscriptionController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const mock_data_service_1 = require("../services/mock-data.service");
|
||||
let SubscriptionController = class SubscriptionController {
|
||||
constructor(mockData) {
|
||||
this.mockData = mockData;
|
||||
}
|
||||
createSubscription(ise2, mco, body) {
|
||||
console.log('[MOCK] Création subscription:', { ise2, mco, body });
|
||||
if (!ise2 || !mco) {
|
||||
throw new common_1.HttpException({
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: '2001',
|
||||
text: 'Missing required headers',
|
||||
},
|
||||
},
|
||||
}, common_1.HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
if (Math.random() < 0.1) {
|
||||
throw new common_1.HttpException({
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: '3010',
|
||||
text: 'The subscription already exists',
|
||||
},
|
||||
},
|
||||
}, common_1.HttpStatus.CONFLICT);
|
||||
}
|
||||
const subscription = this.mockData.createSubscription(body);
|
||||
setTimeout(() => {
|
||||
this.sendSubscriptionNotification(subscription, 'orderCreation');
|
||||
}, 2000);
|
||||
return subscription;
|
||||
}
|
||||
getSubscription(id) {
|
||||
const subscription = this.mockData.getSubscription(id);
|
||||
if (!subscription) {
|
||||
throw new common_1.HttpException({
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: '3011',
|
||||
text: 'Subscription not found',
|
||||
},
|
||||
},
|
||||
}, common_1.HttpStatus.NOT_FOUND);
|
||||
}
|
||||
return subscription;
|
||||
}
|
||||
deleteSubscription(id) {
|
||||
const deleted = this.mockData.deleteSubscription(id);
|
||||
if (!deleted) {
|
||||
throw new common_1.HttpException({
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: '3011',
|
||||
text: 'Subscription not found',
|
||||
},
|
||||
},
|
||||
}, common_1.HttpStatus.NOT_FOUND);
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.sendSubscriptionNotification({ id }, 'orderDeletion');
|
||||
}, 1000);
|
||||
return '';
|
||||
}
|
||||
sendSubscriptionNotification(subscription, eventType) {
|
||||
console.log(`[MOCK] Notification ${eventType} pour subscription ${subscription.id}`);
|
||||
}
|
||||
};
|
||||
exports.SubscriptionController = SubscriptionController;
|
||||
__decorate([
|
||||
(0, common_1.Post)('digipay_sub/productOrder'),
|
||||
__param(0, (0, common_1.Headers)('x-orange-ise2')),
|
||||
__param(1, (0, common_1.Headers)('x-orange-mco')),
|
||||
__param(2, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, String, Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], SubscriptionController.prototype, "createSubscription", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('digipay_sub/productOrder/:id'),
|
||||
__param(0, (0, common_1.Param)('id')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], SubscriptionController.prototype, "getSubscription", null);
|
||||
__decorate([
|
||||
(0, common_1.Delete)('digipay_sub/productOrder/:id'),
|
||||
__param(0, (0, common_1.Param)('id')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], SubscriptionController.prototype, "deleteSubscription", null);
|
||||
exports.SubscriptionController = SubscriptionController = __decorate([
|
||||
(0, common_1.Controller)('payment/mea/v1'),
|
||||
__metadata("design:paramtypes", [mock_data_service_1.MockDataService])
|
||||
], SubscriptionController);
|
||||
//# sourceMappingURL=subscription.controller.js.map
|
||||
1
dist/controllers/subscription.controller.js.map
vendored
Normal file
1
dist/controllers/subscription.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"subscription.controller.js","sourceRoot":"","sources":["../../src/controllers/subscription.controller.ts"],"names":[],"mappings":"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"}
|
||||
0
dist/data/mock-database.d.ts
vendored
Normal file
0
dist/data/mock-database.d.ts
vendored
Normal file
1
dist/data/mock-database.js
vendored
Normal file
1
dist/data/mock-database.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
//# sourceMappingURL=mock-database.js.map
|
||||
1
dist/data/mock-database.js.map
vendored
Normal file
1
dist/data/mock-database.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"mock-database.js","sourceRoot":"","sources":["../../src/data/mock-database.ts"],"names":[],"mappings":""}
|
||||
1
dist/main.d.ts
vendored
Normal file
1
dist/main.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export {};
|
||||
19
dist/main.js
vendored
Normal file
19
dist/main.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const core_1 = require("@nestjs/core");
|
||||
const app_module_1 = require("./app.module");
|
||||
const swagger_1 = require("@nestjs/swagger");
|
||||
async function bootstrap() {
|
||||
const app = await core_1.NestFactory.create(app_module_1.AppModule);
|
||||
const config = new swagger_1.DocumentBuilder()
|
||||
.setTitle('API DCB / SMS / Payment')
|
||||
.setDescription('Documentation des endpoints mock Orange DCB')
|
||||
.setVersion('1.0')
|
||||
.addBearerAuth()
|
||||
.build();
|
||||
const document = swagger_1.SwaggerModule.createDocument(app, config);
|
||||
swagger_1.SwaggerModule.setup('api-docs', app, document);
|
||||
await app.listen(process.env.PORT ?? 3000);
|
||||
}
|
||||
bootstrap();
|
||||
//# sourceMappingURL=main.js.map
|
||||
1
dist/main.js.map
vendored
Normal file
1
dist/main.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,6CAAiE;AAEjE,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,CAAC;IAEhD,MAAM,MAAM,GAAG,IAAI,yBAAe,EAAE;SACjC,QAAQ,CAAC,yBAAyB,CAAC;SACnC,cAAc,CAAC,8CAA8C,CAAC;SAC9D,UAAU,CAAC,KAAK,CAAC;SACjB,aAAa,EAAE;SACf,KAAK,EAAE,CAAC;IACX,MAAM,QAAQ,GAAG,uBAAa,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC3D,uBAAa,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC/C,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC7C,CAAC;AACD,SAAS,EAAE,CAAC"}
|
||||
8
dist/middleware/auth.middleware.d.ts
vendored
Normal file
8
dist/middleware/auth.middleware.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
import { NestMiddleware } from '@nestjs/common';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { TokenService } from '../services/token.service';
|
||||
export declare class AuthMiddleware implements NestMiddleware {
|
||||
private tokenService;
|
||||
constructor(tokenService: TokenService);
|
||||
use(req: Request, res: Response, next: NextFunction): void;
|
||||
}
|
||||
50
dist/middleware/auth.middleware.js
vendored
Normal file
50
dist/middleware/auth.middleware.js
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AuthMiddleware = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const token_service_1 = require("../services/token.service");
|
||||
let AuthMiddleware = class AuthMiddleware {
|
||||
constructor(tokenService) {
|
||||
this.tokenService = tokenService;
|
||||
}
|
||||
use(req, res, next) {
|
||||
const authHeader = req.headers['authorization'];
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
throw new common_1.HttpException({
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: '401',
|
||||
text: 'Missing or invalid authorization header',
|
||||
},
|
||||
},
|
||||
}, common_1.HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
const token = authHeader.substring(7);
|
||||
if (!this.tokenService.validateToken(token)) {
|
||||
throw new common_1.HttpException({
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: '401',
|
||||
text: 'Invalid or expired token',
|
||||
},
|
||||
},
|
||||
}, common_1.HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
next();
|
||||
}
|
||||
};
|
||||
exports.AuthMiddleware = AuthMiddleware;
|
||||
exports.AuthMiddleware = AuthMiddleware = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__metadata("design:paramtypes", [token_service_1.TokenService])
|
||||
], AuthMiddleware);
|
||||
//# sourceMappingURL=auth.middleware.js.map
|
||||
1
dist/middleware/auth.middleware.js.map
vendored
Normal file
1
dist/middleware/auth.middleware.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.middleware.js","sourceRoot":"","sources":["../../src/middleware/auth.middleware.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,2CAKwB;AAExB,6DAAyD;AAGlD,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB,YAAoB,YAA0B;QAA1B,iBAAY,GAAZ,YAAY,CAAc;IAAG,CAAC;IAElD,GAAG,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;QACjD,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAEhD,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,sBAAa,CACrB;gBACE,YAAY,EAAE;oBACZ,gBAAgB,EAAE;wBAChB,SAAS,EAAE,KAAK;wBAChB,IAAI,EAAE,yCAAyC;qBAChD;iBACF;aACF,EACD,mBAAU,CAAC,YAAY,CACxB,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAEtC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,IAAI,sBAAa,CACrB;gBACE,YAAY,EAAE;oBACZ,gBAAgB,EAAE;wBAChB,SAAS,EAAE,KAAK;wBAChB,IAAI,EAAE,0BAA0B;qBACjC;iBACF;aACF,EACD,mBAAU,CAAC,YAAY,CACxB,CAAC;QACJ,CAAC;QAED,IAAI,EAAE,CAAC;IACT,CAAC;CACF,CAAA;AAtCY,wCAAc;yBAAd,cAAc;IAD1B,IAAA,mBAAU,GAAE;qCAEuB,4BAAY;GADnC,cAAc,CAsC1B"}
|
||||
16
dist/services/mock-data.service.d.ts
vendored
Normal file
16
dist/services/mock-data.service.d.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
export declare class MockDataService {
|
||||
private subscriptions;
|
||||
private transactions;
|
||||
private otpChallenges;
|
||||
private userBalances;
|
||||
constructor();
|
||||
private initializeMockData;
|
||||
generateISE2(msisdn: string, country: string): string;
|
||||
createSubscription(data: any): any;
|
||||
getSubscription(id: string): any;
|
||||
deleteSubscription(id: string): boolean;
|
||||
createTransaction(data: any): any;
|
||||
createOtpChallenge(msisdn: string, country: string): any;
|
||||
validateOtp(challengeId: string, inputOtp: string): any;
|
||||
getUserBalance(ise2: string): any;
|
||||
}
|
||||
125
dist/services/mock-data.service.js
vendored
Normal file
125
dist/services/mock-data.service.js
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.MockDataService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const uuid_1 = require("uuid");
|
||||
let MockDataService = class MockDataService {
|
||||
constructor() {
|
||||
this.subscriptions = new Map();
|
||||
this.transactions = new Map();
|
||||
this.otpChallenges = new Map();
|
||||
this.userBalances = new Map();
|
||||
this.initializeMockData();
|
||||
}
|
||||
initializeMockData() {
|
||||
this.userBalances.set('PDKSUB-200-Q82vHq0+F1WozTeNS/1wBfuULco05YBaeL4yPtJ8ktU=', {
|
||||
balance: 10000,
|
||||
currency: 'CDF',
|
||||
type: 'prepaid',
|
||||
});
|
||||
this.userBalances.set('PDKSUB-200-8Ow1iM0hLPZ+LGZ8j4uwEdQxY1hm4mVwrzTdWiUnuI=', {
|
||||
balance: 5000,
|
||||
currency: 'TND',
|
||||
type: 'prepaid',
|
||||
});
|
||||
}
|
||||
generateISE2(msisdn, country) {
|
||||
const base = `PDKSUB-200-`;
|
||||
const hash = Buffer.from(`${msisdn}-${country}-${Date.now()}`).toString('base64');
|
||||
return base + hash.substring(0, 40);
|
||||
}
|
||||
createSubscription(data) {
|
||||
const subscriptionId = (0, uuid_1.v4)();
|
||||
const subscription = {
|
||||
id: subscriptionId,
|
||||
state: 'Completed',
|
||||
orderDate: new Date().toISOString(),
|
||||
...data,
|
||||
};
|
||||
this.subscriptions.set(subscriptionId, subscription);
|
||||
return subscription;
|
||||
}
|
||||
getSubscription(id) {
|
||||
return this.subscriptions.get(id);
|
||||
}
|
||||
deleteSubscription(id) {
|
||||
return this.subscriptions.delete(id);
|
||||
}
|
||||
createTransaction(data) {
|
||||
const transactionId = (0, uuid_1.v4)();
|
||||
const userBalance = this.getUserBalance(data.endUserId);
|
||||
if (userBalance && userBalance.balance >= data.amount) {
|
||||
userBalance.balance -= data.amount;
|
||||
const transaction = {
|
||||
serverReferenceCode: transactionId,
|
||||
transactionOperationStatus: 'Charged',
|
||||
...data,
|
||||
};
|
||||
this.transactions.set(transactionId, transaction);
|
||||
return { success: true, transaction };
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'POL1000',
|
||||
message: 'User has insufficient credit for transaction',
|
||||
},
|
||||
};
|
||||
}
|
||||
createOtpChallenge(msisdn, country) {
|
||||
const challengeId = (0, uuid_1.v4)();
|
||||
const otp = Math.floor(1000 + Math.random() * 9000).toString();
|
||||
const challenge = {
|
||||
id: challengeId,
|
||||
msisdn,
|
||||
country,
|
||||
otp,
|
||||
createdAt: Date.now(),
|
||||
attempts: 0,
|
||||
};
|
||||
this.otpChallenges.set(challengeId, challenge);
|
||||
console.log(`[MOCK] OTP généré pour ${msisdn}: ${otp}`);
|
||||
return challengeId;
|
||||
}
|
||||
validateOtp(challengeId, inputOtp) {
|
||||
const challenge = this.otpChallenges.get(challengeId);
|
||||
if (!challenge) {
|
||||
return { success: false, error: 'Challenge not found' };
|
||||
}
|
||||
challenge.attempts++;
|
||||
if (challenge.attempts > 3) {
|
||||
return { success: false, error: 'Too many retries' };
|
||||
}
|
||||
if (Date.now() - challenge.createdAt > 300000) {
|
||||
return { success: false, error: 'OTP expired' };
|
||||
}
|
||||
if (challenge.otp === inputOtp) {
|
||||
const ise2 = this.generateISE2(challenge.msisdn, challenge.country);
|
||||
this.otpChallenges.delete(challengeId);
|
||||
return { success: true, ise2 };
|
||||
}
|
||||
return { success: false, error: 'Invalid OTP' };
|
||||
}
|
||||
getUserBalance(ise2) {
|
||||
return (this.userBalances.get(ise2) || {
|
||||
balance: 1000,
|
||||
currency: 'XOF',
|
||||
type: 'prepaid',
|
||||
});
|
||||
}
|
||||
};
|
||||
exports.MockDataService = MockDataService;
|
||||
exports.MockDataService = MockDataService = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__metadata("design:paramtypes", [])
|
||||
], MockDataService);
|
||||
//# sourceMappingURL=mock-data.service.js.map
|
||||
1
dist/services/mock-data.service.js.map
vendored
Normal file
1
dist/services/mock-data.service.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"mock-data.service.js","sourceRoot":"","sources":["../../src/services/mock-data.service.ts"],"names":[],"mappings":"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"}
|
||||
5
dist/services/token.service.d.ts
vendored
Normal file
5
dist/services/token.service.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export declare class TokenService {
|
||||
private tokens;
|
||||
generateToken(): string;
|
||||
validateToken(token: string): boolean;
|
||||
}
|
||||
44
dist/services/token.service.js
vendored
Normal file
44
dist/services/token.service.js
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TokenService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const crypto = require("crypto");
|
||||
let TokenService = class TokenService {
|
||||
constructor() {
|
||||
this.tokens = new Map();
|
||||
}
|
||||
generateToken() {
|
||||
const token = crypto.randomBytes(32).toString('hex');
|
||||
this.tokens.set(token, {
|
||||
createdAt: Date.now(),
|
||||
expiresIn: 3600000,
|
||||
});
|
||||
return token;
|
||||
}
|
||||
validateToken(token) {
|
||||
const tokenData = this.tokens.get(token);
|
||||
if (!tokenData) {
|
||||
if (token === 'test-token-valid') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const now = Date.now();
|
||||
if (now - tokenData.createdAt > tokenData.expiresIn) {
|
||||
this.tokens.delete(token);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
exports.TokenService = TokenService;
|
||||
exports.TokenService = TokenService = __decorate([
|
||||
(0, common_1.Injectable)()
|
||||
], TokenService);
|
||||
//# sourceMappingURL=token.service.js.map
|
||||
1
dist/services/token.service.js.map
vendored
Normal file
1
dist/services/token.service.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"token.service.js","sourceRoot":"","sources":["../../src/services/token.service.ts"],"names":[],"mappings":";;;;;;;;;AACA,2CAA4C;AAC5C,iCAAiC;AAG1B,IAAM,YAAY,GAAlB,MAAM,YAAY;IAAlB;QACG,WAAM,GAAG,IAAI,GAAG,EAAoD,CAAC;IA8B/E,CAAC;IA5BC,aAAa;QACX,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE;YACrB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,SAAS,EAAE,OAAO;SACnB,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACf,CAAC;IAED,aAAa,CAAC,KAAa;QACzB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAEzC,IAAI,CAAC,SAAS,EAAE,CAAC;YAEf,IAAI,KAAK,KAAK,kBAAkB,EAAE,CAAC;gBACjC,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,GAAG,GAAG,SAAS,CAAC,SAAS,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC;YACpD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AA/BY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;GACA,YAAY,CA+BxB"}
|
||||
1
dist/tsconfig.build.tsbuildinfo
vendored
Normal file
1
dist/tsconfig.build.tsbuildinfo
vendored
Normal file
File diff suppressed because one or more lines are too long
17
docker-compose.yml
Normal file
17
docker-compose.yml
Normal file
@ -0,0 +1,17 @@
|
||||
# docker-compose.yml
|
||||
version: '3.8'
|
||||
services:
|
||||
orange-mock-api:
|
||||
build: .
|
||||
ports:
|
||||
- "3001:3001"
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- PORT=3001
|
||||
volumes:
|
||||
- ./src:/app/src
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
ports:
|
||||
- "6379:6379"
|
||||
13
document.md
Normal file
13
document.md
Normal file
@ -0,0 +1,13 @@
|
||||
### Démarrer le mock:
|
||||
docker-compose up
|
||||
### Tester l'intégration:
|
||||
|
||||
npm run test
|
||||
|
||||
### env
|
||||
ORANGE_MOCK_URL=http://localhost:3001
|
||||
ORANGE_OAUTH_URL=http://localhost:3001/oauth/v3/token
|
||||
ORANGE_API_URL=http://localhost:3001/payment/mea/v1
|
||||
|
||||
### Swagger
|
||||
http://localhost:3000/api-docs
|
||||
35
eslint.config.mjs
Normal file
35
eslint.config.mjs
Normal file
@ -0,0 +1,35 @@
|
||||
// @ts-check
|
||||
import eslint from '@eslint/js';
|
||||
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
||||
import globals from 'globals';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: ['eslint.config.mjs'],
|
||||
},
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommendedTypeChecked,
|
||||
eslintPluginPrettierRecommended,
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
...globals.jest,
|
||||
},
|
||||
ecmaVersion: 5,
|
||||
sourceType: 'module',
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'warn',
|
||||
'@typescript-eslint/no-unsafe-argument': 'warn'
|
||||
},
|
||||
},
|
||||
);
|
||||
8
nest-cli.json
Normal file
8
nest-cli.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/nest-cli",
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"deleteOutDir": true
|
||||
}
|
||||
}
|
||||
11579
package-lock.json
generated
Normal file
11579
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
78
package.json
Normal file
78
package.json
Normal file
@ -0,0 +1,78 @@
|
||||
{
|
||||
"name": "dcp-orange-mock",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"start": "nest start",
|
||||
"start:dev": "nest start --watch",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"test:integ": "ts-node ./test/test-integration.ts",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^11.0.1",
|
||||
"@nestjs/core": "^11.0.1",
|
||||
"@nestjs/platform-express": "^11.0.1",
|
||||
"@nestjs/swagger": "^11.2.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@nestjs/cli": "^11.0.0",
|
||||
"@nestjs/schematics": "^11.0.0",
|
||||
"@nestjs/testing": "^11.0.1",
|
||||
"@swc/cli": "^0.6.0",
|
||||
"@swc/core": "^1.10.7",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^22.10.7",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"axios": "^1.4.0",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-prettier": "^5.2.2",
|
||||
"globals": "^15.14.0",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.4.2",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-loader": "^9.5.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.20.0"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"json",
|
||||
"ts"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"testRegex": ".*\\.spec\\.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
},
|
||||
"collectCoverageFrom": [
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
28
src/app.module.ts
Normal file
28
src/app.module.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { AppService } from './app.service';
|
||||
|
||||
import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common';
|
||||
import { AuthController } from './controllers/auth.controller';
|
||||
import { SubscriptionController } from './controllers/subscription.controller';
|
||||
import { BillingController } from './controllers/billing.controller';
|
||||
import { SmsController } from './controllers/sms.controller';
|
||||
import { OtpController } from './controllers/otp.controller';
|
||||
import { MockDataService } from './services/mock-data.service';
|
||||
import { TokenService } from './services/token.service';
|
||||
import { AuthMiddleware } from './middleware/auth.middleware';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [
|
||||
AuthController,
|
||||
SubscriptionController,
|
||||
BillingController,
|
||||
SmsController,
|
||||
OtpController,
|
||||
],
|
||||
providers: [AppService, MockDataService, TokenService],
|
||||
})
|
||||
export class AppModule implements NestModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
consumer.apply(AuthMiddleware).exclude('/oauth/v3/token').forRoutes('*');
|
||||
}
|
||||
}
|
||||
8
src/app.service.ts
Normal file
8
src/app.service.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
getHello(): string {
|
||||
return 'Hello World!';
|
||||
}
|
||||
}
|
||||
34
src/controllers/auth.controller.ts
Normal file
34
src/controllers/auth.controller.ts
Normal file
@ -0,0 +1,34 @@
|
||||
// src/controllers/auth.controller.ts
|
||||
import { Controller, Post, Body, Headers } from '@nestjs/common';
|
||||
import { TokenService } from '../services/token.service';
|
||||
|
||||
@Controller('oauth/v3')
|
||||
export class AuthController {
|
||||
constructor(private tokenService: TokenService) {}
|
||||
@Post('token')
|
||||
generateToken(
|
||||
@Headers('authorization') authHeader: string,
|
||||
@Body('grant_type') grantType: string,
|
||||
) {
|
||||
// Validation basique du Basic Auth
|
||||
if (!authHeader || !authHeader.startsWith('Basic ')) {
|
||||
return {
|
||||
error: 'invalid_client',
|
||||
error_description: 'Invalid authentication credentials',
|
||||
};
|
||||
}
|
||||
if (grantType !== 'client_credentials') {
|
||||
return {
|
||||
error: 'unsupported_grant_type',
|
||||
error_description: 'Only client_credentials is supported',
|
||||
};
|
||||
}
|
||||
// Générer un token mock
|
||||
const token = this.tokenService.generateToken();
|
||||
return {
|
||||
token_type: 'Bearer',
|
||||
access_token: token,
|
||||
expires_in: 3600,
|
||||
};
|
||||
}
|
||||
}
|
||||
59
src/controllers/billing.controller.ts
Normal file
59
src/controllers/billing.controller.ts
Normal file
@ -0,0 +1,59 @@
|
||||
// src/controllers/billing.controller.ts
|
||||
import { Controller, Post, Body, Headers, HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { MockDataService } from '../services/mock-data.service';
|
||||
|
||||
@Controller('payment/mea/v1')
|
||||
export class BillingController {
|
||||
constructor(private mockData: MockDataService) {}
|
||||
|
||||
@Post('acr:X-Orange-ISE2/transactions/amount')
|
||||
chargeUser(
|
||||
@Headers('x-orange-ise2') ise2: string,
|
||||
@Headers('x-orange-mco') mco: string,
|
||||
@Body() body: any,
|
||||
) {
|
||||
console.log('[MOCK] Charge request:', { ise2, mco, body });
|
||||
|
||||
const { amountTransaction } = body;
|
||||
|
||||
if (!amountTransaction) {
|
||||
throw new HttpException({
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: 'SVC0002',
|
||||
text: 'Invalid input value for message part amountTransaction'
|
||||
}
|
||||
}
|
||||
}, HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
const amount = parseFloat(amountTransaction.paymentAmount.chargingInformation.amount);
|
||||
|
||||
// Simuler une transaction
|
||||
const result = this.mockData.createTransaction({
|
||||
endUserId: ise2,
|
||||
amount,
|
||||
...amountTransaction,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
throw new HttpException({
|
||||
requestError: {
|
||||
policyException: {
|
||||
messageId: result.error.code,
|
||||
text: result.error.message
|
||||
}
|
||||
}
|
||||
}, HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
return {
|
||||
amountTransaction: {
|
||||
...amountTransaction,
|
||||
serverReferenceCode: result.transaction.serverReferenceCode,
|
||||
transactionOperationStatus: 'Charged',
|
||||
resourceURL: `http://localhost:3001/payment/mea/v1/transactions/${result.transaction.serverReferenceCode}`
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
94
src/controllers/otp.controller.ts
Normal file
94
src/controllers/otp.controller.ts
Normal file
@ -0,0 +1,94 @@
|
||||
// src/controllers/otp.controller.ts
|
||||
import { Controller, Post, Body, Param, HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { MockDataService } from '../services/mock-data.service';
|
||||
|
||||
@Controller('challenge/v1')
|
||||
export class OtpController {
|
||||
constructor(private mockData: MockDataService) {}
|
||||
|
||||
@Post('challenges')
|
||||
createChallenge(@Body() body: any) {
|
||||
console.log('[MOCK] OTP Challenge creation:', body);
|
||||
|
||||
const { challenge } = body;
|
||||
|
||||
if (!challenge || challenge.method !== 'OTP-SMS-AUTH') {
|
||||
throw new HttpException({
|
||||
error: {
|
||||
code: 232740003,
|
||||
message: 'Invalid input value',
|
||||
description: 'Invalid challenge method'
|
||||
}
|
||||
}, HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
const msisdnInput = challenge.inputs.find(i => i.type === 'MSISDN');
|
||||
if (!msisdnInput) {
|
||||
throw new HttpException({
|
||||
error: {
|
||||
code: 232740000,
|
||||
message: 'Missing input',
|
||||
description: 'MSISDN is required'
|
||||
}
|
||||
}, HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
const challengeId = this.mockData.createOtpChallenge(
|
||||
msisdnInput.value,
|
||||
challenge.country
|
||||
);
|
||||
|
||||
return {
|
||||
challenge: {
|
||||
...challenge,
|
||||
result: []
|
||||
},
|
||||
location: `/challenge/v1/challenges/${challengeId}`
|
||||
};
|
||||
}
|
||||
|
||||
@Post('challenges/:id')
|
||||
validateChallenge(
|
||||
@Param('id') challengeId: string,
|
||||
@Body() body: any,
|
||||
) {
|
||||
console.log('[MOCK] OTP Challenge validation:', { challengeId, body });
|
||||
|
||||
const { challenge } = body;
|
||||
const otpInput = challenge.inputs.find(i => i.type === 'confirmationCode');
|
||||
|
||||
if (!otpInput || !otpInput.value) {
|
||||
throw new HttpException({
|
||||
error: {
|
||||
code: 232740203,
|
||||
message: 'Invalid challenge inputs',
|
||||
description: 'OTP code is required'
|
||||
}
|
||||
}, HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
const result = this.mockData.validateOtp(challengeId, otpInput.value);
|
||||
|
||||
if (!result.success) {
|
||||
throw new HttpException({
|
||||
error: {
|
||||
code: 232740201,
|
||||
message: 'Authorization denied',
|
||||
description: result.error
|
||||
}
|
||||
}, HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
return {
|
||||
challenge: {
|
||||
...challenge,
|
||||
result: [
|
||||
{
|
||||
type: 'ise2',
|
||||
value: result.ise2
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
52
src/controllers/sms.controller.ts
Normal file
52
src/controllers/sms.controller.ts
Normal file
@ -0,0 +1,52 @@
|
||||
// src/controllers/sms.controller.ts
|
||||
import {
|
||||
Controller,
|
||||
Post,
|
||||
Body,
|
||||
Headers,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { MockDataService } from '../services/mock-data.service';
|
||||
|
||||
@Controller('smsmessaging/service/mea/v1')
|
||||
export class SmsController {
|
||||
constructor(private mockData: MockDataService) {}
|
||||
|
||||
//@Post('outbound/tel:+:msisdn/requests') // Original line
|
||||
@Post('/outbound/tel:msisdn/requests')
|
||||
sendSms(
|
||||
@Headers('x-orange-ise2') ise2: string,
|
||||
@Headers('x-orange-mco') mco: string,
|
||||
@Body() body: any,
|
||||
) {
|
||||
console.log('[MOCK] SMS MT request:', { ise2, mco, body });
|
||||
|
||||
const { outboundSMSMessageRequest } = body;
|
||||
|
||||
if (!outboundSMSMessageRequest) {
|
||||
throw new HttpException(
|
||||
{
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: 'SVC0002',
|
||||
text: 'Invalid request format',
|
||||
},
|
||||
},
|
||||
},
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
|
||||
// Simuler l'envoi du SMS
|
||||
const messageId = `SMS-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
||||
|
||||
return {
|
||||
outboundSMSMessageRequest: {
|
||||
...outboundSMSMessageRequest,
|
||||
clientCorrelator: messageId,
|
||||
resourceURL: `http://localhost:3001/smsmessaging/v1/outbound/requests/${messageId}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
120
src/controllers/subscription.controller.ts
Normal file
120
src/controllers/subscription.controller.ts
Normal file
@ -0,0 +1,120 @@
|
||||
// src/controllers/subscription.controller.ts
|
||||
import {
|
||||
Controller,
|
||||
Post,
|
||||
Get,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
Headers,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { MockDataService } from '../services/mock-data.service';
|
||||
|
||||
@Controller('payment/mea/v1')
|
||||
export class SubscriptionController {
|
||||
constructor(private mockData: MockDataService) {}
|
||||
|
||||
@Post('digipay_sub/productOrder')
|
||||
createSubscription(
|
||||
@Headers('x-orange-ise2') ise2: string,
|
||||
@Headers('x-orange-mco') mco: string,
|
||||
@Body() body: any,
|
||||
) {
|
||||
console.log('[MOCK] Création subscription:', { ise2, mco, body });
|
||||
|
||||
// Validation
|
||||
if (!ise2 || !mco) {
|
||||
throw new HttpException(
|
||||
{
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: '2001',
|
||||
text: 'Missing required headers',
|
||||
},
|
||||
},
|
||||
},
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
|
||||
// Simuler une souscription existante (10% de chance)
|
||||
if (Math.random() < 0.1) {
|
||||
throw new HttpException(
|
||||
{
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: '3010',
|
||||
text: 'The subscription already exists',
|
||||
},
|
||||
},
|
||||
},
|
||||
HttpStatus.CONFLICT,
|
||||
);
|
||||
}
|
||||
|
||||
const subscription = this.mockData.createSubscription(body);
|
||||
|
||||
// Simuler l'envoi d'une notification webhook (avec délai)
|
||||
setTimeout(() => {
|
||||
this.sendSubscriptionNotification(subscription, 'orderCreation');
|
||||
}, 2000);
|
||||
|
||||
return subscription;
|
||||
}
|
||||
|
||||
@Get('digipay_sub/productOrder/:id')
|
||||
getSubscription(@Param('id') id: string) {
|
||||
const subscription = this.mockData.getSubscription(id);
|
||||
|
||||
if (!subscription) {
|
||||
throw new HttpException(
|
||||
{
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: '3011',
|
||||
text: 'Subscription not found',
|
||||
},
|
||||
},
|
||||
},
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return subscription;
|
||||
}
|
||||
|
||||
@Delete('digipay_sub/productOrder/:id')
|
||||
deleteSubscription(@Param('id') id: string) {
|
||||
const deleted = this.mockData.deleteSubscription(id);
|
||||
|
||||
if (!deleted) {
|
||||
throw new HttpException(
|
||||
{
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: '3011',
|
||||
text: 'Subscription not found',
|
||||
},
|
||||
},
|
||||
},
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
// Simuler notification de désinscription
|
||||
setTimeout(() => {
|
||||
this.sendSubscriptionNotification({ id }, 'orderDeletion');
|
||||
}, 1000);
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private sendSubscriptionNotification(subscription: any, eventType: string) {
|
||||
console.log(
|
||||
`[MOCK] Notification ${eventType} pour subscription ${subscription.id}`,
|
||||
);
|
||||
// Dans un vrai mock, vous pourriez faire un HTTP POST vers l'URL de callback
|
||||
}
|
||||
}
|
||||
0
src/data/mock-database.ts
Normal file
0
src/data/mock-database.ts
Normal file
18
src/main.ts
Normal file
18
src/main.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
// ⚡ Config Swagger
|
||||
const config = new DocumentBuilder()
|
||||
.setTitle('API DCB / SMS / Payment')
|
||||
.setDescription('Documentation des endpoints mock Orange DCB')
|
||||
.setVersion('1.0')
|
||||
.addBearerAuth() // si tu veux tester avec un token
|
||||
.build();
|
||||
const document = SwaggerModule.createDocument(app, config);
|
||||
SwaggerModule.setup('api-docs', app, document);
|
||||
await app.listen(process.env.PORT ?? 3000);
|
||||
}
|
||||
bootstrap();
|
||||
50
src/middleware/auth.middleware.ts
Normal file
50
src/middleware/auth.middleware.ts
Normal file
@ -0,0 +1,50 @@
|
||||
// src/middleware/auth.middleware.ts
|
||||
import {
|
||||
Injectable,
|
||||
NestMiddleware,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { TokenService } from '../services/token.service';
|
||||
|
||||
@Injectable()
|
||||
export class AuthMiddleware implements NestMiddleware {
|
||||
constructor(private tokenService: TokenService) {}
|
||||
|
||||
use(req: Request, res: Response, next: NextFunction) {
|
||||
const authHeader = req.headers['authorization'];
|
||||
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
throw new HttpException(
|
||||
{
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: '401',
|
||||
text: 'Missing or invalid authorization header',
|
||||
},
|
||||
},
|
||||
},
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
|
||||
const token = authHeader.substring(7);
|
||||
|
||||
if (!this.tokenService.validateToken(token)) {
|
||||
throw new HttpException(
|
||||
{
|
||||
requestError: {
|
||||
serviceException: {
|
||||
messageId: '401',
|
||||
text: 'Invalid or expired token',
|
||||
},
|
||||
},
|
||||
},
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
}
|
||||
157
src/services/mock-data.service.ts
Normal file
157
src/services/mock-data.service.ts
Normal file
@ -0,0 +1,157 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
// src/services/mock-data.service.ts
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
@Injectable()
|
||||
export class MockDataService {
|
||||
private subscriptions = new Map();
|
||||
private transactions = new Map();
|
||||
private otpChallenges = new Map();
|
||||
private userBalances = new Map();
|
||||
|
||||
constructor() {
|
||||
this.initializeMockData();
|
||||
}
|
||||
|
||||
private initializeMockData() {
|
||||
// Initialiser quelques utilisateurs mock
|
||||
this.userBalances.set(
|
||||
'PDKSUB-200-Q82vHq0+F1WozTeNS/1wBfuULco05YBaeL4yPtJ8ktU=',
|
||||
{
|
||||
balance: 10000,
|
||||
currency: 'CDF',
|
||||
type: 'prepaid',
|
||||
},
|
||||
);
|
||||
|
||||
this.userBalances.set(
|
||||
'PDKSUB-200-8Ow1iM0hLPZ+LGZ8j4uwEdQxY1hm4mVwrzTdWiUnuI=',
|
||||
{
|
||||
balance: 5000,
|
||||
currency: 'TND',
|
||||
type: 'prepaid',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Génération d'ISE2 mock
|
||||
generateISE2(msisdn: string, country: string): string {
|
||||
const base = `PDKSUB-200-`;
|
||||
const hash = Buffer.from(`${msisdn}-${country}-${Date.now()}`).toString(
|
||||
'base64',
|
||||
);
|
||||
return base + hash.substring(0, 40);
|
||||
}
|
||||
|
||||
// Créer une souscription
|
||||
createSubscription(data: any): any {
|
||||
const subscriptionId = uuidv4();
|
||||
const subscription = {
|
||||
id: subscriptionId,
|
||||
state: 'Completed',
|
||||
orderDate: new Date().toISOString(),
|
||||
...data,
|
||||
};
|
||||
|
||||
this.subscriptions.set(subscriptionId, subscription);
|
||||
return subscription;
|
||||
}
|
||||
|
||||
// Récupérer une souscription
|
||||
getSubscription(id: string): any {
|
||||
return this.subscriptions.get(id);
|
||||
}
|
||||
|
||||
// Supprimer une souscription
|
||||
deleteSubscription(id: string): boolean {
|
||||
return this.subscriptions.delete(id);
|
||||
}
|
||||
|
||||
// Créer une transaction de paiement
|
||||
createTransaction(data: any): any {
|
||||
const transactionId = uuidv4();
|
||||
const userBalance = this.getUserBalance(data.endUserId);
|
||||
|
||||
if (userBalance && userBalance.balance >= data.amount) {
|
||||
// Déduire le montant
|
||||
userBalance.balance -= data.amount;
|
||||
|
||||
const transaction = {
|
||||
serverReferenceCode: transactionId,
|
||||
transactionOperationStatus: 'Charged',
|
||||
...data,
|
||||
};
|
||||
|
||||
this.transactions.set(transactionId, transaction);
|
||||
return { success: true, transaction };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'POL1000',
|
||||
message: 'User has insufficient credit for transaction',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Créer un challenge OTP
|
||||
createOtpChallenge(msisdn: string, country: string): any {
|
||||
const challengeId = uuidv4();
|
||||
const otp = Math.floor(1000 + Math.random() * 9000).toString();
|
||||
|
||||
const challenge = {
|
||||
id: challengeId,
|
||||
msisdn,
|
||||
country,
|
||||
otp,
|
||||
createdAt: Date.now(),
|
||||
attempts: 0,
|
||||
};
|
||||
|
||||
this.otpChallenges.set(challengeId, challenge);
|
||||
|
||||
console.log(`[MOCK] OTP généré pour ${msisdn}: ${otp}`);
|
||||
|
||||
return challengeId;
|
||||
}
|
||||
|
||||
// Valider un OTP
|
||||
validateOtp(challengeId: string, inputOtp: string): any {
|
||||
const challenge = this.otpChallenges.get(challengeId);
|
||||
|
||||
if (!challenge) {
|
||||
return { success: false, error: 'Challenge not found' };
|
||||
}
|
||||
|
||||
challenge.attempts++;
|
||||
|
||||
if (challenge.attempts > 3) {
|
||||
return { success: false, error: 'Too many retries' };
|
||||
}
|
||||
|
||||
if (Date.now() - challenge.createdAt > 300000) {
|
||||
// 5 minutes
|
||||
return { success: false, error: 'OTP expired' };
|
||||
}
|
||||
|
||||
if (challenge.otp === inputOtp) {
|
||||
const ise2 = this.generateISE2(challenge.msisdn, challenge.country);
|
||||
this.otpChallenges.delete(challengeId);
|
||||
return { success: true, ise2 };
|
||||
}
|
||||
|
||||
return { success: false, error: 'Invalid OTP' };
|
||||
}
|
||||
|
||||
getUserBalance(ise2: string): any {
|
||||
return (
|
||||
this.userBalances.get(ise2) || {
|
||||
balance: 1000,
|
||||
currency: 'XOF',
|
||||
type: 'prepaid',
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
37
src/services/token.service.ts
Normal file
37
src/services/token.service.ts
Normal file
@ -0,0 +1,37 @@
|
||||
// src/services/token.service.ts
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
@Injectable()
|
||||
export class TokenService {
|
||||
private tokens = new Map<string, { createdAt: number; expiresIn: number }>();
|
||||
|
||||
generateToken(): string {
|
||||
const token = crypto.randomBytes(32).toString('hex');
|
||||
this.tokens.set(token, {
|
||||
createdAt: Date.now(),
|
||||
expiresIn: 3600000, // 1 heure
|
||||
});
|
||||
return token;
|
||||
}
|
||||
|
||||
validateToken(token: string): boolean {
|
||||
const tokenData = this.tokens.get(token);
|
||||
|
||||
if (!tokenData) {
|
||||
// Pour le mock, accepter certains tokens de test
|
||||
if (token === 'test-token-valid') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
if (now - tokenData.createdAt > tokenData.expiresIn) {
|
||||
this.tokens.delete(token);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
25
test/app.e2e-spec.ts
Normal file
25
test/app.e2e-spec.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import * as request from 'supertest';
|
||||
import { App } from 'supertest/types';
|
||||
import { AppModule } from './../src/app.module';
|
||||
|
||||
describe('AppController (e2e)', () => {
|
||||
let app: INestApplication<App>;
|
||||
|
||||
beforeEach(async () => {
|
||||
const moduleFixture: TestingModule = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = moduleFixture.createNestApplication();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it('/ (GET)', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/')
|
||||
.expect(200)
|
||||
.expect('Hello World!');
|
||||
});
|
||||
});
|
||||
9
test/jest-e2e.json
Normal file
9
test/jest-e2e.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"moduleFileExtensions": ["js", "json", "ts"],
|
||||
"rootDir": ".",
|
||||
"testEnvironment": "node",
|
||||
"testRegex": ".e2e-spec.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
}
|
||||
}
|
||||
122
test/test-integration.ts
Normal file
122
test/test-integration.ts
Normal file
@ -0,0 +1,122 @@
|
||||
// test-integration.ts
|
||||
import axios from 'axios';
|
||||
|
||||
const BASE_URL = 'http://localhost:3000';
|
||||
let accessToken = '';
|
||||
|
||||
async function testOAuth() {
|
||||
console.log('1. Test OAuth Token Generation...');
|
||||
const response = await axios.post(`${BASE_URL}/oauth/v3/token`,
|
||||
'grant_type=client_credentials',
|
||||
{
|
||||
headers: {
|
||||
'Authorization': 'Basic ' + Buffer.from('clientId:clientSecret').toString('base64'),
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
accessToken = response.data.access_token;
|
||||
console.log('✅ Token obtenu:', accessToken);
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
async function testSubscription() {
|
||||
console.log('\n2. Test Subscription...');
|
||||
const response = await axios.post(
|
||||
`${BASE_URL}/payment/mea/v1/digipay_sub/productOrder`,
|
||||
{
|
||||
note: { text: 'test data' },
|
||||
relatedPublicKey: {
|
||||
id: 'PDKSUB-200-test123',
|
||||
name: 'ISE2',
|
||||
},
|
||||
relatedParty: [
|
||||
{
|
||||
id: 'TESTPARTNER',
|
||||
name: 'Test Partner',
|
||||
role: 'partner'
|
||||
},
|
||||
{
|
||||
id: 'TESTRETAILER',
|
||||
name: 'Test Retailer',
|
||||
role: 'retailer'
|
||||
}
|
||||
],
|
||||
orderItem: {
|
||||
action: 'add',
|
||||
state: 'Completed',
|
||||
product: {
|
||||
id: 'TEST_PRODUCT',
|
||||
productCharacteristic: [
|
||||
{ name: 'amount', value: '100.0' },
|
||||
{ name: 'currency', value: 'XOF' },
|
||||
{ name: 'periodicity', value: '86400' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'X-Orange-ISE2': 'PDKSUB-200-test123',
|
||||
'X-Orange-MCO': 'OCI',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
console.log('✅ Subscription créée:', response.data.id);
|
||||
return response.data.id;
|
||||
}
|
||||
|
||||
async function testCharge() {
|
||||
console.log('\n3. Test Charge...');
|
||||
const response = await axios.post(
|
||||
`${BASE_URL}/payment/mea/v1/acr:X-Orange-ISE2/transactions/amount`,
|
||||
{
|
||||
amountTransaction: {
|
||||
endUserId: 'acr:X-Orange-ISE2',
|
||||
paymentAmount: {
|
||||
chargingInformation: {
|
||||
amount: '10.0',
|
||||
currency: 'XOF',
|
||||
description: 'Test charge'
|
||||
},
|
||||
chargingMetaData: {
|
||||
onBehalfOf: 'TESTRETAILER',
|
||||
purchaseCategoryCode: 'VOD',
|
||||
serviceId: 'TEST_SERVICE'
|
||||
}
|
||||
},
|
||||
transactionOperationStatus: 'Charged',
|
||||
referenceCode: 'ref123',
|
||||
clientCorrelator: 'corr123'
|
||||
}
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'X-Orange-ISE2': 'PDKSUB-200-Q82vHq0+F1WozTeNS/1wBfuULco05YBaeL4yPtJ8ktU=',
|
||||
'X-Orange-MCO': 'OCI',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
console.log('✅ Charge effectuée:', response.data.amountTransaction.serverReferenceCode);
|
||||
}
|
||||
|
||||
// Exécuter les tests
|
||||
async function runTests() {
|
||||
try {
|
||||
await testOAuth();
|
||||
const subscriptionId = await testSubscription();
|
||||
await testCharge();
|
||||
console.log('\n✅ Tous les tests sont passés!');
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
runTests();
|
||||
4
tsconfig.build.json
Normal file
4
tsconfig.build.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||
}
|
||||
21
tsconfig.json
Normal file
21
tsconfig.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "ES2021",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitAny": false,
|
||||
"strictBindCallApply": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user