diff --git a/controllers/linkedin.js b/controllers/linkedin.js index 47a9c72..2d81576 100644 --- a/controllers/linkedin.js +++ b/controllers/linkedin.js @@ -2,12 +2,16 @@ const axios = require("axios"); const querystring = require("querystring"); +import puppeteer from "puppeteer"; const clientId = "780w7gsy8eysmj"; const clientSecret = "WPL_AP1.w6OTTkAndAdT3PYF.UZEcwQ=="; const redirectUri = "http://localhost:4200/api/auth/linkedin/callback"; const scope = "openid profile email"; +const email = "amaury@maizy.net"; +const password = "2Qh*fJrp+l7M6g>8P~}/S$Bc2Yvf&-vd"; + let accessToken = ""; const authenticateUser = (req, res) => { @@ -87,8 +91,55 @@ const getUserProfile = async (req, res) => { } }; +const scrapeLinkedInProfile = async (profileUrl) => { + const browser = await puppeteer.launch({ headless: false }); // headless: true si tu veux sans UI + const page = await browser.newPage(); + + // 1. Aller sur la page de login + await page.goto("https://www.linkedin.com/login", { + waitUntil: "networkidle2", + }); + + // 2. Connexion avec identifiants + await page.type("#username", email, { delay: 50 }); + await page.type("#password", password, { delay: 50 }); + await Promise.all([ + page.click('[type="submit"]'), + page.waitForNavigation({ waitUntil: "networkidle2" }), + ]); + + // 3. Aller sur le profil + await page.goto(profileUrl, { waitUntil: "networkidle2" }); + + // 4. Extraire les infos + const profileData = await page.evaluate(() => { + const getText = (selector) => + document.querySelector(selector)?.innerText || null; + const getAllText = (selector) => + Array.from(document.querySelectorAll(selector)).map((el) => + el.innerText.trim() + ); + + return { + name: getText(".pv-text-details__left-panel h1"), + headline: getText(".pv-text-details__left-panel .text-body-medium"), + location: getText(".pv-text-details__left-panel .text-body-small"), + about: + getText(".pv-about-section") || + getText(".display-flex.ph5.pv3 .break-words"), + experiences: getAllText(".pv-entity__summary-info"), + education: getAllText(".pv-education-entity"), + skills: getAllText(".pv-skill-category-entity__name-text"), + }; + }); + + await browser.close(); + return profileData; +}; + module.exports = { authenticateUser, handleCallback, getUserProfile, + scrapeLinkedInProfile, }; diff --git a/routes/api.routes.js b/routes/api.routes.js index 3da77bb..1275907 100644 --- a/routes/api.routes.js +++ b/routes/api.routes.js @@ -10,4 +10,14 @@ router.get("/auth/linkedin", authenticateUser); // Callback route for LinkedIn OAuth2 router.get("/auth/linkedin/callback", handleCallback); +// Traitement du formulaire d'URL LinkedIn +router.post("/me/link", express.urlencoded({ extended: true }), (req, res) => { + if (!req.session.user) return res.redirect("/"); + req.session.user.linkedinUrl = req.body.linkedinUrl; + res.send(` +
URL LinkedIn enregistrée : ${req.body.linkedinUrl}
+ Retour + `); +}); + module.exports = router; diff --git a/routes/front.routes.js b/routes/front.routes.js index 4573f68..fe032e4 100644 --- a/routes/front.routes.js +++ b/routes/front.routes.js @@ -7,6 +7,11 @@ const { getUserProfile } = require("../controllers/linkedin"); // Page d'accueil router.get("/", (req, res) => { + const user = req.session.user; + if (user) { + return res.redirect("/me"); + } + res.send(`URL LinkedIn enregistrée : ${req.body.linkedinUrl}
- Retour - `); + if (!user.linkedinUrl) { + return res.send(` +