add id360 service

This commit is contained in:
OxSaitama 2023-07-27 14:14:44 +02:00
parent 29a8e23c43
commit 5dae259fc2
13 changed files with 533 additions and 7094 deletions

7054
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -59,7 +59,6 @@
"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.4", "puppeteer": "^21.3.4",
@ -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",

View File

@ -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

View 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;
}
}
}

View 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;
}
}
}

View File

@ -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);
}); });

View File

@ -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);
}, },
}; };

View File

@ -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;

View File

@ -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 },
});
}
} }

View File

@ -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,
}; };
} }

View 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;
}
}

View File

@ -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);
}
} }

View File

@ -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