Skip to content

Commit

Permalink
fix: Lbac 1734 securisation de /user/:userId (#802)
Browse files Browse the repository at this point in the history
* fix: extraction de la fonction getUser dans l'api client

* fix: typing dans UserValidationHistory

* fix: changement de permission + extraction de updateUser

* fix: permission
  • Loading branch information
remy-auricoste authored Nov 15, 2023
1 parent 454625b commit c10da68
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 111 deletions.
4 changes: 2 additions & 2 deletions .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ fileignoreconfig:
- filename: server/tests/integration/http/passwordRoutes.test.ts
checksum: e9869aceb9bb23877dccf1c6e2de729bfe685f7e40231c465fc40cdcc7c68c14
- filename: server/tests/unit/security/accessTokenService.test.ts
checksum: 58153e7e57ef450bfbf061f322cd8b7643dba12513b183194b4eafdb166f58d3
checksum: 232b1bae52a4d4f961637f59b09da5e480147864c76980a2b86e77a73bb36923
- filename: server/tests/unit/security/authorisationService.test.ts
checksum: 581074420be582973bbfcdfafe1f700ca32f56e331911609cdc1cb2fb2626383
- filename: shared/constants/recruteur.ts
checksum: 28af032d2eb26aec7dd3bb1d32253f992a036626c36a92eb1e7ff07599fd0b2b
- filename: shared/helpers/generateUri.ts
checksum: 6542db0d3eca959c6e81d574f8b71d4b18d2f1af21042ca5ed4dff319cd39555
checksum: 03ecb8627c19374e97450e5974ca6a5f51e269a8bb1cf5d372a8c2a2aca72cfa
- filename: shared/helpers/openapi/__snapshots__/generateOpenapi.test.ts.snap
checksum: 9358c7f8155efcfc5687be3f01ae3516a05988118304c124a3358094aa966363
- filename: shared/helpers/openapi/generateOpenapi.test.ts
Expand Down
5 changes: 2 additions & 3 deletions shared/routes/user.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export const zUserRecruteurRoutes = {
},
securityScheme: {
auth: "cookie-session",
access: "recruiter:manage",
access: "user:manage",
ressources: {
user: [
{
Expand Down Expand Up @@ -157,7 +157,6 @@ export const zUserRecruteurRoutes = {
"/user/:userId": {
method: "put",
path: "/user/:userId",
// TODO_SECURITY_FIX session et cookie + permissions
params: z.object({ userId: zObjectId }).strict(),
body: ZUserRecruteurWritable.pick({
last_name: true,
Expand All @@ -174,7 +173,7 @@ export const zUserRecruteurRoutes = {
},
securityScheme: {
auth: "cookie-session",
access: "recruiter:manage",
access: "user:manage",
ressources: {
user: [{ _id: { type: "params", key: "userId" } }],
},
Expand Down
4 changes: 0 additions & 4 deletions ui/components/espace_pro/Admin/utilisateurs/UserView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,10 @@ const UserView: FC<Props> = ({ user, refetchUser }) => {
{ title: `${user.first_name} ${user.last_name}` },
]}
/>

<Heading as="h2" fontSize="2xl" mb={[3, 6]} mt={3}>
Fiche utilisateur
</Heading>

<UserForm user={user} onDelete={() => router.push("/espace-pro/admin/utilisateurs")} onUpdate={() => refetchUser()} />

{/* @ts-expect-error */}
<UserValidationHistory histories={user.status} />
</>
)
Expand Down
165 changes: 80 additions & 85 deletions ui/components/espace_pro/UserValidationHistory.tsx
Original file line number Diff line number Diff line change
@@ -1,99 +1,94 @@
import { Badge, Box, Table, TableContainer, Tbody, Td, Text, Th, Thead, Tr } from "@chakra-ui/react"
import dayjs from "dayjs"
import { memo, useCallback, useEffect, useState } from "react"
import { useCallback, useEffect, useState } from "react"
import { IUserStatusValidation } from "shared"

import { apiGet } from "@/utils/api.utils"
import { getUser } from "@/utils/api"

import LoadingEmptySpace from "./LoadingEmptySpace"

// eslint-disable-next-line react/display-name
export default memo(
({
// @ts-expect-error: TODO
histories,
}) => {
const [historic, setHistoric] = useState([])
export const UserValidationHistory = ({ histories }: { histories: IUserStatusValidation[] }) => {
const [historic, setHistoric] = useState<(IUserStatusValidation & { first_name?: string; last_name?: string })[]>([])

const getValidator = useCallback(async () => {
const buffer = await Promise.all(
histories.map(async (user) => {
if (user.user !== "SERVEUR") {
try {
const result = await apiGet(`/user/:userId`, { params: { userId: user.user } })
user.first_name = result.first_name
user.last_name = result.last_name
return user
} catch (error) {
console.error(error)
}
const getValidator = useCallback(async () => {
const buffer = await Promise.all(
histories.map(async (statusChange) => {
if (statusChange.user !== "SERVEUR") {
try {
const result = await getUser(statusChange.user)
const { first_name, last_name } = result
return { ...statusChange, first_name, last_name }
} catch (error) {
console.error(error)
}
}
return statusChange
})
)
setHistoric(buffer)
}, [])

return user
})
)
setHistoric(buffer)
}, [])

useEffect(() => {
getValidator()
}, [historic.length > 0, histories])
useEffect(() => {
getValidator()
}, [historic.length > 0, histories])

if (historic.length === 0) {
return <LoadingEmptySpace />
}
if (historic.length === 0) {
return <LoadingEmptySpace />
}

const getStatut = (status) => {
switch (status) {
case "VALIDÉ":
return <Badge variant="active">{status}</Badge>
case "EN ATTENTE DE VALIDATION":
return <Badge variant="awaiting">{status}</Badge>
case "DESACTIVÉ":
return <Badge variant="inactive">{status}</Badge>
default:
return <Badge>{status}</Badge>
}
const getStatut = (status) => {
switch (status) {
case "VALIDÉ":
return <Badge variant="active">{status}</Badge>
case "EN ATTENTE DE VALIDATION":
return <Badge variant="awaiting">{status}</Badge>
case "DESACTIVÉ":
return <Badge variant="inactive">{status}</Badge>
default:
return <Badge>{status}</Badge>
}
}

return (
<Box mt={10}>
<hr />
<Box mt={5}>
<Text fontSize="20px" fontWeight={700}>
Historique du compte
</Text>
<TableContainer mt={4}>
<Table variant="simple">
<Thead>
<Tr>
<Th>#</Th>
<Th>Date</Th>
<Th>Statut</Th>
<Th>Type de validation</Th>
<Th>Opérateur</Th>
<Th>Motif</Th>
</Tr>
</Thead>
<Tbody>
{historic
.map(({ date, status, first_name, last_name, validation_type, reason, user }, i) => {
return (
<Tr key={i}>
<Td>{i + 1}</Td>
<Td>{dayjs(date).format("DD/MM/YYYY")}</Td>
<Td>{getStatut(status)}</Td>
<Td>{validation_type}</Td>
<Td>{first_name && last_name ? `${first_name} ${last_name}` : <Badge>{user}</Badge>}</Td>
<Td>{reason}</Td>
</Tr>
)
})
.reverse()}
</Tbody>
</Table>
</TableContainer>
</Box>
return (
<Box mt={10}>
<hr />
<Box mt={5}>
<Text fontSize="20px" fontWeight={700}>
Historique du compte
</Text>
<TableContainer mt={4}>
<Table variant="simple">
<Thead>
<Tr>
<Th>#</Th>
<Th>Date</Th>
<Th>Statut</Th>
<Th>Type de validation</Th>
<Th>Opérateur</Th>
<Th>Motif</Th>
</Tr>
</Thead>
<Tbody>
{historic
.map(({ date, status, first_name, last_name, validation_type, reason, user }, i) => {
return (
<Tr key={i}>
<Td>{i + 1}</Td>
<Td>{dayjs(date).format("DD/MM/YYYY")}</Td>
<Td>{getStatut(status)}</Td>
<Td>{validation_type}</Td>
<Td>{first_name && last_name ? `${first_name} ${last_name}` : <Badge>{user}</Badge>}</Td>
<Td>{reason}</Td>
</Tr>
)
})
.reverse()}
</Tbody>
</Table>
</TableContainer>
</Box>
)
}
)
</Box>
)
}

export default UserValidationHistory
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import * as Yup from "yup"

import { getAuthServerSideProps } from "@/common/SSR/getAuthServerSideProps"
import { useAuth } from "@/context/UserContext"
import { apiGet } from "@/utils/api.utils"

import { AUTHTYPE } from "../../../../../../common/contants"
import useUserHistoryUpdate from "../../../../../../common/hooks/useUserHistoryUpdate"
Expand All @@ -43,7 +42,7 @@ import {
import { OpcoSelect } from "../../../../../../components/espace_pro/CreationRecruteur/OpcoSelect"
import { authProvider, withAuth } from "../../../../../../components/espace_pro/withAuth"
import { ArrowDropRightLine, ArrowRightLine } from "../../../../../../theme/components/icons"
import { updateEntreprise } from "../../../../../../utils/api"
import { getUser, updateEntreprise } from "../../../../../../utils/api"

function DetailEntreprise() {
const confirmationDesactivationUtilisateur = useDisclosure()
Expand All @@ -52,11 +51,11 @@ function DetailEntreprise() {
const toast = useToast()
const { user } = useAuth()
const router = useRouter()
const { siret_userId } = router.query as { siret_userId: string } // Here userId
const { siret_userId } = router.query as { siret_userId: string }

const { data: userRecruteur, isLoading } = useQuery("user", {
enabled: !!siret_userId,
queryFn: () => apiGet(`/user/:userId`, { params: { userId: siret_userId } }),
queryFn: () => getUser(siret_userId),
cacheTime: 0,
})

Expand Down Expand Up @@ -272,7 +271,6 @@ function DetailEntreprise() {
</SimpleGrid>
{(user.type === AUTHTYPE.OPCO || user.type === AUTHTYPE.ADMIN) && (
<Box mb={12}>
{/* @ts-expect-error: TODO */}
<UserValidationHistory histories={userRecruteur.status} />
</Box>
)}
Expand Down
9 changes: 2 additions & 7 deletions ui/pages/espace-pro/administration/users/[userId].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import * as Yup from "yup"

import { getAuthServerSideProps } from "@/common/SSR/getAuthServerSideProps"
import { useAuth } from "@/context/UserContext"
import { apiGet } from "@/utils/api.utils"

import { AUTHTYPE } from "../../../../common/contants"
import useUserHistoryUpdate from "../../../../common/hooks/useUserHistoryUpdate"
Expand All @@ -43,7 +42,7 @@ import {
import { OpcoSelect } from "../../../../components/espace_pro/CreationRecruteur/OpcoSelect"
import { authProvider, withAuth } from "../../../../components/espace_pro/withAuth"
import { ArrowDropRightLine, ArrowRightLine } from "../../../../theme/components/icons"
import { updateEntreprise } from "../../../../utils/api"
import { getUser, updateEntreprise } from "../../../../utils/api"

function DetailEntreprise() {
const router = useRouter()
Expand Down Expand Up @@ -118,10 +117,7 @@ function DetailEntreprise() {
}
}

const { data: userRecruteur, isLoading }: { data: any; isLoading: boolean } = useQuery("user", () => apiGet(`/user/:userId`, { params: { userId } }), {
cacheTime: 0,
enabled: !!userId,
})
const { data: userRecruteur, isLoading } = useQuery("user", () => getUser(userId), { cacheTime: 0, enabled: !!userId })
// @ts-expect-error: TODO
const userMutation = useMutation(({ userId, establishment_id, values }) => updateEntreprise(userId, establishment_id, values), {
onSuccess: () => {
Expand Down Expand Up @@ -273,7 +269,6 @@ function DetailEntreprise() {
</SimpleGrid>
{(user.type === AUTHTYPE.OPCO || user.type === AUTHTYPE.ADMIN) && (
<Box mb={12}>
{/* @ts-expect-error: TODO */}
<UserValidationHistory histories={userRecruteur.status} />
</Box>
)}
Expand Down
6 changes: 3 additions & 3 deletions ui/pages/espace-pro/compte.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as Yup from "yup"

import { getAuthServerSideProps } from "@/common/SSR/getAuthServerSideProps"
import { useAuth } from "@/context/UserContext"
import { apiGet, apiPut } from "@/utils/api.utils"
import { apiPut } from "@/utils/api.utils"

import { AUTHTYPE } from "../../common/contants"
import { LoadingEmptySpace } from "../../components/espace_pro"
Expand All @@ -17,7 +17,7 @@ import Layout from "../../components/espace_pro/Layout"
import ModificationCompteEmail from "../../components/espace_pro/ModificationCompteEmail"
import { authProvider, withAuth } from "../../components/espace_pro/withAuth"
import { ArrowDropRightLine, ArrowRightLine } from "../../theme/components/icons"
import { updateEntreprise } from "../../utils/api"
import { getUser, updateEntreprise } from "../../utils/api"

function Compte() {
const client = useQueryClient()
Expand All @@ -42,7 +42,7 @@ function Compte() {
}
}

const { data, isLoading } = useQuery("user", () => apiGet(`/user/:userId`, { params: { userId: user._id.toString() } }))
const { data, isLoading } = useQuery("user", () => getUser(user._id.toString()))

const userMutation = useMutation(({ userId, establishment_id, values }: any) => updateEntreprise(userId, establishment_id, values), {
onSuccess: () => {
Expand Down
6 changes: 4 additions & 2 deletions ui/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export const createEtablissementDelegation = ({ data, jobId }: { jobId: string;
/**
* User API
*/
export const getUser = (userId: string) => apiGet("/user/:userId", { params: { userId } })
const updateUser = (userId: string, user) => apiPut("/user/:userId", { params: { userId }, body: user })
export const getUserStatus = (userId: string) => apiGet("/user/status/:userId", { params: { userId } })
export const updateUserValidationHistory = (userId: string, state: IUserStatusValidationJson) =>
apiPut("/user/:userId/history", { params: { userId }, body: state }).catch(errorHandler)
Expand All @@ -56,9 +58,9 @@ export const deleteEntreprise = (userId: string, recruiterId: string) => apiDele
/**
* KBA 20230511 : (migration db) : casting des valueurs coté collection recruiter, car les champs ne sont plus identiques avec la collection userRecruteur.
*/
export const updateEntreprise = async (userId: string, establishment_id, user) =>
export const updateEntreprise = async (userId: string, establishment_id: string, user: any) =>
await Promise.all([
apiPut(`/user/:userId`, { params: { userId }, body: user }),
updateUser(userId, user),
//
updateFormulaire(establishment_id, user),
])
Expand Down

0 comments on commit c10da68

Please sign in to comment.