Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions libs/data/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@
]
}
},
"update-trainings": {
"executor": "nx:run-commands",
"options": {
"cwd": "libs/data",
"commands": [
"npx tsx src/scripts/updateBaserowTrainings.ts"
]
}
},
"generate-programs": {
"executor": "nx:run-commands",
"options": {
Expand Down
17 changes: 17 additions & 0 deletions libs/data/src/common/baserow/abstractBaserow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,21 @@ export abstract class AbstractBaserow {
}
throw Error('Baserow token not found.')
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
protected async _patchRow(tableId: number, rowId: number, data: Record<string, any>): Promise<void> {
try {
await axios.patch(`${this._baseUrl}/database/rows/table/${tableId}/${rowId}/?user_field_names=true`, data, this._axiosHeader)
} catch (error) {
console.error(`Error patching row ${rowId} in table ${tableId}:`, error)
}
}

protected async _createRow(tableId: number, data: Record<string, any>): Promise<void> {
try {
await axios.post(`${this._baseUrl}/database/rows/table/${tableId}/?user_field_names=true`, data, this._axiosHeader)
} catch (error) {
console.error(`Error creating row in table ${tableId}:`, error)
}
}
}
47 changes: 47 additions & 0 deletions libs/data/src/common/baserow/trainingBaserow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { AbstractBaserow } from './abstractBaserow'
import { BaserowTraining } from './types'
import { Training } from '../../trainings/types'

export class TrainingBaserow extends AbstractBaserow {
private readonly _tableId = 620771
private _trainings: BaserowTraining[] = []

async getAll(): Promise<BaserowTraining[]> {
return (this._trainings = await this._getTableData<BaserowTraining>(this._tableId))
}

async patchOrCreate(training: Training): Promise<void> {
if (!this._trainings.length) {
throw new Error('TrainingBaserow: No trainings loaded. Call getAll() first.')
}

const match = this._trainings.find((baserowTraining) => baserowTraining['Id Ademe'] === training.id)

const payload: Partial<BaserowTraining> = {
'Id Ademe': training.id,
'Futures Sessions': training.session ? JSON.stringify(Array.isArray(training.session) ? training.session : [training.session]) : '',
Titre: training.Libellé_de_la_formation,
Promesse: training.Chapeau_pour_site_web,
'Url ADEME': training.Lien_URL_vers_la_fiche_programme,
Objectifs: training.Objectifs_de_la_formation,
Thématique: training.Thème._,
Modalité: training.Modalité_de_dispense._ + ' | ' + training.Modalités_et_moyens_pédagogiques,
'Codes Sections': Array.isArray(training.Id_section_code) ? training.Id_section_code.map((item) => item.id).join(', ') : '',
Cible: training.Public_cible,
Programme: training.Programme,
Prérequis: training.Prérequis,
Tarif: training.Tarif_net_de_taxes,
Durée: training.Durée_totale_en_heures,
'Nombre de jours': training.Nombre_de_jours_de_formation,
'Nombre de sessions à venir': Array.isArray(training.session) ? training.session.length : training.session ? 1 : 0,
'Nombre de participants par session':
'De ' + training.Nombre_de_participants_minimum + ' à ' + training.Nombre_de_participants_maximum
}

if (match && match.id) {
await this._patchRow(this._tableId, match.id, payload)
} else {
await this._createRow(this._tableId, payload)
}
}
}
20 changes: 20 additions & 0 deletions libs/data/src/common/baserow/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,23 @@ export interface BaserowTestimony extends Id, BaserowSectors {
'Mise en avant': number
'Nom entreprise': string
}

export interface BaserowTraining extends Id {
'Id Ademe': string
'Futures Sessions': string
Titre: string
Promesse: string
'Url ADEME': string
Objectifs: string
Thématique: string
'Nombre de sessions à venir': number
'Nombre de participants par session': string
Modalité: string
'Codes Sections': string
Cible: string
Programme: string
Prérequis: string
Tarif: string
Durée: string
'Nombre de jours': string
}
12 changes: 12 additions & 0 deletions libs/data/src/scripts/updateBaserowTrainings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { TrainingFeatures } from '../trainings/trainingFeatures'

console.log('Start the Training updates')

new TrainingFeatures()
.loadTrainings()
.then(() => {
console.log('Project data generated')
})
.catch((error) => {
console.error('Error during the project data generation:', error)
})
22 changes: 22 additions & 0 deletions libs/data/src/trainings/trainingFeatures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { parseStringPromise } from 'xml2js'
import axios from 'axios'
import { Training } from './types'
import { TrainingBaserow } from '../common/baserow/trainingBaserow'

export class TrainingFeatures {
async loadTrainings(): Promise<Training[]> {
const xmlPath = 'https://formations.ademe.fr/tmp/flux_formations_agir.xml'
const xmlContent = await axios.get(xmlPath).then((res) => res.data)
const parsed = await parseStringPromise(xmlContent, { mergeAttrs: true, explicitArray: false })
const formations: Training[] = parsed.formations.module || []

const trainingBaserow = new TrainingBaserow()
await trainingBaserow.getAll()
for (const formation of formations) {
await trainingBaserow.patchOrCreate(formation)
await new Promise((res) => setTimeout(res, 200))
}

return []
}
}
49 changes: 49 additions & 0 deletions libs/data/src/trainings/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
export interface TrainingSession {
id: number
type: string
modality: string
label: string
city: string
startDate: Date
endDate: Date
closingDate: Date
durationHours: number
durationDays: number
minParticipants: number
maxParticipants: number
}

export interface Training {
id: string
ID_technique_du_module: string
Lien_URL_vers_la_fiche_programme: string
Picto_de_la_thématique: string
Chapeau_pour_site_web: string
Libellé_de_la_formation: string
Code_stage: string
Type_de_formation: { _: string; id: string }
Modalité_de_dispense: { _: string; id: string }
Grandes_cibles: string
Type_de_dispositif: { id: string }[]
Id_section_code: { id: string }[]
Thème: { _: string; id: string }
Statut_de_publication: string
Date_de_création: string
Date_de_dernière_modification: string
Au_catalogue_Qualiopi: { _: string; id: string }
Conception: { _: string; id: string }
Programme: string
Public_cible: string
Prérequis: string
Objectifs_de_la_formation: string
Modalités_et_moyens_pédagogiques: string
Modalités_évaluation: string
Equipe_pédagogique: string
Durée_totale_en_heures: string
Nombre_de_jours_de_formation: string
Nombre_de_participants_minimum: string
Nombre_de_participants_maximum: string
Tarif_net_de_taxes: string
Session_payante: string
session?: TrainingSession[]
}
24 changes: 23 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"start": "node apps/nuxt/.output/server/index.mjs --port $PORT",
"build:etl": "nx run @tee/etl:build-docker",
"build:start": "npm run build && npm run start",
"update:trainings": "nx run @tee/data:update-trainings",
"generate:programs": "nx run @tee/data:generate-programs",
"generate:projects": "nx run @tee/data:generate-projects",
"generate:testimonies": "nx run @tee/data:generate-testimonies",
Expand Down Expand Up @@ -84,6 +85,7 @@
"vite": "^5.0.0",
"vue": "^3.5.11",
"vue-router": "^4.3.3",
"xml2js": "^0.6.2",
"zod": "^3.24.1"
},
"devDependencies": {
Expand Down
Loading