diff --git a/.infra/files/configs/mongodb/seed.gpg b/.infra/files/configs/mongodb/seed.gpg index 5b94f01e05..af49a2366e 100644 --- a/.infra/files/configs/mongodb/seed.gpg +++ b/.infra/files/configs/mongodb/seed.gpg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9fdaa57b6d751a468c9d66696ae44aab98443b2a58586ca7866d38d3e6803958 -size 644811608 +oid sha256:761323cfd10877427e2098e94fa2b6ce65d229960dea0c8ba79f079d4a56a19d +size 580408856 diff --git a/.talismanrc b/.talismanrc index a76b7068e6..d48901fd10 100644 --- a/.talismanrc +++ b/.talismanrc @@ -22,7 +22,7 @@ fileignoreconfig: - filename: .infra/files/configs/mailpit/auth checksum: 0c02db6c367747bfd696e8c93ed78c456fe311452e7a4ee1d7d5acc88f3b2189 - filename: .infra/files/configs/mongodb/seed.gpg - checksum: 3cb836a5c356c64ac6634c8aeb03b9737950a66ed61d9ae8f6b1528ad7b17434 + checksum: e09bc952da0dbeb33331dc317980e6537dc4d37674ca08748246d4d093b82294 - filename: .infra/vault/vault.yml checksum: 1a62fbc5e3e877b5241d59c61fda05a61b6c8bb4fb7f5662f2f1bc44c288782b - filename: server/.env.test diff --git a/server/src/http/routes/auth/login.controller.ts b/server/src/http/routes/auth/login.controller.ts index b7a7ad77eb..cc6244f3f7 100644 --- a/server/src/http/routes/auth/login.controller.ts +++ b/server/src/http/routes/auth/login.controller.ts @@ -15,34 +15,23 @@ import { Server } from "../../server" export default (server: Server) => { server.post( - "/login/confirmation-email", + "/login/:userId/resend-confirmation-email", { - schema: zRoutes.post["/login/confirmation-email"], - preHandler: [], + schema: zRoutes.post["/login/:userId/resend-confirmation-email"], + onRequest: server.auth(zRoutes.post["/login/:userId/resend-confirmation-email"]), }, async (req, res) => { - try { - const { email } = req.body - const formatedEmail = email.toLowerCase() - const user = await getUser({ email: formatedEmail }) - - if (!user) { - return res.status(400).send({ error: true, reason: "UNKNOWN" }) - } - - const { is_email_checked } = user - - if (is_email_checked) { - return res.status(400).send({ error: true, reason: "VERIFIED" }) - } - await sendUserConfirmationEmail(user) - return res.status(200).send({}) - } catch (error) { - return res.status(400).send({ - errorMessage: "l'adresse mail n'est pas valide.", - details: error, - }) + const { userId } = req.params + const user = await getUser({ _id: userId }) + if (!user) { + return res.status(400).send({ error: true, reason: "UNKNOWN" }) + } + const { is_email_checked } = user + if (is_email_checked) { + return res.status(400).send({ error: true, reason: "VERIFIED" }) } + await sendUserConfirmationEmail(user) + return res.status(200).send({}) } ) diff --git a/server/src/http/routes/etablissementRecruteur.controller.ts b/server/src/http/routes/etablissementRecruteur.controller.ts index 9f042ee968..53c9a861b7 100644 --- a/server/src/http/routes/etablissementRecruteur.controller.ts +++ b/server/src/http/routes/etablissementRecruteur.controller.ts @@ -165,6 +165,7 @@ export default (server: Server) => { if (result.errorCode === BusinessErrorCodes.ALREADY_EXISTS) throw Boom.forbidden(result.message) else throw Boom.badRequest(result.message) } + await startSession(req.body.email, res) return res.status(200).send(result) } case CFA: { diff --git a/server/src/http/routes/formulaire.controller.ts b/server/src/http/routes/formulaire.controller.ts index 01a8fb0d8b..e917e5129e 100644 --- a/server/src/http/routes/formulaire.controller.ts +++ b/server/src/http/routes/formulaire.controller.ts @@ -31,6 +31,7 @@ export default (server: Server) => { "/formulaire/:establishment_id", { schema: zRoutes.get["/formulaire/:establishment_id"], + onRequest: [server.auth(zRoutes.get["/formulaire/:establishment_id"])], }, async (req, res) => { const result = await getFormulaire({ establishment_id: req.params.establishment_id }) @@ -149,7 +150,7 @@ export default (server: Server) => { "/formulaire/:establishment_id/offre", { schema: zRoutes.post["/formulaire/:establishment_id/offre"], - // preHandler: [server.auth(zRoutes.post["/formulaire/:establishment_id/offre"])], + onRequest: [server.auth(zRoutes.post["/formulaire/:establishment_id/offre"])], bodyLimit: 5 * 1024 ** 2, // 5MB }, async (req, res) => { @@ -195,6 +196,7 @@ export default (server: Server) => { "/formulaire/offre/:jobId/delegation", { schema: zRoutes.post["/formulaire/offre/:jobId/delegation"], + onRequest: [server.auth(zRoutes.post["/formulaire/offre/:jobId/delegation"])], }, async (req, res) => { const { etablissementCatalogueIds } = req.body diff --git a/server/src/http/routes/user.controller.ts b/server/src/http/routes/user.controller.ts index bd8039dc57..92fe61910c 100644 --- a/server/src/http/routes/user.controller.ts +++ b/server/src/http/routes/user.controller.ts @@ -1,6 +1,8 @@ import Boom from "boom" import { IJob, getUserStatus, zRoutes } from "shared/index" +import { stopSession } from "@/common/utils/session.service" + import { Recruiter, UserRecruteur } from "../../common/model/index" import { getStaticFilePath } from "../../common/utils/getStaticFilePath" import config from "../../config" @@ -170,6 +172,7 @@ export default (server: Server) => { "/user/status/:userId", { schema: zRoutes.get["/user/status/:userId"], + onRequest: [server.auth(zRoutes.get["/user/status/:userId"])], }, async (req, res) => { const user = await UserRecruteur.findOne({ _id: req.params.userId }).lean() @@ -282,7 +285,7 @@ export default (server: Server) => { "/user", { schema: zRoutes.delete["/user"], - preHandler: [], + onRequest: [server.auth(zRoutes.delete["/user"])], }, async (req, res) => { const { userId, recruiterId } = req.query @@ -292,7 +295,7 @@ export default (server: Server) => { if (recruiterId) { await deleteFormulaire(recruiterId) } - + await stopSession(req, res) return res.status(200).send({}) } ) diff --git a/server/src/security/authenticationService.ts b/server/src/security/authenticationService.ts index e5b2346552..cdefcf1d0f 100644 --- a/server/src/security/authenticationService.ts +++ b/server/src/security/authenticationService.ts @@ -53,9 +53,11 @@ async function authCookieSession(req: FastifyRequest): Promise export type IJob = z.output export type IJobWritable = z.output export type IJobJson = Jsonify> + +export const ZNewDelegations = z + .object({ + etablissementCatalogueIds: z.array(z.string()), + }) + .strict() + +export type INewDelegations = z.input diff --git a/shared/models/usersRecruteur.model.ts b/shared/models/usersRecruteur.model.ts index f0ee8fb187..e60a618b4f 100644 --- a/shared/models/usersRecruteur.model.ts +++ b/shared/models/usersRecruteur.model.ts @@ -8,14 +8,12 @@ import { ZGlobalAddress } from "./address.model" import { zObjectId } from "./common" const etatUtilisateurValues = Object.values(ETAT_UTILISATEUR) +export const ZEtatUtilisateur = z.enum([etatUtilisateurValues[0], ...etatUtilisateurValues.slice(1)]).describe("Statut de l'utilisateur") export const ZUserStatusValidation = z .object({ validation_type: z.enum(["AUTOMATIQUE", "MANUELLE"]).describe("Processus de validation lors de l'inscription de l'utilisateur"), - status: z - .enum([etatUtilisateurValues[0], ...etatUtilisateurValues.slice(1)]) - .nullish() - .describe("Statut de l'utilisateur"), + status: ZEtatUtilisateur.nullish(), reason: z.string().nullish().describe("Raison du changement de statut"), user: z.string().describe("Utilisateur ayant effectué la modification | SERVEUR si le compte a été validé automatiquement"), date: z.date().nullish().describe("Date de l'évènement"), diff --git a/shared/routes/formulaire.route.ts b/shared/routes/formulaire.route.ts index a0cc022677..33699f8185 100644 --- a/shared/routes/formulaire.route.ts +++ b/shared/routes/formulaire.route.ts @@ -10,15 +10,19 @@ export const zFormulaireRoute = { "/formulaire/:establishment_id": { method: "get", path: "/formulaire/:establishment_id", - // TODO_SECURITY_FIX gestion des permissions - // TODO_SECURITY_FIX session gérée par cookie server params: z.object({ establishment_id: z.string() }).strict(), response: { // TODO ANY TO BE FIXED "200": z.any(), // "2xx": ZRecruiter, }, - securityScheme: null, + securityScheme: { + auth: "cookie-session", + access: "recruiter:manage", + ressources: { + recruiter: [{ establishment_id: { type: "params", key: "establishment_id" } }], + }, + }, }, "/formulaire/offre/f/:jobId": { method: "get", @@ -63,7 +67,6 @@ export const zFormulaireRoute = { "/formulaire/:establishment_id/offre": { method: "post", path: "/formulaire/:establishment_id/offre", - // TODO_SECURITY_FIX gestion des permissions // TODO_SECURITY_FIX limiter les champs autorisés à la modification. Utiliser un "ZRecruiterNew" (ou un autre nom du genre ZFormulaire) params: z.object({ establishment_id: z.string() }).strict(), // TODO nonstrict TO BE FIXED on the frontend @@ -73,13 +76,17 @@ export const zFormulaireRoute = { // "2xx": ZRecruiter, "200": z.any(), }, - securityScheme: null, + securityScheme: { + auth: "cookie-session", + access: "recruiter:add_job", + ressources: { + recruiter: [{ establishment_id: { type: "params", key: "establishment_id" } }], + }, + }, }, "/formulaire/offre/:jobId/delegation": { method: "post", path: "/formulaire/offre/:jobId/delegation", - // TODO_SECURITY_FIX gestion des permissions - // TODO_SECURITY_FIX session gérée par cookie server params: z.object({ jobId: zObjectId }).strict(), body: z .object({ @@ -88,10 +95,16 @@ export const zFormulaireRoute = { .strict(), response: { // TODO ANY TO BE FIXED - "2xx": z.any(), + "200": z.any(), // "2xx": ZRecruiter, }, - securityScheme: null, + securityScheme: { + auth: "cookie-session", + access: "job:manage", + ressources: { + job: [{ _id: { type: "params", key: "jobId" } }], + }, + }, }, }, put: { diff --git a/shared/routes/index.ts b/shared/routes/index.ts index 5d470f87ee..0bef7d4e0f 100644 --- a/shared/routes/index.ts +++ b/shared/routes/index.ts @@ -61,19 +61,27 @@ const zRoutesGet: typeof zRoutesGetP1 & typeof zRoutesGetP2 & typeof zRoutesGetP ...zRoutesGetP3, } as const -const zRoutesPost = { +const zRoutesPost1 = { ...zApplicationRoutes.post, ...zLoginRoutes.post, ...zTrainingLinksRoutes.post, ...zUnsubscribeRoute.post, ...zUserRecruteurRoutes.post, ...zV1JobsRoutes.post, +} as const + +const zRoutesPost2 = { ...zFormulaireRoute.post, ...zRecruiterRoutes.post, ...zCampaignWebhookRoutes.post, ...zEtablissementRoutes.post, ...zAppointmentsRoute.post, ...zEmailsRoutes.post, +} + +const zRoutesPost = { + ...zRoutesPost1, + ...zRoutesPost2, } as const const zRoutesPut = { diff --git a/shared/routes/login.routes.ts b/shared/routes/login.routes.ts index 836be2aa31..e6d218790a 100644 --- a/shared/routes/login.routes.ts +++ b/shared/routes/login.routes.ts @@ -1,23 +1,29 @@ import { z } from "../helpers/zodWithOpenApi" import { ZUserRecruteurPublic } from "../models" +import { zObjectId } from "../models/common" import { IRoutesDef } from "./common.routes" export const zLoginRoutes = { post: { - "/login/confirmation-email": { + "/login/:userId/resend-confirmation-email": { method: "post", - path: "/login/confirmation-email", - // TODO_SECURITY_FIX faire en sorte que le lien magique ne soit pas human readable. Rename en /resend-confirmation-email - body: z + path: "/login/:userId/resend-confirmation-email", + params: z .object({ - email: z.string().email(), + userId: zObjectId, }) .strict(), response: { "200": z.object({}).strict(), }, - securityScheme: null, + securityScheme: { + auth: "cookie-session", + access: "user:manage", + ressources: { + user: [{ _id: { key: "userId", type: "params" } }], + }, + }, }, "/login/magiclink": { method: "post", diff --git a/shared/routes/recruiters.routes.ts b/shared/routes/recruiters.routes.ts index 4bc96e4fa2..bebc373c2c 100644 --- a/shared/routes/recruiters.routes.ts +++ b/shared/routes/recruiters.routes.ts @@ -156,7 +156,7 @@ export const zRecruiterRoutes = { ]), response: { // TODO ANY TO BE FIXED - "2xx": z.any(), + "200": z.any(), // "2xx": z.union([ // z // .object({ diff --git a/shared/routes/user.routes.ts b/shared/routes/user.routes.ts index 86382d120e..328e9db13d 100644 --- a/shared/routes/user.routes.ts +++ b/shared/routes/user.routes.ts @@ -1,6 +1,6 @@ import { z } from "../helpers/zodWithOpenApi" import { zObjectId } from "../models/common" -import { ZUserRecruteur, ZUserRecruteurWritable, ZUserStatusValidation } from "../models/usersRecruteur.model" +import { ZEtatUtilisateur, ZUserRecruteur, ZUserRecruteurWritable, ZUserStatusValidation } from "../models/usersRecruteur.model" import { IRoutesDef, ZResError } from "./common.routes" @@ -115,10 +115,19 @@ export const zUserRecruteurRoutes = { }) .strict(), response: { - // TODO ANY TO BE FIXED - "200": z.any(), + "200": z + .object({ + status_current: ZEtatUtilisateur, + }) + .strict(), + }, + securityScheme: { + auth: "cookie-session", + access: "user:manage", + ressources: { + user: [{ _id: { type: "params", key: "userId" } }], + }, }, - securityScheme: null, }, }, post: { @@ -204,8 +213,6 @@ export const zUserRecruteurRoutes = { "/user": { method: "delete", path: "/user", - // TODO_SECURITY_FIX session et cookie + permissions - // TODO return json format querystring: z .object({ userId: zObjectId, @@ -215,7 +222,22 @@ export const zUserRecruteurRoutes = { response: { "200": z.object({}).strict(), }, - securityScheme: null, + securityScheme: { + auth: "cookie-session", + access: "recruiter:manage", + ressources: { + user: [ + { + _id: { type: "query", key: "userId" }, + }, + ], + recruiter: [ + { + _id: { type: "query", key: "recruiterId" }, + }, + ], + }, + }, }, "/admin/users/:userId": { method: "delete", diff --git a/ui/components/espace_pro/AjouterVoeux.tsx b/ui/components/espace_pro/AjouterVoeux.tsx index 941ac3dc5b..739a0e164a 100644 --- a/ui/components/espace_pro/AjouterVoeux.tsx +++ b/ui/components/espace_pro/AjouterVoeux.tsx @@ -28,13 +28,13 @@ import dayjs from "dayjs" import { Formik } from "formik" import omit from "lodash/omit" import { useRouter } from "next/router" -import { useContext, useEffect, useState } from "react" +import { useContext, useState } from "react" +import { useQuery } from "react-query" import { TRAINING_CONTRACT_TYPE } from "shared/constants/recruteur" import { JOB_STATUS } from "shared/models/job.model" import * as Yup from "yup" import { useAuth } from "@/context/UserContext" -import { apiPost } from "@/utils/api.utils" import { AUTHTYPE } from "../../common/contants" import { publicConfig } from "../../config.public" @@ -42,7 +42,7 @@ import { LogoContext } from "../../context/contextLogo" import { WidgetContext } from "../../context/contextWidget" import { ArrowRightLine, ExternalLinkLine, InfoCircle, Minus, Plus, Warning } from "../../theme/components/icons" import { J1S, Parcoursup } from "../../theme/components/logos_pro" -import { getFormulaire, getRelatedEtablissementsFromRome, getRomeDetail } from "../../utils/api" +import { createOffre, getFormulaire, getRelatedEtablissementsFromRome, getRomeDetail } from "../../utils/api" import DropdownCombobox from "./DropdownCombobox" @@ -70,13 +70,16 @@ const ChampNombre = ({ value, max, name, handleChange, label }) => { const AjouterVoeuxForm = (props) => { const [inputJobItems, setInputJobItems] = useState([]) - const [formulaire, setFormulaire] = useState(null) const [haveProposals, setHaveProposals] = useState(false) const router = useRouter() - const { user } = useAuth() - const { establishment_id, email, userId, type } = router.query as { establishment_id: string; email: string; userId: string; type: string } + const { data: formulaire } = useQuery("offre-liste", { + enabled: !!establishment_id, + queryFn: () => getFormulaire(establishment_id), + }) + + const { user } = useAuth() const minDate = dayjs().format(DATE_FORMAT) @@ -146,7 +149,7 @@ const AjouterVoeuxForm = (props) => { * @return {Promise} */ const submitFromDepotRapide = async (values) => { - const formulaire = (await apiPost("/formulaire/:establishment_id/offre", { params: { establishment_id }, body: values })) as any + const formulaire = await createOffre(establishment_id, values) formulaire.jobs.slice(-1) const [job] = formulaire.jobs.slice(-1) await handleRedirectionAfterSubmit(formulaire, job, false) @@ -171,16 +174,6 @@ const AjouterVoeuxForm = (props) => { setHaveProposals(!!data.length) } - useEffect(() => { - async function fetchData() { - if (establishment_id) { - const { data: formulaire } = (await getFormulaire(establishment_id)) as any - setFormulaire(formulaire) - } - } - fetchData() - }, [establishment_id]) - return ( { delete payload.opco } createEtablissement(payload) - .then(({ data }) => { + .then((data) => { if (data.user.status[0].status === "VALIDÉ") { if (data.user.type === AUTHTYPE.ENTREPRISE) { // Dépot simplifié @@ -180,9 +180,10 @@ export const InformationCreationCompte = () => { } setSubmitting(false) }) - .catch(({ response }) => { + .catch((error) => { + console.error(error) + const { response } = error const payload: { error: string; statusCode: number; message: string } = response.data - console.error(payload.error) setFieldError("email", payload.message) setSubmitting(false) }) diff --git a/ui/components/espace_pro/CreationOffre.tsx b/ui/components/espace_pro/CreationOffre.tsx index 08815e3bc2..02f5329cad 100644 --- a/ui/components/espace_pro/CreationOffre.tsx +++ b/ui/components/espace_pro/CreationOffre.tsx @@ -3,11 +3,11 @@ import { useRouter } from "next/router" import { useQuery, useQueryClient } from "react-query" import { useAuth } from "@/context/UserContext" -import { apiPost, apiPut } from "@/utils/api.utils" +import { apiPut } from "@/utils/api.utils" import { AUTHTYPE } from "../../common/contants" import { ArrowDropRightLine } from "../../theme/components/icons" -import { getOffre } from "../../utils/api" +import { createOffre, getOffre } from "../../utils/api" import { AjouterVoeux, LoadingEmptySpace } from "." @@ -40,7 +40,7 @@ export default function CreationOffre() { }) .finally(() => router.push(`/espace-pro/administration/entreprise/${establishment_id}`)) } else { - const formulaire = (await apiPost("/formulaire/:establishment_id/offre", { params: { establishment_id }, body: values })) as any + const formulaire = await createOffre(establishment_id, values) if (user.type === AUTHTYPE.ENTREPRISE) { // Create the offer and return the form with the related offer created return { diff --git a/ui/components/espace_pro/ListeOffres.tsx b/ui/components/espace_pro/ListeOffres.tsx index d9931bc8ad..4a5cbd49e8 100644 --- a/ui/components/espace_pro/ListeOffres.tsx +++ b/ui/components/espace_pro/ListeOffres.tsx @@ -77,16 +77,17 @@ export default function ListeOffres() { dayjs.extend(relativeTime) + const { establishment_id } = router.query as { establishment_id: string } const { data, isLoading } = useQuery("offre-liste", { - enabled: !!router.query.establishment_id, - queryFn: () => getFormulaire(router.query.establishment_id), + enabled: !!establishment_id, + queryFn: () => getFormulaire(establishment_id), }) - if (isLoading || !router.query.establishment_id) { + if (isLoading || !establishment_id) { return } - const { jobs = [], establishment_raison_sociale, establishment_siret, establishment_id, geo_coordinates, _id: dataId } = data.data ?? {} + const { jobs = [], establishment_raison_sociale, establishment_siret, geo_coordinates, _id: dataId } = data ?? {} const entrepriseTitle = establishment_raison_sociale ?? establishment_siret const getOffreCreationUrl = () => { diff --git a/ui/components/espace_pro/Proposition/Offre/PropositionOffreId.tsx b/ui/components/espace_pro/Proposition/Offre/PropositionOffreId.tsx index 4060ae170c..5d50f9a78a 100644 --- a/ui/components/espace_pro/Proposition/Offre/PropositionOffreId.tsx +++ b/ui/components/espace_pro/Proposition/Offre/PropositionOffreId.tsx @@ -10,7 +10,7 @@ import { getFormulaire, patchOffre } from "../../../../utils/api" export default function PropositionOffreId() { const router = useRouter() - const { idFormulaire, jobId, siretFormateur } = router.query + const { idFormulaire, jobId, siretFormateur } = router.query as { idFormulaire: string; jobId: string; siretFormateur: string } const toast = useToast() const [job, setJob]: [any, (t: any) => void] = useState() diff --git a/ui/pages/espace-pro/administration/entreprise/[establishment_id]/edition.tsx b/ui/pages/espace-pro/administration/entreprise/[establishment_id]/edition.tsx index cf883e7f7a..a833be9bae 100644 --- a/ui/pages/espace-pro/administration/entreprise/[establishment_id]/edition.tsx +++ b/ui/pages/espace-pro/administration/entreprise/[establishment_id]/edition.tsx @@ -147,14 +147,15 @@ function EditionEntrepriseContact() { const router = useRouter() const { user } = useAuth() - const { data, isLoading } = useQuery("formulaire-edition", () => getFormulaire(router.query.establishment_id), { cacheTime: 0, enabled: !!router.query.establishment_id }) + const { establishment_id } = router.query as { establishment_id: string } + const { data, isLoading } = useQuery("formulaire-edition", () => getFormulaire(establishment_id), { cacheTime: 0, enabled: !!establishment_id }) - if (isLoading || !router.query.establishment_id) { + if (isLoading || !establishment_id) { return } // add type ENTREPRISE for legale information - const entreprise = { ...data.data, type: AUTHTYPE.ENTREPRISE } + const entreprise = { ...data, type: AUTHTYPE.ENTREPRISE } return ( @@ -168,7 +169,7 @@ function EditionEntrepriseContact() { - {data.data.establishment_raison_sociale} + {entreprise.establishment_raison_sociale} diff --git a/ui/pages/espace-pro/creation/fin.tsx b/ui/pages/espace-pro/creation/fin.tsx index a18bf49949..d488d634e5 100644 --- a/ui/pages/espace-pro/creation/fin.tsx +++ b/ui/pages/espace-pro/creation/fin.tsx @@ -4,13 +4,11 @@ import { useRouter } from "next/router" import { useContext, useState } from "react" import { useQuery, useQueryClient } from "react-query" -import { apiGet } from "@/utils/api.utils" - import { AuthentificationLayout, LoadingEmptySpace } from "../../../components/espace_pro" import { WidgetContext } from "../../../context/contextWidget" import { InfoCircle } from "../../../theme/components/icons" import { MailCloud } from "../../../theme/components/logos" -import { sendValidationLink } from "../../../utils/api" +import { getUserStatus, sendValidationLink } from "../../../utils/api" function parseQueryString(value: string | string[]): string { return Array.isArray(value) ? value[0] : value @@ -44,8 +42,8 @@ export default function DepotRapideFin() { * KBA 20230130 : retry set to false to avoid waiting for failure if user is from dashboard (userId is not passed) * - To be changed with userID in URL params */ - const { isFetched } = useQuery("userdetail", () => apiGet("/user/status/:userId", { params: { userId } }), { - retry: userId ? true : false, + const { isFetched } = useQuery("userdetail", () => getUserStatus(userId), { + enabled: Boolean(userId), onSettled: (data) => { if (data?.status_current === "ERROR") { setUserIsInError(true) @@ -73,8 +71,8 @@ export default function DepotRapideFin() { return } - const resendMail = (email) => { - sendValidationLink({ email }) + const resendMail = () => { + sendValidationLink(userId) .then(() => { toast({ title: "Email envoyé.", @@ -139,10 +137,10 @@ export default function DepotRapideFin() { - {userIsInError && ( + {!userIsInError && ( Vous n’avez pas reçu le mail ? - @@ -164,10 +162,10 @@ export default function DepotRapideFin() { Afin de finaliser la diffusion de votre besoin auprès des jeunes, merci de confirmer votre adresse mail en cliquant sur le lien que nous venons de vous transmettre à l’adresse suivante: {email}. - {userIsInError && ( + {!userIsInError && ( Vous n’avez pas reçu le mail ? - diff --git a/ui/utils/api.ts b/ui/utils/api.ts index 15a04142ce..6f30954764 100644 --- a/ui/utils/api.ts +++ b/ui/utils/api.ts @@ -1,9 +1,10 @@ import { captureException } from "@sentry/nextjs" import Axios from "axios" +import { IJobWritable, INewDelegations } from "shared" import { publicConfig } from "../config.public" -import { apiGet, apiPut } from "./api.utils" +import { apiDelete, apiGet, apiPost, apiPut } from "./api.utils" const API = Axios.create({ baseURL: publicConfig.apiEndpoint, @@ -19,7 +20,7 @@ const errorHandler = (error: any): undefined => { * Formulaire API */ -export const getFormulaire = (establishment_id) => API.get(`/formulaire/${establishment_id}`).catch(errorHandler) +export const getFormulaire = (establishment_id: string) => apiGet("/formulaire/:establishment_id", { params: { establishment_id } }).catch(errorHandler) export const postFormulaire = (form) => API.post(`/formulaire`, form) export const archiveFormulaire = (establishment_id) => API.delete(`/formulaire/${establishment_id}`).catch(errorHandler) @@ -29,20 +30,22 @@ export const archiveDelegatedFormulaire = (siret) => API.delete(`/formulaire/del * Offre API */ export const getOffre = (jobId) => API.get(`/formulaire/offre/f/${jobId}`) - +export const createOffre = (establishment_id: string, newOffre: IJobWritable) => apiPost("/formulaire/:establishment_id/offre", { params: { establishment_id }, body: newOffre }) export const patchOffre = (jobId, data, config) => API.patch(`/formulaire/offre/${jobId}`, data, config).catch(errorHandler) export const cancelOffre = (jobId) => API.put(`/formulaire/offre/${jobId}/cancel`) export const cancelOffreFromAdmin = (jobId, data) => API.put(`/formulaire/offre/f/${jobId}/cancel`, data) export const extendOffre = (jobId) => apiPut(`/formulaire/offre/:jobId/extend`, { params: { jobId } }) export const fillOffre = (jobId) => API.put(`/formulaire/offre/${jobId}/provided`) -export const createEtablissementDelegation = ({ data, jobId }) => API.post(`/formulaire/offre/${jobId}/delegation`, data) +export const createEtablissementDelegation = ({ data, jobId }: { jobId: string; data: INewDelegations }) => + apiPost(`/formulaire/offre/:jobId/delegation`, { params: { jobId }, body: data }) /** * User API */ +export const getUserStatus = (userId: string) => apiGet("/user/status/:userId", { params: { userId } }) export const updateUserValidationHistory = async (userId, state) => await API.put(`user/${userId}/history`, state).catch(errorHandler) export const deleteCfa = async (userId) => await API.delete(`/user`, { params: { userId } }).catch(errorHandler) -export const deleteEntreprise = async (userId, recruiterId) => await API.delete(`/user`, { params: { userId, recruiterId } }).catch(errorHandler) +export const deleteEntreprise = (userId: string, recruiterId: string) => apiDelete(`/user`, { querystring: { userId, recruiterId } }).catch(errorHandler) // Temporaire, en attendant d'ajuster le modèle pour n'avoir qu'une seul source de données pour les entreprises /** @@ -59,7 +62,7 @@ export const updateEntreprise = async (userId: string, establishment_id, user) = * Auth API */ export const sendMagiclink = async (email) => await API.post(`/login/magiclink`, email) -export const sendValidationLink = async (email) => await API.post(`/login/confirmation-email`, email) +export const sendValidationLink = async (userId: string) => await apiPost("/login/:userId/resend-confirmation-email", { params: { userId } }) /** * Etablissement API @@ -90,7 +93,7 @@ export const getEntrepriseOpco = async (siret: string) => { } } -export const createEtablissement = (etablissement) => API.post("/etablissement/creation", etablissement) +export const createEtablissement = (etablissement) => apiPost("/etablissement/creation", { body: etablissement }) export const getRomeDetail = (rome: string) => API.get(`/rome/detail/${rome}`) export const getRelatedEtablissementsFromRome = ({ rome, latitude, longitude }: { rome: string; latitude: number; longitude: number }) =>