Merge Dev in Staging
This commit is contained in:
commit
1cbb2f3ec6
1
.gitignore
vendored
1
.gitignore
vendored
@ -51,3 +51,4 @@ cabal.project.local~
|
|||||||
.HTF/
|
.HTF/
|
||||||
.ghc.environment.*
|
.ghc.environment.*
|
||||||
id_rsa
|
id_rsa
|
||||||
|
.cache
|
||||||
|
9
.puppeteerrc.cjs
Normal file
9
.puppeteerrc.cjs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const {join} = require('path');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import("puppeteer").Configuration}
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
// Changes the cache location for Puppeteer.
|
||||||
|
cacheDirectory: join(__dirname, '.cache', 'puppeteer'),
|
||||||
|
};
|
6985
package-lock.json
generated
6985
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -59,10 +59,9 @@
|
|||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"next": "^13.1.5",
|
"next": "^13.1.5",
|
||||||
"node-cache": "^5.1.2",
|
"node-cache": "^5.1.2",
|
||||||
"node-fetch": "^2.6.11",
|
|
||||||
"node-schedule": "^2.1.1",
|
"node-schedule": "^2.1.1",
|
||||||
"prisma-query": "^2.0.0",
|
"prisma-query": "^2.0.0",
|
||||||
"puppeteer": "^21.3.2",
|
"puppeteer": "^21.3.4",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
@ -81,11 +80,11 @@
|
|||||||
"@types/module-alias": "^2.0.1",
|
"@types/module-alias": "^2.0.1",
|
||||||
"@types/multer": "^1.4.7",
|
"@types/multer": "^1.4.7",
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.11.18",
|
||||||
"@types/node-fetch": "^2.6.3",
|
|
||||||
"@types/node-schedule": "^2.1.0",
|
"@types/node-schedule": "^2.1.0",
|
||||||
"@types/uuid": "^9.0.0",
|
"@types/uuid": "^9.0.0",
|
||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
"jest": "^29.5.0",
|
"jest": "^29.5.0",
|
||||||
|
"node-fetch": "^3.3.2",
|
||||||
"nodemon": "^2.0.20",
|
"nodemon": "^2.0.20",
|
||||||
"prettier": "2.8.4",
|
"prettier": "2.8.4",
|
||||||
"prisma": "^4.11.0",
|
"prisma": "^4.11.0",
|
||||||
|
@ -4,6 +4,7 @@ import ApiController from "@Common/system/controller-pattern/ApiController";
|
|||||||
import { Service } from "typedi";
|
import { Service } from "typedi";
|
||||||
import UserNotification from "le-coffre-resources/dist/Notary/UserNotification";
|
import UserNotification from "le-coffre-resources/dist/Notary/UserNotification";
|
||||||
import UserNotificationService from "@Services/common/UserNotificationService/UserNotificationService";
|
import UserNotificationService from "@Services/common/UserNotificationService/UserNotificationService";
|
||||||
|
import authHandler from "@App/middlewares/AuthHandler";
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
@Service()
|
@Service()
|
||||||
@ -15,15 +16,21 @@ export default class UserNotificationController extends ApiController {
|
|||||||
/**
|
/**
|
||||||
* @description Get all customers
|
* @description Get all customers
|
||||||
*/
|
*/
|
||||||
@Get("/api/v1/notifications")
|
@Get("/api/v1/notifications", [authHandler])
|
||||||
protected async get(req: Request, response: Response) {
|
protected async get(req: Request, response: Response) {
|
||||||
try {
|
try {
|
||||||
//get query
|
//get query
|
||||||
let query;
|
let query: any = {};
|
||||||
if (req.query["q"]) {
|
if (req.query["q"]) {
|
||||||
query = JSON.parse(req.query["q"] as string);
|
query = JSON.parse(req.query["q"] as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (query.where) {
|
||||||
|
query.where = { ...query.where, user: { uid: req.body.user.uid } };
|
||||||
|
} else {
|
||||||
|
query.where = { user: { uid: req.body.user.uid } };
|
||||||
|
}
|
||||||
|
query.include = { notification: true };
|
||||||
//call service to get prisma entity
|
//call service to get prisma entity
|
||||||
const userNotificationEntities = await this.userNotificationService.get(query);
|
const userNotificationEntities = await this.userNotificationService.get(query);
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { Response, Request } from "express";
|
|||||||
import { Controller, Post } from "@ControllerPattern/index";
|
import { Controller, Post } from "@ControllerPattern/index";
|
||||||
import ApiController from "@Common/system/controller-pattern/ApiController";
|
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||||
import { Service } from "typedi";
|
import { Service } from "typedi";
|
||||||
import AuthService from "@Services/common/AuthService/AuthService";
|
import AuthService, { ICustomerJwtPayload } from "@Services/common/AuthService/AuthService";
|
||||||
import { JwtPayload } from "jsonwebtoken";
|
import { JwtPayload } from "jsonwebtoken";
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
@ -12,22 +12,26 @@ export default class CustomerController extends ApiController {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post("/api/v1/france-connect/customer/login/:email")
|
// @Post("/api/v1/france-connect/customer/login/:email")
|
||||||
protected async login(req: Request, response: Response) {
|
// protected async login(req: Request, response: Response) {
|
||||||
try {
|
// try {
|
||||||
const email = req.params["email"];
|
// const email = req.params["email"];
|
||||||
if (!email) throw new Error("email is required");
|
// if (!email) throw new Error("email is required");
|
||||||
|
|
||||||
const payload = await this.authService.getCustomerJwtPayload(email);
|
// const payload = await this.authService.getCustomerJwtPayload(email);
|
||||||
const accessToken = this.authService.generateAccessToken(payload);
|
// if (!payload) {
|
||||||
const refreshToken = this.authService.generateRefreshToken(payload);
|
// this.httpNotFoundRequest(response);
|
||||||
//success
|
// return;
|
||||||
this.httpSuccess(response, { accessToken, refreshToken });
|
// }
|
||||||
} catch (error) {
|
// const accessToken = this.authService.generateAccessToken(payload);
|
||||||
this.httpInternalError(response);
|
// const refreshToken = this.authService.generateRefreshToken(payload);
|
||||||
return;
|
// //success
|
||||||
}
|
// this.httpSuccess(response, { accessToken, refreshToken });
|
||||||
}
|
// } catch (error) {
|
||||||
|
// this.httpInternalError(response);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@Post("/api/v1/france-connect/customer/refresh-token")
|
@Post("/api/v1/france-connect/customer/refresh-token")
|
||||||
protected async refreshToken(req: Request, response: Response) {
|
protected async refreshToken(req: Request, response: Response) {
|
||||||
@ -50,7 +54,7 @@ export default class CustomerController extends ApiController {
|
|||||||
const customer = customerPayload as JwtPayload;
|
const customer = customerPayload as JwtPayload;
|
||||||
delete customer.iat;
|
delete customer.iat;
|
||||||
delete customer!.exp;
|
delete customer!.exp;
|
||||||
accessToken = this.authService.generateAccessToken(customer);
|
accessToken = this.authService.generateAccessToken({...customer} as ICustomerJwtPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
//success
|
//success
|
||||||
|
90
src/app/api/id360/CustomerController.ts
Normal file
90
src/app/api/id360/CustomerController.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { Response, Request } from "express";
|
||||||
|
import { Controller, Post } from "@ControllerPattern/index";
|
||||||
|
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
import Id360Service from "@Services/common/Id360Service/Id360Service";
|
||||||
|
import CustomersService from "@Services/customer/CustomersService/CustomersService";
|
||||||
|
import AuthService from "@Services/common/AuthService/AuthService";
|
||||||
|
import { Customer } from "le-coffre-resources/dist/SuperAdmin";
|
||||||
|
|
||||||
|
@Controller()
|
||||||
|
@Service()
|
||||||
|
export default class CustomerController extends ApiController {
|
||||||
|
constructor(private id360Service: Id360Service, private customerService: CustomersService, private authService: AuthService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post("/api/v1/id360/customers/login")
|
||||||
|
protected async login(req: Request, response: Response) {
|
||||||
|
try {
|
||||||
|
const enrollment = await this.id360Service.createFranceConnectEnrollment();
|
||||||
|
this.httpSuccess(response, { enrollment });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
this.httpInternalError(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post("/api/v1/id360/customers/login-callback/:callbackToken")
|
||||||
|
protected async loginCallback(req: Request, response: Response) {
|
||||||
|
const callbackToken = req.params["callbackToken"];
|
||||||
|
if (!callbackToken) {
|
||||||
|
this.httpBadRequest(response, "callback Token is required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const enrollment = await this.id360Service.getEnrollment(callbackToken);
|
||||||
|
console.log("enrollment", enrollment);
|
||||||
|
if (enrollment.status !== "OK") {
|
||||||
|
this.httpUnauthorized(response, "Enrollment status is not OK");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const customerData = await this.id360Service.getReport(enrollment.id);
|
||||||
|
console.log(customerData.external_methods.france_connect.results);
|
||||||
|
const customer = await this.customerService.get({
|
||||||
|
where: {
|
||||||
|
contact: {
|
||||||
|
last_name: { contains: customerData.external_methods.france_connect.results.france_connect_out_userinfo[0].family_name,
|
||||||
|
mode: 'insensitive' },
|
||||||
|
first_name: { contains: customerData.external_methods.france_connect.results.france_connect_out_userinfo[0].given_name.split(" ")[0],
|
||||||
|
mode: 'insensitive'},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
contact: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(customer);
|
||||||
|
// const contact = await this.customerService.getByEmail(
|
||||||
|
// customerData.external_methods.france_connect.results.france_connect_out_userinfo[0].email,
|
||||||
|
// );
|
||||||
|
if (customer.length === 0) {
|
||||||
|
this.httpNotFoundRequest(response, "Customer not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const customersHydrated = Customer.hydrateArray<Customer>(customer);
|
||||||
|
const payload = await this.authService.getCustomerJwtPayload(customersHydrated[0]!);
|
||||||
|
const accessToken = this.authService.generateAccessToken(payload);
|
||||||
|
const refreshToken = this.authService.generateRefreshToken(payload);
|
||||||
|
this.httpSuccess(response, { accessToken, refreshToken });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
this.httpInternalError(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post("/api/v1/id360/token")
|
||||||
|
protected async getToken(req: Request, response: Response) {
|
||||||
|
try {
|
||||||
|
const token = await this.id360Service.getId360Token();
|
||||||
|
this.httpSuccess(response, { token });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
this.httpInternalError(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
src/app/api/id360/DocumentController.ts
Normal file
65
src/app/api/id360/DocumentController.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { Response, Request } from "express";
|
||||||
|
import { Controller, Post } from "@ControllerPattern/index";
|
||||||
|
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
import Id360Service from "@Services/common/Id360Service/Id360Service";
|
||||||
|
|
||||||
|
@Controller()
|
||||||
|
@Service()
|
||||||
|
export default class DocumentController extends ApiController {
|
||||||
|
constructor(private id360Service: Id360Service) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Get customer created from ID360 authentification
|
||||||
|
* @todo Used for test, should be removed
|
||||||
|
* @returns User
|
||||||
|
*/
|
||||||
|
@Post("/api/v1/id360/enrollment-callback/")
|
||||||
|
protected async getDocumentVerificationFromId360(req: Request, response: Response) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log("document callback", req, response)
|
||||||
|
this.httpSuccess(response);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
this.httpInternalError(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post("/api/v1/id360/customer-callback/")
|
||||||
|
protected async getCustomerVerificationFromId360(req: Request, response: Response) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log("customer callback", req, response)
|
||||||
|
this.httpSuccess(response);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
this.httpInternalError(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post("/api/v1/id360/enrollment/:documentId")
|
||||||
|
protected async createEnrollment(req: Request, response: Response) {
|
||||||
|
try {
|
||||||
|
const documentId = req.params["documentId"];
|
||||||
|
if (!documentId) {
|
||||||
|
this.httpBadRequest(response, "Missing document id");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const enrl = await this.id360Service.createEnrollment(documentId!);
|
||||||
|
console.log(enrl)
|
||||||
|
|
||||||
|
//success
|
||||||
|
this.httpSuccess(response);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
this.httpInternalError(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,7 @@ import { Response, Request } from "express";
|
|||||||
import { Controller, Post } from "@ControllerPattern/index";
|
import { Controller, Post } from "@ControllerPattern/index";
|
||||||
import ApiController from "@Common/system/controller-pattern/ApiController";
|
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||||
import { Service } from "typedi";
|
import { Service } from "typedi";
|
||||||
import AuthService from "@Services/common/AuthService/AuthService";
|
import AuthService, { IUserJwtPayload } from "@Services/common/AuthService/AuthService";
|
||||||
import { JwtPayload } from "jsonwebtoken";
|
|
||||||
|
|
||||||
import IdNotService from "@Services/common/IdNotService/IdNotService";
|
import IdNotService from "@Services/common/IdNotService/IdNotService";
|
||||||
|
|
||||||
@ -54,6 +53,10 @@ export default class UserController extends ApiController {
|
|||||||
if (!id) throw new Error("idnot is required");
|
if (!id) throw new Error("idnot is required");
|
||||||
|
|
||||||
const payload = await this.authService.getUserJwtPayload(id);
|
const payload = await this.authService.getUserJwtPayload(id);
|
||||||
|
if (!payload) {
|
||||||
|
this.httpNotFoundRequest(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const accessToken = this.authService.generateAccessToken(payload);
|
const accessToken = this.authService.generateAccessToken(payload);
|
||||||
const refreshToken = this.authService.generateRefreshToken(payload);
|
const refreshToken = this.authService.generateRefreshToken(payload);
|
||||||
|
|
||||||
@ -85,9 +88,7 @@ export default class UserController extends ApiController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = userPayload as JwtPayload;
|
const user = userPayload as IUserJwtPayload;
|
||||||
delete user.iat;
|
|
||||||
delete user!.exp;
|
|
||||||
accessToken = this.authService.generateAccessToken(user);
|
accessToken = this.authService.generateAccessToken(user);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -46,6 +46,8 @@ import CustomersController from "./api/customer/CustomersController";
|
|||||||
import AppointmentsController from "./api/super-admin/AppointmentsController";
|
import AppointmentsController from "./api/super-admin/AppointmentsController";
|
||||||
import VotesController from "./api/super-admin/VotesController";
|
import VotesController from "./api/super-admin/VotesController";
|
||||||
import LiveVoteController from "./api/super-admin/LiveVoteController";
|
import LiveVoteController from "./api/super-admin/LiveVoteController";
|
||||||
|
import DocumentControllerId360 from "./api/id360/DocumentController";
|
||||||
|
import CustomerControllerId360 from "./api/id360/CustomerController";
|
||||||
|
|
||||||
import UserNotificationController from "./api/common/UserNotificationController";
|
import UserNotificationController from "./api/common/UserNotificationController";
|
||||||
|
|
||||||
@ -105,5 +107,7 @@ export default {
|
|||||||
Container.get(OfficeFolderAnchorsController);
|
Container.get(OfficeFolderAnchorsController);
|
||||||
Container.get(CustomersController);
|
Container.get(CustomersController);
|
||||||
Container.get(UserNotificationController);
|
Container.get(UserNotificationController);
|
||||||
|
Container.get(DocumentControllerId360);
|
||||||
|
Container.get(CustomerControllerId360);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -85,6 +85,30 @@ export class BackendVariables {
|
|||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
public readonly ENV!: string;
|
public readonly ENV!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly DOCAPOST_BASE_URL!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly DOCAPOST_ROOT!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly DOCAPOST_VERSION!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly DOCAPOST_DOCUMENT_PROCESS_ID!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly DOCAPOST_CONNECT_PROCESS_ID!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly BACK_API_HOST!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly DOCAPOST_APP_ID!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly DOCAPOST_APP_PASSWORD!: string;
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
this.DATABASE_PORT = process.env["DATABASE_PORT"]!;
|
this.DATABASE_PORT = process.env["DATABASE_PORT"]!;
|
||||||
@ -114,6 +138,15 @@ export class BackendVariables {
|
|||||||
this.SECURE_API_KEY = process.env["SECURE_API_KEY"]!;
|
this.SECURE_API_KEY = process.env["SECURE_API_KEY"]!;
|
||||||
this.SECURE_API_BASE_URL = process.env["SECURE_API_BASE_URL"]!;
|
this.SECURE_API_BASE_URL = process.env["SECURE_API_BASE_URL"]!;
|
||||||
this.ENV = process.env["ENV"]!;
|
this.ENV = process.env["ENV"]!;
|
||||||
|
this.DOCAPOST_BASE_URL = process.env["DOCAPOST_BASE_URL"]!;
|
||||||
|
this.DOCAPOST_ROOT = process.env["DOCAPOST_ROOT"]!;
|
||||||
|
this.DOCAPOST_VERSION = process.env["DOCAPOST_VERSION"]!;
|
||||||
|
this.DOCAPOST_DOCUMENT_PROCESS_ID = process.env["DOCAPOST_DOCUMENT_PROCESS_ID"]!;
|
||||||
|
this.DOCAPOST_CONNECT_PROCESS_ID = process.env["DOCAPOST_CONNECT_PROCESS_ID"]!;
|
||||||
|
this.BACK_API_HOST = process.env["BACK_API_HOST"]!;
|
||||||
|
this.DOCAPOST_APP_ID = process.env["DOCAPOST_APP_ID"]!;
|
||||||
|
this.DOCAPOST_APP_PASSWORD = process.env["DOCAPOST_APP_PASSWORD"]!;
|
||||||
|
|
||||||
}
|
}
|
||||||
public async validate(groups?: string[]) {
|
public async validate(groups?: string[]) {
|
||||||
const validationOptions = groups ? { groups } : undefined;
|
const validationOptions = groups ? { groups } : undefined;
|
||||||
|
@ -1,24 +1,37 @@
|
|||||||
|
|
||||||
import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService";
|
import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService";
|
||||||
import { Documents } from "@prisma/client";
|
import { Documents } from "@prisma/client";
|
||||||
import User, { Document, Vote } from "le-coffre-resources/dist/SuperAdmin";
|
import User, { Document, OfficeFolder, Vote } from "le-coffre-resources/dist/SuperAdmin";
|
||||||
import { Service } from "typedi";
|
import { Service } from "typedi";
|
||||||
import NotificationsService from "@Services/common/NotificationsService/NotificationsService";
|
import NotificationsService from "@Services/common/NotificationsService/NotificationsService";
|
||||||
import UsersService from "@Services/super-admin/UsersService/UsersService";
|
import UsersService from "@Services/super-admin/UsersService/UsersService";
|
||||||
|
import OfficeFoldersService from "@Services/super-admin/OfficeFoldersService/OfficeFoldersService";
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class NotificationBuilder {
|
export default class NotificationBuilder {
|
||||||
public constructor(private notificationsService : NotificationsService, private documentsService: DocumentsService, private usersService: UsersService){}
|
public constructor(
|
||||||
|
private notificationsService: NotificationsService,
|
||||||
|
private documentsService: DocumentsService,
|
||||||
|
private usersService: UsersService,
|
||||||
|
private foldersService: OfficeFoldersService,
|
||||||
|
) {}
|
||||||
|
|
||||||
public async sendDocumentDepositedNotification(documentEntity: Documents) {
|
public async sendDocumentDepositedNotification(documentEntity: Documents) {
|
||||||
if (documentEntity.document_status !== "DEPOSITED") return;
|
if (documentEntity.document_status !== "DEPOSITED") return;
|
||||||
|
|
||||||
const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, { depositor: {include: {contact: true}}, folder:{include:{ office: true, stakeholders: true}} });
|
const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, {
|
||||||
|
depositor: { include: { contact: true } },
|
||||||
|
folder: { include: { office: true, stakeholders: true } },
|
||||||
|
});
|
||||||
if (!documentPrisma) throw new Error("Document not found");
|
if (!documentPrisma) throw new Error("Document not found");
|
||||||
const document = Document.hydrate<Document>(documentPrisma);
|
const document = Document.hydrate<Document>(documentPrisma);
|
||||||
|
|
||||||
this.notificationsService.create({
|
this.notificationsService.create({
|
||||||
message: "Votre client " + document.depositor?.contact?.first_name + " " + document.depositor?.contact?.last_name + " vous a envoyé un document à valider",
|
message:
|
||||||
|
"Votre client " +
|
||||||
|
document.depositor?.contact?.first_name +
|
||||||
|
" " +
|
||||||
|
document.depositor?.contact?.last_name +
|
||||||
|
" vous a envoyé un document à valider",
|
||||||
redirection_url: "",
|
redirection_url: "",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
@ -27,14 +40,21 @@ export default class NotificationBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async sendDocumentAnchoredNotification(documentEntity: Documents) {
|
public async sendDocumentAnchoredNotification(documentEntity: Documents) {
|
||||||
|
const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, {
|
||||||
const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, { depositor: {include: {contact: true}}, folder:{include:{ folder_anchor : true ,office: true, stakeholders: true}} });
|
depositor: { include: { contact: true } },
|
||||||
|
folder: { include: { folder_anchor: true, office: true, stakeholders: true } },
|
||||||
|
});
|
||||||
if (!documentPrisma) throw new Error("Document not found");
|
if (!documentPrisma) throw new Error("Document not found");
|
||||||
const document = Document.hydrate<Document>(documentPrisma);
|
const document = Document.hydrate<Document>(documentPrisma);
|
||||||
if (document.folder?.anchor?.status !== "VERIFIED_ON_CHAIN") return;
|
if (document.folder?.anchor?.status !== "VERIFIED_ON_CHAIN") return;
|
||||||
|
|
||||||
this.notificationsService.create({
|
this.notificationsService.create({
|
||||||
message: "Le dossier " + document.folder?.folder_number + " - " + document.folder?.name + " a été certifié. Vous pouvez désormais télécharger le certificat de dépôt pour le mettre dans la GED de votre logiciel de rédaction d'acte.",
|
message:
|
||||||
|
"Le dossier " +
|
||||||
|
document.folder?.folder_number +
|
||||||
|
" - " +
|
||||||
|
document.folder?.name +
|
||||||
|
" a été certifié. Vous pouvez désormais télécharger le certificat de dépôt pour le mettre dans la GED de votre logiciel de rédaction d'acte.",
|
||||||
redirection_url: "",
|
redirection_url: "",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
@ -47,10 +67,15 @@ export default class NotificationBuilder {
|
|||||||
const superAdminList = await this.usersService.get({ where: { role: { label: "super-admin" } } });
|
const superAdminList = await this.usersService.get({ where: { role: { label: "super-admin" } } });
|
||||||
let message = "";
|
let message = "";
|
||||||
if (vote.appointment.choice === "NOMINATE") {
|
if (vote.appointment.choice === "NOMINATE") {
|
||||||
message = "Un collaborateur souhaite attribuer le titre de Super Administrateur à " + vote.appointment.targeted_user + ". Cliquez ici pour voter."
|
message =
|
||||||
}
|
"Un collaborateur souhaite attribuer le titre de Super Administrateur à " +
|
||||||
else if(vote.appointment.choice === "DISMISS"){
|
vote.appointment.targeted_user +
|
||||||
message = "Un collaborateur souhaite retirer le titre de Super Administrateur à " + vote.appointment.targeted_user + ". Cliquez ici pour voter."
|
". Cliquez ici pour voter.";
|
||||||
|
} else if (vote.appointment.choice === "DISMISS") {
|
||||||
|
message =
|
||||||
|
"Un collaborateur souhaite retirer le titre de Super Administrateur à " +
|
||||||
|
vote.appointment.targeted_user +
|
||||||
|
". Cliquez ici pour voter.";
|
||||||
}
|
}
|
||||||
|
|
||||||
this.notificationsService.create({
|
this.notificationsService.create({
|
||||||
@ -82,4 +107,34 @@ export default class NotificationBuilder {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async sendDocumentExpiringSoonNotification(folderUid: string, expirationDate: Date) {
|
||||||
|
const day = expirationDate.getDate();
|
||||||
|
const month = expirationDate.getMonth() + 1; // Months are 0-based, so add 1
|
||||||
|
const year = expirationDate.getFullYear();
|
||||||
|
|
||||||
|
// Ensure that the day and month have two digits (e.g., 01, 02, 11)
|
||||||
|
const formattedDay = day < 10 ? `0${day}` : `${day}`;
|
||||||
|
const formattedMonth = month < 10 ? `0${month}` : `${month}`;
|
||||||
|
|
||||||
|
const formattedDate = `${formattedDay}/${formattedMonth}/${year}`;
|
||||||
|
|
||||||
|
const folderPrisma = await this.foldersService.getByUid(folderUid, { stakeholders: true, office: true });
|
||||||
|
if (!folderPrisma) throw new Error("Document not found");
|
||||||
|
const folder = OfficeFolder.hydrate<OfficeFolder>(folderPrisma);
|
||||||
|
|
||||||
|
this.notificationsService.create({
|
||||||
|
message:
|
||||||
|
"Vous devez valider le dossier " +
|
||||||
|
folder.folder_number +
|
||||||
|
" - " +
|
||||||
|
folder.name +
|
||||||
|
" avant le " +
|
||||||
|
formattedDate +
|
||||||
|
" (date limite d'expiration des documents).",
|
||||||
|
redirection_url: "",
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
user: folder.stakeholders || [],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,4 +147,16 @@ export default class DocumentsRepository extends BaseRepository {
|
|||||||
include: { folder: { include: { office: true } }, document_type: { include: { office: true } } },
|
include: { folder: { include: { office: true } }, document_type: { include: { office: true } } },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Find unique document with relations
|
||||||
|
*/
|
||||||
|
public async findOneByUidWithFiles(uid: string) {
|
||||||
|
return this.model.findUnique({
|
||||||
|
where: {
|
||||||
|
uid: uid,
|
||||||
|
},
|
||||||
|
include: { files: true },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import CronService from "@Services/common/CronService/CronService";
|
|||||||
const variables = await Container.get(BackendVariables).validate();
|
const variables = await Container.get(BackendVariables).validate();
|
||||||
Container.get(CronService).archiveFiles();
|
Container.get(CronService).archiveFiles();
|
||||||
await Container.get(CronService).updateUsers();
|
await Container.get(CronService).updateUsers();
|
||||||
|
Container.get(CronService).checkDocumentsExpiration();
|
||||||
if(variables.ENV !== "dev"){
|
if(variables.ENV !== "dev"){
|
||||||
Container.get(CronService).sendMails();
|
Container.get(CronService).sendMails();
|
||||||
Container.get(CronService).sendRecapMails();
|
Container.get(CronService).sendRecapMails();
|
||||||
|
@ -71,7 +71,10 @@ export default class AnchoringProofService extends BaseService {
|
|||||||
* @description : Generate a PDF file from a SVG template from anchoring proof data
|
* @description : Generate a PDF file from a SVG template from anchoring proof data
|
||||||
*/
|
*/
|
||||||
public async generate(data: AnchoringProofData): Promise<Buffer> {
|
public async generate(data: AnchoringProofData): Promise<Buffer> {
|
||||||
const browser = await puppeteer.launch();
|
const browser = await puppeteer.launch({
|
||||||
|
headless: "new",
|
||||||
|
args: ["--no-sandbox", "--disable-setuid-sandbox"],
|
||||||
|
});
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
|
|
||||||
var htmlContent = `
|
var htmlContent = `
|
||||||
|
@ -4,14 +4,14 @@ import { BackendVariables } from "@Common/config/variables/Variables";
|
|||||||
import { Service } from "typedi";
|
import { Service } from "typedi";
|
||||||
import UsersService from "@Services/super-admin/UsersService/UsersService";
|
import UsersService from "@Services/super-admin/UsersService/UsersService";
|
||||||
import CustomersService from "@Services/super-admin/CustomersService/CustomersService";
|
import CustomersService from "@Services/super-admin/CustomersService/CustomersService";
|
||||||
import ContactService from "../ContactService";
|
|
||||||
import { ECustomerStatus } from "@prisma/client";
|
import { ECustomerStatus } from "@prisma/client";
|
||||||
|
import { Customer } from "le-coffre-resources/dist/Notary";
|
||||||
|
|
||||||
enum PROVIDER_OPENID {
|
enum PROVIDER_OPENID {
|
||||||
idNot = "idNot",
|
idNot = "idNot",
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ICustomerJwtPayload {
|
export interface ICustomerJwtPayload {
|
||||||
customerId: string;
|
customerId: string;
|
||||||
email: string;
|
email: string;
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@ export interface IdNotJwtPayload {
|
|||||||
entity_idn: string,
|
entity_idn: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IUserJwtPayload {
|
export interface IUserJwtPayload {
|
||||||
userId: string;
|
userId: string;
|
||||||
openId: {
|
openId: {
|
||||||
providerName: PROVIDER_OPENID;
|
providerName: PROVIDER_OPENID;
|
||||||
@ -35,24 +35,18 @@ interface IUserJwtPayload {
|
|||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class AuthService extends BaseService {
|
export default class AuthService extends BaseService {
|
||||||
constructor(protected variables: BackendVariables, private userService: UsersService, private customerService: CustomersService, private contactService: ContactService) {
|
constructor(protected variables: BackendVariables, private userService: UsersService, private customerService: CustomersService) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getCustomerJwtPayload(email:string): Promise<ICustomerJwtPayload | null> {
|
public async getCustomerJwtPayload(customer: Customer): Promise<ICustomerJwtPayload | null> {
|
||||||
const contact = await this.contactService.getByEmail(email);
|
|
||||||
if (!contact) return null;
|
|
||||||
const customer = await this.customerService.getByUid(contact.customers!.uid, { contact: true });
|
|
||||||
if (!customer) return null;
|
|
||||||
|
|
||||||
if(customer.status === ECustomerStatus["PENDING"]) {
|
if(customer.status === ECustomerStatus["PENDING"]) {
|
||||||
customer.status = ECustomerStatus["VALIDATED"];
|
customer.status = ECustomerStatus["VALIDATED"];
|
||||||
this.customerService.update(customer.uid, customer);
|
this.customerService.update(customer.uid!, customer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
customerId: customer.uid,
|
customerId: customer.uid!,
|
||||||
email: contact.email,
|
email: customer.contact!.email,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,14 +3,22 @@ import { CronJob } from "cron";
|
|||||||
import MailchimpService from "../MailchimpService/MailchimpService";
|
import MailchimpService from "../MailchimpService/MailchimpService";
|
||||||
import FilesService from "../FilesService/FilesService";
|
import FilesService from "../FilesService/FilesService";
|
||||||
import IdNotService from "../IdNotService/IdNotService";
|
import IdNotService from "../IdNotService/IdNotService";
|
||||||
|
import { PrismaClient } from "@prisma/client";
|
||||||
|
import NotificationBuilder from "@Common/notifications/NotificationBuilder";
|
||||||
|
// import { PrismaClient } from "@prisma/client";
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class CronService {
|
export default class CronService {
|
||||||
constructor(private mailchimpService: MailchimpService, private filesService: FilesService, private idNotService: IdNotService) {}
|
constructor(
|
||||||
|
private mailchimpService: MailchimpService,
|
||||||
|
private filesService: FilesService,
|
||||||
|
private idNotService: IdNotService,
|
||||||
|
private notificationBuilder: NotificationBuilder
|
||||||
|
) {}
|
||||||
|
|
||||||
public async sendMails() {
|
public async sendMails() {
|
||||||
const cronJob = new CronJob("*/15 * * * * *", async () => { // Every 15 seconds
|
const cronJob = new CronJob("*/15 * * * * *", async () => {
|
||||||
|
// Every 15 seconds
|
||||||
try {
|
try {
|
||||||
await this.mailchimpService.sendEmails();
|
await this.mailchimpService.sendEmails();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -25,7 +33,8 @@ export default class CronService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async sendRecapMails() {
|
public async sendRecapMails() {
|
||||||
const cronJob = new CronJob("0 20 * * FRI", async () => { // Every friday at 20:00
|
const cronJob = new CronJob("0 20 * * FRI", async () => {
|
||||||
|
// Every friday at 20:00
|
||||||
try {
|
try {
|
||||||
await this.mailchimpService.sendRecapEmails();
|
await this.mailchimpService.sendRecapEmails();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -40,7 +49,8 @@ export default class CronService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async archiveFiles() {
|
public async archiveFiles() {
|
||||||
const cronJob = new CronJob("0 0 * * MON", async () => { // Every monday at midnight
|
const cronJob = new CronJob("0 0 * * MON", async () => {
|
||||||
|
// Every monday at midnight
|
||||||
try {
|
try {
|
||||||
await this.filesService.archiveOldFiles();
|
await this.filesService.archiveOldFiles();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -54,7 +64,8 @@ export default class CronService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async updateUsers() {
|
public async updateUsers() {
|
||||||
const cronJob = new CronJob("0 0 * * *", async () => { // Once a day at midnight
|
const cronJob = new CronJob("0 0 * * *", async () => {
|
||||||
|
// Once a day at midnight
|
||||||
try {
|
try {
|
||||||
await this.idNotService.updateOffices();
|
await this.idNotService.updateOffices();
|
||||||
await this.idNotService.updateUsers();
|
await this.idNotService.updateUsers();
|
||||||
@ -67,4 +78,33 @@ export default class CronService {
|
|||||||
cronJob.start();
|
cronJob.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async checkDocumentsExpiration() {
|
||||||
|
const cronJob = new CronJob("*/10 * * * * *", async () => {
|
||||||
|
// Once a day at midnight
|
||||||
|
try {
|
||||||
|
const prisma = new PrismaClient();
|
||||||
|
const expiringDocuments15Days: [{uid: string, expiration_date: Date}] = await prisma.$queryRaw
|
||||||
|
`SELECT distinct o.uid, f.created_at as expiration_date
|
||||||
|
FROM documents d
|
||||||
|
JOIN files f ON d.uid=f.document_uid
|
||||||
|
JOIN office_folders o ON o.uid=d.folder_uid
|
||||||
|
WHERE o.folder_anchor_uid IS null
|
||||||
|
AND d.document_status = 'DEPOSITED'
|
||||||
|
AND current_date = (DATE(f.created_at) + interval '3 months' - interval '2 days');`;
|
||||||
|
|
||||||
|
expiringDocuments15Days.forEach(expiringFolder => {
|
||||||
|
this.notificationBuilder.sendDocumentExpiringSoonNotification(expiringFolder.uid, expiringFolder.expiration_date);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Start job
|
||||||
|
if (!cronJob.running) {
|
||||||
|
cronJob.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
272
src/services/common/Id360Service/Id360Service.ts
Normal file
272
src/services/common/Id360Service/Id360Service.ts
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
import BaseService from "@Services/BaseService";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
import { BackendVariables } from "@Common/config/variables/Variables";
|
||||||
|
import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService";
|
||||||
|
import FilesService from "../FilesService/FilesService";
|
||||||
|
|
||||||
|
type EnrollmentResponse = {
|
||||||
|
url: string;
|
||||||
|
id: number;
|
||||||
|
api_key: string;
|
||||||
|
callback_url: string;
|
||||||
|
browser_callback_url: string;
|
||||||
|
client_reference: string;
|
||||||
|
status: string;
|
||||||
|
reason: string | null;
|
||||||
|
create_date: string;
|
||||||
|
starting_time: string | null;
|
||||||
|
finished_time: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
type EnrollmentInfoResponse = {
|
||||||
|
status: string;
|
||||||
|
browser_callback_url: string;
|
||||||
|
browser_callback_token: string;
|
||||||
|
user_process_done_time: string | null;
|
||||||
|
routes: {
|
||||||
|
uses_biometric: boolean;
|
||||||
|
datas: {};
|
||||||
|
document_classes: string[];
|
||||||
|
constraints: string[];
|
||||||
|
id: string;
|
||||||
|
status: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type ReportInfoReponse = {
|
||||||
|
enrollment: {
|
||||||
|
callback_url: string;
|
||||||
|
browser_callback_url: string;
|
||||||
|
client_reference: string;
|
||||||
|
};
|
||||||
|
process_uuid: string;
|
||||||
|
id: number;
|
||||||
|
status: string;
|
||||||
|
process_id: number;
|
||||||
|
external_methods: {
|
||||||
|
france_connect: {
|
||||||
|
status: string;
|
||||||
|
creation_time: string;
|
||||||
|
starting_time: string;
|
||||||
|
finished_time: string;
|
||||||
|
supplier_reference: string;
|
||||||
|
results: {
|
||||||
|
france_connect_out_token: [
|
||||||
|
{
|
||||||
|
token_type: string;
|
||||||
|
scope: string;
|
||||||
|
access_token: string;
|
||||||
|
expires_in: number;
|
||||||
|
id_token: string;
|
||||||
|
expires_at: number;
|
||||||
|
},
|
||||||
|
];
|
||||||
|
france_connect_out_userinfo: [
|
||||||
|
{
|
||||||
|
sub: string;
|
||||||
|
given_name: string;
|
||||||
|
family_name: string;
|
||||||
|
birthdate: string;
|
||||||
|
gender: string;
|
||||||
|
preferred_username: string;
|
||||||
|
email: string;
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
archive_reference: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type LoginResponse = {
|
||||||
|
token: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class Id360Service extends BaseService {
|
||||||
|
private id360Token: string | null = null;
|
||||||
|
private id360TokenExpiration: number | null = null;
|
||||||
|
|
||||||
|
constructor(private variables: BackendVariables, private documentsService: DocumentsService, private filesService: FilesService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createFranceConnectEnrollment() {
|
||||||
|
const authHeader = `Token ${await this.getId360Token()}`;
|
||||||
|
const bodyArgs = {
|
||||||
|
callback_url: `${this.variables.BACK_API_HOST}/id360/customer-callback/`,
|
||||||
|
browser_callback_url: `${this.variables.APP_HOST}/id360/customer-callback/`,
|
||||||
|
callback_headers: {},
|
||||||
|
};
|
||||||
|
const res = await fetch(
|
||||||
|
`${this.variables.DOCAPOST_BASE_URL + this.variables.DOCAPOST_ROOT + this.variables.DOCAPOST_VERSION}/process/${
|
||||||
|
this.variables.DOCAPOST_CONNECT_PROCESS_ID
|
||||||
|
}/enrollment/`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(bodyArgs),
|
||||||
|
headers: { "Content-Type": "application/json", Accept: "application/json", Authorization: authHeader },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const resJson = (await res.json()) as EnrollmentResponse;
|
||||||
|
console.log(resJson.id);
|
||||||
|
return {
|
||||||
|
franceConnectUrl: `${this.variables.DOCAPOST_BASE_URL}static/process_ui/index.html#/enrollment/${resJson.api_key}`,
|
||||||
|
processId: resJson.id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createEnrollment(documentUid: string) {
|
||||||
|
const authHeader = `Token ${await this.getId360Token()}`;
|
||||||
|
const bodyArgs = {
|
||||||
|
callback_url: `${this.variables.BACK_API_HOST}/id360/enrollment-callback/`,
|
||||||
|
browser_callback_url: `${
|
||||||
|
this.variables.APP_LABEL + this.variables.BACK_API_HOST + this.variables.APP_ROOT_URL
|
||||||
|
}/id360/enrollment-callback/`,
|
||||||
|
client_reference: documentUid,
|
||||||
|
callback_headers: {},
|
||||||
|
};
|
||||||
|
const res = await fetch(
|
||||||
|
`${this.variables.DOCAPOST_BASE_URL + this.variables.DOCAPOST_ROOT + this.variables.DOCAPOST_VERSION}/process/${
|
||||||
|
this.variables.DOCAPOST_DOCUMENT_PROCESS_ID
|
||||||
|
}/enrollment/`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(bodyArgs),
|
||||||
|
headers: { "Content-Type": "application/json", Accept: "application/json", Authorization: authHeader },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const resJson = (await res.json()) as EnrollmentResponse;
|
||||||
|
console.log(resJson);
|
||||||
|
const route = await this.getRouteId(resJson.api_key);
|
||||||
|
await this.selectRoute(resJson.api_key, route);
|
||||||
|
console.log(route);
|
||||||
|
await this.uploadDocument(resJson.api_key, documentUid);
|
||||||
|
|
||||||
|
return await this.getReport(resJson.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async uploadDocument(apiKey: string, documentUid: string) {
|
||||||
|
const document = await this.documentsService.getByUidWithFiles(documentUid);
|
||||||
|
if (document && document.files && document.files.length > 1) {
|
||||||
|
const IDrecto = await this.filesService.download(document.files[0]!.uid);
|
||||||
|
const IDverso = await this.filesService.download(document.files[1]!.uid);
|
||||||
|
const rectoBlobData = new Blob([new Uint8Array(Array.from(IDrecto!.buffer))], { type: "application/octet-stream" });
|
||||||
|
const versoBlobData = new Blob([new Uint8Array(Array.from(IDverso!.buffer))], { type: "application/octet-stream" });
|
||||||
|
const resRecto = await fetch(
|
||||||
|
`${
|
||||||
|
this.variables.DOCAPOST_BASE_URL + this.variables.DOCAPOST_ROOT + this.variables.DOCAPOST_VERSION
|
||||||
|
}/enrollment/flow/document/id_document_image/?total_pages=2&uploaded_page=0`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
body: rectoBlobData,
|
||||||
|
headers: { "Content-Type": "application/octet-stream", Accept: "*/*", "x-api-key": apiKey },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const resVerso = await fetch(
|
||||||
|
`${
|
||||||
|
this.variables.DOCAPOST_BASE_URL + this.variables.DOCAPOST_ROOT + this.variables.DOCAPOST_VERSION
|
||||||
|
}/enrollment/flow/document/id_document_image/?total_pages=2&uploaded_page=1`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
body: versoBlobData,
|
||||||
|
headers: { "Content-Type": "application/octet-stream", Accept: "*/*", "x-api-key": apiKey },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(await resRecto.json(), await resVerso.json());
|
||||||
|
|
||||||
|
await this.finalizeEnrollment(apiKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getReport(enrollmentId: number) {
|
||||||
|
const authHeader = `Token ${await this.getId360Token()}`;
|
||||||
|
const res = await fetch(
|
||||||
|
`${
|
||||||
|
this.variables.DOCAPOST_BASE_URL + this.variables.DOCAPOST_ROOT + this.variables.DOCAPOST_VERSION
|
||||||
|
}/enrollment/${enrollmentId}/report/`,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: { "Content-Type": "application/json", Authorization: authHeader },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return (await res.json()) as ReportInfoReponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getEnrollment(token: string) {
|
||||||
|
const res = await fetch(
|
||||||
|
`${
|
||||||
|
this.variables.DOCAPOST_BASE_URL + this.variables.DOCAPOST_ROOT + this.variables.DOCAPOST_VERSION
|
||||||
|
}/enrollment/status/${token}`,
|
||||||
|
{ method: "GET" },
|
||||||
|
);
|
||||||
|
return (await res.json()) as EnrollmentResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async finalizeEnrollment(apiKey: string) {
|
||||||
|
return await fetch(
|
||||||
|
`${
|
||||||
|
this.variables.DOCAPOST_BASE_URL + this.variables.DOCAPOST_ROOT + this.variables.DOCAPOST_VERSION
|
||||||
|
}/enrollment/flow/finalize_enrollment/`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: { "x-api-key": apiKey, Accept: "application/json" },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getRouteId(apiKey: string) {
|
||||||
|
const res = await fetch(
|
||||||
|
`${
|
||||||
|
this.variables.DOCAPOST_BASE_URL + this.variables.DOCAPOST_ROOT + this.variables.DOCAPOST_VERSION
|
||||||
|
}/enrollment/flow/enrollment_info/`,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: { "x-api-key": apiKey, Accept: "application/json" },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const resJson = (await res.json()) as EnrollmentInfoResponse;
|
||||||
|
return resJson.routes[0]!.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async selectRoute(apiKey: string, routeId: string) {
|
||||||
|
return await fetch(
|
||||||
|
`${
|
||||||
|
this.variables.DOCAPOST_BASE_URL + this.variables.DOCAPOST_ROOT + this.variables.DOCAPOST_VERSION
|
||||||
|
}/enrollment/flow/route/${routeId}/select`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: { "x-api-key": apiKey, Accept: "application/json" },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getId360Token() {
|
||||||
|
if (!this.id360Token || !this.id360TokenExpiration || this.id360TokenExpiration < Date.now()) {
|
||||||
|
this.id360Token = await this.login();
|
||||||
|
this.id360TokenExpiration = Date.now() + 1000 * 60 * 14; // 14 minutes
|
||||||
|
}
|
||||||
|
return this.id360Token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async login(): Promise<string> {
|
||||||
|
const bodyArgs = {
|
||||||
|
username: this.variables.DOCAPOST_APP_ID,
|
||||||
|
password: this.variables.DOCAPOST_APP_PASSWORD,
|
||||||
|
};
|
||||||
|
const res = await fetch(
|
||||||
|
`${this.variables.DOCAPOST_BASE_URL + this.variables.DOCAPOST_ROOT + this.variables.DOCAPOST_VERSION}/user/login/`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(bodyArgs),
|
||||||
|
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return ((await res.json()) as LoginResponse).token;
|
||||||
|
}
|
||||||
|
}
|
@ -4,13 +4,14 @@ import { Emails, PrismaClient } from "@prisma/client";
|
|||||||
import { Service } from "typedi";
|
import { Service } from "typedi";
|
||||||
import MailchimpClient from "@mailchimp/mailchimp_transactional";
|
import MailchimpClient from "@mailchimp/mailchimp_transactional";
|
||||||
import { BackendVariables } from "@Common/config/variables/Variables";
|
import { BackendVariables } from "@Common/config/variables/Variables";
|
||||||
|
import EmailBuilder from "@Common/emails/EmailBuilder";
|
||||||
// import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService";
|
// import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService";
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class MailchimpService extends BaseService {
|
export default class MailchimpService extends BaseService {
|
||||||
private static readonly from = "vincent.alamelle@smart-chain.fr";
|
private static readonly from = "vincent.alamelle@smart-chain.fr";
|
||||||
|
|
||||||
constructor(private emailRepository: EmailRepository, protected variables: BackendVariables) {
|
constructor(private emailRepository: EmailRepository, protected variables: BackendVariables, private emailBuilder: EmailBuilder) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,11 +86,7 @@ export default class MailchimpService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async sendEmail(email: Emails) {
|
private async sendEmail(email: Emails) {
|
||||||
console.log("sendEmail");
|
|
||||||
|
|
||||||
const apiKey = this.variables.MAILCHIMP_API_KEY;
|
const apiKey = this.variables.MAILCHIMP_API_KEY;
|
||||||
console.log(apiKey);
|
|
||||||
|
|
||||||
const mailchimpApiClient = MailchimpClient(apiKey!);
|
const mailchimpApiClient = MailchimpClient(apiKey!);
|
||||||
|
|
||||||
await mailchimpApiClient.messages.sendTemplate({
|
await mailchimpApiClient.messages.sendTemplate({
|
||||||
@ -121,7 +118,7 @@ export default class MailchimpService extends BaseService {
|
|||||||
|
|
||||||
public async sendRecapEmails() {
|
public async sendRecapEmails() {
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
const usersToEmail = await prisma.$queryRaw
|
const usersToEmail: [{email: string, civility: string, last_name: string}] = await prisma.$queryRaw
|
||||||
`SELECT DISTINCT c.email, c.civility, c.last_name
|
`SELECT DISTINCT c.email, c.civility, c.last_name
|
||||||
FROM Contacts c
|
FROM Contacts c
|
||||||
JOIN Users u ON c.uid = u.contact_uid
|
JOIN Users u ON c.uid = u.contact_uid
|
||||||
@ -129,6 +126,6 @@ export default class MailchimpService extends BaseService {
|
|||||||
JOIN Documents d ON of.uid = d.folder_uid
|
JOIN Documents d ON of.uid = d.folder_uid
|
||||||
WHERE d.document_status = 'DEPOSITED';`
|
WHERE d.document_status = 'DEPOSITED';`
|
||||||
|
|
||||||
console.log(usersToEmail);
|
await this.emailBuilder.sendRecapEmails(usersToEmail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { Customers, Prisma } from "@prisma/client";
|
import { Customers, Prisma } from "@prisma/client";
|
||||||
import CustomersRepository from "@Repositories/CustomersRepository";
|
import CustomersRepository from "@Repositories/CustomersRepository";
|
||||||
|
import ContactRepository from "@Repositories/ContactRepository";
|
||||||
import BaseService from "@Services/BaseService";
|
import BaseService from "@Services/BaseService";
|
||||||
import { Service } from "typedi";
|
import { Service } from "typedi";
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class CustomersService extends BaseService {
|
export default class CustomersService extends BaseService {
|
||||||
constructor(private customerRepository: CustomersRepository) {
|
constructor(private customerRepository: CustomersRepository, private contactRepository: ContactRepository) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,4 +33,14 @@ export default class CustomersService extends BaseService {
|
|||||||
public async getByContact(contactUid: string): Promise<Customers | null> {
|
public async getByContact(contactUid: string): Promise<Customers | null> {
|
||||||
return this.customerRepository.findOneByContact(contactUid);
|
return this.customerRepository.findOneByContact(contactUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Get a customer by contact uid
|
||||||
|
* @throws {Error} If customer cannot be get by contact uid
|
||||||
|
*/
|
||||||
|
public async getByEmail(contactUid: string) {
|
||||||
|
return this.contactRepository.findOneByEmail(contactUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Documents, Prisma } from "@prisma/client";
|
import { Documents, Files, Prisma } from "@prisma/client";
|
||||||
import { Document } from "le-coffre-resources/dist/SuperAdmin";
|
import { Document } from "le-coffre-resources/dist/SuperAdmin";
|
||||||
import DocumentsRepository from "@Repositories/DocumentsRepository";
|
import DocumentsRepository from "@Repositories/DocumentsRepository";
|
||||||
import BaseService from "@Services/BaseService";
|
import BaseService from "@Services/BaseService";
|
||||||
@ -65,6 +65,14 @@ export default class DocumentsService extends BaseService {
|
|||||||
return this.documentsRepository.findOneByUid(uid, query);
|
return this.documentsRepository.findOneByUid(uid, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Get a document by uid
|
||||||
|
* @throws {Error} If document cannot be get by uid
|
||||||
|
*/
|
||||||
|
public async getByUidWithFiles(uid: string): Promise<Documents & {files: Files[] | null} | null> {
|
||||||
|
return this.documentsRepository.findOneByUidWithFiles(uid);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description : Get a document by uid
|
* @description : Get a document by uid
|
||||||
* @throws {Error} If document cannot be get by uid
|
* @throws {Error} If document cannot be get by uid
|
||||||
|
Loading…
x
Reference in New Issue
Block a user