diff --git a/packages/hasura/metadata/actions.yaml b/packages/hasura/metadata/actions.yaml index fd4e64dd..4c2c9882 100644 --- a/packages/hasura/metadata/actions.yaml +++ b/packages/hasura/metadata/actions.yaml @@ -2,26 +2,31 @@ actions: - name: disableAction definition: kind: synchronous - handler: '{{APP_URL}}/api/accounts/disable' + handler: "{{APP_URL}}/api/accounts/disable" forward_client_headers: true request_transform: method: PUT query_params: {} template_engine: Kriti version: 2 + permissions: + - role: user - name: enableAction definition: kind: synchronous - handler: '{{APP_URL}}/api/accounts/enable' + handler: "{{APP_URL}}/api/accounts/enable" + forward_client_headers: true request_transform: method: PUT query_params: {} template_engine: Kriti version: 2 + permissions: + - role: user - name: onboardingRequestAction definition: kind: synchronous - handler: '{{APP_URL}}/api/onboarding/request' + handler: "{{APP_URL}}/api/onboarding/request" forward_client_headers: true permissions: - role: anonymous @@ -29,7 +34,7 @@ actions: - name: onboardingReviewAction definition: kind: synchronous - handler: '{{APP_URL}}/api/onboarding/review' + handler: "{{APP_URL}}/api/onboarding/review" forward_client_headers: true permissions: - role: user diff --git a/src/components/users/index.tsx b/src/components/users/index.tsx index be85b2f0..d01adfb3 100644 --- a/src/components/users/index.tsx +++ b/src/components/users/index.tsx @@ -7,22 +7,23 @@ import statusOk from "@/utils/status-ok" import UserList from "@/components/users/user-list" import { usePagedUsers } from "@/hooks/use-paged-users" import useSelectedUser from "@/hooks/use-selected-user" -import AccountDeleteModal from "./delete-account-modal" import UserSelected from "@/components/users/user-selected" import { - revokeAccount, + disableAccount, detachUserServiceAccount, mapUser, mergeUsers, mutateUser, + enableAccount, } from "@/hooks/use-users" +import AccountToggleModal from "./toggle-account-modal" const Users = () => { const { mutate } = useSWRConfig() const { pagedUsers } = usePagedUsers() const [droppedUser, setDroppedUser] = useState() const { selectedUser, setSelectedUser } = useSelectedUser() - const [accountToDelete, setAccountToDelete] = useState() + const [accountToToggle, setAccountToToggle] = useState() useEffect(() => { if (pagedUsers && pagedUsers.length && !selectedUser) { @@ -51,27 +52,35 @@ const Users = () => { } } - const handleDeleteAccount = (account: ServiceAccount) => { - setAccountToDelete(account) + const handleToggleAccount = (accountToToggle: AccountToToggle) => { + setAccountToToggle(accountToToggle) } - const handleConfirmDeleteAccount = async () => { - const { status, body } = await revokeAccount( - accountToDelete as ServiceAccount - ) - if (statusOk(status)) { + const handleConfirmToggleAccount = async ( + accountToToggle: AccountToToggle + ) => { + let response + if (accountToToggle.disable) { + response = await disableAccount(accountToToggle.account) + } else { + response = await enableAccount(accountToToggle.account) + } + if (statusOk(response.status)) { mutate("/users") } - return { status, body } + return response } return (
- setAccountToDelete(undefined)} + + handleConfirmToggleAccount(accountToToggle as AccountToToggle) + } + onRequestClose={() => setAccountToToggle(undefined)} /> { onUserDrop={setDroppedUser} onUserEdit={handleUserEdit} onAccountsChange={(account) => handleAccountsChange(account)} - onDeleteAccount={handleDeleteAccount} + onToggleAccount={handleToggleAccount} />
diff --git a/src/components/users/delete-account-modal.tsx b/src/components/users/toggle-account-modal.tsx similarity index 82% rename from src/components/users/delete-account-modal.tsx rename to src/components/users/toggle-account-modal.tsx index 9f72ca63..fc4afa07 100644 --- a/src/components/users/delete-account-modal.tsx +++ b/src/components/users/toggle-account-modal.tsx @@ -2,11 +2,13 @@ import { useState } from "react" import Modal from "react-modal" import Loader from "../common/loader" -const AccountDeleteModal = ({ +const AccountToggleModal = ({ + disable, isOpen, onConfirm, onRequestClose, }: { + disable: boolean | undefined isOpen: boolean onConfirm: () => Promise<{ status: number; body: string }> onRequestClose: () => void @@ -36,24 +38,21 @@ const AccountDeleteModal = ({ className="modal" ariaHideApp={false} onRequestClose={handleRequestClose} - contentLabel="Delete account modal" + contentLabel="Toggle account modal" overlayClassName="modal-overlay" > -

Révoquer un accès

+

{disable ? "Désactiver" : "Activer"} un accès


{!isConfirmed ? ( <>

- Vous allez supprimer un accès utilisateur sur un outil de la - Fabrique. -

-

- Cela sera réellement répercuté sur le service concerné et peut être - irréversible. + Vous allez {disable ? "désactiver" : "activer"} un accès utilisateur + sur un outil de la Fabrique.

+

Cela sera répercuté sur le service concerné.


diff --git a/src/components/users/user-selected.tsx b/src/components/users/user-selected.tsx index 87528a4f..976a8fef 100644 --- a/src/components/users/user-selected.tsx +++ b/src/components/users/user-selected.tsx @@ -8,12 +8,12 @@ const UserSelected = ({ onUserDrop, onUserEdit, onAccountsChange, - onDeleteAccount, + onToggleAccount, }: { onUserDrop: (user: User) => void onUserEdit: (user: User) => void onAccountsChange: (account: ServiceAccount) => void - onDeleteAccount: (account: ServiceAccount) => void + onToggleAccount: (account: AccountToToggle) => void }) => { const users = useUsers() const { selectedUser, setSelectedUser } = useSelectedUser() @@ -34,7 +34,7 @@ const UserSelected = ({ onUserDrop={onUserDrop} onUserEdit={onUserEdit} onAccountsChange={onAccountsChange} - onDeleteAccount={onDeleteAccount} + onToggleAccount={onToggleAccount} /> ) : (
diff --git a/src/components/users/user-service-info.tsx b/src/components/users/user-service-info.tsx index c2c835c8..ac7e9bbe 100644 --- a/src/components/users/user-service-info.tsx +++ b/src/components/users/user-service-info.tsx @@ -185,12 +185,12 @@ const UserServiceInfo = ({ account, isSingleAccount, onDetachAccount, - onDeleteAccount, + onToggleAccount, }: { account: ServiceAccount isSingleAccount: boolean onDetachAccount: (account: ServiceAccount) => void - onDeleteAccount: (account: ServiceAccount) => void + onToggleAccount: (account: AccountToToggle) => void }) => { const ref = useSpringRef() @@ -221,13 +221,21 @@ const UserServiceInfo = ({ )} - + {account.disabled ? ( + + ) : ( + + )}
{account.type === "github" && } diff --git a/src/components/users/user-services.tsx b/src/components/users/user-services.tsx index ef888639..a4c79435 100644 --- a/src/components/users/user-services.tsx +++ b/src/components/users/user-services.tsx @@ -3,11 +3,11 @@ import UserServiceInfo from "@/components/users/user-service-info" const UserServices = ({ services, onDetachAccount, - onDeleteAccount, + onToggleAccount, }: { services: ServiceAccount[] onDetachAccount: (account: ServiceAccount) => void - onDeleteAccount: (account: ServiceAccount) => void + onToggleAccount: (account: AccountToToggle) => void }) => { const isSingleAccount = services.length <= 1 @@ -19,7 +19,7 @@ const UserServices = ({ account={account} isSingleAccount={isSingleAccount} onDetachAccount={onDetachAccount} - onDeleteAccount={onDeleteAccount} + onToggleAccount={onToggleAccount} /> ))} diff --git a/src/hooks/use-users.ts b/src/hooks/use-users.ts index 537ba2c0..f60416f7 100644 --- a/src/hooks/use-users.ts +++ b/src/hooks/use-users.ts @@ -9,7 +9,8 @@ import { insertUser, updateService, mergeUsers as mergeUsersQuery, - revokeAction, + disableAction, + enableAction, } from "@/queries/index" import logAction from "@/utils/log-action" import { getSession } from "next-auth/react" @@ -160,23 +161,28 @@ export const detachUserServiceAccount = async (account: ServiceAccount) => { }) } -export const revokeAccount = async (account: ServiceAccount) => { - const accountServiceID = - account.type === "ovh" - ? account.data.primaryEmailAddress - : account.type === "github" || account.type === "matomo" - ? account.data.login - : account.data.id +export const disableAccount = async (account: ServiceAccount) => { + const { + disableAction: { status, body }, + } = await graphQLFetcher({ + query: disableAction, + includeCookie: true, + parameters: { + serviceAccountId: account.id, + }, + }) + + return { status, body } +} +export const enableAccount = async (account: ServiceAccount) => { const { - revokeAction: { status, body }, + enableAction: { status, body }, } = await graphQLFetcher({ - query: revokeAction, + query: enableAction, includeCookie: true, parameters: { - serviceName: account.type, - accountID: account.id, - accountServiceID, + serviceAccountId: account.id, }, }) diff --git a/src/pages/api/accounts/disable.ts b/src/pages/api/accounts/disable.ts index bc7a601e..663c9c2e 100644 --- a/src/pages/api/accounts/disable.ts +++ b/src/pages/api/accounts/disable.ts @@ -30,7 +30,7 @@ const Disable = async (req: NextApiRequest, res: NextApiResponse) => { const bodySchema = z.object({ id: z.string().uuid(), }) - const parsedBody = bodySchema.safeParse(req.body) + const parsedBody = bodySchema.safeParse(req.body.input.data) if (!parsedBody.success) { logger.error(parsedBody.error) res.status(400).json({ message: "Bad Request" }) @@ -63,16 +63,16 @@ const Disable = async (req: NextApiRequest, res: NextApiResponse) => { let response: APIResponse if (serviceAccount.type === "mattermost") { - const res = await disableMattermostAccount(serviceAccount.data.id) - response = { status: res.status, body: await res.json() } + const r = await disableMattermostAccount(serviceAccount.data.id) + response = { status: r.status, body: await r.json() } } else if (serviceAccount.type === "github") { - const res = await disableGithubAccount(serviceAccount.data.login) - response = { status: res.status, body: await res.json() } + const r = await disableGithubAccount(serviceAccount.data.login) + response = { status: r.status, body: await r.text() } // Github does not always send valid JSON } else if (serviceAccount.type == "ovh") { - const res = await disableOvhAccount(serviceAccount.data.primaryEmailAddress) - return { - status: res.success ? "200" : "500", - body: res.success ? res.data : res.error, + const r = await disableOvhAccount(serviceAccount.data.primaryEmailAddress) + response = { + status: r.success ? 200 : 500, + body: r.success ? (r.data as string) : JSON.stringify(r.error), } } else { logger.error( @@ -90,8 +90,8 @@ const Disable = async (req: NextApiRequest, res: NextApiResponse) => { query: updateService, token, parameters: { - id: serviceAccount.id, - _set: { disabled: true }, + serviceId: serviceAccount.id, + service: { disabled: true }, }, }) } diff --git a/src/pages/api/accounts/enable.ts b/src/pages/api/accounts/enable.ts index 3ae16b32..b997eb74 100644 --- a/src/pages/api/accounts/enable.ts +++ b/src/pages/api/accounts/enable.ts @@ -30,7 +30,7 @@ const Enable = async (req: NextApiRequest, res: NextApiResponse) => { const bodySchema = z.object({ id: z.string().uuid(), }) - const parsedBody = bodySchema.safeParse(req.body) + const parsedBody = bodySchema.safeParse(req.body.input.data) if (!parsedBody.success) { logger.error(parsedBody.error) res.status(400).json({ message: "Bad Request" }) @@ -100,8 +100,8 @@ const Enable = async (req: NextApiRequest, res: NextApiResponse) => { query: updateService, token, parameters: { - id: serviceAccount.id, - _set: { disabled: false }, + serviceId: serviceAccount.id, + service: { disabled: false }, }, }) } diff --git a/src/queries/index.ts b/src/queries/index.ts index ae8de36b..bec644a3 100644 --- a/src/queries/index.ts +++ b/src/queries/index.ts @@ -10,6 +10,7 @@ const userFragment = gql` id data type + disabled } } ` @@ -38,7 +39,7 @@ export const getUsers = gql` ` export const getService = gql` - query getService($id! uuid!) { + query getService($id: uuid!) { services_by_pk(id: $id) { id type @@ -267,19 +268,18 @@ export const confirmOnboardingRequest = gql` } ` -export const revokeAction = gql` - mutation revokeAction( - $accountID: String! - $accountServiceID: String! - $serviceName: String! - ) { - revokeAction( - data: { - accountID: $accountID - accountServiceID: $accountServiceID - serviceName: $serviceName - } - ) { +export const disableAction = gql` + mutation disableAction($serviceAccountId: uuid!) { + disableAction(data: { id: $serviceAccountId }) { + body + status + } + } +` + +export const enableAction = gql` + mutation enableAction($serviceAccountId: uuid!) { + enableAction(data: { id: $serviceAccountId }) { body status } diff --git a/src/services/disablers/github.ts b/src/services/disablers/github.ts index 4b749dc2..c59aa146 100644 --- a/src/services/disablers/github.ts +++ b/src/services/disablers/github.ts @@ -7,7 +7,7 @@ export function disableGithubAccount(username: string) { { method: "DELETE", headers: { - accept: "application/vnd.github.v3+json", + accept: "application/vnd.github+json", authorization: `Bearer ${GITHUB_API_TOKEN}`, }, } diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 2bb90f6d..4ac038bf 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -31,9 +31,15 @@ interface ZammadGroup { name: string } +interface AccountToToggle { + disable: boolean + account: ServiceAccount +} + interface BasicServiceAccount { id: string type: ServiceName + disabled: boolean } interface GithubServiceAccount extends BasicServiceAccount {