Skip to content

Commit

Permalink
feat: cleanup + token cron job (#1369)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevbarns authored Jul 23, 2024
1 parent 004d0cc commit 303e112
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 112 deletions.
103 changes: 14 additions & 89 deletions server/src/common/apis/FranceTravail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { IFranceTravailAccess, IFranceTravailAccessType } from "shared/models/fr

import config from "@/config"
import { FTResponse } from "@/services/ftjob.service.types"
import { IAppelattionDetailsFromAPI, IRomeDetailsFromAPI, ZFTApiToken } from "@/services/rome.service.types"
import { ZFTApiToken } from "@/services/rome.service.types"

import { logger } from "../logger"
import { getDbCollection } from "../utils/mongodbUtils"
Expand All @@ -18,58 +18,48 @@ import getApiClient from "./client"

const axiosClient = getApiClient({}, { cache: false })

const getFTTokenFromDB = async (access_type: IFranceTravailAccessType): Promise<IFranceTravailAccess["access_token"] | undefined> => {
const getFranceTravailTokenFromDB = async (access_type: IFranceTravailAccessType): Promise<IFranceTravailAccess["access_token"] | undefined> => {
const data = await getDbCollection("francetravail_access").findOne({ access_type }, { projection: { access_token: 1, _id: 0 } })
return data?.access_token
}
const updateFTTokenInDB = async ({ access_type, access_token }: { access_type: IFranceTravailAccessType; access_token: string }) =>
const updateFranceTravailTokenInDB = async ({ access_type, access_token }: { access_type: IFranceTravailAccessType; access_token: string }) =>
await getDbCollection("francetravail_access").findOneAndUpdate(
{ access_type },
{ $set: { access_token }, $setOnInsert: { _id: new ObjectId(), created_at: new Date() } },
{ upsert: true }
)

const ROME_ACCESS = querystring.stringify({
grant_type: "client_credentials",
client_id: config.esdClientId,
client_secret: config.esdClientSecret,
scope: `application_${config.esdClientId} api_romev1 nomenclatureRome`,
})

const ROME_V4_ACCESS = querystring.stringify({
grant_type: "client_credentials",
client_id: config.esdClientId,
client_secret: config.esdClientSecret,
scope: `application_${config.esdClientId} api_rome-metiersv1 nomenclatureRome`,
})

const OFFRES_ACCESS = querystring.stringify({
grant_type: "client_credentials",
client_id: config.esdClientId,
client_secret: config.esdClientSecret,
scope: `application_${config.esdClientId} api_offresdemploiv2 o2dsoffre`,
})

const getFtAccessToken = async (access: IFranceTravailAccessType): Promise<string> => {
const token = await getFTTokenFromDB(access)
const getToken = async (access: IFranceTravailAccessType) => {
const token = await getFranceTravailTokenFromDB(access)
if (token) {
return token
} else {
return await getFranceTravailTokenFromAPI(access)
}
}

export const getFranceTravailTokenFromAPI = async (access: IFranceTravailAccessType): Promise<string> => {
try {
logger.info(`requesting new FT token for access=${access}`)
const tokenParams = access === "OFFRE" ? OFFRES_ACCESS : access === "ROME" ? ROME_ACCESS : ROME_V4_ACCESS
const tokenParams = OFFRES_ACCESS // if other access are needed, update this value.
const response = await axiosClient.post(`${config.franceTravailIO.authUrl}?realm=partenaire`, tokenParams, {
headers: { "Content-Type": "application/x-www-form-urlencoded" },
timeout: 7000,
timeout: 3000,
})

const validation = ZFTApiToken.safeParse(response.data)
if (!validation.success) {
throw Boom.internal("inattendu: FT api token format non valide", { error: validation.error })
}

await updateFTTokenInDB({ access_type: access, access_token: validation.data.access_token })
await updateFranceTravailTokenInDB({ access_type: access, access_token: validation.data.access_token })

return validation.data.access_token
} catch (error: any) {
Expand All @@ -91,7 +81,7 @@ export const searchForFtJobs = async (params: {
insee?: string
distance?: number
}): Promise<FTResponse | null | ""> => {
const token = await getFtAccessToken("OFFRE")
const token = await getToken("OFFRE")

try {
const extendedParams = {
Expand Down Expand Up @@ -121,7 +111,7 @@ export const searchForFtJobs = async (params: {
* @description Get a FT Job
*/
export const getFtJob = async (id: string) => {
const token = await getFtAccessToken("OFFRE")
const token = await getToken("OFFRE")
const result = await axiosClient.get(`${config.franceTravailIO.baseUrl}/offresdemploi/v2/offres/${id}`, {
headers: {
"Content-Type": "application/json",
Expand All @@ -133,71 +123,6 @@ export const getFtJob = async (id: string) => {
return result
}

/**
* Utilitaire à garder pour interroger les référentiels FT non documentés par ailleurs
* Liste des référentiels disponible sur https://www.emploi-store-dev.fr/portail-developpeur-cms/home/catalogue-des-api/documentation-des-api/api/api-offres-demploi-v2/referentiels.html
*
* @param {string} referentiel
*/
export const getFtReferentiels = async (referentiel: string) => {
try {
const token = await getFtAccessToken("OFFRE")

const data = await axiosClient.get(`${config.franceTravailIO.baseUrl}/offresdemploi/v2/referentiel/${referentiel}`, {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: `Bearer ${token}`,
},
})

return data
} catch (error: any) {
sentryCaptureException(error, { extra: { responseData: error.response?.data } })
}
}

/**
* @deprecated use getRomeDetailsFromDB instead
* @param romeCode
* @returns
*/
export const getRomeDetailsFromAPI = async (romeCode: string): Promise<IRomeDetailsFromAPI | null | undefined> => {
const token = await getFtAccessToken("ROME")

try {
const { data } = await axiosClient.get<IRomeDetailsFromAPI>(`${config.franceTravailIO.baseUrl}/rome/v1/metier/${romeCode}`, {
headers: {
Authorization: `Bearer ${token}`,
},
})

return data
} catch (error: any) {
sentryCaptureException(error, { extra: { responseData: error.response?.data } })
return null
}
}

export const getAppellationDetailsFromAPI = async (appellationCode: string): Promise<IAppelattionDetailsFromAPI | null | undefined> => {
const token = await getFtAccessToken("ROME")

try {
const { data } = await axiosClient.get<IAppelattionDetailsFromAPI>(`${config.franceTravailIO.baseUrl}/rome/v1/appellation/${appellationCode}`, {
headers: {
Authorization: `Bearer ${token}`,
},
})

return data
} catch (error: any) {
sentryCaptureException(error, { extra: { responseData: error.response?.data } })
if (error.response.status === 404) {
return null
}
}
}

/**
* Sends CSV file to France Travail API through a "form data".
*/
Expand Down
3 changes: 3 additions & 0 deletions server/src/jobs/franceTravail/generateFranceTravailAccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { getFranceTravailTokenFromAPI } from "../../common/apis/FranceTravail"

export const generateFranceTravailAccess = async () => await getFranceTravailTokenFromAPI("OFFRE")
7 changes: 7 additions & 0 deletions server/src/jobs/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import updateDomainesMetiers from "./domainesMetiers/updateDomainesMetiers"
import updateDomainesMetiersFile from "./domainesMetiers/updateDomainesMetiersFile"
import { importCatalogueFormationJob } from "./formationsCatalogue/formationsCatalogue"
import { updateParcoursupAndAffelnetInfoOnFormationCatalogue } from "./formationsCatalogue/updateParcoursupAndAffelnetInfoOnFormationCatalogue"
import { generateFranceTravailAccess } from "./franceTravail/generateFranceTravailAccess"
import { addJob, executeJob } from "./jobs_actions"
import { createApiUser } from "./lba_recruteur/api/createApiUser"
import { disableApiUser } from "./lba_recruteur/api/disableApiUser"
Expand Down Expand Up @@ -207,6 +208,10 @@ export const CronsMap = {
cron_string: "00 10,13,17 * * *",
handler: () => addJob({ name: "metabase:role-management:create", payload: {} }),
},
"Génération du token France Travail pour la récupération des offres": {
cron_string: "*/5 * * * *",
handler: () => addJob({ name: "francetravail:token-offre", payload: {} }),
},
} satisfies Record<string, Omit<CronDef, "name">>

export type CronName = keyof typeof CronsMap
Expand All @@ -225,6 +230,8 @@ export async function runJob(job: IInternalJobsCronTask | IInternalJobsSimple):
return CronsMap[job.name].handler()
}
switch (job.name) {
case "francetravail:token-offre":
return generateFranceTravailAccess()
case "recreate:indexes":
return recreateIndexes()
case "lbajobs:export:s3":
Expand Down
7 changes: 0 additions & 7 deletions server/src/jobs/lbb/runFTReferentiels.ts

This file was deleted.

17 changes: 1 addition & 16 deletions server/src/services/ftjob.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Boom from "boom"
import { LBA_ITEM_TYPE_OLD } from "shared/constants/lbaitem"
import { TRAINING_CONTRACT_TYPE } from "shared/constants/recruteur"

import { getFtJob, getFtReferentiels, searchForFtJobs } from "@/common/apis/FranceTravail"
import { getFtJob, searchForFtJobs } from "@/common/apis/FranceTravail"

import { IApiError, manageApiError } from "../common/utils/errorManager"
import { roundDistance } from "../common/utils/geolib"
Expand All @@ -25,21 +25,6 @@ const correspondancesNatureContrat = {
"Contrat apprentissage": TRAINING_CONTRACT_TYPE.APPRENTISSAGE,
}

/**
* Utilitaire à garder pour interroger les référentiels PE non documentés par ailleurs
* Liste des référentiels disponible sur https://www.emploi-store-dev.fr/portail-developpeur-cms/home/catalogue-des-api/documentation-des-api/api/api-offres-demploi-v2/referentiels.html
*
* @param {string} referentiel
*/
export const getFtApiReferentiels = async (referentiel: string) => {
try {
const referentiels = await getFtReferentiels(referentiel)
console.info(`Référentiel ${referentiel} :`, referentiels) // retour car utilisation en mode CLI uniquement
} catch (error) {
console.error("error getReferentiel ", error)
}
}

/**
* formule de modification du rayon de distance pour prendre en compte les limites des communes
* @param {number} radius le rayon de recherche en km
Expand Down

0 comments on commit 303e112

Please sign in to comment.