From db0a75ec34c1acbbd5e910861c786db3308b6e5a Mon Sep 17 00:00:00 2001 From: Maxime Golfier <25312957+maxgfr@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:47:33 +0200 Subject: [PATCH] refactor(auth): utilisation de `next-auth` (#1322) * fix: code * fix: code * fix: code * fix: code * fix: permissions * fix: permissions * fix: permissions * fix: permissions * fix: permissions * fix: permissions * fix: permissions * fix: permissions * fix: permissions * fix: permissions * feat: upgrade urql (#1332) * fix: permissions * fix: permissions * fix: permissions * fix: permissions * fix: permissions * fix: items * fix: items * fix: items * fix: items * fix: items * fix: items * fix: items * fix: items * fix: items * fix: items * fix: items * fix: delete db logic * fix: delete db logic * fix: delete db logic * fix: delete db logic * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: regex * fix: naming * fix: naming * fix: naming * fix: test * fix: test * fix: test * fix: test * fix: test * fix: test * fix: test * fix: test * fix: test * fix: test * fix: test * fix: test * fix: test * fix: test * fix: bug * fix: merge * fix: merge * fix: merge * fix: bug * fix: returning * fix: returning * fix: merge * fix: types * fix: types * fix: done * Update targets/frontend/src/components/user/List.tsx Co-authored-by: Caroline <4971715+carolineBda@users.noreply.github.com> * fix: done * fix: creation compte --------- Co-authored-by: Caroline <4971715+carolineBda@users.noreply.github.com> --- .../templates/contributions.configmap.yaml | 9 - .../contributions.sealed-secret.yaml | 17 - .../env/dev/templates/www.sealed-secret.yaml | 3 +- .kontinuous/env/dev/values.yaml | 4 +- .../templates/contributions.configmap.yaml | 9 - .../contributions.sealed-secret.yaml | 17 - .../preprod/templates/www.sealed-secret.yaml | 3 +- .kontinuous/env/preprod/values.yaml | 10 +- .../templates/contributions.configmap.yaml | 10 - .../contributions.sealed-secret.yaml | 14 - .../env/prod/templates/www.sealed-secret.yaml | 3 +- .kontinuous/env/prod/values.yaml | 23 +- .kontinuous/sql/post-restore.sql | 102 +-- .kontinuous/values.yaml | 6 +- README.md | 13 +- shared/elasticsearch/.eslintignore | 1 + shared/elasticsearch/package.json | 2 +- shared/elasticsearch/src/index.d.ts | 9 + shared/types/index.ts | 1 - shared/types/package.json | 2 +- shared/utils/package.json | 8 +- shared/utils/src/gql-client.ts | 16 +- targets/alert-cli/package.json | 8 +- .../__tests__/editorialContents.test.ts | 92 +- .../__tests__/mailTemplates.test.ts | 36 +- .../src/diff/shared/fetchPrequalified.ts | 2 +- .../src/diff/shared/getSupportedAgreements.ts | 2 +- .../src/repositories/AlertRepository.ts | 6 +- .../src/repositories/FicheSPRepository.ts | 8 +- .../src/repositories/SourcesRepository.ts | 8 +- .../src/repositories/WarningRepository.ts | 6 +- targets/export-elasticsearch/Dockerfile | 5 +- targets/export-elasticsearch/package.json | 2 +- .../src/ingester/common/fetchGlossary.ts | 2 +- .../contributions/fetchCcUnextended.ts | 2 +- .../updateExportEsStatusWithDocumentsCount.ts | 2 +- .../src/ingester/ingest.ts | 3 +- .../prequalified/fetchPrequalified.ts | 2 +- .../src/ingester/suggestion.test.ts | 1 - .../src/ingester/suggestion.ts | 1 - .../src/ingester/themes/fetchThemes.ts | 2 +- .../src/repositories/agreements.ts | 2 +- .../src/repositories/graphql/mutation.ts | 4 +- .../src/repositories/graphql/queries.ts | 10 +- .../src/repositories/status.ts | 2 +- targets/frontend/Dockerfile | 3 + targets/frontend/next.config.js | 19 +- targets/frontend/package.json | 42 +- .../__tests__/contenus/contentList.test.tsx | 17 - targets/frontend/src/components/Roles.tsx | 32 - .../src/components/changes/ChangeGroup.tsx | 2 + .../frontend/src/components/comments/index.js | 7 +- .../contributions/answers/Answer.tsx | 13 +- .../contributions/answers/Comments.tsx | 7 +- .../answers/__tests__/AnswerForm.test.tsx | 98 ++- .../contributions/questions/EditQuestion.tsx | 7 +- .../editorialContent/ContentSections.tsx | 2 +- .../src/components/fiches-sp/addFiche.js | 15 +- .../components/fiches-sp/fichesSpContainer.js | 34 +- .../home/InvisibleLinkedDocument.tsx | 3 +- .../src/components/layout/UserMenu.tsx | 18 +- .../src/components/layout/auth.layout.tsx | 13 +- .../components/login/{index.js => index.tsx} | 43 +- .../src/components/storage/DropZone.tsx | 2 +- .../frontend/src/components/themes/List.js | 5 +- targets/frontend/src/components/user/List.js | 170 ---- targets/frontend/src/components/user/List.tsx | 131 +++ .../src/components/user/PasswordForm.js | 15 +- .../frontend/src/components/user/UserForm.js | 31 +- .../src/components/utils/SnackBar.tsx | 2 +- targets/frontend/src/config.ts | 4 +- targets/frontend/src/hoc/CustomUrqlClient.js | 33 - targets/frontend/src/hoc/UserProvider.js | 79 -- targets/frontend/src/hoc/getDisplayName.js | 4 - targets/frontend/src/hooks/exportEs.ts | 13 +- targets/frontend/src/hooks/useUser.js | 6 - targets/frontend/src/lib/api/ApiClient.ts | 24 +- targets/frontend/src/lib/auth/cookie.ts | 56 -- targets/frontend/src/lib/auth/exchanges.js | 74 -- targets/frontend/src/lib/auth/jwt.js | 63 -- targets/frontend/src/lib/auth/token.js | 84 -- .../contenus/getDocument.query.graphql | 0 .../contenus/updateDocument.mutation.graphql | 0 .../src/lib/{duration.js => duration.ts} | 14 +- .../src/lib/emails/activateAccount.ts | 25 - .../src/lib/emails/getAccountSecretToken.ts | 32 - .../frontend/src/lib/emails/lostPassword.js | 29 - .../src/lib/emails/passwordChangeConfirm.js | 19 - targets/frontend/src/lib/emails/sendmail.js | 13 - targets/frontend/src/lib/regex.js | 2 - .../src/modules/agreements/api/query.ts | 2 +- .../components/Creation/agreement.mutation.ts | 3 +- .../components/Edition/agreement.mutation.ts | 3 +- .../components/Edition/agreement.query.ts | 3 +- .../components/Edition/delete.mutation.ts | 3 +- .../agreements/components/List/list.query.ts | 3 +- .../modules/authentification/activateUser.ts | 76 ++ .../authentification/changePassword.ts | 84 ++ .../modules/authentification/createUser.ts | 71 ++ .../modules/authentification/deleteUser.ts | 43 + .../authentification/generateAccessToken.ts | 68 ++ .../modules/authentification/resetPassword.ts | 48 + .../src/modules/authentification/signIn.ts | 122 +++ .../modules/authentification/utils/errors.ts | 19 + .../authentification/utils/exchanges.ts | 43 + .../src/modules/authentification/utils/jwt.ts | 107 +++ .../authentification/utils/regex.ts} | 6 +- .../src/modules/contribution/api/query.ts | 2 +- targets/frontend/src/modules/emails/send.ts | 24 + .../emails/sendActivateAccountEmail.ts | 26 + .../modules/emails/sendLostPasswordEmail.ts | 27 + .../src/modules/export/components/export.tsx | 10 +- .../src/modules/export/document.query.ts | 8 +- .../informations/api/informations.query.ts | 2 +- .../informationsEdit/Informations.query.ts | 3 +- .../deleteInformation.mutation.ts | 3 +- .../editInformation.mutation.ts | 4 +- .../src/modules/models/api/modelsQuery.ts | 2 +- .../components/Creation/model.mutation.ts | 3 +- .../components/Edition/model.mutation.ts | 3 +- .../models/components/Edition/model.query.ts | 61 +- .../components/Edition/publish.mutation.ts | 25 +- .../models/components/List/list.query.ts | 3 +- .../edition/prequalifiedDelete.mutation.ts | 3 +- .../useContributionReferencesQuery.tsx | 3 +- targets/frontend/src/pages/_app.js | 55 -- targets/frontend/src/pages/_app.tsx | 46 + .../src/pages/agreements/[agreementId].tsx | 4 +- .../src/pages/agreements/creation.tsx | 4 +- .../frontend/src/pages/agreements/index.tsx | 4 +- .../src/pages/alerts/[[...params]].tsx | 4 +- .../api/actions/email_account_activation.ts | 40 - .../api/actions/email_password_request.js | 32 - .../src/pages/api/activate_account.js | 89 -- .../src/pages/api/auth/[...nextauth].ts | 56 ++ .../frontend/src/pages/api/change_password.js | 84 -- .../src/pages/api/get_user_email.gql.js | 13 - .../src/pages/api/{graphql.js => graphql.ts} | 14 +- targets/frontend/src/pages/api/login.gql.js | 35 - targets/frontend/src/pages/api/login.js | 100 --- targets/frontend/src/pages/api/logout.js | 54 -- .../frontend/src/pages/api/password.gql.js | 55 -- .../src/pages/api/refresh_token.gql.js | 53 -- .../frontend/src/pages/api/refresh_token.js | 97 -- .../frontend/src/pages/api/renew_password.js | 9 - .../frontend/src/pages/api/reset_password.js | 76 -- targets/frontend/src/pages/api/sitemap.ts | 2 +- .../frontend/src/pages/api/storage/[path].ts | 11 - .../frontend/src/pages/api/storage/index.ts | 11 - .../frontend/src/pages/api/users/activate.ts | 31 + .../frontend/src/pages/api/users/create.ts | 53 ++ .../frontend/src/pages/api/users/delete.ts | 49 ++ .../src/pages/api/users/password/change.ts | 54 ++ .../src/pages/api/users/password/reset.ts | 30 + .../api/{validation.js => validation.ts} | 2 +- .../frontend/src/pages/change_password.tsx | 64 +- targets/frontend/src/pages/contenus/[id].tsx | 8 +- .../pages/contenus/create/[[...source]].tsx | 4 +- .../frontend/src/pages/contenus/edit/[id].tsx | 5 +- .../frontend/src/pages/contenus/fiches-sp.tsx | 4 +- targets/frontend/src/pages/contenus/index.tsx | 4 +- .../contributions/answers/[answerId].tsx | 4 +- .../src/pages/contributions/index.tsx | 4 +- .../contributions/questions/[questionId].tsx | 4 +- targets/frontend/src/pages/duplicates.tsx | 4 +- targets/frontend/src/pages/fichiers.tsx | 6 +- .../frontend/src/pages/ghost-documents.tsx | 4 +- .../src/pages/glossary/edit/[[...id]].js | 4 +- targets/frontend/src/pages/glossary/index.js | 14 +- .../src/pages/{healthz.js => healthz.tsx} | 0 targets/frontend/src/pages/index.tsx | 4 +- .../frontend/src/pages/informations/[id].tsx | 4 +- .../src/pages/informations/creation.tsx | 4 +- .../frontend/src/pages/informations/index.tsx | 4 +- targets/frontend/src/pages/kali/blocks.js | 4 +- .../src/pages/{login.js => login.tsx} | 42 +- targets/frontend/src/pages/mises-a-jour.tsx | 4 +- .../frontend/src/pages/models/[modelId].tsx | 4 +- .../frontend/src/pages/models/creation.tsx | 4 +- targets/frontend/src/pages/models/index.tsx | 4 +- .../frontend/src/pages/prequalified/[id].tsx | 4 +- .../src/pages/prequalified/create.tsx | 4 +- .../frontend/src/pages/prequalified/index.tsx | 4 +- .../{reset_password.js => reset_password.tsx} | 73 +- .../frontend/src/pages/themes/[[...id]].js | 27 +- .../frontend/src/pages/themes/[id]/create.js | 4 +- targets/frontend/src/pages/themes/create.js | 4 +- .../frontend/src/pages/themes/edit/[id].js | 4 +- targets/frontend/src/pages/unthemed.js | 6 +- targets/frontend/src/pages/user/edit.js | 74 -- targets/frontend/src/pages/user/edit/[id].js | 92 -- targets/frontend/src/pages/user/new.js | 68 -- targets/frontend/src/pages/user/password.js | 25 - targets/frontend/src/pages/users.js | 34 - .../{user/account.js => users/account.tsx} | 29 +- targets/frontend/src/pages/users/index.tsx | 53 ++ targets/frontend/src/pages/users/new.tsx | 37 + targets/frontend/src/pages/users/password.tsx | 34 + .../src/{index.d.ts => types/graphql.d.ts} | 0 targets/frontend/src/types/next-auth.d.ts | 17 + targets/frontend/tsconfig.json | 1 - targets/hasura/metadata/actions.graphql | 25 - targets/hasura/metadata/actions.yaml | 41 - .../default/tables/auth_refresh_tokens.yaml | 4 - .../default/tables/auth_user_roles.yaml | 7 - .../databases/default/tables/auth_users.yaml | 96 +- .../tables/contribution_answer_comments.yaml | 4 +- .../tables/public_document_relations.yaml | 10 - .../default/tables/public_documents.yaml | 18 - .../default/tables/public_glossary.yaml | 13 - .../default/tables/public_kali_blocks.yaml | 8 - .../tables/public_package_version.yaml | 8 - .../default/tables/public_roles.yaml | 15 - .../databases/default/tables/tables.yaml | 4 - .../down.sql | 3 + .../up.sql | 1 + .../down.sql | 5 + .../up.sql | 1 + .../down.sql | 5 + .../up.sql | 1 + .../down.sql | 1 + .../up.sql | 1 + .../down.sql | 3 + .../up.sql | 1 + .../down.sql | 5 + .../up.sql | 1 + .../down.sql | 3 + .../up.sql | 1 + .../down.sql | 3 + .../up.sql | 1 + .../down.sql | 1 + .../up.sql | 1 + .../down.sql | 1 + .../up.sql | 1 + .../down.sql | 1 + .../up.sql | 1 + .../down.sql | 1 + .../up.sql | 1 + .../down.sql | 1 + .../up.sql | 1 + .../down.sql | 1 + .../up.sql | 1 + .../down.sql | 5 + .../up.sql | 3 + .../down.sql | 1 + .../up.sql | 1 + .../down.sql | 1 + .../up.sql | 1 + .../down.sql | 1 + .../up.sql | 1 + .../down.sql | 2 + .../up.sql | 2 + .../down.sql | 2 + .../up.sql | 2 + .../down.sql | 3 + .../up.sql | 3 + .../down.sql | 4 + .../up.sql | 1 + .../down.sql | 4 + .../up.sql | 2 + .../down.sql | 4 + .../up.sql | 1 + .../down.sql | 4 + .../up.sql | 1 + .../down.sql | 4 + .../up.sql | 1 + .../down.sql | 2 + .../up.sql | 1 + targets/ingester/package.json | 2 +- .../kali/load-supported-agreements.ts | 2 +- .../ContributionRepository.ts | 9 +- .../src/lib/hasura-mutations-queries.ts | 90 +- .../fetchAgreementsWithKaliId.ts | 2 +- .../transform/fichesServicePublic/index.ts | 2 +- yarn.lock | 826 ++++++++++-------- 275 files changed, 2642 insertions(+), 3332 deletions(-) delete mode 100644 .kontinuous/env/dev/templates/contributions.configmap.yaml delete mode 100644 .kontinuous/env/dev/templates/contributions.sealed-secret.yaml delete mode 100644 .kontinuous/env/preprod/templates/contributions.configmap.yaml delete mode 100644 .kontinuous/env/preprod/templates/contributions.sealed-secret.yaml delete mode 100644 .kontinuous/env/prod/templates/contributions.configmap.yaml delete mode 100644 .kontinuous/env/prod/templates/contributions.sealed-secret.yaml create mode 100644 shared/elasticsearch/src/index.d.ts delete mode 100644 targets/frontend/src/__tests__/contenus/contentList.test.tsx delete mode 100644 targets/frontend/src/components/Roles.tsx rename targets/frontend/src/components/login/{index.js => index.tsx} (71%) delete mode 100644 targets/frontend/src/components/user/List.js create mode 100644 targets/frontend/src/components/user/List.tsx delete mode 100644 targets/frontend/src/hoc/CustomUrqlClient.js delete mode 100644 targets/frontend/src/hoc/UserProvider.js delete mode 100644 targets/frontend/src/hoc/getDisplayName.js delete mode 100644 targets/frontend/src/hooks/useUser.js delete mode 100644 targets/frontend/src/lib/auth/cookie.ts delete mode 100644 targets/frontend/src/lib/auth/exchanges.js delete mode 100644 targets/frontend/src/lib/auth/jwt.js delete mode 100644 targets/frontend/src/lib/auth/token.js rename targets/frontend/src/{pages => lib}/contenus/getDocument.query.graphql (100%) rename targets/frontend/src/{pages => lib}/contenus/updateDocument.mutation.graphql (100%) rename targets/frontend/src/lib/{duration.js => duration.ts} (59%) delete mode 100644 targets/frontend/src/lib/emails/activateAccount.ts delete mode 100644 targets/frontend/src/lib/emails/getAccountSecretToken.ts delete mode 100644 targets/frontend/src/lib/emails/lostPassword.js delete mode 100644 targets/frontend/src/lib/emails/passwordChangeConfirm.js delete mode 100644 targets/frontend/src/lib/emails/sendmail.js delete mode 100644 targets/frontend/src/lib/regex.js create mode 100644 targets/frontend/src/modules/authentification/activateUser.ts create mode 100644 targets/frontend/src/modules/authentification/changePassword.ts create mode 100644 targets/frontend/src/modules/authentification/createUser.ts create mode 100644 targets/frontend/src/modules/authentification/deleteUser.ts create mode 100644 targets/frontend/src/modules/authentification/generateAccessToken.ts create mode 100644 targets/frontend/src/modules/authentification/resetPassword.ts create mode 100644 targets/frontend/src/modules/authentification/signIn.ts create mode 100644 targets/frontend/src/modules/authentification/utils/errors.ts create mode 100644 targets/frontend/src/modules/authentification/utils/exchanges.ts create mode 100644 targets/frontend/src/modules/authentification/utils/jwt.ts rename targets/frontend/src/{lib/auth/auth.const.ts => modules/authentification/utils/regex.ts} (53%) create mode 100644 targets/frontend/src/modules/emails/send.ts create mode 100644 targets/frontend/src/modules/emails/sendActivateAccountEmail.ts create mode 100644 targets/frontend/src/modules/emails/sendLostPasswordEmail.ts delete mode 100644 targets/frontend/src/pages/_app.js create mode 100644 targets/frontend/src/pages/_app.tsx delete mode 100644 targets/frontend/src/pages/api/actions/email_account_activation.ts delete mode 100644 targets/frontend/src/pages/api/actions/email_password_request.js delete mode 100644 targets/frontend/src/pages/api/activate_account.js create mode 100644 targets/frontend/src/pages/api/auth/[...nextauth].ts delete mode 100644 targets/frontend/src/pages/api/change_password.js delete mode 100644 targets/frontend/src/pages/api/get_user_email.gql.js rename targets/frontend/src/pages/api/{graphql.js => graphql.ts} (57%) delete mode 100644 targets/frontend/src/pages/api/login.gql.js delete mode 100644 targets/frontend/src/pages/api/login.js delete mode 100644 targets/frontend/src/pages/api/logout.js delete mode 100644 targets/frontend/src/pages/api/password.gql.js delete mode 100644 targets/frontend/src/pages/api/refresh_token.gql.js delete mode 100644 targets/frontend/src/pages/api/refresh_token.js delete mode 100644 targets/frontend/src/pages/api/renew_password.js delete mode 100644 targets/frontend/src/pages/api/reset_password.js create mode 100644 targets/frontend/src/pages/api/users/activate.ts create mode 100644 targets/frontend/src/pages/api/users/create.ts create mode 100644 targets/frontend/src/pages/api/users/delete.ts create mode 100644 targets/frontend/src/pages/api/users/password/change.ts create mode 100644 targets/frontend/src/pages/api/users/password/reset.ts rename targets/frontend/src/pages/api/{validation.js => validation.ts} (60%) rename targets/frontend/src/pages/{healthz.js => healthz.tsx} (100%) rename targets/frontend/src/pages/{login.js => login.tsx} (51%) rename targets/frontend/src/pages/{reset_password.js => reset_password.tsx} (54%) delete mode 100644 targets/frontend/src/pages/user/edit.js delete mode 100644 targets/frontend/src/pages/user/edit/[id].js delete mode 100644 targets/frontend/src/pages/user/new.js delete mode 100644 targets/frontend/src/pages/user/password.js delete mode 100644 targets/frontend/src/pages/users.js rename targets/frontend/src/pages/{user/account.js => users/account.tsx} (59%) create mode 100644 targets/frontend/src/pages/users/index.tsx create mode 100644 targets/frontend/src/pages/users/new.tsx create mode 100644 targets/frontend/src/pages/users/password.tsx rename targets/frontend/src/{index.d.ts => types/graphql.d.ts} (100%) create mode 100644 targets/frontend/src/types/next-auth.d.ts create mode 100644 targets/hasura/migrations/default/1710942991576_drop_table_auth_refresh_tokens/down.sql create mode 100644 targets/hasura/migrations/default/1710942991576_drop_table_auth_refresh_tokens/up.sql create mode 100644 targets/hasura/migrations/default/1710943179800_delete_fk_auth_user_roles_user_roles_user_id_fkey/down.sql create mode 100644 targets/hasura/migrations/default/1710943179800_delete_fk_auth_user_roles_user_roles_user_id_fkey/up.sql create mode 100644 targets/hasura/migrations/default/1710943186197_delete_fk_auth_user_roles_user_roles_role_fkey/down.sql create mode 100644 targets/hasura/migrations/default/1710943186197_delete_fk_auth_user_roles_user_roles_role_fkey/up.sql create mode 100644 targets/hasura/migrations/default/1710943195146_alter_table_auth_user_roles_drop_constraint_user_roles_user_id_role_key/down.sql create mode 100644 targets/hasura/migrations/default/1710943195146_alter_table_auth_user_roles_drop_constraint_user_roles_user_id_role_key/up.sql create mode 100644 targets/hasura/migrations/default/1710943204983_drop_table_auth_user_roles/down.sql create mode 100644 targets/hasura/migrations/default/1710943204983_drop_table_auth_user_roles/up.sql create mode 100644 targets/hasura/migrations/default/1710943530563_delete_fk_auth_users_users_default_role_fkey/down.sql create mode 100644 targets/hasura/migrations/default/1710943530563_delete_fk_auth_users_users_default_role_fkey/up.sql create mode 100644 targets/hasura/migrations/default/1710943562140_drop_table_public_roles/down.sql create mode 100644 targets/hasura/migrations/default/1710943562140_drop_table_public_roles/up.sql create mode 100644 targets/hasura/migrations/default/1710945049362_drop_table_public_pipelines/down.sql create mode 100644 targets/hasura/migrations/default/1710945049362_drop_table_public_pipelines/up.sql create mode 100644 targets/hasura/migrations/default/1710946501277_alter_table_auth_users_update_comment/down.sql create mode 100644 targets/hasura/migrations/default/1710946501277_alter_table_auth_users_update_comment/up.sql create mode 100644 targets/hasura/migrations/default/1710947045361_alter_table_auth_users_alter_column_default_role/down.sql create mode 100644 targets/hasura/migrations/default/1710947045361_alter_table_auth_users_alter_column_default_role/up.sql create mode 100644 targets/hasura/migrations/default/1710947065729_alter_table_auth_users_alter_column_deleted/down.sql create mode 100644 targets/hasura/migrations/default/1710947065729_alter_table_auth_users_alter_column_deleted/up.sql create mode 100644 targets/hasura/migrations/default/1710947130787_alter_table_auth_users_alter_column_secret_token/down.sql create mode 100644 targets/hasura/migrations/default/1710947130787_alter_table_auth_users_alter_column_secret_token/up.sql create mode 100644 targets/hasura/migrations/default/1710947143482_alter_table_auth_users_alter_column_active/down.sql create mode 100644 targets/hasura/migrations/default/1710947143482_alter_table_auth_users_alter_column_active/up.sql create mode 100644 targets/hasura/migrations/default/1710947167029_alter_table_auth_users_alter_column_secret_token_expires_at/down.sql create mode 100644 targets/hasura/migrations/default/1710947167029_alter_table_auth_users_alter_column_secret_token_expires_at/up.sql create mode 100644 targets/hasura/migrations/default/1710947221940_alter_table_auth_users_add_column_access_token/down.sql create mode 100644 targets/hasura/migrations/default/1710947221940_alter_table_auth_users_add_column_access_token/up.sql create mode 100644 targets/hasura/migrations/default/1710947243237_alter_table_auth_users_alter_column_refresh_token/down.sql create mode 100644 targets/hasura/migrations/default/1710947243237_alter_table_auth_users_alter_column_refresh_token/up.sql create mode 100644 targets/hasura/migrations/default/1710947451028_alter_table_auth_users_alter_column_refresh_token_expires_at/down.sql create mode 100644 targets/hasura/migrations/default/1710947451028_alter_table_auth_users_alter_column_refresh_token_expires_at/up.sql create mode 100644 targets/hasura/migrations/default/1711289415888_alter_table_auth_users_alter_column_expires_at/down.sql create mode 100644 targets/hasura/migrations/default/1711289415888_alter_table_auth_users_alter_column_expires_at/up.sql create mode 100644 targets/hasura/migrations/default/1711289911681_alter_table_auth_users_alter_column_refresh_token/down.sql create mode 100644 targets/hasura/migrations/default/1711289911681_alter_table_auth_users_alter_column_refresh_token/up.sql create mode 100644 targets/hasura/migrations/default/1711289930124_alter_table_auth_users_alter_column_refresh_token/down.sql create mode 100644 targets/hasura/migrations/default/1711289930124_alter_table_auth_users_alter_column_refresh_token/up.sql create mode 100644 targets/hasura/migrations/default/1711289953743_alter_table_auth_users_alter_column_access_token/down.sql create mode 100644 targets/hasura/migrations/default/1711289953743_alter_table_auth_users_alter_column_access_token/up.sql create mode 100644 targets/hasura/migrations/default/1711469151306_alter_table_auth_users_drop_column_access_token/down.sql create mode 100644 targets/hasura/migrations/default/1711469151306_alter_table_auth_users_drop_column_access_token/up.sql create mode 100644 targets/hasura/migrations/default/1711469221795_alter_table_auth_users_add_column_access_token/down.sql create mode 100644 targets/hasura/migrations/default/1711469221795_alter_table_auth_users_add_column_access_token/up.sql create mode 100644 targets/hasura/migrations/default/1711541152381_alter_table_auth_users_drop_column_refresh_token/down.sql create mode 100644 targets/hasura/migrations/default/1711541152381_alter_table_auth_users_drop_column_refresh_token/up.sql create mode 100644 targets/hasura/migrations/default/1711541174570_alter_table_auth_users_drop_column_access_token/down.sql create mode 100644 targets/hasura/migrations/default/1711541174570_alter_table_auth_users_drop_column_access_token/up.sql create mode 100644 targets/hasura/migrations/default/1711541187969_alter_table_auth_users_drop_column_expires_in/down.sql create mode 100644 targets/hasura/migrations/default/1711541187969_alter_table_auth_users_drop_column_expires_in/up.sql create mode 100644 targets/hasura/migrations/default/1711541218864_drop_index_users_access_token_key/down.sql create mode 100644 targets/hasura/migrations/default/1711541218864_drop_index_users_access_token_key/up.sql diff --git a/.kontinuous/env/dev/templates/contributions.configmap.yaml b/.kontinuous/env/dev/templates/contributions.configmap.yaml deleted file mode 100644 index 1f59b16aa..000000000 --- a/.kontinuous/env/dev/templates/contributions.configmap.yaml +++ /dev/null @@ -1,9 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: contributions -data: - CDTN_API_URL: "https://cdtn-api.fabrique.social.gouv.fr" - API_URI: "http://www" - HASURA_GRAPHQL_ENDPOINT: "http://hasura/v1/graphql" - NODE_ENV: "production" diff --git a/.kontinuous/env/dev/templates/contributions.sealed-secret.yaml b/.kontinuous/env/dev/templates/contributions.sealed-secret.yaml deleted file mode 100644 index c0d415307..000000000 --- a/.kontinuous/env/dev/templates/contributions.sealed-secret.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -apiVersion: "bitnami.com/v1alpha1" -kind: "SealedSecret" -metadata: - annotations: &a1 - sealedsecrets.bitnami.com/cluster-wide: "true" - name: contributions - namespace: null -spec: - encryptedData: - HASURA_GRAPHQL_ADMIN_SECRET: AgC4DoTx/Burraa4LQnxWJ8pa4gK7mSHWd4fFFUHWeVrTmcoxLRyVVqH8ajgXFBZ1uksTujs8LM0eDtxeO/d6e88y7lF8epCutVm/9Lr39E8eMA4zwMU6QNrCX4j34YRonf4vbOnlUfm88XKek7DTOsUsbTp5BbO/IrESzabBJ9ntLBAdCVK+j6eGZyCC44VcfszHoiQINwi0Iax66KuA4oUvpQuTdTbB20wr9vzZarMatDDQRYtjugtYFzQQAv45+BZscb1Q+cMz+MXGOeJTDpFrhhV0OeDp5llEDhmx3nhyeRGyeWZdvONrDl4lDvftO6b8CTV1jBaoCX1r8pKcdp69WbkX2V+62lqamr5bmgJiuBWeOTHT1qQrv9uuInhrBBrkcHrXXMKlTY+p9auY/IQLw9CyBn41sK+RDteQfoZFRHSo2UOipbfgB5j9mCVnyJLDYLfyH4TEdGM6lkCATnKHr7Jz16IeR+GwmLfHrHkv3TW6zPijBBZRVcC5Z6LQNVv/6BzrKlzOkgZCKsX5pgaQWQBDSJSe8QGkx3Ccik6XpC/jgdHPEuP8zqDhE4VzWM6FrsxLAvso5WWNgdmS3i01RFa+pnFK7wLp7oLtDjKo7GyG2mXGt2B2+uvUffAmrE4jTCIbjUQtgrHHDBpq0hhxrG0njbh3SL29fNz1FeaXOFdubRfs0Zg2aNXtwDFHDrM8jCt/Yj4mY21uKup82mQZG6FCENCx+Hl7GGtuhs= - HASURA_GRAPHQL_JWT_SECRET: AgDSW4ceV9HFoxBNqg/hGa6uunl76cjtKBRSYf5LEPKzNHtXixd73LoFGa2y6/cQ/yGevNU6k7w62pkbWnz5rNAznsBE8QtBt1eRKQqjyJJ21m4sWI/MK6UI3gUS/Ad+LeCMxSoKG3XEzFSAwSndSXsgmwAP4KPpBF83DvdpVVpZtAjvPbNYNE6Ocjhtmt/TLqWjsV4Z+hkS8CKGk+PsYDEuR74Mj5TJys0MALJA9TB2dTIqMHOVZofD8T9hKH42yJWCDruH+gNNPKcleG/R0Pt7LJSamZtsqtXdxeE02tB+I9/VaEMrBL2WCJKhGHTjlDxexl4V/fswFYgXc/T4+hmPVB76xWVi6yFfggD/tLcAvgw3Ivdmbk/1c4CayKjU0+B+57EVrRqCGbJieBfbv6L3EWjU0uQj/uJEaZxIF4st3/r+iSGnrtPveBqnUgkJeqOmhf4sWJwE3xsPJM2kNYDPelWpYdxpoPaq3PNcLs7WpxMtRvwvvz2LMsWhEuUyHpe5yLOvi5swhcGqX1ALxGxfxzV+O229WfuTmV/kGUmcHhdf/VXdJRa+PYS83YK39wC1ZsoXJvPjAvEMgoTaRE8NHPWVD2ookNwdiRQIoLrSrGMP6F+Team2KtCic9ONYnM2wwUj2JCQRkFX2LZXwm9g9uR/Leuyd/IL5+tczwfF+PHfs6TQv+uKVz2qoZQZk4myQ/0JwHluOSXHTwEWkvuwGYO8QMTDOTTdp4Dor3kN7hQZyvWf41V/EHmOoLeFsdpQkWexo1FWHRZYtgG7ZVrgs07bY65gY6c1tZOKFaWhacTuneiLosz79vxn5omsFpjOOiWdSQOPZU8GkGxqJVq16H3VJg== - template: - metadata: - annotations: *a1 - name: contributions - type: "Opaque" diff --git a/.kontinuous/env/dev/templates/www.sealed-secret.yaml b/.kontinuous/env/dev/templates/www.sealed-secret.yaml index e9beb0e11..74c155f85 100644 --- a/.kontinuous/env/dev/templates/www.sealed-secret.yaml +++ b/.kontinuous/env/dev/templates/www.sealed-secret.yaml @@ -15,7 +15,8 @@ spec: PUBLICATION_SECRET: AgAtDPOTr9khd47wV5WPXJaLSj+6Kmh5N/Wt9SJUTmRgn9jp8trclhS5DvZxmfVv/rYRRiDTuPATDR4yMbfvtrO9ABAhmRZFvmU5VbxdtCDrc9qtv5ZJ4dsYIVxyXIad7+CumHkunXYSwgmCqr2bvv5oeWRmTx2x4uwaNzhEKQ4hUzYCyWp9laJHt5mYT/c/IWZu0PaDXJQVWQuep3fJvjtxQw9EZVy+ehGAqyClL7bkqT1KVrVBDfvpPeO97O2e2de49RcdZSCtBTmGDHKg7fwUziBJSSI8ObtUMzWm56223XZXKqrxdChAlWJE05tHsvowa18NadFDjJwVt3RtPp+HguVj+I7PiTJMTjyZpsmHlr767teLYrXAoAVc9MRrGeznvYw4i0DhNFZXfyYghSKnKPW4yfYzNKwX50huCyQethn1TqU6MAYGrWiyx9XsaHy3bNgAO4ru9o8WV7bfyeRRsABMoiubyq9RCxfOXRU3cbWYaiS8aiPxALZRKjhSeQhJ5ufdL700rJWV2nuoxXG8jjR3yw3bpCL6imIrLRIAP1+Wki5I8Qo98dfBBF/nahEWeXdCqCjpImfSLUioKMes2IrH8ragfja+85x06S8717b67qyBqtGeGAfX2JYLDWILoA0k9RdzyIwuakAZkChGoWTUy8aRjC7GJIKCQ5IKZ5FQr0IuVVjj1xoGBh6O/sFsOLF7/sA3hRcvirzcCFvCIwsmHs/q4K1iU7nDR0WE1AUV/uccbP3yzAzv6gqElztn1f/LOpA01b2Wn9YAzi6S65wUXUWx7UAx6YaiiofmnySnseSNfE+8 ACTIONS_SECRET: AgCrnvsRqo0y0d2B5jJOSfdsu7zPJ+DmjbS7GVXRYEHOMIi2tLwuuNvZdRk7iBc/DtbCrIA4Wg55gKTUD1XYtzIYcdysovYTDEBl1IcR1/9mSzbYB7XXWrBfsyP36UbNIEah/caigryy0THA4Rulde6yZ71lSIX3nmpXObEdoO3AHfGQtQE948CCwQdA/9SI90bvvCp9aYJ+oGbB4xqipguchUQIFH8UpRxsWywFQo7I6ao/lB6KfxIxdLxfEFOwisFEHWdranEE/ai2QJrzE0Eeo5y0jcp8FMJ2WvWmIVNrg+4mfDK4dzmSozbP06X03FDWLtRmkU3F5M42/aqBRSCw1kU2yuTNjP3DzyIdwOEYRIShzU5A2RaGWzLclkeqjQQFXSXs0Ju3mcaD6C8WWde+A7tFm9pSrx8yp8PkG+7E5DfNsC8jMQnIFDLIqgcFMPF6vnOyb6HS1fW/Aa0O7xD2Oq6Gpx6wyw0GzZ6ZB8IkUp1PMc+bNNR0bY6Rh0PjdjPXuyPFVuZ1zHc9Kpd9pYhNr06ldiOe6ZrtI/GEAUJe2DEtkZYDjVu6A5IdEFIn1mTW/+H5EduxQv6NuVzYudNg2n6/wC2S8637EkyPrgklHS+lCxMr7N9uHPRHJm+tAB5bwds/jZjivHrePv52rVtZxSaPc1AchoORsGqbJks2L3u0Bu7o2sdDtNAj2vyxp39FHpgeMqNbBF21nyohjhXvR7gPWvzBGl1+0au6CJfqEkOzgovbI4hPmUWzXbf0jW6pMcAERiQ04h07ZjqyHYRAXw4J9Gm1GDooxNDdVi7yOu1dI4iKoLwD SMTP_EMAIL_USER: AgA3OzfISPZpiKp5P3PhpgzY5avfiU54p9oMn60Jn0ebNnj4+GSrXQ52v9OTIrL/WthPZhD9HdjjconiWsWnxXeaHTRkXup3XxLy3yV3L9HLnVbG0vMTsVvfPo2GezqACHu9JLWoq+noa3uzQc/d/lM1s8oxbNtVqWCD4sFPTdJxgPkY1TukvdmjfwA5J8S5iELdfGKT01z/4JyhU2R4zFPSR8w5PSl0Eelob+wP2FxMH+/TLwpbiNfVEY04jAMG3W4dOD7FZC6RCH9LfKSOvjce/E0aGqx5dTycjpKmwtwg5YYhWeA3k5Chwk5EfYE/y0KTEZm+cKo2NdyHFUemepTKVcj+Cvz2gE1KQfOiuvxQ8WyPCmeMiwQ5+ehVeEQeXaqtLQyJt4bOGCmatnXdtbIFfAWEEExMilWcvobIwZt2hQjp+IRKfK5zfo/vTSSdazNApSiEPKgwwfyS/kNE9KVqam/2KaG3pexRn74V9b4CqDByeU84QWdF3RdVP9Itkn8GjXlhOV7Y7mTFNAUJjuHmgUjvOYBk/yg4ZDc7B3ky3hiYAPQuvh5+7+EiOcn4S4/2Ro3oJzy7TSmvgG/iGyakKF1HbpAbMeqlmaqTZ3x0lglZ7gbHLMP5MLdwetJq//vSueI4YaXLfC4ewbvCbUE8z7lxbhu8tnprodL5+aXHzBiInmAc+VizrLltyYAkb7qmaQxNNqBJEx9WgmTJGUipfo5OtQ7ByUiHzPI8/wBuUg== - SMTP_EMAIL_PASSWORD: AgCtNDmA/H1w1O9yj8J9ykjNe8ap6iO5Rd+zjbzWF/IXkqFrK3TUcTaLD9IXltnA3Oeru0rSVTJcPfQwzV9brriIjmrSHjuJK2c5vzQ113x8w9DTpiBk0S5wRHOigwexGxouj1G1MbDrgcB4a6cNMDMJAMxP98uJyzncX2uigDzTTWLh0xVGO1ipNYmgOF9MyNYpkJLYEpSeIQEtNjfUUEcSIrBkrAVLCC6fJUu8trbKXNPGShobw15pmY9rbv25lzz3o3js/biGLgmb5QG3oRcWc5OySN/z59rlD8yrw35ZIdEIDU946XONjtUSoLx4sH3T0fZxNUr3UOm25n6j5ltq4tO+xKx+K3/K91svOpRwv6nM094rQNFghjLajwiWF2VSInWmh1PsNZxIs3S8mFQmiC9x1fcmqG0EsAQoWzwuDDUInCM/S7vIAg8eLUBts+Rkg5/QM7Tjk8qmT+3581+hiP+PJSF+jWHDUfxt+/xisRmMjIM8HN/iTAfLy0XLi39kmOiXPROtd5yvTKmLU7hIDSMu25i9yQEJNV1tMiJIIBpqqGVcFVNk0qMN/Gh7i1tKhJjGS9k/YlUa0jAi1pe1MCW9o6wXyur9PAv75+7qvpzl9rqICDQtGFEbkdZAX6YcXV4JpGoitmmPHm7xsrG66yvsRXRyqX51IN67g9ZFWrelER0jmYYf/SpahpbJ5kMuQ1rd0Wk90JnmXiCNyBxbGE7PjHQUmwu9i0GS5ksgAw== + SMTP_EMAIL_PASSWORD: AgBkMR2sljz+elx13UNpkObHNBCBAUodfosCZoQnbF2vOVSi/KlqNPIcDRjh7RZOgvU9j6RosanfRFWpE8ofX6CEC0CHGYVep8CRnF4O7/ZyQBw07E/SkXAmmcqqtvhrDvw/iuJ2y8g0nUfr54eLsKaxRh+yVQVO+bdp4P/8MEXO6KE/LJTq4Mx/Mz8qHAggfu5h6gRe1gRYifBVi7RXx7zco81DlYqC0hkN+BAgugBfc5jsHOFBI3cs0Lq4DHN3BQsBZbiMGAxhldoj2wTxKs+AUIFsJTdn/2KHmV3KCIvlqwSzhvvc0F2mG6dQtdOcQzzz21Qsrb7eSqaCQ56/ccUOP7315ULMtiay8oxO+xI6GEcY8eISho0lSNC3AsS5MawphPzkpIYjGinYRdg3Xexe9Ca6ZEpEfkpLXoz7wGoSKrFUMZ7liK3iAGLv2w7ZD/+mYm+Qppv+ref+4EN5KD9/wGjVwnCyDIlHtrOpG1wqbQp1OmnWU8TmCs7qVWF5W1+Xpx+DspxnqSxvAiY/hTa3QfvScmx5XzLs3HD5S8ResVc8oWBuGFxqjkDMRYpTK7Iy76MV9Yj1kk062AvDIC6oCeawGz8Pyj3Ie2JU9skoBSvTwZm19bO4WYxviiRNTvLcWiQWHw/Ig3oE27JE17r7loNiLPtzdXSpf2nI4w9s2l6antUxK5H1oIKQAW9qayuLMpHQSqkGuI9oxVM0Wg592+VcXITVVARm2LzVeyZ6mg== + NEXTAUTH_SECRET: AgCBtu+fBXvdor7ruSn6nQDfm6a25Y/OBT/d7+stqAFD3XCLp18MTCFFFNva/p2qhQ2AOuPBKV4JvDe7+OgtwHgg8aVdiIs4VsLEDSCHQfKXTQ8ns9e0kUfV4uJiGeKGaP4aHjRK54PVIV55JUPBzJtse2OcRohK/jIaY6P/KlkGsshRg2O5BRicEhPBIcS/TbegwmLWePPlLHIKtbsT11eWDYIHfq1FDs6vozpxFF9ytcNjulnB4/pk9HZsLPgFADLpwjFj59L8kbOskgaITdFWstEo2J+UAxR0y+dn4S6j1affqEUmWM/K/kJgSM25CCvnZ1vrrymWJ0bcA76SlS45/TWt+8stTxwMaAvtanysUppymuJvKH5Mnw26ZBbMXL0NpJZ+0XnLmqJR4MC0xIaStxahvngqv8qQe0yXCn74SMxSCiXsf2ao6mGXNCj62dxp47OUgF20uDS93ABLpkemOdcsZLzUZrjs1ZpYExJE+H8+uRp+ntkp3+kxyFqM+5IR6g+53OqdaNDJtdcgx4Lb9of0n+VWSwuH99rY8KKtfHZa0px326hksXrMGSi1bmZMTjh4LNg6RGMF3J35fRTL1RiaL1J/ie6ucBCBOJwuwnh47jWdkS7WEhz86FXFIIRkDQwNd3WNE2BNGaQ6tkgoHpvMa1fLI8/UeHinH6kcQQoXw6AwzK848ZJN5Ybl0DXaB0o51TKVIgO/eXCJiVjC2fI+94FV1EFlh4dSPqeEalK7SwXMYftnSW/+1w== template: metadata: annotations: *a1 diff --git a/.kontinuous/env/dev/values.yaml b/.kontinuous/env/dev/values.yaml index b8bc6031e..05029bcc8 100644 --- a/.kontinuous/env/dev/values.yaml +++ b/.kontinuous/env/dev/values.yaml @@ -1,6 +1,6 @@ hasura: imagePackage: hasura - ~needs: [post-restore, build-hasura] + ~needs: [build-hasura] ~preDeploy.cleaner: match: kind: Deployment @@ -73,7 +73,7 @@ pg: jobs: runs: post-restore: - ~needs: [pg] + ~needs: [pg, hasura] use: psql with: sqlFile: .kontinuous/sql/post-restore.sql diff --git a/.kontinuous/env/preprod/templates/contributions.configmap.yaml b/.kontinuous/env/preprod/templates/contributions.configmap.yaml deleted file mode 100644 index 1f59b16aa..000000000 --- a/.kontinuous/env/preprod/templates/contributions.configmap.yaml +++ /dev/null @@ -1,9 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: contributions -data: - CDTN_API_URL: "https://cdtn-api.fabrique.social.gouv.fr" - API_URI: "http://www" - HASURA_GRAPHQL_ENDPOINT: "http://hasura/v1/graphql" - NODE_ENV: "production" diff --git a/.kontinuous/env/preprod/templates/contributions.sealed-secret.yaml b/.kontinuous/env/preprod/templates/contributions.sealed-secret.yaml deleted file mode 100644 index c0d415307..000000000 --- a/.kontinuous/env/preprod/templates/contributions.sealed-secret.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -apiVersion: "bitnami.com/v1alpha1" -kind: "SealedSecret" -metadata: - annotations: &a1 - sealedsecrets.bitnami.com/cluster-wide: "true" - name: contributions - namespace: null -spec: - encryptedData: - HASURA_GRAPHQL_ADMIN_SECRET: AgC4DoTx/Burraa4LQnxWJ8pa4gK7mSHWd4fFFUHWeVrTmcoxLRyVVqH8ajgXFBZ1uksTujs8LM0eDtxeO/d6e88y7lF8epCutVm/9Lr39E8eMA4zwMU6QNrCX4j34YRonf4vbOnlUfm88XKek7DTOsUsbTp5BbO/IrESzabBJ9ntLBAdCVK+j6eGZyCC44VcfszHoiQINwi0Iax66KuA4oUvpQuTdTbB20wr9vzZarMatDDQRYtjugtYFzQQAv45+BZscb1Q+cMz+MXGOeJTDpFrhhV0OeDp5llEDhmx3nhyeRGyeWZdvONrDl4lDvftO6b8CTV1jBaoCX1r8pKcdp69WbkX2V+62lqamr5bmgJiuBWeOTHT1qQrv9uuInhrBBrkcHrXXMKlTY+p9auY/IQLw9CyBn41sK+RDteQfoZFRHSo2UOipbfgB5j9mCVnyJLDYLfyH4TEdGM6lkCATnKHr7Jz16IeR+GwmLfHrHkv3TW6zPijBBZRVcC5Z6LQNVv/6BzrKlzOkgZCKsX5pgaQWQBDSJSe8QGkx3Ccik6XpC/jgdHPEuP8zqDhE4VzWM6FrsxLAvso5WWNgdmS3i01RFa+pnFK7wLp7oLtDjKo7GyG2mXGt2B2+uvUffAmrE4jTCIbjUQtgrHHDBpq0hhxrG0njbh3SL29fNz1FeaXOFdubRfs0Zg2aNXtwDFHDrM8jCt/Yj4mY21uKup82mQZG6FCENCx+Hl7GGtuhs= - HASURA_GRAPHQL_JWT_SECRET: AgDSW4ceV9HFoxBNqg/hGa6uunl76cjtKBRSYf5LEPKzNHtXixd73LoFGa2y6/cQ/yGevNU6k7w62pkbWnz5rNAznsBE8QtBt1eRKQqjyJJ21m4sWI/MK6UI3gUS/Ad+LeCMxSoKG3XEzFSAwSndSXsgmwAP4KPpBF83DvdpVVpZtAjvPbNYNE6Ocjhtmt/TLqWjsV4Z+hkS8CKGk+PsYDEuR74Mj5TJys0MALJA9TB2dTIqMHOVZofD8T9hKH42yJWCDruH+gNNPKcleG/R0Pt7LJSamZtsqtXdxeE02tB+I9/VaEMrBL2WCJKhGHTjlDxexl4V/fswFYgXc/T4+hmPVB76xWVi6yFfggD/tLcAvgw3Ivdmbk/1c4CayKjU0+B+57EVrRqCGbJieBfbv6L3EWjU0uQj/uJEaZxIF4st3/r+iSGnrtPveBqnUgkJeqOmhf4sWJwE3xsPJM2kNYDPelWpYdxpoPaq3PNcLs7WpxMtRvwvvz2LMsWhEuUyHpe5yLOvi5swhcGqX1ALxGxfxzV+O229WfuTmV/kGUmcHhdf/VXdJRa+PYS83YK39wC1ZsoXJvPjAvEMgoTaRE8NHPWVD2ookNwdiRQIoLrSrGMP6F+Team2KtCic9ONYnM2wwUj2JCQRkFX2LZXwm9g9uR/Leuyd/IL5+tczwfF+PHfs6TQv+uKVz2qoZQZk4myQ/0JwHluOSXHTwEWkvuwGYO8QMTDOTTdp4Dor3kN7hQZyvWf41V/EHmOoLeFsdpQkWexo1FWHRZYtgG7ZVrgs07bY65gY6c1tZOKFaWhacTuneiLosz79vxn5omsFpjOOiWdSQOPZU8GkGxqJVq16H3VJg== - template: - metadata: - annotations: *a1 - name: contributions - type: "Opaque" diff --git a/.kontinuous/env/preprod/templates/www.sealed-secret.yaml b/.kontinuous/env/preprod/templates/www.sealed-secret.yaml index e9beb0e11..946b3ce53 100644 --- a/.kontinuous/env/preprod/templates/www.sealed-secret.yaml +++ b/.kontinuous/env/preprod/templates/www.sealed-secret.yaml @@ -15,7 +15,8 @@ spec: PUBLICATION_SECRET: AgAtDPOTr9khd47wV5WPXJaLSj+6Kmh5N/Wt9SJUTmRgn9jp8trclhS5DvZxmfVv/rYRRiDTuPATDR4yMbfvtrO9ABAhmRZFvmU5VbxdtCDrc9qtv5ZJ4dsYIVxyXIad7+CumHkunXYSwgmCqr2bvv5oeWRmTx2x4uwaNzhEKQ4hUzYCyWp9laJHt5mYT/c/IWZu0PaDXJQVWQuep3fJvjtxQw9EZVy+ehGAqyClL7bkqT1KVrVBDfvpPeO97O2e2de49RcdZSCtBTmGDHKg7fwUziBJSSI8ObtUMzWm56223XZXKqrxdChAlWJE05tHsvowa18NadFDjJwVt3RtPp+HguVj+I7PiTJMTjyZpsmHlr767teLYrXAoAVc9MRrGeznvYw4i0DhNFZXfyYghSKnKPW4yfYzNKwX50huCyQethn1TqU6MAYGrWiyx9XsaHy3bNgAO4ru9o8WV7bfyeRRsABMoiubyq9RCxfOXRU3cbWYaiS8aiPxALZRKjhSeQhJ5ufdL700rJWV2nuoxXG8jjR3yw3bpCL6imIrLRIAP1+Wki5I8Qo98dfBBF/nahEWeXdCqCjpImfSLUioKMes2IrH8ragfja+85x06S8717b67qyBqtGeGAfX2JYLDWILoA0k9RdzyIwuakAZkChGoWTUy8aRjC7GJIKCQ5IKZ5FQr0IuVVjj1xoGBh6O/sFsOLF7/sA3hRcvirzcCFvCIwsmHs/q4K1iU7nDR0WE1AUV/uccbP3yzAzv6gqElztn1f/LOpA01b2Wn9YAzi6S65wUXUWx7UAx6YaiiofmnySnseSNfE+8 ACTIONS_SECRET: AgCrnvsRqo0y0d2B5jJOSfdsu7zPJ+DmjbS7GVXRYEHOMIi2tLwuuNvZdRk7iBc/DtbCrIA4Wg55gKTUD1XYtzIYcdysovYTDEBl1IcR1/9mSzbYB7XXWrBfsyP36UbNIEah/caigryy0THA4Rulde6yZ71lSIX3nmpXObEdoO3AHfGQtQE948CCwQdA/9SI90bvvCp9aYJ+oGbB4xqipguchUQIFH8UpRxsWywFQo7I6ao/lB6KfxIxdLxfEFOwisFEHWdranEE/ai2QJrzE0Eeo5y0jcp8FMJ2WvWmIVNrg+4mfDK4dzmSozbP06X03FDWLtRmkU3F5M42/aqBRSCw1kU2yuTNjP3DzyIdwOEYRIShzU5A2RaGWzLclkeqjQQFXSXs0Ju3mcaD6C8WWde+A7tFm9pSrx8yp8PkG+7E5DfNsC8jMQnIFDLIqgcFMPF6vnOyb6HS1fW/Aa0O7xD2Oq6Gpx6wyw0GzZ6ZB8IkUp1PMc+bNNR0bY6Rh0PjdjPXuyPFVuZ1zHc9Kpd9pYhNr06ldiOe6ZrtI/GEAUJe2DEtkZYDjVu6A5IdEFIn1mTW/+H5EduxQv6NuVzYudNg2n6/wC2S8637EkyPrgklHS+lCxMr7N9uHPRHJm+tAB5bwds/jZjivHrePv52rVtZxSaPc1AchoORsGqbJks2L3u0Bu7o2sdDtNAj2vyxp39FHpgeMqNbBF21nyohjhXvR7gPWvzBGl1+0au6CJfqEkOzgovbI4hPmUWzXbf0jW6pMcAERiQ04h07ZjqyHYRAXw4J9Gm1GDooxNDdVi7yOu1dI4iKoLwD SMTP_EMAIL_USER: AgA3OzfISPZpiKp5P3PhpgzY5avfiU54p9oMn60Jn0ebNnj4+GSrXQ52v9OTIrL/WthPZhD9HdjjconiWsWnxXeaHTRkXup3XxLy3yV3L9HLnVbG0vMTsVvfPo2GezqACHu9JLWoq+noa3uzQc/d/lM1s8oxbNtVqWCD4sFPTdJxgPkY1TukvdmjfwA5J8S5iELdfGKT01z/4JyhU2R4zFPSR8w5PSl0Eelob+wP2FxMH+/TLwpbiNfVEY04jAMG3W4dOD7FZC6RCH9LfKSOvjce/E0aGqx5dTycjpKmwtwg5YYhWeA3k5Chwk5EfYE/y0KTEZm+cKo2NdyHFUemepTKVcj+Cvz2gE1KQfOiuvxQ8WyPCmeMiwQ5+ehVeEQeXaqtLQyJt4bOGCmatnXdtbIFfAWEEExMilWcvobIwZt2hQjp+IRKfK5zfo/vTSSdazNApSiEPKgwwfyS/kNE9KVqam/2KaG3pexRn74V9b4CqDByeU84QWdF3RdVP9Itkn8GjXlhOV7Y7mTFNAUJjuHmgUjvOYBk/yg4ZDc7B3ky3hiYAPQuvh5+7+EiOcn4S4/2Ro3oJzy7TSmvgG/iGyakKF1HbpAbMeqlmaqTZ3x0lglZ7gbHLMP5MLdwetJq//vSueI4YaXLfC4ewbvCbUE8z7lxbhu8tnprodL5+aXHzBiInmAc+VizrLltyYAkb7qmaQxNNqBJEx9WgmTJGUipfo5OtQ7ByUiHzPI8/wBuUg== - SMTP_EMAIL_PASSWORD: AgCtNDmA/H1w1O9yj8J9ykjNe8ap6iO5Rd+zjbzWF/IXkqFrK3TUcTaLD9IXltnA3Oeru0rSVTJcPfQwzV9brriIjmrSHjuJK2c5vzQ113x8w9DTpiBk0S5wRHOigwexGxouj1G1MbDrgcB4a6cNMDMJAMxP98uJyzncX2uigDzTTWLh0xVGO1ipNYmgOF9MyNYpkJLYEpSeIQEtNjfUUEcSIrBkrAVLCC6fJUu8trbKXNPGShobw15pmY9rbv25lzz3o3js/biGLgmb5QG3oRcWc5OySN/z59rlD8yrw35ZIdEIDU946XONjtUSoLx4sH3T0fZxNUr3UOm25n6j5ltq4tO+xKx+K3/K91svOpRwv6nM094rQNFghjLajwiWF2VSInWmh1PsNZxIs3S8mFQmiC9x1fcmqG0EsAQoWzwuDDUInCM/S7vIAg8eLUBts+Rkg5/QM7Tjk8qmT+3581+hiP+PJSF+jWHDUfxt+/xisRmMjIM8HN/iTAfLy0XLi39kmOiXPROtd5yvTKmLU7hIDSMu25i9yQEJNV1tMiJIIBpqqGVcFVNk0qMN/Gh7i1tKhJjGS9k/YlUa0jAi1pe1MCW9o6wXyur9PAv75+7qvpzl9rqICDQtGFEbkdZAX6YcXV4JpGoitmmPHm7xsrG66yvsRXRyqX51IN67g9ZFWrelER0jmYYf/SpahpbJ5kMuQ1rd0Wk90JnmXiCNyBxbGE7PjHQUmwu9i0GS5ksgAw== + SMTP_EMAIL_PASSWORD: AgBkMR2sljz+elx13UNpkObHNBCBAUodfosCZoQnbF2vOVSi/KlqNPIcDRjh7RZOgvU9j6RosanfRFWpE8ofX6CEC0CHGYVep8CRnF4O7/ZyQBw07E/SkXAmmcqqtvhrDvw/iuJ2y8g0nUfr54eLsKaxRh+yVQVO+bdp4P/8MEXO6KE/LJTq4Mx/Mz8qHAggfu5h6gRe1gRYifBVi7RXx7zco81DlYqC0hkN+BAgugBfc5jsHOFBI3cs0Lq4DHN3BQsBZbiMGAxhldoj2wTxKs+AUIFsJTdn/2KHmV3KCIvlqwSzhvvc0F2mG6dQtdOcQzzz21Qsrb7eSqaCQ56/ccUOP7315ULMtiay8oxO+xI6GEcY8eISho0lSNC3AsS5MawphPzkpIYjGinYRdg3Xexe9Ca6ZEpEfkpLXoz7wGoSKrFUMZ7liK3iAGLv2w7ZD/+mYm+Qppv+ref+4EN5KD9/wGjVwnCyDIlHtrOpG1wqbQp1OmnWU8TmCs7qVWF5W1+Xpx+DspxnqSxvAiY/hTa3QfvScmx5XzLs3HD5S8ResVc8oWBuGFxqjkDMRYpTK7Iy76MV9Yj1kk062AvDIC6oCeawGz8Pyj3Ie2JU9skoBSvTwZm19bO4WYxviiRNTvLcWiQWHw/Ig3oE27JE17r7loNiLPtzdXSpf2nI4w9s2l6antUxK5H1oIKQAW9qayuLMpHQSqkGuI9oxVM0Wg592+VcXITVVARm2LzVeyZ6mg== + NEXTAUTH_SECRET: AgB5M+KK4ntXerfY5kek+HXOU7i/LDp/06lok0pX5Q2bMoBxvMe1pOHOxcCeiNTOj629X8PJJejCUeWVjB4TNoN+MM/1ky13IMt7dVuWfHF7mtnlRzK56X5meMjSQmvQF4iG+OMYVvjlVFCGPW28E3Rb0whafudipPUtACEgG9bSlZHEQKL+4GqjMewSwVw7U2QWYChIivdKvyC58rVyMfWiCtTAw7NJdoiogzUElMkvwrmzNdMOUa90JbAT44tq/It+hqvpukLkuZ2fkPTA2961N9CooWiaF0VjRGlOgCfRs0AWJdLlh0lBneRdWOmjyrLsz86QTQ8C2v1IF/+OcADPlqa2DvrxOjvDIJjHKpVXh5c9YnKIHIfYUfv5M3P1CfVtTjtgepZB3Gt4lIli3zSfqXTJSuvFtM2yL0Goon8OHKoAFb8D82VZWjEmUn0PsJAYsB4CjiJq5gsXftMtmBI+3cP+HnHWMBNVH6frPV69cem8hvnya71XpJ5KKMwAoQKcSmK1LqTbv7pUGx8GyM/WdeoAwF3Y75z8iDv6RH9qL6wbx7z1mLBm58TFxOS7zn331/oUaDdzFSgqli0FSbAPDiQxrxZLJjVKebe1HdLtK3X39En3L9GAp7bLx0AtSBrze6vP0XQ1FBTap7sl/H4sE3V0jbbZFMRPgyobjj3YpFiP8eIOvE3JBpqcZ+s7mMTgtWXVVgSKdicW63kygloxBmo92UBBmnUYFXJThHfl30rhfF6CwhxM//y22A== template: metadata: annotations: *a1 diff --git a/.kontinuous/env/preprod/values.yaml b/.kontinuous/env/preprod/values.yaml index ba502099c..01128e1e3 100644 --- a/.kontinuous/env/preprod/values.yaml +++ b/.kontinuous/env/preprod/values.yaml @@ -1,6 +1,6 @@ hasura: imagePackage: hasura - ~needs: [post-restore, build-hasura] + ~needs: [build-hasura] ~preDeploy.cleaner: match: kind: Deployment @@ -16,8 +16,10 @@ hasura: www: host: cdtn-admin-preprod.ovh.fabrique.social.gouv.fr env: - - name: "FRONTEND_HOST" - value: cdtn-admin-preprod.ovh.fabrique.social.gouv.fr + - name: NEXTAUTH_URL + value: https://cdtn-admin-preprod.ovh.fabrique.social.gouv.fr + - name: NEXT_PUBLIC_BASE_PATH + value: https://cdtn-admin-preprod.ovh.fabrique.social.gouv.fr pg: ~chart: pg @@ -52,7 +54,7 @@ pg: jobs: runs: post-restore: - ~needs: [pg] + ~needs: [pg, hasura] use: psql with: sqlFile: .kontinuous/sql/post-restore.sql diff --git a/.kontinuous/env/prod/templates/contributions.configmap.yaml b/.kontinuous/env/prod/templates/contributions.configmap.yaml deleted file mode 100644 index c2f191a0f..000000000 --- a/.kontinuous/env/prod/templates/contributions.configmap.yaml +++ /dev/null @@ -1,10 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: contributions -data: - CDTN_API_URL: "https://cdtn-api.fabrique.social.gouv.fr" - API_URI: "http://www" - HASURA_GRAPHQL_ENDPOINT: "http://hasura/v1/graphql" - NODE_ENV: "production" - diff --git a/.kontinuous/env/prod/templates/contributions.sealed-secret.yaml b/.kontinuous/env/prod/templates/contributions.sealed-secret.yaml deleted file mode 100644 index 1122df7f0..000000000 --- a/.kontinuous/env/prod/templates/contributions.sealed-secret.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: "bitnami.com/v1alpha1" -kind: "SealedSecret" -metadata: - name: contributions - namespace: cdtn-admin -spec: - encryptedData: - HASURA_GRAPHQL_ADMIN_SECRET: AgA/oEQJToFMrm/N+uHwfhDnRu7XDNm+Bkioqq1a8cGNuwhNC51dl3rxHw0l4l4ggpcRsHR/gt4h1V/kHjsKtfKSl1opnvAqlHeEiFHMqs3Dv27o+rLR8xYxrbW//3ZXKXeQufIKkrg8eD4ZGzc9KvR/HdOQtJ4oG3hWc+Lq/47C55wfBWjvGRnrlGf4IcnmZ6JEK0mF+AukD6Jd+BFAyeVhzZ52/1W1w55rWNrOf3OkjUEJAwDVakqnkAjK42gGAZh25XvkvV23PUeopL5oX4GqmdQctMU12kX+QwPy+B0biIE9LKCeohAZlDfxY4KrUsXRnWD7W8M9YpmTqdDOpHdJov/0hd8mjfsrxA3HOfVPxVMvieXbICEiUtkcOPxuuuidU89Iz+WFO2NM20IOeCVQWCba1OT4pM5pX4IKUB01Hj7Or57nhZa7DWpVL4HWIFdeRHlZFXpSRj3d4gUo4LlumGgFwtBhr+rU9/KGsdMtaWXuMIZXx7g6UcaaMxi69Qc0tZastY922NA+KQW3/r9I1+NJm+8lcNBndl5YlvYos5eodPnfgAo77+5RV5R2idNf7nDJZ9/hZCp28k8Dh97cMhAclT/Xc7gVloiFZuCuzlmlKyBS3D3mSdAml6P7q55LxP0oPq/U0UAKiq27+lAJt7LCYT8qrqVwUX50O8ODeC6lAwxdPqtn+rncEkt1gkEF+pcv0DGPuZN0YykxI5USza7x9cCc2ol4YxyY0IU= - HASURA_GRAPHQL_JWT_SECRET: AgBk8DBUbfxqEW+0c9Omk5p+fL8ZCpL93AvZ0dKENqZHqPgE5Eou3eqce0Yp1eXhx3zpfhyXUWug/Io5FiIotje9VHoVzCzU40o/AK8E6pJ5lX5frcyH4VSn1iABoBp2zU3351DQNAs9KX7JhPaRqgkGgddjSAWNV+m+RQyBurJncNvP7CpE2e3379VEJJqhBxgYKiN32vtjmEPZHEIl23hkuPH7GyOdP8OO+ZBMG8wkHUuMsl4GHKgJicHydPeP3GVdfvD0GQR5x+zmrEMyGob/2oedsCCeKfURxH+QP/F7c4L8EYDerbHxH7FZdFBqG5ogmc35OUkyLWGTZl/8gJfslt7OyWzH1J1vo+C7n1kthxRh1lCWAyBz0Gv6kkm3uroyXJFfmWbR19zQNP5TsrjqZUD28hmWyE0wxI5/L+h1cdsqCkm5cupe0u1lXFmArMU90LAzrRR6M5jZJpkwOGOIrAwJ6Ohsgue7DIEB/jPiwdCMXBs9PP2iLyqfR6suUgngfYoHMNtiBHX+b05OxhoJDunEFWo9tYfweby/DeGH6KV2/T55rmBNh4eGgHNmAiG4Mx4IVXkGqr22CkHHz36SHliHeF5jXmIfo6UBrEEQBJ4OKBuJSINuDqFQNS8ENME2MgfEd8xttWJxs3An4jYihhGdBnA5IYcxiCzD8No2VIop89CKrCCtfsKnmBKvfbbVfk5Z3k+0DBmAO6NXqMQZ18mgVod6pjueB3YfLCoDH1L3hs31OH3lupzic9OY4MkKGkYn6Yppt/oErAp/Cc02bPm1QeUva2OUekZ9/Ar9EC6vvasohmBWbVEMLXV1xQPOxDHjTpGe6h26Ok3PJohQCxnfLw== - template: - metadata: - name: contributions - namespace: cdtn-admin - type: "Opaque" diff --git a/.kontinuous/env/prod/templates/www.sealed-secret.yaml b/.kontinuous/env/prod/templates/www.sealed-secret.yaml index 66954a27f..5924cca4d 100644 --- a/.kontinuous/env/prod/templates/www.sealed-secret.yaml +++ b/.kontinuous/env/prod/templates/www.sealed-secret.yaml @@ -13,7 +13,8 @@ spec: ACTIONS_SECRET: AgCWU6Pn0IIMGcekJimMYAxSQkb9aeuEJ9iSfw79f6LaXeODP1u/K2epb6oqvMaAtoz3uTYM2r8sInJbv1xe0YULFLlo8qzFNaubCcQHg6pSjBTNe/snhgz10rv1VvvYDstMKvelsq++uLc0D4jTU77g5pVYhXbRvx6WaBDV4BD5pld+9z9fj3xSoO673KZduWGL++WeKK+YYDoGxeGq6/3AZ7ZiqXuKACVpOwmhjado9RGZ5LlZnl6mjzlqw9SpY409+EtODRTVtCUT6ZfzaQhyoc8rSB1nhOIu1Tyq9sRx/oIPBNOprs7jTreTu/W7oSXt1nDv8JjeIDG8YDoAYcX6kELvo5SAdo1BhAz83jRfEvvnWFRITA30esF5DHGLaWO+IzolItJYV/eB6YV5jGSazfPNSVxkKj/L5TCRrP0fsQX8DUdJdA4FfVxEjudm1Y8R7MACSOl838syUiBQfJ1mH5vBQvrMvo8gM2O19nppcqv/KekMQebisKa//kGuVzlMCgLQ4fBb91S5HDWcdFjomc17Oeh1u0lF/LHsuW/2Y6I7BqgCVUSCDa7rygLs/0l26EJRrJPc2C8jsWzE+nWKICnASnlWQCgJR6InhUK01cnFazrU78es9skz7ddna8gPtfZ4VCwEozkLYoDL+AgEm8yPZGji1HG0SiouOfbMT/V8hXE7yMoybxSjllYNvEY8mpErzdr79wqs15jYCS26SBvVCxwyGNwi703gvMSVOf7l07C0ycGzDDxbMB97CQghuBWQ+Qi5VlS5XrpkpeQ17d3Xse4ybFLln1c8bLxDTjLvQl9IqlpY SMTP_URL: AgCqFuKEjVA6tgdsxGgY8keFMW2TvUP7uT6g3dNp8rJ39vv4mMd1tq8ovhcStAdaDLYN6ABg2mZbiVziHLc69RSasMXZttq0CnEvJZJm0cT2FTVNPjIKl8/ztTkfVqmdyR+mnZ/SUmpIN0RqmYoPP24MDVV5DdYiyJ1Wvhn1JSFRrnSbQWGUkz1WDbMbIoQFv0R0R4H0wWNUXgnTDcgU0icdYfM5aS0iiZA/4KUNwtMwvchM1D+knIxVx5LqhdUSYA4IZm7jZVEIWLwBuoqQp4FvnTJCBq401JAUaJUvEU5PXH/4jehsrOKAJxeUEpcwi99JQqolztaiwayazUfwZupQzMmwZQnSEDrhu0vv45SVpr340QLiKCFSEOiQQKBVnhJl++NNJWZurue+JXKkweF2NGokfzAU3cGQAyeidp9oyU++D0OoXoro3ebsHGl0rS7VoJKr5DUVv1P159pFa7rf1eeli8Av3FfV89qxCGO8u4WfqD7vR8v1AznhVRJ06i9DVgU3t7w4rTfpz+TecaqE9dDadpvYWBYyQuc/c71ITjBrxxxCLU+pXtHugzgxknPq/QMFSNORM5+DqWj8oXpCrJ4OdvKr2w7hKhnEHfS6W6XrHp2wvy/jgcJDWItU1HGTSKC6L5s9tkOL5RJNvY9MtN+RtF0wrZap3+1jMt+UnR+zfH1+wpXM3m1MNnwpsB4lyuDeeSGiBgozx/ps0n/KRg== SMTP_EMAIL_USER: AgCAbWUriV9eddBicYAGAbh4gUL7UUS8TO82d+d1aakTh4smOeXPxzspjAgW4jx87NPfkxQTM3Bn7UiyBDnzvX5pkBfgoLk2Okw6lDoo1rr4cG/joNa6YgrLkG0GxM4U6jalrt17czWTZU4aG65d2hzzau37n1ND7rZcG9z5ghJvBwsl/Mw8QBAMzjHP4Hrx+ko/wMFprQ7TXcRb0Bwun3LYLk/dsKQPhlvGEwypCcz0R+i9zMTOGDaHpH8ckOPgCkq1YQZaSP+YMoSRf+uPcgQaFQzjJijW5c/G7WYLV231dI0N8iHQ9D/nYX3pLNbgeFx4Xv5u149z5B/lDFAhuLoEQCAgb6f3vZK9SCy5MVcs69a61qmt4l4g+k0OQa2KQGusUhjYQgpP15PcS0vAiUqIuWfDVeN2XjDY4ndOOdGvZI3Ha4WkF/KXGmzga2H/B8pJv7vJU0ZLOalStfvbisRyrAXIfuP9xWK38ueM+EMecwpkjsSo7tVYBTq4a9/Ex7KGmO709rCFD7X1MNCeIKhE1GYfVuvD/NZd7PQuTPlPPDHNqioE/LFNP+LTbOQyZz/qPVaWf73bROaR549Ly2J8VdxhL+vVMX1DYwX5neP10+c1kQyyeJ7WDEhPvAZjxoAMqRQqZnqKmcXrk3yp9gZjN5rrryvMXxpHLaXtwPd2BmvIVX/1TBMoFDzWJkA2YbYS6f2C7d5DEy5kfUsVo3mecdNzLoa5BI+r1lcvWXG3cw== - SMTP_EMAIL_PASSWORD: AgATIjhVjzNxsNBAGLcaR0wb+5NO6Q+lZsNf/DF6ZBSfjDyWOigApRZuE9nThbOj47h1UuUwbO6n9JWM2QPBFIfTFQVc2es0xr82kRW/VQ3sFooalunKeGvyDwlSjoDnrYfkqo/e/GcZDTjUHJXWJwzazPPwNCeFrrY6SLkF4rdT142CBzRb7Fduut/PT0q0Gh7TWIvaZJL/3YKxXBcms4DhJkuWt0jHLkaP7g7h+2XDQU0OIkyOS77V1Idz3xeSWa/xVCtgqcO8KLNihPHYj1rSixucwAsa7sDB1UvcnfMFHZode+nMIffmgqm3j8nflu1TQFsIjarRkSSFF4+j7aYSTMhwsO2req50ynOe9KdvWZI3kmt8+NBdw+OT5Y5jVZAFhN++UL1DguHF0xgt/T06nCP1gBREsONBR316FYSezhQFtGgqN3iEnZIyvyAFmhTbYxFCLu6/fbxYWk+S51juhsG/DQdRv/ooc1MPXiAdZBiC6qd2fEjXqosZTtsWoVKF/jmD777NEwnia9fmmNu+tkPn/5Vn7BBCpkKdFV2TGnYMUkqevTWOABXTAQ+ZDXROjjW6MbUTuP8n0ouyNTdyi/+zpzFutcx5s/CCkj4EFk7s+jIyBWFDDlP4tBAWvlUNSDunU6YachfMSXNKu9LOoAsNuiXYgOkkDhN0dO043LT3umSFo7w8pipjVBZDnRlNMqsCxYkSDwaNAu17ef8oDjyvG14NKm6QnqWfBiof8g== + SMTP_EMAIL_PASSWORD: AgBtliPh8gkWIccG+vUvA9T/Lcl3+8zEhWPiXXyRrxttZQCArJbcfiSBRW7Bxvr8H1tA19o3h418ERqp7ApmZ/r3/Wt1gZ2S1/4n0PBpmUAQDlM6lWS4vRd6x+IB+dYAdFUYJ7z2Q1Ox5k0MO3JzfqP/V4OS6kMLTu9H9ox+a3bUYjsffsd8WF/gtFVKha64pd/cKvwzdpnf+rj1PLk1T/WBPlD2mudOxC1QDXTf/vfVWbi6vfEHtFJdYT6YYft1j6ERptXgfPm2ktnuiTMBA/OnjiIc5DlTbihkvnyqAP1VCJyhRKcqnihTY25lOlAbrkAD4Gf7c6UfzJfwLWgonFGpZ/3/x7fsTmsyaud/k6psqMRMqP6VvCaih176TiMSucyWWP+PfhpDd63T5wTcalUl+jaCnNA8kDb6Z0rGvOC97Vbcq5cr5RmmN0RLILrOrSQRg89xI19HhASCwDNDOqA53JkUV5rhxpPq1JnxcJ14hDetcOjUolel4IjSko5uSKKsgN1ai2VUcdjwhC8MAK0mMa6u5uSCk9WdVgPw6RaY995iu8ESanMLmCqG2H6gWoeoJngy9rwLMqYiOsiivaS9IdKBDRV1bp4B68JE7qUZNo4nXfwL3NGl+UG9rTCsEMwh8glUKvrIMmMe3SQjCoFC88xnYW9ct3i6DwDttlPDxMwMzbQ2yQ82Ir3W3XVg8U4kcDyByvfMWTRLJQdtAS8sTdCF0LxEekGFcHYkBDse6g== + NEXTAUTH_SECRET: AgBQ6EwdQCXcVSKZGuMMLKbJcqIDpo9Hi6NQZwzahODKiE/i2AXWqA7Pc0SIRIHcD2OB3kJVWQSTYQUpmoY4NqIHXleVAZ/4obNXrHYBfvrDt+0qANSMgDFsAjnwqLCHUZ0Y1PDhdMuoc3Mm8uMfWEhNIGrAF1XrVRH36NeEZPsdXlEKODPt7sAkM06SqQmJXyXDmmxHy3By9dBKKxYsq+xArtMZEPIi7Fx64XSUzKeJDMPl2OmwvKJbtyJJIZ7yw8hjT3KvIACUpLfktnInpXhd3QbAG8d7V2FNMUDP3TMNKuiafLs5aNXgbV3MBeY9HtZ7JFDrQYNZfT6FMCNPw/Q0KEfj1U5JSKbbdLAQ21l4+C8nxoK9s6z6yI86c++YgO6dQWYj+nRuRdATZ+GL3ZbjLNQd63IDIKPzc8Haqsy2WCUDESkb9eQKEI+c6vhpfS0Sr4xer7s7KlHu4VYZHc1UAqMESxJOoJMciOsHYJLjYV6822UsMEumbxOVNpR+KsV2H0+h+/Y8pfWp6turjVRD0fXnFHT42JC2mCUt2FKgmxsx4cSyz9guG8P7hH5idov1JUkBrNlvVbumY5+R1fcUgwrHNGOQqktLbXhXFiSUtw0+IYYDl9QIG79tQx68Jl51IShnAV5IFOtuSYkMi6cRV6TPueKGK9+MxE81QZvOz7PSbFgvsV3qTD/wfCmbacIYsAY0XXrpS0R9VxjC8aUSQ6ncj76MegKFSBCrPpCkZI13qxjPzi5y0C1iJA== template: metadata: name: www diff --git a/.kontinuous/env/prod/values.yaml b/.kontinuous/env/prod/values.yaml index c851893db..1a41ec8fe 100644 --- a/.kontinuous/env/prod/values.yaml +++ b/.kontinuous/env/prod/values.yaml @@ -4,8 +4,10 @@ www: annotations: nginx.ingress.kubernetes.io/whitelist-source-range: 185.24.184.196,185.24.185.196,185.24.186.196,185.24.187.196,185.24.187.254,164.131.160.1,164.131.160.2,164.131.160.3,164.131.160.4,164.131.160.5,164.131.160.6,164.131.160.17,164.131.160.18,164.131.160.19,164.131.160.20,164.131.160.21,164.131.160.22,164.131.160.33,164.131.160.34,164.131.160.35,164.131.160.36,164.131.160.37,164.131.160.38,164.131.160.49,164.131.160.50,164.131.160.51,164.131.160.52,164.131.160.53,164.131.160.54,45.80.34.219 env: - - name: "FRONTEND_HOST" - value: cdtn-admin.fabrique.social.gouv.fr + - name: NEXTAUTH_URL + value: https://cdtn-admin.fabrique.social.gouv.fr + - name: NEXT_PUBLIC_BASE_PATH + value: https://cdtn-admin.fabrique.social.gouv.fr resources: limits: cpu: "200m" @@ -14,23 +16,6 @@ www: cpu: "100m" memory: "256Mi" -contributions: - autoscale: - enabled: true - minReplicas: 2 - maxReplicas: 3 - host: cdtn-contributions.fabrique.social.gouv.fr - ingress: - annotations: - nginx.ingress.kubernetes.io/whitelist-source-range: 185.24.184.196,185.24.185.196,185.24.186.196,185.24.187.196,185.24.187.254,164.131.160.1,164.131.160.2,164.131.160.3,164.131.160.4,164.131.160.5,164.131.160.6,164.131.160.17,164.131.160.18,164.131.160.19,164.131.160.20,164.131.160.21,164.131.160.22,164.131.160.33,164.131.160.34,164.131.160.35,164.131.160.36,164.131.160.37,164.131.160.38,164.131.160.49,164.131.160.50,164.131.160.51,164.131.160.52,164.131.160.53,164.131.160.54,45.80.34.219 - resources: - limits: - cpu: "100m" - memory: "256Mi" - requests: - cpu: "100m" - memory: "256Mi" - export: replicas: 1 resources: diff --git a/.kontinuous/sql/post-restore.sql b/.kontinuous/sql/post-restore.sql index cb4acf291..751fe8a44 100644 --- a/.kontinuous/sql/post-restore.sql +++ b/.kontinuous/sql/post-restore.sql @@ -1,87 +1,35 @@ -with user_ids as ( - select distinct id - from auth.users -) -update "auth"."users" -set password = '$argon2i$v=19$m=4096,t=3,p=1$n9eoWSv+5sCgc7SjB5hLig$iBQ7NzrHHLkJSku/dCetNs+n/JI1CMdkWaoZsUekLU8', - email = u.id || '@travail.gouv.fr' -from user_ids u -where u.id = users.id; --- --- DISABLE TRIGGERS --- +-- Anonymize users +UPDATE auth.users as u +SET + password = '$argon2i$v=19$m=4096,t=3,p=1$n9eoWSv+5sCgc7SjB5hLig$iBQ7NzrHHLkJSku/dCetNs+n/JI1CMdkWaoZsUekLU8', + email = u.id || '@travail.gouv.fr', + name = CONCAT( + UPPER(SUBSTRING(name FROM 1 FOR 1)), + CASE + WHEN POSITION(' ' IN name) > 0 THEN UPPER(SUBSTRING(name FROM POSITION(' ' IN name)+1 FOR 1)) + ELSE '' + END + ); -ALTER TABLE auth.users DISABLE TRIGGER USER; -WITH admin_row AS ( - INSERT INTO auth.users (email, PASSWORD, name, default_role, active, id) - VALUES ( - 'codedutravailnumerique@travail.gouv.fr', - '$argon2i$v=19$m=4096,t=3,p=1$n9eoWSv+5sCgc7SjB5hLig$iBQ7NzrHHLkJSku/dCetNs+n/JI1CMdkWaoZsUekLU8', - 'Administrateur', - 'super', - TRUE, - 'd8b11bd2-dd16-4632-b5de-0e7021faadeb' - ) - RETURNING id, - default_role -) -INSERT INTO auth.user_roles (ROLE, user_id) -SELECT default_role, - id -FROM admin_row; -WITH admin_row AS ( - INSERT INTO auth.users (email, PASSWORD, name, default_role, active, id) - VALUES ( - 'utilisateur@travail.gouv.fr', - '$argon2i$v=19$m=4096,t=3,p=1$PqKPf9cxunVLLtEcINHhWQ$CwHKhk71fc8LGp6BWbcFPzQ2ftOiHa7vUkp1eAqVHSM', - 'Utilisateur', - 'user', - TRUE, - '3d6dddc4-e117-4772-9288-cd8a608693e4' - ) - RETURNING id, - default_role -) -INSERT INTO auth.user_roles (ROLE, user_id) -SELECT default_role, - id -FROM admin_row; --- --- create empty audit logs table --- +-- Add a fake user +INSERT INTO auth.users (email, password, name, role, is_active, id) +VALUES ( + 'codedutravailnumerique@travail.gouv.fr', + '$argon2i$v=19$m=4096,t=3,p=1$n9eoWSv+5sCgc7SjB5hLig$iBQ7NzrHHLkJSku/dCetNs+n/JI1CMdkWaoZsUekLU8', + 'Administrateur', + 'super', + TRUE, + 'd8b11bd2-dd16-4632-b5de-0e7021faadeb' + ); -CREATE TABLE IF NOT EXISTS audit.logged_actions ( - event_id bigserial primary key, - schema_name text not null, - table_name text not null, - relid oid not null, - session_user_name text, - hasura_user jsonb, - action_tstamp_tx TIMESTAMP WITH TIME ZONE NOT NULL, - action_tstamp_stm TIMESTAMP WITH TIME ZONE NOT NULL, - action_tstamp_clock TIMESTAMP WITH TIME ZONE NOT NULL, - transaction_id bigint, - application_name text, - client_addr inet, - client_port integer, - client_query text, - action TEXT NOT NULL CHECK (action IN ('I', 'D', 'U', 'T')), - row_data jsonb, - changed_fields jsonb, - statement_only boolean not null -); --- --- ENABLE TRIGGERS --- +-- Remove all data from audit tables +TRUNCATE audit.logged_actions; -ALTER TABLE auth.users ENABLE TRIGGER USER; --- -- Kill all connections ! -- Make all connected services restart ! -- Hasura migration will be re-applyed. --- - SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE pid <> pg_backend_pid() AND datname = '${PGDATABASE}'; + diff --git a/.kontinuous/values.yaml b/.kontinuous/values.yaml index d61021d8f..b8281172a 100644 --- a/.kontinuous/values.yaml +++ b/.kontinuous/values.yaml @@ -51,8 +51,10 @@ www: - secretRef: name: s3 env: - - name: "FRONTEND_HOST" - value: "{{.Values.global.host}}" + - name: NEXTAUTH_URL + value: https://www-{{.Values.global.host}} + - name: NEXT_PUBLIC_BASE_PATH + value: https://www-{{.Values.global.host}} resources: limits: cpu: "100m" diff --git a/README.md b/README.md index 3e03f02bc..02fc9df08 100644 --- a/README.md +++ b/README.md @@ -80,22 +80,15 @@ An administration website is available to configure and inject custom data. This step starts the frontend project (based on `next.js`). User and admin accounts are automatically created by the Hasura step. -| Type | Username | Password | -| ----- | -------------------------------------- | -------- | -| Admin | codedutravailnumerique@travail.gouv.fr | admin | -| User | utilisateur@travail.gouv.fr | user | +| Type | Username | Password | Role | +| ----- | -------------------------------------- | -------- | ----- | +| Admin | codedutravailnumerique@travail.gouv.fr | admin | super | Frontend is reachable at the address > Run the frontend (it starts Hasura as dependency): > > ```sh -> docker compose up www -> ``` -> -> or via npm -> -> ```sh > yarn workspace frontend dev > ``` diff --git a/shared/elasticsearch/.eslintignore b/shared/elasticsearch/.eslintignore index 3c3629e64..8170577a9 100644 --- a/shared/elasticsearch/.eslintignore +++ b/shared/elasticsearch/.eslintignore @@ -1 +1,2 @@ node_modules +*.d.ts diff --git a/shared/elasticsearch/package.json b/shared/elasticsearch/package.json index 5b040945b..3dfe56ac9 100644 --- a/shared/elasticsearch/package.json +++ b/shared/elasticsearch/package.json @@ -43,5 +43,5 @@ ] }, "sideEffects": false, - "typings": "src/index.d.ts" + "types": "src/index.d.ts" } diff --git a/shared/elasticsearch/src/index.d.ts b/shared/elasticsearch/src/index.d.ts new file mode 100644 index 000000000..a625fdad6 --- /dev/null +++ b/shared/elasticsearch/src/index.d.ts @@ -0,0 +1,9 @@ +export const createIndex: any; +export const deleteOldIndex: any; +export const documentMapping: any; +export const DOCUMENTS: string; +export const indexDocumentsBatched: any; +export const SUGGESTIONS: string; +export const vectorizeDocument: any; +export const version: any; +export const suggestionMapping: any; diff --git a/shared/types/index.ts b/shared/types/index.ts index a7177d8f6..c3283a8df 100644 --- a/shared/types/index.ts +++ b/shared/types/index.ts @@ -435,7 +435,6 @@ export interface User { id: string; name: string; email: string; - created_at: Date; } export interface ExportEsStatus { diff --git a/shared/types/package.json b/shared/types/package.json index d1f576e3e..c6d2d16af 100644 --- a/shared/types/package.json +++ b/shared/types/package.json @@ -12,6 +12,6 @@ "devDependencies": { "@socialgouv/kali-data-types": "^2.127.0", "@socialgouv/legi-data-types": "^2.73.1", - "typescript": "^4.9.5" + "typescript": "^5.4.3" } } diff --git a/shared/utils/package.json b/shared/utils/package.json index f5d7ff9df..1b694557b 100644 --- a/shared/utils/package.json +++ b/shared/utils/package.json @@ -5,9 +5,9 @@ "@socialgouv/cdtn-sources": "^4.91.1", "@socialgouv/cdtn-utils": "^4.109.0", "@socialgouv/dila-api-client": "^1.2.4", - "@urql/core": "^2.4.3", - "graphql": "^16.3.0", - "isomorphic-unfetch": "^3.1.0", + "@urql/core": "^4.3.0", + "graphql": "^16.8.1", + "isomorphic-unfetch": "^4.0.2", "uuid": "^9.0.1", "winston": "3.3.3", "xxhashjs": "^0.2.2" @@ -27,6 +27,6 @@ "@types/uuid": "^9.0.5", "@types/xxhashjs": "^0.2.2", "jest": "^29.7.0", - "typescript": "^5.3.3" + "typescript": "^5.4.3" } } diff --git a/shared/utils/src/gql-client.ts b/shared/utils/src/gql-client.ts index ef7dd0b77..ab9c47b92 100644 --- a/shared/utils/src/gql-client.ts +++ b/shared/utils/src/gql-client.ts @@ -1,12 +1,17 @@ -import { createClient } from "@urql/core"; +import { + cacheExchange, + createClient, + fetchExchange, + gql as gqlHelper, +} from "@urql/core"; import fetch from "isomorphic-unfetch"; -type GqlClient = { +type GqlClientParameter = { graphqlEndpoint: string; adminSecret: string; }; -const defaultProps: GqlClient = { +const defaultProps: GqlClientParameter = { graphqlEndpoint: process.env.HASURA_GRAPHQL_ENDPOINT ?? "http://localhost:8080/v1/graphql", adminSecret: process.env.HASURA_GRAPHQL_ADMIN_SECRET ?? "admin1", @@ -24,4 +29,9 @@ export const gqlClient = (props = defaultProps) => maskTypename: true, requestPolicy: "network-only", url: props.graphqlEndpoint, + exchanges: [cacheExchange, fetchExchange], }); + +export type GqlClient = ReturnType; + +export const gql = gqlHelper; diff --git a/targets/alert-cli/package.json b/targets/alert-cli/package.json index 3d63660f7..aef28a15b 100644 --- a/targets/alert-cli/package.json +++ b/targets/alert-cli/package.json @@ -32,18 +32,18 @@ "@socialgouv/kali-data-types": "2.127.0", "@socialgouv/legi-data-types": "2.73.1", "@types/diff": "^5.0.3", - "@types/jest": "27.4.0", + "@types/jest": "^29.5.12", "@types/memoizee": "0.4.6", "@types/node": "16.11.11", "@types/semver": "7.3.8", "@types/unist": "2.0.6", "@vercel/ncc": "0.34.0", "builtin-modules": "3.2.0", - "jest": "27.0.6", + "jest": "^29.7.0", "lint-staged": "12.0.0", - "ts-jest": "27.0.5", + "ts-jest": "^29.1.2", "ts-node": "10.8.0", - "typescript": "4.7.2" + "typescript": "^5.4.3" }, "scripts": { "build": "ncc build ./src/index.ts -o ./dist -e nodegit -s", diff --git a/targets/alert-cli/src/diff/dila/extractReferences/__tests__/editorialContents.test.ts b/targets/alert-cli/src/diff/dila/extractReferences/__tests__/editorialContents.test.ts index 269d1d037..17e85a486 100644 --- a/targets/alert-cli/src/diff/dila/extractReferences/__tests__/editorialContents.test.ts +++ b/targets/alert-cli/src/diff/dila/extractReferences/__tests__/editorialContents.test.ts @@ -26,51 +26,51 @@ test("extractMailTemplateRef", async () => { payload as EditorialContentSubset[] ); expect(references).toMatchInlineSnapshot(` -Array [ - Object { - "document": Object { - "id": "be3ba4c0-4540-4c38-9203-65bc732486a0", - "source": "information", - "title": "Intéressement et participation : nouveautés Covid-19", - }, - "references": Array [ - Object { - "dila_cid": "LEGIARTI000041747466", - "dila_container_id": "cdtn", - "dila_id": "LEGIARTI000041747466", - "title": "article LEGIARTI000041747466", - "url": "", + [ + { + "document": { + "id": "be3ba4c0-4540-4c38-9203-65bc732486a0", + "source": "information", + "title": "Intéressement et participation : nouveautés Covid-19", + }, + "references": [ + { + "dila_cid": "LEGIARTI000041747466", + "dila_container_id": "cdtn", + "dila_id": "LEGIARTI000041747466", + "title": "article LEGIARTI000041747466", + "url": "", + }, + { + "dila_cid": "LEGIARTI000041979663", + "dila_container_id": "cdtn", + "dila_id": "LEGIARTI000041979663", + "title": "article LEGIARTI000041979663", + "url": "", + }, + { + "dila_cid": "LEGIARTI000038613233", + "dila_container_id": "cdtn", + "dila_id": "LEGIARTI000038613233", + "title": "article LEGIARTI000038613233", + "url": "", + }, + { + "dila_cid": "LEGIARTI000041973737", + "dila_container_id": "cdtn", + "dila_id": "LEGIARTI000041973737", + "title": "article LEGIARTI000041973737", + "url": "", + }, + { + "dila_cid": "LEGIARTI000042012392", + "dila_container_id": "cdtn", + "dila_id": "LEGIARTI000042012392", + "title": "article LEGIARTI000042012392", + "url": "", + }, + ], }, - Object { - "dila_cid": "LEGIARTI000041979663", - "dila_container_id": "cdtn", - "dila_id": "LEGIARTI000041979663", - "title": "article LEGIARTI000041979663", - "url": "", - }, - Object { - "dila_cid": "LEGIARTI000038613233", - "dila_container_id": "cdtn", - "dila_id": "LEGIARTI000038613233", - "title": "article LEGIARTI000038613233", - "url": "", - }, - Object { - "dila_cid": "LEGIARTI000041973737", - "dila_container_id": "cdtn", - "dila_id": "LEGIARTI000041973737", - "title": "article LEGIARTI000041973737", - "url": "", - }, - Object { - "dila_cid": "LEGIARTI000042012392", - "dila_container_id": "cdtn", - "dila_id": "LEGIARTI000042012392", - "title": "article LEGIARTI000042012392", - "url": "", - }, - ], - }, -] -`); + ] + `); }); diff --git a/targets/alert-cli/src/diff/dila/extractReferences/__tests__/mailTemplates.test.ts b/targets/alert-cli/src/diff/dila/extractReferences/__tests__/mailTemplates.test.ts index aa44fa0b9..093bc58e5 100644 --- a/targets/alert-cli/src/diff/dila/extractReferences/__tests__/mailTemplates.test.ts +++ b/targets/alert-cli/src/diff/dila/extractReferences/__tests__/mailTemplates.test.ts @@ -26,23 +26,23 @@ test("extractMailTemplateRef", async () => { payload as MailTemplateSubset[] ); expect(references).toMatchInlineSnapshot(` -Array [ - Object { - "document": Object { - "id": "576b0a92-16de-449e-a9d0-199e89d674cd", - "source": "modeles_de_courriers", - "title": "document de test", - }, - "references": Array [ - Object { - "dila_cid": "LEGIARTI000035643605", - "dila_container_id": "cdtn", - "dila_id": "LEGIARTI000035643605", - "title": "article LEGIARTI000035643605", - "url": "", + [ + { + "document": { + "id": "576b0a92-16de-449e-a9d0-199e89d674cd", + "source": "modeles_de_courriers", + "title": "document de test", + }, + "references": [ + { + "dila_cid": "LEGIARTI000035643605", + "dila_container_id": "cdtn", + "dila_id": "LEGIARTI000035643605", + "title": "article LEGIARTI000035643605", + "url": "", + }, + ], }, - ], - }, -] -`); + ] + `); }); diff --git a/targets/alert-cli/src/diff/shared/fetchPrequalified.ts b/targets/alert-cli/src/diff/shared/fetchPrequalified.ts index 1eadae1ec..3338b2f67 100644 --- a/targets/alert-cli/src/diff/shared/fetchPrequalified.ts +++ b/targets/alert-cli/src/diff/shared/fetchPrequalified.ts @@ -27,7 +27,7 @@ export async function fetchPrequalified(): Promise< HasuraDocumentWithRelations[] | undefined > { const res = await gqlClient() - .query(fetchPrequalifiedQuery) + .query(fetchPrequalifiedQuery, {}) .toPromise(); if (res.error) { throw res.error; diff --git a/targets/alert-cli/src/diff/shared/getSupportedAgreements.ts b/targets/alert-cli/src/diff/shared/getSupportedAgreements.ts index a7c8503c0..f11e8da6d 100644 --- a/targets/alert-cli/src/diff/shared/getSupportedAgreements.ts +++ b/targets/alert-cli/src/diff/shared/getSupportedAgreements.ts @@ -16,7 +16,7 @@ interface HasuraReturn { export async function getSupportedAgreements(): Promise { const res = await gqlClient() - .query(fetchSupportedAgreements) + .query(fetchSupportedAgreements, {}) .toPromise(); if (res.error || !res.data) { throw new Error( diff --git a/targets/alert-cli/src/repositories/AlertRepository.ts b/targets/alert-cli/src/repositories/AlertRepository.ts index ee2ca5709..68b27f98e 100644 --- a/targets/alert-cli/src/repositories/AlertRepository.ts +++ b/targets/alert-cli/src/repositories/AlertRepository.ts @@ -1,7 +1,7 @@ -import { Client } from "@urql/core/dist/types/client"; import { AlertChanges, AlertInfo, HasuraAlert } from "@shared/types"; import { batchPromises } from "../utils/batch-promises"; import { DaresAlertInsert } from "../dares/types"; +import { GqlClient } from "@shared/utils"; const insertAlertsMutation = ` mutation insert_alert($alert: alerts_insert_input!) { @@ -25,9 +25,9 @@ interface InsertAlertData { } export class AlertRepository { - private client: Client; + private client: GqlClient; - constructor(client: Client) { + constructor(client: GqlClient) { this.client = client; } diff --git a/targets/alert-cli/src/repositories/FicheSPRepository.ts b/targets/alert-cli/src/repositories/FicheSPRepository.ts index f9d61b580..a4c98efa2 100644 --- a/targets/alert-cli/src/repositories/FicheSPRepository.ts +++ b/targets/alert-cli/src/repositories/FicheSPRepository.ts @@ -1,4 +1,4 @@ -import { Client } from "@urql/core/dist/types/client"; +import { GqlClient } from "@shared/utils"; const query = ` query vdd { @@ -14,15 +14,15 @@ export interface FicheServicePublicIdsResult { } export class FicheSPRepository { - client: Client; + client: GqlClient; - constructor(client: Client) { + constructor(client: GqlClient) { this.client = client; } async getFicheServicePublicIds(): Promise { const result = await this.client - .query(query) + .query(query, {}) .toPromise(); if (result.error || !result.data) { console.error(result.error); diff --git a/targets/alert-cli/src/repositories/SourcesRepository.ts b/targets/alert-cli/src/repositories/SourcesRepository.ts index da2c101db..185e6a6f0 100644 --- a/targets/alert-cli/src/repositories/SourcesRepository.ts +++ b/targets/alert-cli/src/repositories/SourcesRepository.ts @@ -1,4 +1,4 @@ -import { Client } from "@urql/core/dist/types/client"; +import { GqlClient } from "@shared/utils"; import { Source } from "../types"; const sourcesQuery = ` @@ -40,15 +40,15 @@ interface UpdateSourceResult { } export class SourcesRepository { - private client: Client; + private client: GqlClient; - constructor(client: Client) { + constructor(client: GqlClient) { this.client = client; } async load() { const result = await this.client - .query(sourcesQuery) + .query(sourcesQuery, {}) .toPromise(); if (result.error || !result.data) { console.error(result.error); diff --git a/targets/alert-cli/src/repositories/WarningRepository.ts b/targets/alert-cli/src/repositories/WarningRepository.ts index 4214194a2..b118e0ac8 100644 --- a/targets/alert-cli/src/repositories/WarningRepository.ts +++ b/targets/alert-cli/src/repositories/WarningRepository.ts @@ -1,4 +1,4 @@ -import { Client } from "@urql/core/dist/types/client"; +import { GqlClient } from "@shared/utils"; const insertAlertsMutation = ` mutation insertAlertWarning($article: String!, $document: String!, $source: String!) { @@ -15,9 +15,9 @@ interface InsertWarning { } export class WarningRepository { - private client: Client; + private client: GqlClient; - constructor(client: Client) { + constructor(client: GqlClient) { this.client = client; } diff --git a/targets/export-elasticsearch/Dockerfile b/targets/export-elasticsearch/Dockerfile index 0fb64dacf..68a8fc1eb 100644 --- a/targets/export-elasticsearch/Dockerfile +++ b/targets/export-elasticsearch/Dockerfile @@ -24,10 +24,9 @@ RUN yarn workspace @shared/utils build FROM deps as dist COPY --from=build-utils /app/shared/utils ./shared/utils COPY --from=build-types /app/shared/types ./shared/types - COPY shared/eslint-config ./shared/eslint-config/ COPY targets/export-elasticsearch ./targets/export-elasticsearch/ - +COPY shared/elasticsearch ./shared/elasticsearch RUN yarn workspace export-elasticsearch build RUN yarn workspaces focus --production export-elasticsearch && yarn cache clean @@ -41,7 +40,7 @@ COPY --from=dist /app/shared/utils/build /app/shared/utils/build COPY --from=dist /app/shared/utils/package.json /app/shared/utils/package.json COPY --from=dist /app/shared/types/build /app/shared/types/build COPY --from=dist /app/shared/types/package.json /app/shared/types/package.json -COPY shared/elasticsearch /app/shared/elasticsearch +COPY --from=dist /app/shared/elasticsearch /app/shared/elasticsearch COPY --from=dist /app/targets/export-elasticsearch/dataset /app/targets/export-elasticsearch/dataset COPY --from=dist /app/targets/export-elasticsearch/package.json /app/targets/export-elasticsearch/package.json COPY --from=dist /app/targets/export-elasticsearch/build /app/targets/export-elasticsearch/build diff --git a/targets/export-elasticsearch/package.json b/targets/export-elasticsearch/package.json index 7f4430770..ec0a3f22e 100644 --- a/targets/export-elasticsearch/package.json +++ b/targets/export-elasticsearch/package.json @@ -65,6 +65,6 @@ "rimraf": "3.0.2", "supertest": "^6.2.2", "timekeeper": "^2.2.0", - "typescript": "4.6.2" + "typescript": "^5.4.3" } } diff --git a/targets/export-elasticsearch/src/ingester/common/fetchGlossary.ts b/targets/export-elasticsearch/src/ingester/common/fetchGlossary.ts index 2f843092c..1ad401754 100644 --- a/targets/export-elasticsearch/src/ingester/common/fetchGlossary.ts +++ b/targets/export-elasticsearch/src/ingester/common/fetchGlossary.ts @@ -25,7 +25,7 @@ export async function getGlossary(): Promise { graphqlEndpoint, adminSecret, }) - .query<{ glossary: Glossary }>(gqlGlossary) + .query<{ glossary: Glossary }>(gqlGlossary, {}) .toPromise(); if (result.error || !result.data) { console.error(result.error); diff --git a/targets/export-elasticsearch/src/ingester/contributions/fetchCcUnextended.ts b/targets/export-elasticsearch/src/ingester/contributions/fetchCcUnextended.ts index 7355b6253..c23f4416b 100644 --- a/targets/export-elasticsearch/src/ingester/contributions/fetchCcUnextended.ts +++ b/targets/export-elasticsearch/src/ingester/contributions/fetchCcUnextended.ts @@ -23,7 +23,7 @@ export async function fetchAgreementUnextended(): Promise { graphqlEndpoint: HASURA_GRAPHQL_ENDPOINT, adminSecret: HASURA_GRAPHQL_ENDPOINT_SECRET, }) - .query(fetchAgreementUnextendedQuery) + .query(fetchAgreementUnextendedQuery, {}) .toPromise(); if (res.error) { throw res.error; diff --git a/targets/export-elasticsearch/src/ingester/exportStatus/updateExportEsStatusWithDocumentsCount.ts b/targets/export-elasticsearch/src/ingester/exportStatus/updateExportEsStatusWithDocumentsCount.ts index 0322dfe57..a5e9b2008 100644 --- a/targets/export-elasticsearch/src/ingester/exportStatus/updateExportEsStatusWithDocumentsCount.ts +++ b/targets/export-elasticsearch/src/ingester/exportStatus/updateExportEsStatusWithDocumentsCount.ts @@ -37,7 +37,7 @@ export async function updateExportEsStatusWithDocumentsCount( graphqlEndpoint: HASURA_GRAPHQL_ENDPOINT, adminSecret: HASURA_GRAPHQL_ENDPOINT_SECRET, }) - .query(getExportEsStatusQuery) + .query(getExportEsStatusQuery, {}) .toPromise(); if (latestExportEs.error || !latestExportEs.data) { diff --git a/targets/export-elasticsearch/src/ingester/ingest.ts b/targets/export-elasticsearch/src/ingester/ingest.ts index a5ed3f834..401c7e00b 100644 --- a/targets/export-elasticsearch/src/ingester/ingest.ts +++ b/targets/export-elasticsearch/src/ingester/ingest.ts @@ -8,10 +8,9 @@ import { SUGGESTIONS, vectorizeDocument, version, - //@ts-expect-error } from "@socialgouv/cdtn-elasticsearch"; import { logger } from "@shared/utils"; -import { Sources, SOURCES } from "@socialgouv/cdtn-sources"; +import { SOURCES } from "@socialgouv/cdtn-sources"; import pMap from "p-map"; import { cdtnDocumentsGen } from "./cdtnDocuments"; diff --git a/targets/export-elasticsearch/src/ingester/prequalified/fetchPrequalified.ts b/targets/export-elasticsearch/src/ingester/prequalified/fetchPrequalified.ts index f4050e598..e4736ed0d 100644 --- a/targets/export-elasticsearch/src/ingester/prequalified/fetchPrequalified.ts +++ b/targets/export-elasticsearch/src/ingester/prequalified/fetchPrequalified.ts @@ -60,7 +60,7 @@ export async function fetchPrequalified(): Promise< graphqlEndpoint: HASURA_GRAPHQL_ENDPOINT, adminSecret: HASURA_GRAPHQL_ENDPOINT_SECRET, }) - .query(fetchPrequalifiedQuery) + .query(fetchPrequalifiedQuery, {}) .toPromise(); if (res.error) { throw res.error; diff --git a/targets/export-elasticsearch/src/ingester/suggestion.test.ts b/targets/export-elasticsearch/src/ingester/suggestion.test.ts index 53eed9efb..a7bc77348 100644 --- a/targets/export-elasticsearch/src/ingester/suggestion.test.ts +++ b/targets/export-elasticsearch/src/ingester/suggestion.test.ts @@ -1,7 +1,6 @@ import { createIndex, indexDocumentsBatched, - //@ts-expect-error } from "@socialgouv/cdtn-elasticsearch"; import { context } from "./context"; diff --git a/targets/export-elasticsearch/src/ingester/suggestion.ts b/targets/export-elasticsearch/src/ingester/suggestion.ts index 515ebfce2..e487de4ea 100644 --- a/targets/export-elasticsearch/src/ingester/suggestion.ts +++ b/targets/export-elasticsearch/src/ingester/suggestion.ts @@ -2,7 +2,6 @@ import { createIndex, indexDocumentsBatched, suggestionMapping, - //@ts-expect-error } from "@socialgouv/cdtn-elasticsearch"; import fs from "fs"; import { join } from "path"; diff --git a/targets/export-elasticsearch/src/ingester/themes/fetchThemes.ts b/targets/export-elasticsearch/src/ingester/themes/fetchThemes.ts index 8e2eb8672..dc33a765b 100644 --- a/targets/export-elasticsearch/src/ingester/themes/fetchThemes.ts +++ b/targets/export-elasticsearch/src/ingester/themes/fetchThemes.ts @@ -40,7 +40,7 @@ export const fetchThemes = async (): Promise => { graphqlEndpoint, adminSecret, }) - .query(graphQLThemesQuery) + .query(graphQLThemesQuery, {}) .toPromise(); if (result.error || !result.data) { diff --git a/targets/export-elasticsearch/src/repositories/agreements.ts b/targets/export-elasticsearch/src/repositories/agreements.ts index b272a7adc..c851d82c5 100644 --- a/targets/export-elasticsearch/src/repositories/agreements.ts +++ b/targets/export-elasticsearch/src/repositories/agreements.ts @@ -9,7 +9,7 @@ import { listSupportedAgreements } from "./graphql"; export class AgreementsRepository { public async list(): Promise { const res = await gqlClient() - .query<{ agreements: unknown }>(listSupportedAgreements) + .query<{ agreements: unknown }>(listSupportedAgreements, {}) .toPromise(); if (res.error || !res.data) { throw new Error(`Failed to get agreements : ${res.error}`); diff --git a/targets/export-elasticsearch/src/repositories/graphql/mutation.ts b/targets/export-elasticsearch/src/repositories/graphql/mutation.ts index a22b49d11..bac0b3311 100644 --- a/targets/export-elasticsearch/src/repositories/graphql/mutation.ts +++ b/targets/export-elasticsearch/src/repositories/graphql/mutation.ts @@ -8,7 +8,7 @@ mutation createExportEsStatus($id: uuid!, $user_id: uuid!, $environment: String! user { name email - created_at + id } created_at updated_at @@ -25,7 +25,7 @@ mutation updateOneExportEsStatus($id: uuid!, $status: String!, $updated_at: time user { name email - created_at + id } created_at updated_at diff --git a/targets/export-elasticsearch/src/repositories/graphql/queries.ts b/targets/export-elasticsearch/src/repositories/graphql/queries.ts index 02fc7d933..e2bebbf57 100644 --- a/targets/export-elasticsearch/src/repositories/graphql/queries.ts +++ b/targets/export-elasticsearch/src/repositories/graphql/queries.ts @@ -8,7 +8,7 @@ query getAllExport { user { name email - created_at + id } created_at updated_at @@ -27,7 +27,7 @@ query getExportEsStatusByEnvironments($environment: String!) { user { name email - created_at + id } created_at updated_at @@ -46,7 +46,7 @@ query getLatestExportEsStatus($environment: String!) { user { name email - created_at + id } created_at updated_at @@ -66,7 +66,7 @@ query getExportEsById($id: uuid!) { user { name email - created_at + id } created_at updated_at @@ -86,7 +86,7 @@ query getExportEsStatusByStatus($status: String!) { user { name email - created_at + id } created_at updated_at diff --git a/targets/export-elasticsearch/src/repositories/status.ts b/targets/export-elasticsearch/src/repositories/status.ts index 7498b5bb5..ece8d962c 100644 --- a/targets/export-elasticsearch/src/repositories/status.ts +++ b/targets/export-elasticsearch/src/repositories/status.ts @@ -130,7 +130,7 @@ export class ExportRepository { public async getAll(): Promise { try { const res = await gqlClient() - .query<{ export_es_status: ExportEsStatus[] }>(getAllExport) + .query<{ export_es_status: ExportEsStatus[] }>(getAllExport, {}) .toPromise(); if (res.error) { throw res.error; diff --git a/targets/frontend/Dockerfile b/targets/frontend/Dockerfile index 509451730..53aa25330 100644 --- a/targets/frontend/Dockerfile +++ b/targets/frontend/Dockerfile @@ -23,6 +23,9 @@ RUN yarn workspace @shared/utils build FROM deps as dist +ARG NEXT_PUBLIC_BASE_PATH +ENV NEXT_PUBLIC_BASE_PATH=$NEXT_PUBLIC_BASE_PATH + COPY --from=build-types /app/shared/types /app/shared/types COPY --from=build-utils /app/shared/utils /app/shared/utils COPY shared/eslint-config ./shared/eslint-config/ diff --git a/targets/frontend/next.config.js b/targets/frontend/next.config.js index c6bbaf341..955855b72 100644 --- a/targets/frontend/next.config.js +++ b/targets/frontend/next.config.js @@ -1,18 +1,15 @@ -const securityHeaders = [ - { - key: "X-Frame-Options", - value: "deny", - }, - { key: "X-XSS-Protection", value: "1; mode=block" }, - { key: "X-Content-Type-Options", value: "nosniff" }, -]; - module.exports = { async headers() { return [ { - headers: securityHeaders, - // Apply these headers to all routes in your application. + headers: [ + { + key: "X-Frame-Options", + value: "deny", + }, + { key: "X-XSS-Protection", value: "1; mode=block" }, + { key: "X-Content-Type-Options", value: "nosniff" }, + ], source: "/:path*", }, ]; diff --git a/targets/frontend/package.json b/targets/frontend/package.json index 8c7a290be..8ab786e27 100644 --- a/targets/frontend/package.json +++ b/targets/frontend/package.json @@ -21,7 +21,6 @@ "@socialgouv/cdtn-sources": "^4.52.1", "@socialgouv/cdtn-ui": "^4.92.0", "@socialgouv/cdtn-utils": "^4.121.1", - "@socialgouv/matomo-next": "^1.2.2", "@tiptap-pro/extension-details": "^2.3.3", "@tiptap-pro/extension-details-content": "^2.3.3", "@tiptap-pro/extension-details-summary": "^2.3.3", @@ -34,37 +33,34 @@ "@tiptap/pm": "^2.1.12", "@tiptap/react": "^2.1.12", "@tiptap/starter-kit": "^2.1.12", - "@urql/exchange-auth": "^0.1.6", + "@urql/exchange-auth": "^2.1.6", "ace-builds": "^1.31.1", "argon2": "^0.30.3", - "cookie": "^0.4.1", "d3": "^6.7.0", "d3-hierarchy": "^2.0.0", "date-fns": "^2.23.0", "diff": "^5.0.0", "formidable": "^2.0.0", - "graphql": "^16.0.0", - "http-proxy-middleware": "2.0.1", - "isomorphic-unfetch": "^3.1.0", - "jsonwebtoken": "^8.5.1", + "graphql": "^16.8.1", + "http-proxy-middleware": "^3.0.0", + "jsonwebtoken": "^9.0.2", "mammoth": "^1.6.0", "memoizee": "^0.4.15", "micromark": "^2.11.4", "mime-types": "^2.1.35", - "next": "14.0.1", - "next-urql": "^3.2.1", - "nodemailer": "^6.6.5", + "next": "14.1.4", + "next-auth": "^4.24.7", + "nodemailer": "^6.9.13", "p-limit": "^4.0.0", "polished": "^4.1.3", "pretty-bytes": "^5.6.0", - "react": "^18.2.0", + "react": "18.2.0", "react-ace": "^10.1.0", "react-autosuggest": "^10.1.0", - "react-dom": "^18.2.0", + "react-dom": "18.2.0", "react-dropzone": "14.2.3", "react-hook-form": "^7.43.9", "react-icons": "^4.2.0", - "react-is": "^17.0.2", "react-sortable-hoc": "^2.0.0", "rehype-raw": "^5.1.0", "rehype-stringify": "^8.0.0", @@ -76,9 +72,8 @@ "strip-markdown": "^4.2.0", "swr": "^1.0.1", "unified": "^9.2.2", - "urql": "^2.0.5", + "urql": "^4.0.6", "uuid": "^8.3.2", - "wonka": "^4.0.15", "zod": "3.21.4" }, "devDependencies": { @@ -86,34 +81,33 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.5.1", - "@types/cookie": "^0.5.2", "@types/formidable": "^2.0.5", "@types/jest": "^27.4.0", - "@types/jsonwebtoken": "^9.0.3", + "@types/jsonwebtoken": "^9.0.6", "@types/lodash.get": "^4.4.7", - "@types/react": "^17.0.24", - "@types/react-dom": "^18.0.11", - "@urql/devtools": "^2.0.3", + "@types/nodemailer": "^6.4.14", + "@types/react": "18.2.0", + "@types/react-dom": "18.2.0", "eslint": "^8.41.0", - "eslint-config-next": "14.0.1", + "eslint-config-next": "14.1.4", "graphql-tag": "^2.12.6", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", "lint-staged": "^12.0.0", "prop-types": "^15.7.2", - "typescript": "^4.9.5" + "typescript": "^5.4.3" }, "license": "MIT", "main": "index.js", "private": true, "scripts": { "build": "yarn prebuild && next build", - "dev": "yarn predev && next dev -p 3001", + "dev": "yarn predev && NEXTAUTH_URL=http://localhost:3001 NEXTAUTH_SECRET=6ZYMHbt0mxOj9y6mTyG2nJVt2zWDEdckLJz248uflwI= next dev -p 3001", "lint": "next lint", "precommit": "lint-staged", "start": "next start", "predev": "only-include-used-icons", "prebuild": "only-include-used-icons", - "test": "jest" + "test": "jest --silent" } } diff --git a/targets/frontend/src/__tests__/contenus/contentList.test.tsx b/targets/frontend/src/__tests__/contenus/contentList.test.tsx deleted file mode 100644 index ec04b69fb..000000000 --- a/targets/frontend/src/__tests__/contenus/contentList.test.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { render, RenderResult } from "@testing-library/react"; -import { act } from "react-dom/test-utils"; -import { DocumentsPage } from "src/pages/contenus"; - -describe("Given parameters", () => { - describe("When rendering the component DocumentsPage", () => { - let rendering: RenderResult; - beforeEach(async () => { - await act(async () => { - rendering = render(); - }); - }); - it("doit afficher le titre", () => { - expect(rendering.queryAllByText("Contenus")[0]).toBeInTheDocument(); - }); - }); -}); diff --git a/targets/frontend/src/components/Roles.tsx b/targets/frontend/src/components/Roles.tsx deleted file mode 100644 index 30ea2a074..000000000 --- a/targets/frontend/src/components/Roles.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { useQuery } from "urql"; -import { FixedSnackBar } from "./utils/SnackBar"; -import React from "react"; -import { Chip } from "@mui/material"; - -export const getRoleQuery = ` -query getRoles{ - roles { - role - } -} -`; - -export function Roles() { - const [results] = useQuery({ query: getRoleQuery }); - const { data, error, fetching } = results; - - if (fetching) return

loading

; - if (error) - return ( - -
{JSON.stringify(error, null, 2)}
-
- ); - return ( -

- {data.roles.map((role: string) => ( - - ))} -

- ); -} diff --git a/targets/frontend/src/components/changes/ChangeGroup.tsx b/targets/frontend/src/components/changes/ChangeGroup.tsx index f77091883..f815f92cc 100644 --- a/targets/frontend/src/components/changes/ChangeGroup.tsx +++ b/targets/frontend/src/components/changes/ChangeGroup.tsx @@ -25,6 +25,7 @@ import { theme } from "src/theme"; type Props = { label: string; + children: React.ReactNode; }; export const ChangesGroup: React.FC = ({ label, children }) => { @@ -436,6 +437,7 @@ function DilaLabelItem({ info }: DilaLinkProps) { type DilaLinkProps = { info: DilaAddedNode | DilaRemovedNode | DilaModifiedNode; + children?: React.ReactNode; }; const DilaLink: React.FC = ({ info, children }) => { const { parents, id, title } = info; diff --git a/targets/frontend/src/components/comments/index.js b/targets/frontend/src/components/comments/index.js index 2bedc3124..8d3e6c694 100644 --- a/targets/frontend/src/components/comments/index.js +++ b/targets/frontend/src/components/comments/index.js @@ -1,6 +1,5 @@ import PropTypes from "prop-types"; import { useMemo } from "react"; -import { useUser } from "src/hooks/useUser"; import { Card, Alert } from "@mui/material"; import { useMutation, useQuery } from "urql"; @@ -8,6 +7,7 @@ import { Stack } from "../layout/Stack"; import { CommentForm } from "./CommentForm"; import { CommentList } from "./CommentList"; import { theme } from "src/theme"; +import { useSession } from "next-auth/react"; const commentMutation = ` mutation insertNote($data: alert_notes_insert_input!) { @@ -26,7 +26,8 @@ query getComments($alertId: uuid!) { function Comments({ alertId }) { const [, postComment] = useMutation(commentMutation); - const { user } = useUser(); + const { data: session } = useSession(); + const user = session?.user; function sendComment(comment) { return postComment({ @@ -49,7 +50,7 @@ function Comments({ alertId }) { if (error) { return ( -
{JSON.stringify(error, 0, null)}
+
{JSON.stringify(error, null, 2)}
); } diff --git a/targets/frontend/src/components/contributions/answers/Answer.tsx b/targets/frontend/src/components/contributions/answers/Answer.tsx index cb3e3c6e8..e9f7e5ebd 100644 --- a/targets/frontend/src/components/contributions/answers/Answer.tsx +++ b/targets/frontend/src/components/contributions/answers/Answer.tsx @@ -9,7 +9,7 @@ import { Typography, } from "@mui/material"; import React, { useState } from "react"; -import { useUser } from "src/hooks/useUser"; +import { useSession } from "next-auth/react"; import { StatusContainer } from "../status"; import { Answer, Status } from "../type"; @@ -35,7 +35,8 @@ export const ContributionsAnswer = ({ const genericAnswer = useGenericContributionAnswerQuery({ questionId: answer?.questionId, }); - const { user } = useUser() as any; + const { data } = useSession(); + const user = data?.user; const updateAnswer = useContributionAnswerUpdateMutation(); const [snack, setSnack] = useState<{ open: boolean; @@ -52,6 +53,10 @@ export const ContributionsAnswer = ({ throw new Error("Id non définit"); } + if (!user) { + throw new Error("Utilisateur non connecté"); + } + await updateAnswer({ content: data.content, description: data.description, @@ -76,13 +81,13 @@ export const ContributionsAnswer = ({ }); } catch (e: any) { // Dans le cas où il y a une erreur au niveau de la publication (PUBLISHED), on revert le status en VALIDATED - if (newStatus === "PUBLISHED" && answer) { + if (newStatus === "PUBLISHED" && answer && user) { await updateAnswer({ content: data.content, id: answer.id, contentType: data.contentType, status: "VALIDATED", - userId: user?.id, + userId: user.id, contentServicePublicCdtnId: data.contentFichesSpDocument?.cdtnId, kaliReferences: data.kaliReferences, legiReferences: data.legiReferences, diff --git a/targets/frontend/src/components/contributions/answers/Comments.tsx b/targets/frontend/src/components/contributions/answers/Comments.tsx index aaab90b1d..624424e41 100644 --- a/targets/frontend/src/components/contributions/answers/Comments.tsx +++ b/targets/frontend/src/components/contributions/answers/Comments.tsx @@ -4,7 +4,7 @@ import * as React from "react"; import { useMemo } from "react"; import { useForm } from "react-hook-form"; import { FormTextField } from "src/components/forms"; -import { useUser } from "src/hooks/useUser"; +import { useSession } from "next-auth/react"; import { AnswerStatus, @@ -44,7 +44,8 @@ function concatAndSort( } export const Comments = ({ answerId, comments, statuses }: Props) => { - const { user }: any = useUser(); + const { data } = useSession(); + const user = data?.user; const listRef = React.useRef(null); @@ -86,7 +87,7 @@ export const Comments = ({ answerId, comments, statuses }: Props) => { { answerId: answerId, content: data.content, - userId: user.id, + userId: user?.id, }, { additionalTypenames: ["AnswerComments"] } ); diff --git a/targets/frontend/src/components/contributions/answers/__tests__/AnswerForm.test.tsx b/targets/frontend/src/components/contributions/answers/__tests__/AnswerForm.test.tsx index af0035722..875203d83 100644 --- a/targets/frontend/src/components/contributions/answers/__tests__/AnswerForm.test.tsx +++ b/targets/frontend/src/components/contributions/answers/__tests__/AnswerForm.test.tsx @@ -5,6 +5,7 @@ import { fireEvent } from "@testing-library/react"; import { AnswerForm } from "../AnswerForm"; import { AnswerWithStatus } from "../answer.query"; +import { Provider } from "urql"; class ClipboardEventMock extends Event { clipboardData: { @@ -70,6 +71,7 @@ const answerBase: AnswerWithStatus = { id: "0000", name: "Convention collective nationale des transports routiers et activités auxiliaires du transport", kaliId: "KALICONT000005635624", + unextended: false, }, answerComments: [], statuses: [], @@ -144,14 +146,22 @@ const answerBase: AnswerWithStatus = { const onSubmit = jest.fn(() => Promise.resolve()); +const mockClient = { + executeQuery: jest.fn(), + executeMutation: jest.fn(), + executeSubscription: jest.fn(), +}; + describe("AnswerForm", () => { test("Vérifier l'affichage du contenu", () => { render( - + + + ); expect(screen.queryByText("content")).toBeInTheDocument(); @@ -180,11 +190,13 @@ describe("AnswerForm", () => { test("Vérifier l'affichage des options", () => { const { rerender } = render( - + + + ); expect(screen.queryByText("Afficher la réponse")).toBeInTheDocument(); expect( @@ -198,20 +210,22 @@ describe("AnswerForm", () => { ).not.toBeInTheDocument(); rerender( - + + + ); expect(screen.queryByText("Afficher la réponse")).toBeInTheDocument(); expect( @@ -227,11 +241,13 @@ describe("AnswerForm", () => { test("Vérifier que la sauvegarde fonctionne", async () => { render( - + + + ); fireEvent.click(screen.getByText("Sauvegarder")); await waitFor(() => { @@ -241,11 +257,13 @@ describe("AnswerForm", () => { test("Vérifier l'affichage du message d'erreur pour les fiches SP", async () => { render( - + + + ); fireEvent.click(screen.getByText("Utiliser la fiche service public")); userEvent.clear(screen.getByLabelText("Fiche service-public")); @@ -257,11 +275,13 @@ describe("AnswerForm", () => { test("Vérifier l'affichage du message d'erreur pour les références", async () => { render( - + + + ); fireEvent.click(screen.getByText("Ajouter une référence")); fireEvent.click(screen.getByText("Sauvegarder")); diff --git a/targets/frontend/src/components/contributions/questions/EditQuestion.tsx b/targets/frontend/src/components/contributions/questions/EditQuestion.tsx index 3131548c6..c596f13cc 100644 --- a/targets/frontend/src/components/contributions/questions/EditQuestion.tsx +++ b/targets/frontend/src/components/contributions/questions/EditQuestion.tsx @@ -12,7 +12,7 @@ import { countAnswersWithStatus } from "../questionList"; import { Answer } from "../type"; import { StatusStats } from "../status/StatusStats"; import { usePublishContributionMutation } from "../answers/usePublishAnswer"; -import { useUser } from "../../../hooks/useUser"; +import { useSession } from "next-auth/react"; import { useContributionAnswerUpdateStatusMutation } from "../answers/answerStatus.mutation"; export type EditQuestionProps = { @@ -36,10 +36,11 @@ export const EditQuestion = ({ const data = useQuestionQuery({ questionId }); const [tabIndex, setTabIndex] = React.useState(TabValue.answers); const onPublish = usePublishContributionMutation(); - const { user } = useUser() as any; + const { data: session } = useSession(); + const user = session?.user; const updateAnswerStatus = useContributionAnswerUpdateStatusMutation(); - if (data === undefined) { + if (data === undefined || !user) { return ; } diff --git a/targets/frontend/src/components/editorialContent/ContentSections.tsx b/targets/frontend/src/components/editorialContent/ContentSections.tsx index b34de3234..9cedc3242 100644 --- a/targets/frontend/src/components/editorialContent/ContentSections.tsx +++ b/targets/frontend/src/components/editorialContent/ContentSections.tsx @@ -27,7 +27,7 @@ const SortableSectionList = SortableContainer( ))} ) -); +) as any; export function ContentSections({ name }: any) { const { diff --git a/targets/frontend/src/components/fiches-sp/addFiche.js b/targets/frontend/src/components/fiches-sp/addFiche.js index 198ec465d..0a4d0d475 100644 --- a/targets/frontend/src/components/fiches-sp/addFiche.js +++ b/targets/frontend/src/components/fiches-sp/addFiche.js @@ -32,12 +32,15 @@ export function AddFiches() { } const insertFicheServicePublicId = ` -mutation addFichesServicePublic($objects: [service_public_contents_insert_input!]!) { - fiches: insert_service_public_contents(objects: $objects) { - affected_rows - returning { - id, status + mutation addFichesServicePublic( + $objects: [service_public_contents_insert_input!]! + ) { + fiches: insert_service_public_contents(objects: $objects) { + affected_rows + returning { + id + status + } } } -} `; diff --git a/targets/frontend/src/components/fiches-sp/fichesSpContainer.js b/targets/frontend/src/components/fiches-sp/fichesSpContainer.js index 3a0592213..898c5c5da 100644 --- a/targets/frontend/src/components/fiches-sp/fichesSpContainer.js +++ b/targets/frontend/src/components/fiches-sp/fichesSpContainer.js @@ -70,27 +70,29 @@ export function FichesServicePublicContainer() { } const getFicheServicePublicId = ` -query getServicePublicId($offset: Int = 0, $limit: Int = 50) { - ficheIds: v1_fiches_sp( offset: $offset, limit: $limit) { - id, cdtn_id, status, is_available, is_published - } - aggs:v1_fiches_sp_aggregate { - aggregate{ - count + query getServicePublicId($offset: Int = 0, $limit: Int = 50) { + ficheIds: v1_fiches_sp(offset: $offset, limit: $limit) { + id + cdtn_id + status + is_available + is_published + } + aggs: v1_fiches_sp_aggregate { + aggregate { + count + } } } -} `; const deleteFicheServicePublicId = ` -mutation deleteServicePublicIds($ids: [String!] = []) { - delete_service_public_contents(where: { - id: {_in: $ids} - }) { - affected_rows - returning { - id + mutation deleteServicePublicIds($ids: [String!] = []) { + delete_service_public_contents(where: { id: { _in: $ids } }) { + affected_rows + returning { + id + } } } -} `; diff --git a/targets/frontend/src/components/home/InvisibleLinkedDocument.tsx b/targets/frontend/src/components/home/InvisibleLinkedDocument.tsx index fe99ecbac..e3d6c0b07 100644 --- a/targets/frontend/src/components/home/InvisibleLinkedDocument.tsx +++ b/targets/frontend/src/components/home/InvisibleLinkedDocument.tsx @@ -1,7 +1,6 @@ import { HasuraDocument } from "@shared/types"; -import { gql } from "@urql/core"; +import { gql, useQuery } from "urql"; import Link from "next/link"; -import { useQuery } from "urql"; import { Card, CardContent, Typography } from "@mui/material"; import { FixedSnackBar } from "../utils/SnackBar"; import React from "react"; diff --git a/targets/frontend/src/components/layout/UserMenu.tsx b/targets/frontend/src/components/layout/UserMenu.tsx index b4defd85b..af58f1f17 100644 --- a/targets/frontend/src/components/layout/UserMenu.tsx +++ b/targets/frontend/src/components/layout/UserMenu.tsx @@ -10,14 +10,15 @@ import { } from "@mui/material"; import MoreVertIcon from "@mui/icons-material/MoreVert"; import { IoMdContact } from "react-icons/io"; -import { useUser } from "../../hooks/useUser"; +import { useSession, signOut } from "next-auth/react"; import { useState } from "react"; import { theme } from "src/theme"; import { useIsDark } from "@codegouvfr/react-dsfr/useIsDark"; import { fr } from "@codegouvfr/react-dsfr"; export function UserMenu() { - const { user, logout } = useUser() as any; + const { data } = useSession(); + const user = data?.user; const [anchorMenu, setAnchorMenu] = useState(null); const open = Boolean(anchorMenu); const handleClick = (event: React.MouseEvent) => { @@ -68,10 +69,19 @@ export function UserMenu() { - + Mon compte - Déconnexion + + signOut({ + redirect: true, + callbackUrl: "/login", + }) + } + > + Déconnexion + )} diff --git a/targets/frontend/src/components/layout/auth.layout.tsx b/targets/frontend/src/components/layout/auth.layout.tsx index c20ff3963..e57ac6b0f 100644 --- a/targets/frontend/src/components/layout/auth.layout.tsx +++ b/targets/frontend/src/components/layout/auth.layout.tsx @@ -10,7 +10,7 @@ import { } from "@mui/material"; import MenuIcon from "@mui/icons-material/Menu"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { LogoAdmin } from "./LogoAdmin"; import { Navigation } from "./Navigation"; import { UserMenu } from "./UserMenu"; @@ -20,6 +20,8 @@ import { fr } from "@codegouvfr/react-dsfr"; import MuiAppBar, { AppBarProps as MuiAppBarProps } from "@mui/material/AppBar"; import { SnackBar } from "../utils/SnackBar"; import Head from "next/head"; +import { getSession, useSession } from "next-auth/react"; +import { useRouter } from "next/router"; export type LayoutProps = { children: any; @@ -85,6 +87,15 @@ export function Layout({ disableHeadTag = false, }: LayoutProps) { const [menuOpen, setMenuOpen] = useState(true); + const router = useRouter(); + + useEffect(() => { + getSession().then((session) => { + if (!session) { + router.push("/login"); + } + }); + }, [router]); const handleDrawerToggle = () => { setMenuOpen(!menuOpen); diff --git a/targets/frontend/src/components/login/index.js b/targets/frontend/src/components/login/index.tsx similarity index 71% rename from targets/frontend/src/components/login/index.js rename to targets/frontend/src/components/login/index.tsx index 7fd035a49..20ca9e43c 100644 --- a/targets/frontend/src/components/login/index.js +++ b/targets/frontend/src/components/login/index.tsx @@ -1,5 +1,5 @@ import PropTypes from "prop-types"; -import { useForm } from "react-hook-form"; +import { UseFormSetError, useForm } from "react-hook-form"; import { Box, Card, @@ -12,7 +12,16 @@ import { Button } from "../button"; import { Stack } from "../layout/Stack"; import { theme } from "../../theme"; -const LoginForm = ({ authenticate, resetPassword, onSuccess }) => { +type LoginFormProps = { + resetPassword: () => void; + onLogin: ( + email: string, + password: string, + setError: UseFormSetError + ) => void; +}; + +const LoginForm = ({ resetPassword, onLogin }: LoginFormProps) => { const { handleSubmit, register, @@ -21,20 +30,8 @@ const LoginForm = ({ authenticate, resetPassword, onSuccess }) => { formState: { isSubmitting, errors }, } = useForm(); - const submit = async ({ email, password }) => { - try { - const result = await authenticate({ email, password }); - onSuccess(result); - } catch (err) { - setError( - "password", - { - message: "Utilisateur ou mot passe incorrect", - type: "manual", - }, - { shouldFocus: true } - ); - } + const submit = async ({ email, password }: any) => { + onLogin(email, password, setError); }; return ( @@ -56,8 +53,8 @@ const LoginForm = ({ authenticate, resetPassword, onSuccess }) => { type="email" aria-invalid={errors.email ? "true" : "false"} /> - {errors.email && ( - {errors.email?.message} + {errors.email && errors.email.message && ( + {errors.email.message.toString()} )} { type="password" aria-invalid={errors.password ? "true" : "false"} /> - {errors.password && ( - {errors.password?.message} + {errors.password && errors.password.message && ( + {errors.password.message.toString()} )} - - - - - - - Rôle - Nom d’utilisateur - Email - Date de création - Activé - Actions - - - - {data.users.map( - ({ - id, - roles: [{ role } = {}], - name, - email, - created_at, - active, - }) => ( - - - - {role} - - - {name} - {email} - - {new Date(created_at).toLocaleDateString("fr-FR")} - - - {active ? : } - - - - - router.push("/user/edit/[id]", `/user/edit/${id}`) - } - > - Modifier - - confirmDeleteUser(id, email)}> - Supprimer - - - - - ) - )} - -
- - ); -} diff --git a/targets/frontend/src/components/user/List.tsx b/targets/frontend/src/components/user/List.tsx new file mode 100644 index 000000000..d6508f743 --- /dev/null +++ b/targets/frontend/src/components/user/List.tsx @@ -0,0 +1,131 @@ +import { use, useEffect, useState } from "react"; +import { + Alert, + Badge, + Stack, + Table, + TableBody, + TableCell, + TableHead, + TableRow, +} from "@mui/material"; +import { useQuery } from "urql"; + +import { Button, MenuButton, MenuItem } from "../button"; +import { Dialog } from "../dialog"; +import { Check, Cross } from "../utils/icons"; + +const query = ` +query getUsers { + users: auth_users(where: {isDeleted: {_eq: false}}) { + __typename + id + email + name + isActive + isDeleted + createdAt + role + } +} +`; + +type Props = { + onDeleteUser: (userId: string) => Promise; + refresh?: boolean; +}; + +export function UserList({ onDeleteUser }: Props) { + const [showDialog, setShowDialog] = useState(false); + const [selectedUser, setSelectedUser] = useState(); + const open = () => setShowDialog(true); + const close = () => setShowDialog(false); + + const [result, executeQuery] = useQuery({ + query, + }); + const { data, fetching, error } = result; + const users = data?.users || []; + + function confirmDeleteUser(id: string, email: string) { + setSelectedUser({ email, id }); + open(); + } + + async function onClickDeleteUser() { + if (!selectedUser?.id) { + return; + } + close(); + const result = await onDeleteUser(selectedUser.id); + if (result) { + executeQuery({ requestPolicy: "network-only" }); + } + } + + if (fetching) return

chargement...

; + if (error) + return ( + +
{JSON.stringify(error, null, 2)}
+
+ ); + return ( + <> + +

Etes vous sur de vouloir supprimer l’utilisateur

+ {selectedUser?.email} + + + + +
+ + + + Rôle + Nom d’utilisateur + Email + Date de création + Actif + Actions + + + + {users.map(({ id, role, name, email, createdAt, isActive }: any) => ( + + + + {role} + + + {name} + {email} + + {new Date(createdAt).toLocaleDateString("fr-FR")} + + + {isActive ? : } + + + + confirmDeleteUser(id, email)}> + Supprimer + + + + + ))} + +
+ + ); +} diff --git a/targets/frontend/src/components/user/PasswordForm.js b/targets/frontend/src/components/user/PasswordForm.js index 278b98a0a..f4d86b89a 100644 --- a/targets/frontend/src/components/user/PasswordForm.js +++ b/targets/frontend/src/components/user/PasswordForm.js @@ -2,21 +2,21 @@ import Link from "next/link"; import PropTypes from "prop-types"; import { useForm } from "react-hook-form"; import { Button } from "src/components/button"; -import { useUser } from "src/hooks/useUser"; +import { useSession } from "next-auth/react"; import { Stack as StackMUI, TextField as Field } from "@mui/material"; -import { passwordValidation } from "../../lib/auth/auth.const"; import { FormErrorMessage } from "../forms/ErrorMessage"; import { Stack } from "../layout/Stack"; +import { passwordValidation } from "../../modules/authentification/utils/regex"; export function PasswordForm({ onSubmit, - action = "/api/change_password", - backHref = "/user/account", + backHref = "/users/account", changeOldPassword = false, - loading, + loading = false, }) { - const { user } = useUser(); + const { data } = useSession(); + const user = data?.user; const { register, handleSubmit, @@ -63,7 +63,7 @@ export function PasswordForm({ } return ( -
+
Le mot de passe doit faire au moins 12 caractères et doit être composer d'au moins 1 minuscule, 1 majuscule, 1 nombre et 1 caractère @@ -125,7 +125,6 @@ export function PasswordForm({ } PasswordForm.propTypes = { - action: PropTypes.string, backHref: PropTypes.string, changeOldPassword: PropTypes.bool, onSubmit: PropTypes.func.isRequired, diff --git a/targets/frontend/src/components/user/UserForm.js b/targets/frontend/src/components/user/UserForm.js index f845a4bc7..4d630f1c7 100644 --- a/targets/frontend/src/components/user/UserForm.js +++ b/targets/frontend/src/components/user/UserForm.js @@ -2,27 +2,17 @@ import Link from "next/link"; import PropTypes from "prop-types"; import { useForm } from "react-hook-form"; import { Button } from "src/components/button"; -import { - MenuItem, - Select, - Stack as StackMUI, - TextField as Field, -} from "@mui/material"; -import { useQuery } from "urql"; +import { Stack as StackMUI, TextField as Field } from "@mui/material"; import { FormErrorMessage } from "../forms/ErrorMessage"; import { Stack } from "../layout/Stack"; -import { getRoleQuery } from "../Roles"; export function UserForm({ onSubmit, loading = false, user, - isAdmin = false, backHref = "/users", }) { - const [results] = useQuery({ query: getRoleQuery }); - const { data, fetching, error } = results; const { register, handleSubmit, @@ -40,7 +30,7 @@ export function UserForm({
- {isAdmin && ( -
-

Role

- -
- )}
- + {children} diff --git a/targets/frontend/src/config.ts b/targets/frontend/src/config.ts index 89fdc061e..43f1a1d13 100644 --- a/targets/frontend/src/config.ts +++ b/targets/frontend/src/config.ts @@ -1,4 +1,6 @@ export const ACCOUNT_MAIL_SENDER = "contact@fabrique.social.gouv.fr"; export const JWT_TOKEN_EXPIRES = 15; // 15 min export const REFRESH_TOKEN_EXPIRES = 43200; // 30 days in minutes -export const ACTIVATION_TOKEN_EXPIRES = 10080; // 7 days in minutes +export const USER_ACTIVATION_TOKEN_EXPIRES = 1440; // 1 day in minutes +export const BASE_URL = + process.env.NEXT_PUBLIC_BASE_PATH ?? "http://localhost:3001"; diff --git a/targets/frontend/src/hoc/CustomUrqlClient.js b/targets/frontend/src/hoc/CustomUrqlClient.js deleted file mode 100644 index e412a4032..000000000 --- a/targets/frontend/src/hoc/CustomUrqlClient.js +++ /dev/null @@ -1,33 +0,0 @@ -import { withUrqlClient } from "next-urql"; -import { - customAuthExchange, - customErrorExchange, -} from "src/lib/auth/exchanges"; -import { cacheExchange, dedupExchange, fetchExchange } from "urql"; - -export const withCustomUrqlClient = (Component) => - withUrqlClient( - (ssrExchange, ctx) => { - const baseUrl = process.env.FRONTEND_HOST - ? `https://${process.env.FRONTEND_HOST}` - : `http://localhost:3001`; - const isServer = ctx && ctx.req; - const url = isServer ? `${baseUrl}/api/graphql` : "/api/graphql"; - return { - exchanges: [ - process.env.NODE_ENV !== "production" - ? require("@urql/devtools").devtoolsExchange - : null, - dedupExchange, - cacheExchange, - ssrExchange, - customErrorExchange(), - customAuthExchange(ctx), - fetchExchange, - ].filter(Boolean), - requestPolicy: "cache-first", - url, - }; - }, - { ssr: true } - )(Component); diff --git a/targets/frontend/src/hoc/UserProvider.js b/targets/frontend/src/hoc/UserProvider.js deleted file mode 100644 index 8fcd50325..000000000 --- a/targets/frontend/src/hoc/UserProvider.js +++ /dev/null @@ -1,79 +0,0 @@ -import { decode } from "jsonwebtoken"; -import PropTypes from "prop-types"; -import React, { createContext } from "react"; -import { getDisplayName } from "src/hoc/getDisplayName"; -import { Role } from "src/lib/auth/auth.const"; -import { auth } from "src/lib/auth/token"; -import { request } from "src/lib/request"; - -export const UserContext = createContext({}); - -export function withUserProvider(WrappedComponent) { - return class extends React.Component { - static displayName = `withUserProvider(${getDisplayName( - WrappedComponent - )})`; - - static propTypes = { - tokenData: PropTypes.object, - }; - - static async getInitialProps(ctx) { - const token = await auth(ctx); - const componentProps = - WrappedComponent.getInitialProps && - (await WrappedComponent.getInitialProps(ctx)); - - return { - ...componentProps, - tokenData: token ? decode(token.jwt_token) : null, - }; - } - render() { - return ( - - - - ); - } - }; -} - -export const ProvideUser = ({ children, tokenData }) => { - let user = null; - if (tokenData) { - const claims = tokenData["https://hasura.io/jwt/claims"]; - if (claims) { - user = { - id: claims["x-hasura-user-id"], - name: claims["x-hasura-user-name"], - roles: claims["x-hasura-allowed-roles"], - }; - } - } - - async function logout() { - try { - await request("/api/logout", { - credentials: "include", - mode: "same-origin", - }); - } catch (error) { - console.error("[ client logout ] failed", error); - } - window.location = "/login"; - } - const isAuth = Boolean(user); - const isAdmin = user?.roles.includes(Role.SUPER); - - return ( - - {children} - - ); -}; - -ProvideUser.propTypes = { - children: PropTypes.node.isRequired, - tokenData: PropTypes.object, -}; diff --git a/targets/frontend/src/hoc/getDisplayName.js b/targets/frontend/src/hoc/getDisplayName.js deleted file mode 100644 index 7084780e2..000000000 --- a/targets/frontend/src/hoc/getDisplayName.js +++ /dev/null @@ -1,4 +0,0 @@ -// Gets the display name of a JSX component for dev tools -export function getDisplayName(Component) { - return Component.displayName || Component.name || "Component"; -} diff --git a/targets/frontend/src/hooks/exportEs.ts b/targets/frontend/src/hooks/exportEs.ts index 92d234270..b222b2572 100644 --- a/targets/frontend/src/hooks/exportEs.ts +++ b/targets/frontend/src/hooks/exportEs.ts @@ -1,4 +1,5 @@ -import { Environment, ExportEsStatus, Status, User } from "@shared/types"; +import { Environment, ExportEsStatus, Status } from "@shared/types"; +import { Session } from "next-auth"; import { useState } from "react"; import { serializeError } from "serialize-error"; @@ -14,7 +15,7 @@ type ExportEsState = { export function useExportEs(): [ ExportEsState, () => void, - (environment: Environment, user: User) => void, + (environment: Environment, user: Session["user"]) => void, (env: Environment) => Date ] { const [state, setState] = useState({ @@ -66,14 +67,18 @@ export function useExportEs(): [ return lastestCompleted?.created_at; }; - const runExportEs = (environment: Environment, user: User) => { + const runExportEs = (environment: Environment, user: Session["user"]) => { const newExportEs: ExportEsStatus = { created_at: new Date(), environment, id: "0", status: Status.running, updated_at: new Date(), - user, + user: { + email: user.email, + id: user.id, + name: user.name, + }, user_id: user.id, }; setState((state) => ({ diff --git a/targets/frontend/src/hooks/useUser.js b/targets/frontend/src/hooks/useUser.js deleted file mode 100644 index 0ed9e103b..000000000 --- a/targets/frontend/src/hooks/useUser.js +++ /dev/null @@ -1,6 +0,0 @@ -import { useContext } from "react"; -import { UserContext } from "src/hoc/UserProvider"; - -export function useUser() { - return useContext(UserContext); -} diff --git a/targets/frontend/src/lib/api/ApiClient.ts b/targets/frontend/src/lib/api/ApiClient.ts index 690ba5878..dd844df49 100644 --- a/targets/frontend/src/lib/api/ApiClient.ts +++ b/targets/frontend/src/lib/api/ApiClient.ts @@ -1,15 +1,13 @@ -import { Client } from "urql"; import { DocumentNode } from "graphql/index"; -import { TypedDocumentNode } from "@graphql-typed-document-node/core"; -import { OperationContext, OperationResult } from "@urql/core/dist/types/types"; -import { gqlClient } from "@shared/utils"; +import { OperationContext, OperationResult, TypedDocumentNode } from "urql"; +import { gqlClient, GqlClient } from "@shared/utils"; export class ApiClient { - client: Client; + client: GqlClient; hasuraGraphqlAdminSecret: string; sessionVariables?: any; - constructor(client: Client, sessionVariables?: any) { + constructor(client: GqlClient, sessionVariables?: any) { this.client = client; this.hasuraGraphqlAdminSecret = process.env.HASURA_GRAPHQL_ADMIN_SECRET ?? "admin1"; @@ -22,7 +20,7 @@ export class ApiClient { async query( query: DocumentNode | TypedDocumentNode | string, - variables?: Variables, + variables: Variables, context?: Partial ): Promise> { let headers = context?.headers; @@ -34,8 +32,8 @@ export class ApiClient { }; } const result = await this.client - .query(query, variables, { - ...context, + .query(query, variables, { + ...(context as any), fetchOptions: () => ({ ...context?.fetchOptions, headers, @@ -43,12 +41,12 @@ export class ApiClient { }) .toPromise(); - return result; + return result as any; } async mutation( query: DocumentNode | TypedDocumentNode | string, - variables?: Variables, + variables: Variables, context?: Partial ): Promise> { let headers = context?.headers; @@ -61,7 +59,7 @@ export class ApiClient { } const result = await this.client .mutation(query, variables, { - ...context, + ...(context as any), fetchOptions: () => ({ ...context?.fetchOptions, headers, @@ -69,6 +67,6 @@ export class ApiClient { }) .toPromise(); - return result; + return result as any; } } diff --git a/targets/frontend/src/lib/auth/cookie.ts b/targets/frontend/src/lib/auth/cookie.ts deleted file mode 100644 index daf5c681c..000000000 --- a/targets/frontend/src/lib/auth/cookie.ts +++ /dev/null @@ -1,56 +0,0 @@ -import cookie from "cookie"; -import { REFRESH_TOKEN_EXPIRES } from "src/config"; - -export function setJwtCookie( - res: any, - refresh_token?: string, - jwt_token?: string -) { - const cookies = []; - try { - if (refresh_token) { - cookies.push( - cookie.serialize("refresh_token", refresh_token, { - httpOnly: true, - maxAge: REFRESH_TOKEN_EXPIRES * 60, // maxAge in second - path: "/", - sameSite: "strict", - secure: process.env.NODE_ENV === "production", - }) - ); - } - if (jwt_token) { - cookies.push( - cookie.serialize("jwt", jwt_token, { - httpOnly: true, - path: "/", - sameSite: "strict", - secure: process.env.NODE_ENV === "production", - }) - ); - } - if (cookies.length > 0) res.setHeader("Set-Cookie", cookies); - } catch (err) { - console.error("[setJwtCookie]", err); - } -} - -export function removeJwtCookie(res: any) { - const cookies = [ - cookie.serialize("refresh_token", "", { - httpOnly: true, - maxAge: -1, - path: "/", - sameSite: "strict", - secure: process.env.NODE_ENV === "production", - }), - cookie.serialize("jwt", "", { - httpOnly: true, - maxAge: -1, - path: "/", - sameSite: "strict", - secure: process.env.NODE_ENV === "production", - }), - ]; - res.setHeader("Set-Cookie", cookies); -} diff --git a/targets/frontend/src/lib/auth/exchanges.js b/targets/frontend/src/lib/auth/exchanges.js deleted file mode 100644 index 08c414cbe..000000000 --- a/targets/frontend/src/lib/auth/exchanges.js +++ /dev/null @@ -1,74 +0,0 @@ -import { errorExchange, makeOperation } from "@urql/core"; -import { authExchange } from "@urql/exchange-auth"; -import { auth } from "src/lib/auth/token"; - -import { request } from "../request"; - -export function customAuthExchange(ctx) { - return authExchange({ - addAuthToOperation: function addAuthToOperation({ authState, operation }) { - if (!authState?.token) { - return operation; - } - const fetchOptions = - typeof operation.context.fetchOptions === "function" - ? operation.context.fetchOptions() - : operation.context.fetchOptions || {}; - - return makeOperation(operation.kind, operation, { - ...operation.context, - fetchOptions: { - ...fetchOptions, - headers: { - ...fetchOptions.headers, - Authorization: `Bearer ${authState.token}`, - }, - }, - }); - }, - - didAuthError: ({ error }) => { - // check if the error was an auth error (this can be implemented in various ways, e.g. 401 or a special error code) - return error.graphQLErrors.some( - (e) => e.extensions?.code === "invalid-jwt" - ); - }, - - getAuth: async ({ authState }) => { - const result = await auth(ctx); - if (result?.jwt_token) { - // return the new tokens - return { token: result.jwt_token }; - } - - return null; - }, - - willAuthError: ({ authState }) => { - // e.g. check for expiration, existence of auth etc - if (!authState) return true; - return false; - }, - }); -} - -export function customErrorExchange() { - return errorExchange({ - onError: (error) => { - const { graphQLErrors } = error; - // we only get an auth error here when the auth exchange had attempted to refresh auth and getting an auth error again for the second time - const isAuthError = graphQLErrors.some( - (e) => e.extensions?.code === "invalid-jwt" - ); - if (isAuthError) { - // clear storage, log the user out etc - // your app logout logic should trigger here - console.log("errorExchange", "logout"); - request("/api/logout", { - credentials: "include", - mode: "same-origin", - }); - } - }, - }); -} diff --git a/targets/frontend/src/lib/auth/jwt.js b/targets/frontend/src/lib/auth/jwt.js deleted file mode 100644 index 5943a0b7d..000000000 --- a/targets/frontend/src/lib/auth/jwt.js +++ /dev/null @@ -1,63 +0,0 @@ -import jwt, { verify } from "jsonwebtoken"; - -import { JWT_TOKEN_EXPIRES } from "../../config"; - -let jwtSecret; -try { - jwtSecret = JSON.parse( - process.env.HASURA_GRAPHQL_JWT_SECRET ?? - '{"type":"HS256","key":"a_pretty_long_secret_key_that_should_be_at_least_32_char"}' - ); -} catch (error) { - console.error("[JWT], HASURA_GRAPHQL_JWT_SECRET is not a valid json"); -} - -export function generateJwtToken(user) { - const user_roles = user.roles.map((role) => { - return role.role; - }); - if (!user_roles.includes(user.default_role)) { - user_roles.push(user.default_role); - } - return jwt.sign( - { - "https://hasura.io/jwt/claims": { - "x-hasura-allowed-roles": user_roles, - "x-hasura-default-role": user.default_role, - "x-hasura-user-id": user.id.toString(), - "x-hasura-user-name": user.name, - }, - }, - jwtSecret.key, - { - algorithm: jwtSecret.type, - expiresIn: `${JWT_TOKEN_EXPIRES}m`, - } - ); -} - -export function verifyJwtToken(authorizationHeader) { - if (!authorizationHeader) { - throw { message: "no authorization header", type: "badRequest" }; - } - - const auth_split = authorizationHeader.toString().split(" "); - - if (auth_split[0] !== "Bearer" || !auth_split[1]) { - throw { message: "malformed authorization header", type: "badRequest" }; - } - - // get jwt token - const token = auth_split[1]; - - // verify jwt token is OK - let claims; - try { - claims = verify(token, jwtSecret.key, { algorithms: jwtSecret.type }); - } catch (e) { - console.error(e); - throw { message: "Incorrect JWT Token", type: "unauthorized" }; - } - - return claims; -} diff --git a/targets/frontend/src/lib/auth/token.js b/targets/frontend/src/lib/auth/token.js deleted file mode 100644 index e5b3cb429..000000000 --- a/targets/frontend/src/lib/auth/token.js +++ /dev/null @@ -1,84 +0,0 @@ -import Router from "next/router"; - -import { setJwtCookie, removeJwtCookie } from "./cookie"; -import cookie from "cookie"; - -export async function auth(ctx) { - console.log( - "[auth] - refresh token => is server ?", - ctx && ctx.req ? true : false - ); - - const cookieHeader = ctx?.req ? { Cookie: ctx.req.headers.cookie } : {}; - if ( - ctx?.res && - !ctx.res.writableEnded && - !/refresh_token/.test(cookieHeader.Cookie) - ) { - console.log("[auth] no cookie found -> redirect to login"); - ctx.res.writeHead(302, { Location: "/login" }); - ctx.res.end(); - return null; - } - try { - const baseUrl = process.env.FRONTEND_HOST - ? `https://${process.env.FRONTEND_HOST}` - : `http://localhost:3001`; - const isServer = ctx && ctx.req; - const url = isServer - ? `${baseUrl}/api/refresh_token` - : "/api/refresh_token"; - - let body = {}; - - if (cookieHeader && cookieHeader.Cookie) { - let cookies = cookie.parse(cookieHeader.Cookie); - if (cookies && cookies.refresh_token) { - body = { - ...cookies, - }; - } - } - if (body.length === 0) { - console.log("no token found"); - return; - } - const tokenData = await fetch(url, { - headers: { - "Content-Type": "application/json", - "Cache-Control": "no-cache", - ...cookieHeader, - }, - method: "POST", - cache: "no-cache", - mode: "same-origin", - credentials: "include", - body: JSON.stringify({ - refresh_token: body.refresh_token, - }), - }).then((res) => res.json()); - - if (!tokenData.refresh_token) { - throw new Error("no refresh_token found"); - } - - // for ServerSide call, we need to set the Cookie header - // to update the refresh_token value - if (isServer) { - setJwtCookie(ctx.res, tokenData.refresh_token); - } - return tokenData; - } catch (error) { - console.error("[ auth ] refreshToken error ", { error }); - - // we are on server side and its response is not ended yet - if (ctx?.res && !ctx.res.writableEnded) { - removeJwtCookie(ctx.res); - ctx.res.writeHead(302, { Location: "/login" }); - ctx.res.end(); - } else if (ctx && !ctx.req) { - // if we are on the client - Router.push("/login"); - } - } -} diff --git a/targets/frontend/src/pages/contenus/getDocument.query.graphql b/targets/frontend/src/lib/contenus/getDocument.query.graphql similarity index 100% rename from targets/frontend/src/pages/contenus/getDocument.query.graphql rename to targets/frontend/src/lib/contenus/getDocument.query.graphql diff --git a/targets/frontend/src/pages/contenus/updateDocument.mutation.graphql b/targets/frontend/src/lib/contenus/updateDocument.mutation.graphql similarity index 100% rename from targets/frontend/src/pages/contenus/updateDocument.mutation.graphql rename to targets/frontend/src/lib/contenus/updateDocument.mutation.graphql diff --git a/targets/frontend/src/lib/duration.js b/targets/frontend/src/lib/duration.ts similarity index 59% rename from targets/frontend/src/lib/duration.js rename to targets/frontend/src/lib/duration.ts index 6ca5488e7..4839f857c 100644 --- a/targets/frontend/src/lib/duration.js +++ b/targets/frontend/src/lib/duration.ts @@ -9,14 +9,8 @@ export function toSecond(minutes = 0) { return minutes * 60; } -export function getExpiryDate(minutes = 0) { - try { - return new Date(Date.now() + toMs(minutes)); - } catch (error) { - console.error(error); - return null; - } -} - -export const timeSince = (date) => +export const timeSince = (date: string) => formatDistanceToNow(parseISO(date), { locale: frLocale }); + +export const getExpiryDate = (minutes: number) => + new Date(Date.now() + toMs(minutes)).toISOString(); diff --git a/targets/frontend/src/lib/emails/activateAccount.ts b/targets/frontend/src/lib/emails/activateAccount.ts deleted file mode 100644 index 46e83b1a4..000000000 --- a/targets/frontend/src/lib/emails/activateAccount.ts +++ /dev/null @@ -1,25 +0,0 @@ -import sendmail from "./sendmail"; - -export function sendActivateAccountEmail(email: string, secret_token: string) { - const subject = "Activation de votre compte"; - const activateUrl = `${ - process.env.FRONTEND_HOST - ? `https://${process.env.FRONTEND_HOST}` - : `http://localhost:3001` - }/change_password?token=${secret_token}&activate=1`; // todo: dynamic hostname - const text = `Bonjour, - Vous pouvez activer votre compte ${email} afin d'accéder à - l'outil d'administration du cdtn en suivant ce lien : ${activateUrl} - - L'equipe veille CDTN - `; - - const mailOptions = { - from: process.env.ACCOUNT_MAIL_SENDER, - subject, - text, - to: email, - }; - - return sendmail(mailOptions); -} diff --git a/targets/frontend/src/lib/emails/getAccountSecretToken.ts b/targets/frontend/src/lib/emails/getAccountSecretToken.ts deleted file mode 100644 index f0d88ed40..000000000 --- a/targets/frontend/src/lib/emails/getAccountSecretToken.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { gqlClient } from "@shared/utils"; -import { gql } from "@urql/core"; - -const getUserSecretTokenRequest = gql` - query GetUserSecretToken($email: citext!) { - auth_users( - where: { - email: { _eq: $email } - deleted: { _eq: false } - active: { _eq: false } - } - ) { - secret_token - } - } -`; - -export async function getUserSecretToken(email: string) { - const result = await gqlClient() - .query<{ auth_users: [{ secret_token: string }] }, { email: string }>( - getUserSecretTokenRequest, - { - email, - } - ) - .toPromise(); - if (result.error) { - console.error("[getUserSecretToken]", result.error); - throw result.error; - } - return result?.data?.auth_users?.[0]?.secret_token!!; -} diff --git a/targets/frontend/src/lib/emails/lostPassword.js b/targets/frontend/src/lib/emails/lostPassword.js deleted file mode 100644 index b3f36e714..000000000 --- a/targets/frontend/src/lib/emails/lostPassword.js +++ /dev/null @@ -1,29 +0,0 @@ -import sendmail from "./sendmail"; - -export function sendLostPasswordEmail(email, secret_token) { - const activateUrl = `${ - process.env.FRONTEND_HOST - ? `https://${process.env.FRONTEND_HOST}` - : `http://localhost:3001` - }/change_password?token=${secret_token}`; // todo: dynamic hostname - const subject = "Réinitialisation de votre mot de passe"; - const text = ` -Bonjour, -Une demande pour réinitialiser votre de mot de passe est en cours. -Vous pouvez suivre ce lien : ${activateUrl} pour valider la demande. - -Si vous n'etes pas à l'origine de cette demande, pas de soucis, -ne tenez pas compte de de message. - -L'equipe veille CDTN -`; - - var mailOptions = { - from: process.env.ACCOUNT_MAIL_SENDER, - subject, - text, - to: email, - }; - - return sendmail(mailOptions); -} diff --git a/targets/frontend/src/lib/emails/passwordChangeConfirm.js b/targets/frontend/src/lib/emails/passwordChangeConfirm.js deleted file mode 100644 index d284e9c56..000000000 --- a/targets/frontend/src/lib/emails/passwordChangeConfirm.js +++ /dev/null @@ -1,19 +0,0 @@ -import sendmail from "./sendmail"; - -export function sendPasswordChangeConfirmEmail(email) { - const subject = "Modification du mot de passe de votre compte"; - const text = `Bonjour, - Votre mot de passe a bien été modifié pour votre compte. - - L'equipe veille CDTN - `; - - const mailOptions = { - from: process.env.ACCOUNT_MAIL_SENDER, - subject, - text, - to: email, - }; - - return sendmail(mailOptions); -} diff --git a/targets/frontend/src/lib/emails/sendmail.js b/targets/frontend/src/lib/emails/sendmail.js deleted file mode 100644 index c8b0278eb..000000000 --- a/targets/frontend/src/lib/emails/sendmail.js +++ /dev/null @@ -1,13 +0,0 @@ -import nodemailer from "nodemailer"; - -export default function sendmail(mailOptions) { - const transport = nodemailer.createTransport({ - auth: { - pass: process.env.SMTP_EMAIL_PASSWORD ?? "pass", - user: process.env.SMTP_EMAIL_USER ?? "email", - }, - host: process.env.SMTP_URL ?? "smtp.url", - port: 587, - }); - return transport.sendMail(mailOptions).finally(() => transport.close()); -} diff --git a/targets/frontend/src/lib/regex.js b/targets/frontend/src/lib/regex.js deleted file mode 100644 index ba1c5b9db..000000000 --- a/targets/frontend/src/lib/regex.js +++ /dev/null @@ -1,2 +0,0 @@ -export const passwordValidation = - /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*]).{12,32}$/; diff --git a/targets/frontend/src/modules/agreements/api/query.ts b/targets/frontend/src/modules/agreements/api/query.ts index 29a10e676..eecc771cd 100644 --- a/targets/frontend/src/modules/agreements/api/query.ts +++ b/targets/frontend/src/modules/agreements/api/query.ts @@ -1,4 +1,4 @@ -import { gql } from "@urql/core"; +import { gql } from "urql"; import { Agreement } from "../type"; export const agreementQuery = gql` diff --git a/targets/frontend/src/modules/agreements/components/Creation/agreement.mutation.ts b/targets/frontend/src/modules/agreements/components/Creation/agreement.mutation.ts index b64eb657b..1555da136 100644 --- a/targets/frontend/src/modules/agreements/components/Creation/agreement.mutation.ts +++ b/targets/frontend/src/modules/agreements/components/Creation/agreement.mutation.ts @@ -1,5 +1,4 @@ -import { gql } from "@urql/core"; -import { useMutation } from "urql"; +import { gql, useMutation } from "urql"; import { FormDataResult } from "../Common"; import { AgreementsInsertInput } from "../graphql.type"; diff --git a/targets/frontend/src/modules/agreements/components/Edition/agreement.mutation.ts b/targets/frontend/src/modules/agreements/components/Edition/agreement.mutation.ts index 8fb247b3e..fcc7348ff 100644 --- a/targets/frontend/src/modules/agreements/components/Edition/agreement.mutation.ts +++ b/targets/frontend/src/modules/agreements/components/Edition/agreement.mutation.ts @@ -1,5 +1,4 @@ -import { gql } from "@urql/core"; -import { useMutation } from "urql"; +import { gql, useMutation } from "urql"; import { FormDataResult } from "../Common"; import { AgreementsInsertInput } from "../graphql.type"; diff --git a/targets/frontend/src/modules/agreements/components/Edition/agreement.query.ts b/targets/frontend/src/modules/agreements/components/Edition/agreement.query.ts index 4a8e4563a..c73ba2e44 100644 --- a/targets/frontend/src/modules/agreements/components/Edition/agreement.query.ts +++ b/targets/frontend/src/modules/agreements/components/Edition/agreement.query.ts @@ -1,6 +1,5 @@ -import { CombinedError, OperationContext, useQuery } from "urql"; +import { gql, CombinedError, OperationContext, useQuery } from "urql"; import { Agreement } from "../../type"; -import { gql } from "@urql/core"; import { format, parseISO } from "date-fns"; export const getAgreementQuery = gql` diff --git a/targets/frontend/src/modules/agreements/components/Edition/delete.mutation.ts b/targets/frontend/src/modules/agreements/components/Edition/delete.mutation.ts index 7c03c6c43..b23bf2c4e 100644 --- a/targets/frontend/src/modules/agreements/components/Edition/delete.mutation.ts +++ b/targets/frontend/src/modules/agreements/components/Edition/delete.mutation.ts @@ -1,5 +1,4 @@ -import { gql } from "@urql/core"; -import { useMutation } from "urql"; +import { gql, useMutation } from "urql"; const deleteAgreementQuery = gql` mutation DeleteAgreement($id: bpchar!, $initialId: String!) { diff --git a/targets/frontend/src/modules/agreements/components/List/list.query.ts b/targets/frontend/src/modules/agreements/components/List/list.query.ts index c746e497f..6c6c8382d 100644 --- a/targets/frontend/src/modules/agreements/components/List/list.query.ts +++ b/targets/frontend/src/modules/agreements/components/List/list.query.ts @@ -1,5 +1,4 @@ -import { useQuery } from "urql"; -import { gql } from "@urql/core"; +import { gql, useQuery } from "urql"; import { Agreement } from "../../type"; export const listAgreementsQuery = gql` diff --git a/targets/frontend/src/modules/authentification/activateUser.ts b/targets/frontend/src/modules/authentification/activateUser.ts new file mode 100644 index 000000000..5ed6ed3c4 --- /dev/null +++ b/targets/frontend/src/modules/authentification/activateUser.ts @@ -0,0 +1,76 @@ +import { gqlClient } from "@shared/utils"; +import { hash } from "argon2"; +import { gql } from "urql"; +import { AuthGqlError } from "./utils/errors"; +import { getAndVerifyActivationToken } from "./utils/jwt"; + +const getUserQuery = gql` + query getUser($id: uuid!) { + auth_users_by_pk(id: $id) { + password + isDeleted + isActive + } + } +`; + +interface GetUserHasuraResult { + auth_users_by_pk: { + password: string; + }; +} + +const updateQuery = gql` + mutation updatePasswordAndIsActive($id: uuid!, $password: String!) { + update_auth_users_by_pk( + pk_columns: { id: $id } + _set: { password: $password, isActive: true } + ) { + id + } + } +`; + +interface UpdateUserHasuraResult { + update_auth_users_by_pk: { + id: string; + }; +} + +export const activateUser = async ( + token: string, + newPassword: string +): Promise => { + const { id } = await getAndVerifyActivationToken(token); + + const getUserResult = await gqlClient() + .query(getUserQuery, { + id, + }) + .toPromise(); + + if (getUserResult.error || !getUserResult.data?.auth_users_by_pk) { + throw new AuthGqlError({ + cause: getUserResult.error, + message: "User not found", + name: "AUTH_GQL_ERROR", + }); + } + + const password = await hash(newPassword); + + const result = await gqlClient() + .mutation(updateQuery, { + id, + password, + }) + .toPromise(); + + if (result.data?.update_auth_users_by_pk.id !== id || result.error) { + throw new AuthGqlError({ + cause: result.error, + message: "Error to activate user", + name: "AUTH_GQL_ERROR", + }); + } +}; diff --git a/targets/frontend/src/modules/authentification/changePassword.ts b/targets/frontend/src/modules/authentification/changePassword.ts new file mode 100644 index 000000000..11c3bc9fd --- /dev/null +++ b/targets/frontend/src/modules/authentification/changePassword.ts @@ -0,0 +1,84 @@ +import { gqlClient } from "@shared/utils"; +import { hash, verify } from "argon2"; +import { gql } from "urql"; +import { AuthGqlError, AuthUserPasswordDifferent } from "./utils/errors"; + +const getUserQuery = gql` + query getUser($id: uuid!) { + auth_users_by_pk(id: $id) { + password + isDeleted + isActive + } + } +`; + +interface GetUserHasuraResult { + auth_users_by_pk: { + password: string; + }; +} + +const updateQuery = gql` + mutation updatePassword($id: uuid!, $password: String!) { + update_auth_users_by_pk( + pk_columns: { id: $id } + _set: { password: $password } + ) { + id + } + } +`; + +interface UpdateUserHasuraResult { + update_auth_users_by_pk: { + id: string; + }; +} + +export const changePassword = async ( + userId: string, + oldPassword: string, + newPassword: string +): Promise => { + const getUserResult = await gqlClient() + .query(getUserQuery, { + id: userId, + }) + .toPromise(); + + if (getUserResult.error || !getUserResult.data?.auth_users_by_pk) { + throw new AuthGqlError({ + cause: getUserResult.error, + message: "Error to get user", + name: "AUTH_GQL_ERROR", + }); + } + + const userPassword = getUserResult.data.auth_users_by_pk.password; + + const match = await verify(userPassword, oldPassword); + + if (!match) { + throw new AuthUserPasswordDifferent({ + message: "Old password is different from the one stored in database", + name: "AUTH_USER_PASSWORD_DIFFERENT", + cause: null, + }); + } + + const password = await hash(newPassword); + + const result = await gqlClient() + .mutation(updateQuery, { + id: userId, + password, + }) + .toPromise(); + + if (result.data?.update_auth_users_by_pk.id !== userId || result.error) { + return false; + } + + return true; +}; diff --git a/targets/frontend/src/modules/authentification/createUser.ts b/targets/frontend/src/modules/authentification/createUser.ts new file mode 100644 index 000000000..ca1824dba --- /dev/null +++ b/targets/frontend/src/modules/authentification/createUser.ts @@ -0,0 +1,71 @@ +import { gqlClient } from "@shared/utils"; +import { gql } from "urql"; +import { AuthEmailSendError, AuthGqlError } from "./utils/errors"; +import { UserSignedIn } from "./signIn"; +import { sendActivateAccountEmail } from "../emails/sendActivateAccountEmail"; +import { generateActivationToken } from "./utils/jwt"; + +const insertQuery = gql` + mutation insertUser($name: String!, $email: citext!, $role: String!) { + insert_auth_users_one(object: { name: $name, email: $email, role: $role }) { + id + } + } +`; + +interface InsertUserHasuraResult { + insert_auth_users_one: { + id: string; + }; +} + +const deleteQuery = gql` + mutation deleteUser($id: uuid!) { + delete_auth_users_by_pk(id: $id) { + id + } + } +`; + +export const createUser = async ( + name: string, + email: string +): Promise => { + const defaultRole = "super" as UserSignedIn["role"]; + const result = await gqlClient() + .mutation(insertQuery, { + name, + email, + role: defaultRole, + }) + .toPromise(); + + if (result.error || !result.data?.insert_auth_users_one.id) { + throw new AuthGqlError({ + cause: result.error, + message: "Impossible to register user", + name: "AUTH_GQL_ERROR", + }); + } + + const userId = result.data.insert_auth_users_one.id; + + const activationTokenGenerated = generateActivationToken(userId); + + try { + await sendActivateAccountEmail(email, activationTokenGenerated); + } catch (error) { + await gqlClient() + .mutation(deleteQuery, { + id: userId, + }) + .toPromise(); + throw new AuthEmailSendError({ + cause: error, + message: "Impossible to send activation email", + name: "SEND_EMAIL_ERROR", + }); + } + + return true; +}; diff --git a/targets/frontend/src/modules/authentification/deleteUser.ts b/targets/frontend/src/modules/authentification/deleteUser.ts new file mode 100644 index 000000000..93fa936b5 --- /dev/null +++ b/targets/frontend/src/modules/authentification/deleteUser.ts @@ -0,0 +1,43 @@ +import { gqlClient } from "@shared/utils"; +import { gql } from "urql"; + +const deleteQuery = gql` + mutation deleteUser($id: uuid!, $name: String!, $email: citext!) { + update_auth_users_by_pk( + pk_columns: { id: $id } + _set: { + name: $name + email: $email + password: "mot de passe" + isDeleted: true + } + ) { + name + } + } +`; + +interface DeleteUserHasuraResult { + update_auth_users_by_pk: { + name: string; + }; +} + +export const deleteUser = async (userId: string): Promise => { + const deleteResult = await gqlClient() + .mutation(deleteQuery, { + email: `${userId}@gouv.fr`, + id: userId, + name: userId, + }) + .toPromise(); + + if ( + deleteResult.data?.update_auth_users_by_pk.name !== userId || + deleteResult.error + ) { + return false; + } + + return true; +}; diff --git a/targets/frontend/src/modules/authentification/generateAccessToken.ts b/targets/frontend/src/modules/authentification/generateAccessToken.ts new file mode 100644 index 000000000..711951f36 --- /dev/null +++ b/targets/frontend/src/modules/authentification/generateAccessToken.ts @@ -0,0 +1,68 @@ +import { + AuthGqlError, + AuthJwtRefreshError, + AuthUserDeleted, +} from "./utils/errors"; +import { UserStoredInJwt, generateJwtToken, verifyToken } from "./utils/jwt"; +import { JWT_TOKEN_EXPIRES } from "src/config"; +import { UserSignedIn } from "./signIn"; +import { gqlClient } from "@shared/utils"; + +const getUserByMailQuery = ` + query login($email: citext!) { + auth_users(where: {email: {_eq: $email}}) { + isDeleted + } + } +`; + +interface GetUserByMailHasuraResult { + auth_users: { isDeleted: boolean }[]; +} + +export const generateNewAccessToken = async ( + user: UserSignedIn +): Promise => { + const isValid = verifyToken(user.refreshToken); + + if (!isValid) { + throw new AuthJwtRefreshError({ + cause: null, + message: "Invalid refresh token", + name: "AUTH_JWT_REFRESH_ERROR", + }); + } + + const userToSave: UserStoredInJwt = { + id: user.id, + name: user.name, + role: user.role, + }; + + // Sécurité en vérifiant que l'utilisateur n'a pas été supprimé pour lui générer un nouveau token. + const result = await gqlClient() + .query(getUserByMailQuery, { + email: user.email, + }) + .toPromise(); + + if (result.error || !result.data?.auth_users[0]) { + throw new AuthGqlError({ + cause: result.error, + message: "User not find", + name: "AUTH_GQL_ERROR", + }); + } + + if (result.data.auth_users[0].isDeleted) { + throw new AuthUserDeleted({ + message: `${user.email} has been deleted`, + name: "AUTH_USER_DELETED", + cause: null, + }); + } + + const accessTokenGenerated = generateJwtToken(userToSave, JWT_TOKEN_EXPIRES); + + return accessTokenGenerated; +}; diff --git a/targets/frontend/src/modules/authentification/resetPassword.ts b/targets/frontend/src/modules/authentification/resetPassword.ts new file mode 100644 index 000000000..3736aa148 --- /dev/null +++ b/targets/frontend/src/modules/authentification/resetPassword.ts @@ -0,0 +1,48 @@ +import { gqlClient } from "@shared/utils"; +import { hash, verify } from "argon2"; +import { gql } from "urql"; +import { AuthEmailResetPasswordError, AuthGqlError } from "./utils/errors"; +import { sendLostPasswordEmail } from "../emails/sendLostPasswordEmail"; +import { generateActivationToken } from "./utils/jwt"; + +const getUserQuery = gql` + query login($email: citext!) { + auth_users(where: { email: { _eq: $email } }) { + id + } + } +`; + +interface GetUserHasuraResult { + auth_users: { id: string }[]; +} + +export const resetPassword = async (email: string): Promise => { + const getUserResult = await gqlClient() + .query(getUserQuery, { + email, + }) + .toPromise(); + + if (getUserResult.error || !getUserResult.data?.auth_users[0]?.id) { + throw new AuthGqlError({ + cause: getUserResult.error, + message: "Error to get user", + name: "AUTH_GQL_ERROR", + }); + } + + const activationTokenGenerated = generateActivationToken( + getUserResult.data.auth_users[0].id + ); + + try { + await sendLostPasswordEmail(email, activationTokenGenerated); + } catch (error) { + throw new AuthEmailResetPasswordError({ + cause: error, + message: "Impossible to send reset password email", + name: "SEND_EMAIL_RESET_PASSWORD_ERROR", + }); + } +}; diff --git a/targets/frontend/src/modules/authentification/signIn.ts b/targets/frontend/src/modules/authentification/signIn.ts new file mode 100644 index 000000000..0fa33eb3b --- /dev/null +++ b/targets/frontend/src/modules/authentification/signIn.ts @@ -0,0 +1,122 @@ +import { gqlClient } from "@shared/utils"; +import { + AuthGqlError, + AuthUserDeleted, + AuthUserNotActive, + AuthUserNotFound, + AuthUserPasswordDifferent, +} from "./utils/errors"; +import { verify } from "argon2"; +import { UserStoredInJwt, generateJwtToken } from "./utils/jwt"; +import { JWT_TOKEN_EXPIRES, REFRESH_TOKEN_EXPIRES } from "src/config"; +import { gql } from "urql"; + +const signInQuery = gql` + query login($email: citext!) { + auth_users(where: { email: { _eq: $email } }) { + id + email + password + name + isActive + isDeleted + role + } + } +`; + +interface LoginHasuraResult { + auth_users: Required< + Pick & { + password: string; + isActive: boolean; + isDeleted: boolean; + } + >[]; +} + +export type UserSignedIn = { + id: string; + name: string; + email: string; + role: "super" | "user"; + accessToken: string; + refreshToken: string; +}; + +export const signIn = async ( + email: string, + password: string +): Promise => { + const loginResult = await gqlClient() + .query(signInQuery, { + email, + }) + .toPromise(); + + if (loginResult.error) { + throw new AuthGqlError({ + cause: loginResult.error, + message: "Error with password or email", + name: "AUTH_GQL_ERROR", + }); + } + + if ( + loginResult.data?.auth_users.length === 0 || + !loginResult.data?.auth_users[0] + ) { + throw new AuthUserNotFound({ + message: `No user with ${email}`, + name: "AUTH_USER_NOT_FOUND", + cause: null, + }); + } + + const user = loginResult.data.auth_users[0]; + + if (!user.isActive) { + throw new AuthUserNotActive({ + message: `${email} is not activated`, + name: "AUTH_USER_NOT_ACTIVE", + cause: null, + }); + } + + if (user.isDeleted) { + throw new AuthUserDeleted({ + message: `${email} has been deleted`, + name: "AUTH_USER_DELETED", + cause: null, + }); + } + + const match = await verify(user.password, password); + + if (!match) { + throw new AuthUserPasswordDifferent({ + message: "Invalid 'email' or 'password'", + name: "AUTH_USER_PASSWORD_DIFFERENT", + cause: null, + }); + } + + const userToSave: UserStoredInJwt = { + id: user.id, + role: user.role, + name: user.name, + }; + + const accessTokenGenerated = generateJwtToken(userToSave, JWT_TOKEN_EXPIRES); + const refreshTokenGenerated = generateJwtToken( + userToSave, + REFRESH_TOKEN_EXPIRES + ); + + return { + ...userToSave, + email: user.email, + accessToken: accessTokenGenerated, + refreshToken: refreshTokenGenerated, + }; +}; diff --git a/targets/frontend/src/modules/authentification/utils/errors.ts b/targets/frontend/src/modules/authentification/utils/errors.ts new file mode 100644 index 000000000..edd203f1a --- /dev/null +++ b/targets/frontend/src/modules/authentification/utils/errors.ts @@ -0,0 +1,19 @@ +import { ErrorBase } from "src/lib/api"; + +export class AuthGqlError extends ErrorBase<"AUTH_GQL_ERROR"> {} + +export class AuthUserNotFound extends ErrorBase<"AUTH_USER_NOT_FOUND"> {} + +export class AuthUserNotActive extends ErrorBase<"AUTH_USER_NOT_ACTIVE"> {} + +export class AuthUserDeleted extends ErrorBase<"AUTH_USER_DELETED"> {} + +export class AuthUserPasswordDifferent extends ErrorBase<"AUTH_USER_PASSWORD_DIFFERENT"> {} + +export class AuthJwtRefreshError extends ErrorBase<"AUTH_JWT_REFRESH_ERROR"> {} + +export class AuthRefreshTokenExpired extends ErrorBase<"AUTH_REFRESH_TOKEN_EXPIRED"> {} + +export class AuthEmailSendError extends ErrorBase<"SEND_EMAIL_ERROR"> {} + +export class AuthEmailResetPasswordError extends ErrorBase<"SEND_EMAIL_RESET_PASSWORD_ERROR"> {} diff --git a/targets/frontend/src/modules/authentification/utils/exchanges.ts b/targets/frontend/src/modules/authentification/utils/exchanges.ts new file mode 100644 index 000000000..4900447e0 --- /dev/null +++ b/targets/frontend/src/modules/authentification/utils/exchanges.ts @@ -0,0 +1,43 @@ +import { getSession, signOut } from "next-auth/react"; +import { authExchange } from "@urql/exchange-auth"; + +export const authExchangeUrql = authExchange(async (utils) => { + const session = await getSession(); + let accessToken = session?.user.accessToken; + + return { + addAuthToOperation(operation) { + if (accessToken) { + return utils.appendHeaders(operation, { + Authorization: `Bearer ${accessToken}`, + }); + } + return operation; + }, + willAuthError(_operation) { + return !accessToken; + }, + didAuthError(error, _operation) { + return error.graphQLErrors.some( + (e) => + e.extensions?.code === "validation-failed" || + e.extensions?.code === "invalid-jwt" || + e.extensions?.code === "jwt-invalid-claims" + ); + }, + async refreshAuth() { + try { + const session = await getSession(); + if (!session) { + throw new Error("No session"); + } + accessToken = session.user.accessToken; + } catch (_error) { + signOut({ + redirect: true, + callbackUrl: "/login", + }); + } + }, + }; +}); diff --git a/targets/frontend/src/modules/authentification/utils/jwt.ts b/targets/frontend/src/modules/authentification/utils/jwt.ts new file mode 100644 index 000000000..f08aade1a --- /dev/null +++ b/targets/frontend/src/modules/authentification/utils/jwt.ts @@ -0,0 +1,107 @@ +import jwt, { Algorithm, verify } from "jsonwebtoken"; +import { UserSignedIn } from "../signIn"; +import { USER_ACTIVATION_TOKEN_EXPIRES } from "src/config"; + +const getJwtTokenSecret = (): { type: Algorithm; key: string } => { + return JSON.parse( + process.env.HASURA_GRAPHQL_JWT_SECRET ?? + '{"type":"HS256","key":"a_pretty_long_secret_key_that_should_be_at_least_32_char"}' + ); +}; + +export type UserStoredInJwt = Pick; + +export type HasuraJwtToken = { + "https://hasura.io/jwt/claims": { + "x-hasura-allowed-roles": string[]; + "x-hasura-default-role": string; + "x-hasura-user-id": string; + "x-hasura-user-name": string; + }; + iat: number; + exp: number; +}; + +export type ActivationToken = { + id: string; + iat: number; + exp: number; +}; + +export function generateJwtToken( + user: UserStoredInJwt, + expiresInMinutes: number +) { + const jwtSecret = getJwtTokenSecret(); + return jwt.sign( + { + "https://hasura.io/jwt/claims": { + "x-hasura-allowed-roles": [user.role], + "x-hasura-default-role": user.role, + "x-hasura-user-id": user.id, + "x-hasura-user-name": user.name, + } as HasuraJwtToken["https://hasura.io/jwt/claims"], + }, + jwtSecret.key, + { + algorithm: jwtSecret.type, + expiresIn: `${expiresInMinutes}m`, + } + ); +} + +export function getJwtToken(token: string): HasuraJwtToken { + const jwtSecret = getJwtTokenSecret(); + const payloadToken = verify(token, jwtSecret.key, { + algorithms: [jwtSecret.type], + }); + if (typeof payloadToken === "string") { + throw new Error("Invalid token"); + } + return payloadToken as HasuraJwtToken; +} + +export const verifyToken = (token?: string) => { + try { + if (!token) return false; + const tokenVerified = getJwtToken(token); + + const validity = tokenVerified.exp * 1000 - Date.now(); + + if (validity < 0) { + return false; + } + return true; + } catch (error) { + return false; + } +}; + +export function generateActivationToken(id: string) { + const jwtSecret = getJwtTokenSecret(); + return jwt.sign( + { + id, + }, + jwtSecret.key, + { + algorithm: jwtSecret.type, + expiresIn: `${USER_ACTIVATION_TOKEN_EXPIRES}m`, + } + ); +} + +export function getAndVerifyActivationToken(token: string): ActivationToken { + const jwtSecret = getJwtTokenSecret(); + const isValid = verifyToken(token); + if (!isValid) { + throw new Error("Token has expired"); + } + const payloadToken = verify(token, jwtSecret.key, { + algorithms: [jwtSecret.type], + }); + if (typeof payloadToken === "string") { + throw new Error("Invalid token"); + } + return payloadToken as ActivationToken; +} diff --git a/targets/frontend/src/lib/auth/auth.const.ts b/targets/frontend/src/modules/authentification/utils/regex.ts similarity index 53% rename from targets/frontend/src/lib/auth/auth.const.ts rename to targets/frontend/src/modules/authentification/utils/regex.ts index 7a1de472f..dbe9e4e11 100644 --- a/targets/frontend/src/lib/auth/auth.const.ts +++ b/targets/frontend/src/modules/authentification/utils/regex.ts @@ -1,7 +1,5 @@ export const passwordValidation = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*]).{12,32}$/; -export enum Role { - SUPER = "super", - USER = "user", -} +export const emailValidation = + /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; diff --git a/targets/frontend/src/modules/contribution/api/query.ts b/targets/frontend/src/modules/contribution/api/query.ts index 3f0e23948..e692fcf9b 100644 --- a/targets/frontend/src/modules/contribution/api/query.ts +++ b/targets/frontend/src/modules/contribution/api/query.ts @@ -1,4 +1,4 @@ -import { gql } from "@urql/core"; +import { gql } from "urql"; export const getContributionAnswerById = gql` query contribution_answer($id: uuid!) { diff --git a/targets/frontend/src/modules/emails/send.ts b/targets/frontend/src/modules/emails/send.ts new file mode 100644 index 000000000..6cffcc2a5 --- /dev/null +++ b/targets/frontend/src/modules/emails/send.ts @@ -0,0 +1,24 @@ +import nodemailer from "nodemailer"; +import Mail from "nodemailer/lib/mailer"; + +export default function sendMail(mailOptions: Mail.Options) { + if ( + !process.env.SMTP_EMAIL_USER || + !process.env.SMTP_EMAIL_PASSWORD || + !process.env.SMTP_URL + ) { + console.error( + "SMTP_EMAIL_USER, SMTP_EMAIL_PASSWORD and SMTP_URL must be set" + ); + return Promise.resolve(); + } + const transport = nodemailer.createTransport({ + auth: { + pass: process.env.SMTP_EMAIL_PASSWORD, + user: process.env.SMTP_EMAIL_USER, + }, + host: process.env.SMTP_URL, + port: 587, + }); + return transport.sendMail(mailOptions).finally(() => transport.close()); +} diff --git a/targets/frontend/src/modules/emails/sendActivateAccountEmail.ts b/targets/frontend/src/modules/emails/sendActivateAccountEmail.ts new file mode 100644 index 000000000..7c198d2c4 --- /dev/null +++ b/targets/frontend/src/modules/emails/sendActivateAccountEmail.ts @@ -0,0 +1,26 @@ +import { ACCOUNT_MAIL_SENDER, BASE_URL } from "src/config"; +import sendMail from "./send"; + +export function sendActivateAccountEmail(email: string, secret_token: string) { + const activateUrl = `${BASE_URL}/change_password?token=${secret_token}`; + + const subject = "Activation de votre compte"; + + const text = ` + Bonjour, + + Vous pouvez activer votre compte ${email} afin d'accéder à + l'outil d'administration en suivant ce lien : ${activateUrl} + + L'équipe CDTN + `; + + const mailOptions = { + from: ACCOUNT_MAIL_SENDER, + subject, + text, + to: email, + }; + + return sendMail(mailOptions); +} diff --git a/targets/frontend/src/modules/emails/sendLostPasswordEmail.ts b/targets/frontend/src/modules/emails/sendLostPasswordEmail.ts new file mode 100644 index 000000000..55a468040 --- /dev/null +++ b/targets/frontend/src/modules/emails/sendLostPasswordEmail.ts @@ -0,0 +1,27 @@ +import { ACCOUNT_MAIL_SENDER, BASE_URL } from "src/config"; +import sendMail from "./send"; + +export function sendLostPasswordEmail(email: string, secret_token: string) { + const activateUrl = `${BASE_URL}/change_password?token=${secret_token}`; + const subject = "Réinitialisation de votre mot de passe"; + const text = ` + Bonjour, + + Une demande pour réinitialiser votre de mot de passe est en cours. + Vous pouvez suivre ce lien : ${activateUrl} pour valider la demande. + + Si vous n'êtes pas à l'origine de cette demande, pas de soucis, + ne tenez pas compte de de message. + + L'équipe CDTN +`; + + var mailOptions = { + from: ACCOUNT_MAIL_SENDER, + subject, + text, + to: email, + }; + + return sendMail(mailOptions); +} diff --git a/targets/frontend/src/modules/export/components/export.tsx b/targets/frontend/src/modules/export/components/export.tsx index 779a2f4ad..e86cb7ed7 100644 --- a/targets/frontend/src/modules/export/components/export.tsx +++ b/targets/frontend/src/modules/export/components/export.tsx @@ -7,7 +7,7 @@ import { } from "src/components/export-es"; import { Table, Td, Th, Tr } from "src/components/table"; import { useExportEs } from "src/hooks/exportEs"; -import { useUser } from "src/hooks/useUser"; +import { useSession } from "next-auth/react"; import { Button, CircularProgress as Spinner, @@ -25,9 +25,13 @@ export function Export(): JSX.Element { const [exportEsState, getExportEs, runExportEs, getLatestDeployDate] = useExportEs(); - const { user }: any = useUser(); + const { data } = useSession(); + const user = data?.user; - const onTrigger = (env: Environment) => runExportEs(env, user); + const onTrigger = (env: Environment) => { + if (!user) throw new Error("Utilisateur non connecté"); + runExportEs(env, user); + }; useEffect(() => { getExportEs(); diff --git a/targets/frontend/src/modules/export/document.query.ts b/targets/frontend/src/modules/export/document.query.ts index 79dc2ef67..66d4fd495 100644 --- a/targets/frontend/src/modules/export/document.query.ts +++ b/targets/frontend/src/modules/export/document.query.ts @@ -64,11 +64,9 @@ export const useDocumentsQuery = ({ return new Map(); } // Le filtre est temporaire tant que l'ancien outil de contrib est la : exclure les anciennes contribs qui ont une updated date toujours mise à jour - const filtered = result.data.documents - .filter( - (doc) => - doc.source !== SOURCES.CONTRIBUTIONS || !!doc.document?.contentType - ); + const filtered = result.data.documents.filter( + (doc) => doc.source !== SOURCES.CONTRIBUTIONS || !!doc.document?.contentType + ); const grouped = groupBy(filtered, (data) => data.source); grouped.forEach((array, key) => { diff --git a/targets/frontend/src/modules/informations/api/informations.query.ts b/targets/frontend/src/modules/informations/api/informations.query.ts index e0e580c66..4f56bb2ae 100644 --- a/targets/frontend/src/modules/informations/api/informations.query.ts +++ b/targets/frontend/src/modules/informations/api/informations.query.ts @@ -1,4 +1,4 @@ -import { gql } from "@urql/core"; +import { gql } from "urql"; import { Information } from "../type"; export const informationsQuery = gql` diff --git a/targets/frontend/src/modules/informations/components/informationsEdit/Informations.query.ts b/targets/frontend/src/modules/informations/components/informationsEdit/Informations.query.ts index 942a38aac..f8f025dc0 100644 --- a/targets/frontend/src/modules/informations/components/informationsEdit/Informations.query.ts +++ b/targets/frontend/src/modules/informations/components/informationsEdit/Informations.query.ts @@ -1,8 +1,7 @@ -import { CombinedError, OperationContext, useQuery } from "urql"; +import { CombinedError, OperationContext, useQuery, gql } from "urql"; import { format, parseISO } from "date-fns"; import { Information } from "../../type"; -import { gql } from "@urql/core"; const informationsQuery = gql` query informations($id: uuid) { diff --git a/targets/frontend/src/modules/informations/components/informationsEdit/deleteInformation.mutation.ts b/targets/frontend/src/modules/informations/components/informationsEdit/deleteInformation.mutation.ts index 05e3754fd..4b46f6950 100644 --- a/targets/frontend/src/modules/informations/components/informationsEdit/deleteInformation.mutation.ts +++ b/targets/frontend/src/modules/informations/components/informationsEdit/deleteInformation.mutation.ts @@ -1,5 +1,4 @@ -import { OperationResult, useMutation } from "urql"; -import { gql } from "@urql/core"; +import { gql, OperationResult, useMutation } from "urql"; export const deleteInformationMutation = gql` mutation delete_information($id: uuid!, $initialId: String!) { diff --git a/targets/frontend/src/modules/informations/components/informationsEdit/editInformation.mutation.ts b/targets/frontend/src/modules/informations/components/informationsEdit/editInformation.mutation.ts index e7988366f..1778b48ee 100644 --- a/targets/frontend/src/modules/informations/components/informationsEdit/editInformation.mutation.ts +++ b/targets/frontend/src/modules/informations/components/informationsEdit/editInformation.mutation.ts @@ -1,10 +1,8 @@ -import { useMutation } from "urql"; - import { Information } from "../../type"; import { mapInformation } from "./editInformation.mapping"; import { getElementsToDelete } from "src/lib/mutationUtils"; -import { gql } from "@urql/core"; +import { gql, useMutation } from "urql"; export const informationMutation = gql` mutation edit_information( diff --git a/targets/frontend/src/modules/models/api/modelsQuery.ts b/targets/frontend/src/modules/models/api/modelsQuery.ts index 5ff915a0f..cae5e1f21 100644 --- a/targets/frontend/src/modules/models/api/modelsQuery.ts +++ b/targets/frontend/src/modules/models/api/modelsQuery.ts @@ -1,4 +1,4 @@ -import { gql } from "@urql/core"; +import { gql } from "urql"; import { Model } from "../type"; export const modelsQuery = gql` diff --git a/targets/frontend/src/modules/models/components/Creation/model.mutation.ts b/targets/frontend/src/modules/models/components/Creation/model.mutation.ts index 0c7c9ed55..06643e733 100644 --- a/targets/frontend/src/modules/models/components/Creation/model.mutation.ts +++ b/targets/frontend/src/modules/models/components/Creation/model.mutation.ts @@ -1,5 +1,4 @@ -import { gql } from "@urql/core"; -import { useMutation } from "urql"; +import { gql, useMutation } from "urql"; import { LegiReference } from "src/components/forms/LegiReferences/type"; import { FormDataResult } from "../Common"; import { OtherReference } from "../../../../components/forms/OtherReferences/type"; diff --git a/targets/frontend/src/modules/models/components/Edition/model.mutation.ts b/targets/frontend/src/modules/models/components/Edition/model.mutation.ts index 563436490..ae1e97510 100644 --- a/targets/frontend/src/modules/models/components/Edition/model.mutation.ts +++ b/targets/frontend/src/modules/models/components/Edition/model.mutation.ts @@ -1,5 +1,4 @@ -import { gql } from "@urql/core"; -import { useMutation } from "urql"; +import { gql, useMutation } from "urql"; import { LegiReference } from "src/components/forms/LegiReferences/type"; import { FormDataResult } from "../Common"; import { diff --git a/targets/frontend/src/modules/models/components/Edition/model.query.ts b/targets/frontend/src/modules/models/components/Edition/model.query.ts index 81361e7e1..213637447 100644 --- a/targets/frontend/src/modules/models/components/Edition/model.query.ts +++ b/targets/frontend/src/modules/models/components/Edition/model.query.ts @@ -1,40 +1,39 @@ -import { CombinedError, OperationContext, useQuery } from "urql"; import { Model } from "../../type"; -import { gql } from "@urql/core"; +import { gql, CombinedError, OperationContext, useQuery } from "urql"; import { format, parseISO } from "date-fns"; export const listModelsQuery = gql` - query SelectModel($id: uuid!) { - model: model_models_by_pk(id: $id) { - id - title - metaTitle - type - description - metaDescription - previewHTML - createdAt - updatedAt - file { - id - url - size - altText - } - legiReferences: models_legi_references { - legiArticle { - cid - id - label - } - } - otherReferences: models_other_references { - id - label - url - } + query SelectModel($id: uuid!) { + model: model_models_by_pk(id: $id) { + id + title + metaTitle + type + description + metaDescription + previewHTML + createdAt + updatedAt + file { + id + url + size + altText + } + legiReferences: models_legi_references { + legiArticle { + cid + id + label } + } + otherReferences: models_other_references { + id + label + url + } } + } `; export type ModelResult = Model; diff --git a/targets/frontend/src/modules/models/components/Edition/publish.mutation.ts b/targets/frontend/src/modules/models/components/Edition/publish.mutation.ts index c6f05e53e..3235797eb 100644 --- a/targets/frontend/src/modules/models/components/Edition/publish.mutation.ts +++ b/targets/frontend/src/modules/models/components/Edition/publish.mutation.ts @@ -10,19 +10,16 @@ mutation publish_information( } `; -export type PublishMutationResult = ( - id: string -) => Promise; +export type PublishMutationResult = (id: string) => Promise; -export const usePublishMutation = - (): PublishMutationResult => { - const [, execute] = useMutation(publishMutation); - const resultFunction = async (id: string) => { - const result = await execute({ id }); - if (result.error) { - throw new Error(result.error.message); - } - return result; - }; - return resultFunction; +export const usePublishMutation = (): PublishMutationResult => { + const [, execute] = useMutation(publishMutation); + const resultFunction = async (id: string) => { + const result = await execute({ id }); + if (result.error) { + throw new Error(result.error.message); + } + return result; }; + return resultFunction; +}; diff --git a/targets/frontend/src/modules/models/components/List/list.query.ts b/targets/frontend/src/modules/models/components/List/list.query.ts index ccce14c18..5fcaafb26 100644 --- a/targets/frontend/src/modules/models/components/List/list.query.ts +++ b/targets/frontend/src/modules/models/components/List/list.query.ts @@ -1,5 +1,4 @@ -import { useQuery } from "urql"; -import { gql } from "@urql/core"; +import { useQuery, gql } from "urql"; import { Model } from "../../type"; export const listModelsQuery = gql` diff --git a/targets/frontend/src/modules/prequalified/edition/prequalifiedDelete.mutation.ts b/targets/frontend/src/modules/prequalified/edition/prequalifiedDelete.mutation.ts index e4e81603f..ffd603cce 100644 --- a/targets/frontend/src/modules/prequalified/edition/prequalifiedDelete.mutation.ts +++ b/targets/frontend/src/modules/prequalified/edition/prequalifiedDelete.mutation.ts @@ -1,5 +1,4 @@ -import { OperationResult, useMutation } from "urql"; -import { gql } from "@urql/core"; +import { OperationResult, useMutation, gql } from "urql"; export const deletePrequalifiedMutation = gql` mutation delete_prequalified($id: uuid) { diff --git a/targets/frontend/src/modules/references/useContributionReferencesQuery.tsx b/targets/frontend/src/modules/references/useContributionReferencesQuery.tsx index c706e7123..d8d7375ad 100644 --- a/targets/frontend/src/modules/references/useContributionReferencesQuery.tsx +++ b/targets/frontend/src/modules/references/useContributionReferencesQuery.tsx @@ -1,5 +1,4 @@ -import { useQuery } from "urql"; -import { gql } from "@urql/core"; +import { gql, useQuery } from "urql"; const getContributionsReferencesWithDocumentInitialId = gql` query getContributionsReferencesById($id: String!) { diff --git a/targets/frontend/src/pages/_app.js b/targets/frontend/src/pages/_app.js deleted file mode 100644 index 46ec98e08..000000000 --- a/targets/frontend/src/pages/_app.js +++ /dev/null @@ -1,55 +0,0 @@ -import "@reach/menu-button/styles.css"; -import "@reach/dialog/styles.css"; -import "@reach/accordion/styles.css"; -import "../css/modeles.css"; -import { MuiDsfrThemeProvider } from "@codegouvfr/react-dsfr/mui"; - -import { init } from "@socialgouv/matomo-next"; -import getConfig from "next/config"; -import PropTypes from "prop-types"; -import { useEffect } from "react"; - -import { createNextDsfrIntegrationApi } from "@codegouvfr/react-dsfr/next-pagesdir"; -import Link from "next/link"; - -const { withDsfr, dsfrDocumentApi } = createNextDsfrIntegrationApi({ - defaultColorScheme: "system", - Link, - preloadFonts: [ - //"Marianne-Light", - //"Marianne-Light_Italic", - "Marianne-Regular", - //"Marianne-Regular_Italic", - "Marianne-Medium", - //"Marianne-Medium_Italic", - "Marianne-Bold", - //"Marianne-Bold_Italic", - //"Spectral-Regular", - //"Spectral-ExtraBold" - ], -}); - -export { dsfrDocumentApi }; - -function App({ Component, pageProps, err }) { - useEffect(() => { - init({ - siteId: process.env.NEXT_PUBLIC_MATOMO_SITE_ID, - url: process.env.NEXT_PUBLIC_MATOMO_URL, - }); - }, []); - // Workaround for https://github.com/vercel/next.js/issues/8592 - return ( - - - - ); -} - -export default withDsfr(App); - -App.propTypes = { - Component: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), - err: PropTypes.object, - pageProps: PropTypes.object, -}; diff --git a/targets/frontend/src/pages/_app.tsx b/targets/frontend/src/pages/_app.tsx new file mode 100644 index 000000000..900484548 --- /dev/null +++ b/targets/frontend/src/pages/_app.tsx @@ -0,0 +1,46 @@ +import "@reach/menu-button/styles.css"; +import "@reach/dialog/styles.css"; +import "@reach/accordion/styles.css"; +import "../css/modeles.css"; +import { MuiDsfrThemeProvider } from "@codegouvfr/react-dsfr/mui"; +import { SessionProvider } from "next-auth/react"; +import { createNextDsfrIntegrationApi } from "@codegouvfr/react-dsfr/next-pagesdir"; +import Link from "next/link"; +import type { AppProps } from "next/app"; +import { Client, Provider, cacheExchange, fetchExchange } from "urql"; +import { authExchangeUrql } from "src/modules/authentification/utils/exchanges"; +import { BASE_URL } from "src/config"; + +declare module "@codegouvfr/react-dsfr/next-pagesdir" { + interface RegisterLink { + Link: typeof Link; + } +} + +const { withDsfr, dsfrDocumentApi } = createNextDsfrIntegrationApi({ + defaultColorScheme: "system", + Link, + preloadFonts: ["Marianne-Regular", "Marianne-Medium", "Marianne-Bold"], +}); + +export { dsfrDocumentApi }; + +function App({ Component, pageProps: { session, ...pageProps } }: AppProps) { + const client = new Client({ + url: `${BASE_URL}/api/graphql`, + exchanges: [authExchangeUrql, cacheExchange, fetchExchange], + requestPolicy: "cache-and-network", + }); + + return ( + + + + + + + + ); +} + +export default withDsfr(App); diff --git a/targets/frontend/src/pages/agreements/[agreementId].tsx b/targets/frontend/src/pages/agreements/[agreementId].tsx index 1d0170ec6..12ec854ae 100644 --- a/targets/frontend/src/pages/agreements/[agreementId].tsx +++ b/targets/frontend/src/pages/agreements/[agreementId].tsx @@ -1,6 +1,4 @@ import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { useRouter } from "next/router"; import { AgreementEdition } from "../../modules/agreements"; @@ -15,4 +13,4 @@ export function AgreementEditionPage() { ); } -export default withCustomUrqlClient(withUserProvider(AgreementEditionPage)); +export default AgreementEditionPage; diff --git a/targets/frontend/src/pages/agreements/creation.tsx b/targets/frontend/src/pages/agreements/creation.tsx index 1da90c8ad..f0ea97533 100644 --- a/targets/frontend/src/pages/agreements/creation.tsx +++ b/targets/frontend/src/pages/agreements/creation.tsx @@ -1,6 +1,4 @@ import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { AgreementCreation } from "../../modules/agreements"; export function AgreementCreationPage() { @@ -11,4 +9,4 @@ export function AgreementCreationPage() { ); } -export default withCustomUrqlClient(withUserProvider(AgreementCreationPage)); +export default AgreementCreationPage; diff --git a/targets/frontend/src/pages/agreements/index.tsx b/targets/frontend/src/pages/agreements/index.tsx index 5d802dcc9..bc8c7abc0 100644 --- a/targets/frontend/src/pages/agreements/index.tsx +++ b/targets/frontend/src/pages/agreements/index.tsx @@ -1,8 +1,6 @@ import { AgreementList } from "src/modules/agreements"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; export function AgreementsPage() { return ( @@ -12,4 +10,4 @@ export function AgreementsPage() { ); } -export default withCustomUrqlClient(withUserProvider(AgreementsPage)); +export default AgreementsPage; diff --git a/targets/frontend/src/pages/alerts/[[...params]].tsx b/targets/frontend/src/pages/alerts/[[...params]].tsx index e002b3646..8868724e8 100644 --- a/targets/frontend/src/pages/alerts/[[...params]].tsx +++ b/targets/frontend/src/pages/alerts/[[...params]].tsx @@ -15,8 +15,6 @@ import { import { Layout } from "src/components/layout/auth.layout"; import { Stack } from "src/components/layout/Stack"; import { Pagination } from "src/components/pagination"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import type { AlertStatusType } from "src/models"; import { alertStatusWordings } from "src/models"; import { useQuery } from "urql"; @@ -244,4 +242,4 @@ export function AlertPage(): JSX.Element { ); } -export default withCustomUrqlClient(withUserProvider(AlertPage)); +export default AlertPage; diff --git a/targets/frontend/src/pages/api/actions/email_account_activation.ts b/targets/frontend/src/pages/api/actions/email_account_activation.ts deleted file mode 100644 index 918ed1a2c..000000000 --- a/targets/frontend/src/pages/api/actions/email_account_activation.ts +++ /dev/null @@ -1,40 +0,0 @@ -import Boom from "@hapi/boom"; -import { createErrorFor } from "src/lib/apiError"; -import { sendActivateAccountEmail } from "src/lib/emails/activateAccount"; -import { NextApiRequest, NextApiResponse } from "next"; -import { getUserSecretToken } from "../../../lib/emails/getAccountSecretToken"; - -type Response = { message: string; statusCode: number }; - -export default async function ActivateAccount( - req: NextApiRequest, - res: NextApiResponse -) { - const apiError = createErrorFor(res); - if (req.method === "GET") { - console.error("[ActivateAccount] GET method not allowed"); - res.setHeader("Allow", ["POST"]); - return apiError(Boom.methodNotAllowed("GET method not allowed")); - } - - if ( - !req.headers["actions-secret"] || - req.headers["actions-secret"] !== process.env.ACTIONS_SECRET - ) { - console.error("[ActivateAccount] Missing secret or env"); - return apiError(Boom.unauthorized("Missing secret or env")); - } - - const { email } = req.body.input; - try { - const secret_token = await getUserSecretToken(email); - await sendActivateAccountEmail(email, secret_token); - console.log("[actions] send activate account email"); - res.json({ message: "email sent!", statusCode: 200 }); - } catch (error) { - console.error(`[actions] send activation email to ${email} failed`, error); - apiError( - Boom.badGateway(`[actions] send activation email to ${email} failed`) - ); - } -} diff --git a/targets/frontend/src/pages/api/actions/email_password_request.js b/targets/frontend/src/pages/api/actions/email_password_request.js deleted file mode 100644 index 2563e0b7f..000000000 --- a/targets/frontend/src/pages/api/actions/email_password_request.js +++ /dev/null @@ -1,32 +0,0 @@ -import Boom from "@hapi/boom"; -import { createErrorFor } from "src/lib/apiError"; -import { sendLostPasswordEmail } from "src/lib/emails/lostPassword"; - -export default async function AskNewPassword(req, res) { - const apiError = createErrorFor(res); - if (req.method === "GET") { - console.error("[AskNewPassword] GET method not allowed"); - res.setHeader("Allow", ["POST"]); - return apiError(Boom.methodNotAllowed("GET method not allowed")); - } - - if ( - !req.headers["actions-secret"] || - req.headers["actions-secret"] !== process.env.ACTIONS_SECRET - ) { - console.error("[AskNewPassword] Missing secret or env"); - return apiError(Boom.unauthorized("Missing secret or env")); - } - - const { email, secret_token } = req.body.input; - try { - await sendLostPasswordEmail(email, secret_token); - console.log("[actions] send lost password email"); - res.json({ message: "email sent!", statusCode: 200 }); - } catch (error) { - console.error(`[actions] send lost password email to ${email} failed`); - apiError( - Boom.badGateway(`[actions] send lost password email to ${email} failed`) - ); - } -} diff --git a/targets/frontend/src/pages/api/activate_account.js b/targets/frontend/src/pages/api/activate_account.js deleted file mode 100644 index 8ad3605a2..000000000 --- a/targets/frontend/src/pages/api/activate_account.js +++ /dev/null @@ -1,89 +0,0 @@ -import Boom from "@hapi/boom"; -import { z } from "zod"; -import { gqlClient } from "@shared/utils"; -import { hash } from "argon2"; -import { createErrorFor } from "src/lib/apiError"; - -import { sendPasswordChangeConfirmEmail } from "../../lib/emails/passwordChangeConfirm"; -import { getUserEmailQuery } from "./get_user_email.gql"; -import { activateUserMutation } from "./password.gql"; -import { passwordSchema } from "./validation"; - -export function createRequestHandler({ - mutation, - error_message = "error", - success_message = "success", - sendConfirmation = false, -}) { - return async function (req, res) { - const apiError = createErrorFor(res); - - if (req.method === "GET") { - res.setHeader("Allow", ["POST"]); - return apiError(Boom.methodNotAllowed("GET method not allowed")); - } - - const schema = z.object({ - password: passwordSchema, - token: z.string().uuid(), - }); - - const { error, data: value } = schema.safeParse(req.body); - if (error) { - return apiError(Boom.badRequest(error.message)); - } - - const [queryResult, result] = await Promise.all([ - await gqlClient() - .query(getUserEmailQuery, { - secret_token: value.token, - }) - .toPromise(), - await gqlClient() - .mutation(mutation, { - now: new Date().toISOString(), - password: await hash(value.password), - secret_token: value.token, - }) - .toPromise(), - ]); - - if (result.error) { - console.error(result.error); - return apiError(Boom.unauthorized("request failed")); - } - - if (result.data["update_user"].affected_rows === 0) { - return apiError(Boom.unauthorized(error_message)); - } - - console.log("[set password]", value.token); - if (sendConfirmation) { - const [{ email }] = queryResult.data.users; - try { - await sendPasswordChangeConfirmEmail(email); - console.log("[actions] send password change confirmation email"); - res.json({ message: "email sent!", statusCode: 200 }); - } catch (error) { - console.log(error); - console.error( - `[actions] send lost password change confirmation to ${email} failed` - ); - apiError( - Boom.badGateway( - `[actions] send change confirmation email to ${email} failed` - ) - ); - } - } - - res.json({ message: success_message }); - }; -} - -export default createRequestHandler({ - errorMessage: - "Account is already activated, the secret token has expired or there is no account.", - mutation: activateUserMutation, - success_message: "user activated !", -}); diff --git a/targets/frontend/src/pages/api/auth/[...nextauth].ts b/targets/frontend/src/pages/api/auth/[...nextauth].ts new file mode 100644 index 000000000..6330de411 --- /dev/null +++ b/targets/frontend/src/pages/api/auth/[...nextauth].ts @@ -0,0 +1,56 @@ +import NextAuth, { NextAuthOptions, Session } from "next-auth"; +import CredentialsProvider from "next-auth/providers/credentials"; +import { REFRESH_TOKEN_EXPIRES } from "src/config"; +import { generateNewAccessToken } from "src/modules/authentification/generateAccessToken"; +import { verifyToken } from "src/modules/authentification/utils/jwt"; +import { UserSignedIn, signIn } from "src/modules/authentification/signIn"; + +export const authOptions: NextAuthOptions = { + providers: [ + CredentialsProvider({ + name: "Credentials", + credentials: { + email: { label: "Email", type: "text" }, + password: { label: "Password", type: "password" }, + }, + authorize: async (credentials) => { + if (!credentials) { + return null; + } + const user = await signIn(credentials.email, credentials.password); + return user; + }, + }), + ], + pages: { + signIn: "/login", + }, + callbacks: { + session: ({ session, token }) => { + return { + ...session, + user: { + id: token.id, + accessToken: token.accessToken, + email: token.email, + name: token.name, + role: token.role, + } as Session["user"], + }; + }, + jwt: async ({ token, user }) => { + const tokenUser: UserSignedIn = { ...token, ...user } as any; + const isAccessTokenValid = verifyToken(tokenUser.accessToken); + if (!isAccessTokenValid) { + const newAccessToken = await generateNewAccessToken(tokenUser); + tokenUser.accessToken = newAccessToken; + } + return tokenUser; + }, + }, + session: { + maxAge: REFRESH_TOKEN_EXPIRES * 60, + }, +}; + +export default NextAuth(authOptions); diff --git a/targets/frontend/src/pages/api/change_password.js b/targets/frontend/src/pages/api/change_password.js deleted file mode 100644 index 77e0ca3d2..000000000 --- a/targets/frontend/src/pages/api/change_password.js +++ /dev/null @@ -1,84 +0,0 @@ -import Boom from "@hapi/boom"; -import { z } from "zod"; -import { gqlClient } from "@shared/utils"; -import { hash, verify } from "argon2"; -import { createErrorFor } from "src/lib/apiError"; - -import { sendPasswordChangeConfirmEmail } from "../../lib/emails/passwordChangeConfirm"; -import { changeMyPasswordMutation, getOldPassword } from "./password.gql"; -import { passwordSchema } from "./validation"; - -export default async function changePassword(req, res) { - const apiError = createErrorFor(res); - - if (req.method === "GET") { - res.setHeader("Allow", ["POST"]); - return apiError(Boom.methodNotAllowed("GET method not allowed")); - } - - const schema = z.object({ - id: z.string().uuid(), - oldPassword: z.string(), - password: passwordSchema, - }); - - const { error, data: value } = schema.safeParse(req.body); - if (error) { - return apiError(Boom.badRequest(error.message)); - } - - let result = await gqlClient() - .query(getOldPassword, { - id: value.id, - }) - .toPromise(); - - if (result.error) { - console.error(result.error); - return apiError(Boom.serverUnavailable("get old password failed")); - } - - const { user } = result.data; - if (!user) { - return apiError(Boom.unauthorized("Invalid id or password")); - } - // see if password hashes matches - const match = await verify(user.password, value.oldPassword); - - if (!match) { - console.error("old password does not match"); - return apiError(Boom.unauthorized("Invalid id or password")); - } - - result = await gqlClient() - .mutation(changeMyPasswordMutation, { - id: value.id, - password: await hash(value.password), - }) - .toPromise(); - - if (result.error) { - console.error(result.error); - return apiError(Boom.serverUnavailable("set new password failed")); - } - - console.log("[change password]", value.id); - const { email } = user; - try { - await sendPasswordChangeConfirmEmail(email); - console.log("[actions] send password change confirmation email"); - res.json({ message: "email sent!", statusCode: 200 }); - } catch (error) { - console.error(error); - console.error( - `[actions] send lost password change confirmation to ${email} failed` - ); - apiError( - Boom.badGateway( - `[actions] send change confirmation email to ${email} failed` - ) - ); - } - - res.json({ message: "password updated" }); -} diff --git a/targets/frontend/src/pages/api/get_user_email.gql.js b/targets/frontend/src/pages/api/get_user_email.gql.js deleted file mode 100644 index 8417ddaf5..000000000 --- a/targets/frontend/src/pages/api/get_user_email.gql.js +++ /dev/null @@ -1,13 +0,0 @@ -export const getUserEmailQuery = ` - query get_user_email( - $secret_token: uuid! - ) { - users: auth_users ( - where: { - secret_token: { _eq: $secret_token } - } - ) { - email - } - } - `; diff --git a/targets/frontend/src/pages/api/graphql.js b/targets/frontend/src/pages/api/graphql.ts similarity index 57% rename from targets/frontend/src/pages/api/graphql.js rename to targets/frontend/src/pages/api/graphql.ts index 457d0b980..c9d59697a 100644 --- a/targets/frontend/src/pages/api/graphql.js +++ b/targets/frontend/src/pages/api/graphql.ts @@ -1,28 +1,20 @@ import { createProxyMiddleware } from "http-proxy-middleware"; +// Note : Utiliser un proxy évite d'exposer publiquement le Hasura GraphQL endpoint + export const config = { api: { + externalResolver: true, bodyParser: false, }, - externalResolver: true, }; const proxy = createProxyMiddleware({ changeOrigin: true, - followRedirects: true, - logLevel: "debug", - onError: (err, req, res) => { - res.writeHead(500, { - "Content-Type": "text/plain", - }); - res.end("Something went wrong. We've been notified."); - }, pathRewrite: { "^/api/graphql": "/v1/graphql" }, prependPath: false, target: process.env.HASURA_GRAPHQL_ENDPOINT ?? "http://localhost:8080/v1/graphql", - ws: true, - xfwd: true, // proxy websockets }); export default proxy; diff --git a/targets/frontend/src/pages/api/login.gql.js b/targets/frontend/src/pages/api/login.gql.js deleted file mode 100644 index 30d50ca9e..000000000 --- a/targets/frontend/src/pages/api/login.gql.js +++ /dev/null @@ -1,35 +0,0 @@ -export const loginQuery = ` - query login( - $username: citext! - ) { - users: auth_users ( - where: { - email: { _eq: $username} - } - ) { - id - password - active - deleted - name - default_role - roles: user_roles { - role - } - } - } - `; - -export const refreshTokenMutation = ` - mutation insertRefreshToken ( - $refresh_token_data: auth_refresh_tokens_insert_input! - ) { - insert_data: insert_auth_refresh_tokens ( - objects: [$refresh_token_data] - ) { - returning { - refresh_token - } - } - } -`; diff --git a/targets/frontend/src/pages/api/login.js b/targets/frontend/src/pages/api/login.js deleted file mode 100644 index 73104946f..000000000 --- a/targets/frontend/src/pages/api/login.js +++ /dev/null @@ -1,100 +0,0 @@ -import Boom from "@hapi/boom"; -import { z } from "zod"; -import { gqlClient } from "@shared/utils"; -import { verify } from "argon2"; -import { createErrorFor } from "src/lib/apiError"; -import { generateJwtToken } from "src/lib/auth/jwt"; -import { setJwtCookie } from "src/lib/auth/cookie"; -import { getExpiryDate } from "src/lib/duration"; - -import { loginQuery, refreshTokenMutation } from "./login.gql"; - -import { JWT_TOKEN_EXPIRES, REFRESH_TOKEN_EXPIRES } from "../../config"; - -export default async function login(req, res) { - const apiError = createErrorFor(res); - - if (req.method === "GET") { - res.setHeader("Allow", ["POST"]); - return apiError(Boom.methodNotAllowed("GET method not allowed")); - } - // validate username and password - const schema = z.object({ - password: z.string(), - username: z.string(), - }); - - const { error, data: value } = schema.safeParse(req.body); - - if (error) { - console.error(error); - return apiError(Boom.badRequest(error.details[0].message)); - } - - const { username, password } = value; - - const loginResult = await gqlClient() - .query(loginQuery, { - username, - }) - .toPromise(); - - if (loginResult.error) { - console.error(loginResult.error); - return apiError(Boom.serverUnavailable("login error")); - } - - if (loginResult.data.users?.length === 0) { - console.error("No user with 'username'", username); - return apiError(Boom.unauthorized("Invalid 'username' or 'password'")); - } - - // check if we got any user back - const user = loginResult.data[`users`][0]; - - if (!user.active) { - return apiError(Boom.unauthorized("User not activated.")); - } - - if (user.deleted) { - return apiError(Boom.unauthorized("Invalid 'username' or 'password'")); - } - - // see if password hashes matches - const match = await verify(user.password, password); - - if (!match) { - console.error("Password does not match"); - return apiError(Boom.unauthorized("Invalid 'username' or 'password'")); - } - - const jwt_token = generateJwtToken(user); - - const refreshTokenResult = await gqlClient() - .mutation(refreshTokenMutation, { - refresh_token_data: { - expires_at: getExpiryDate(REFRESH_TOKEN_EXPIRES), - user_id: user.id, - }, - }) - .toPromise(); - - if (refreshTokenResult.error) { - return apiError( - Boom.badImplementation( - "Could not update 'refresh token' for user", - username - ) - ); - } - - const { refresh_token } = refreshTokenResult.data.insert_data.returning[0]; - - setJwtCookie(res, refresh_token, jwt_token); - - res.json({ - jwt_token, - jwt_token_expiry: getExpiryDate(JWT_TOKEN_EXPIRES), - refresh_token, - }); -} diff --git a/targets/frontend/src/pages/api/logout.js b/targets/frontend/src/pages/api/logout.js deleted file mode 100644 index 6b07ac309..000000000 --- a/targets/frontend/src/pages/api/logout.js +++ /dev/null @@ -1,54 +0,0 @@ -import Boom from "@hapi/boom"; -import { z } from "zod"; -import { gqlClient } from "@shared/utils"; -import { createErrorFor } from "src/lib/apiError"; -import { removeJwtCookie } from "src/lib/auth/cookie"; - -export default async function logout(req, res) { - const apiError = createErrorFor(res); - - const schema = z.object({ - refresh_token: z.string().uuid(), - }); - - let { error, data: value } = schema.safeParse(req.cookies); - - if (error) { - res = schema.safeParse(req.body); - error = res.error; - value = res.data; - } - - if (error) { - return apiError(Boom.badRequest(error.details[0].message)); - } - - const { refresh_token } = value; - - // delete refresh token passed in data - const result = await gqlClient() - .mutation(mutation, { - refresh_token: refresh_token, - }) - .toPromise(); - - if (result.error) { - console.error("logout error", result.error); - } - - removeJwtCookie(res); - - res.json({ message: "user logout !" }); -} - -const mutation = `mutation deleteRefreshToken( - $refresh_token: uuid!, -) { - delete_refresh_token: delete_auth_refresh_tokens ( - where: { - refresh_token: { _eq: $refresh_token } - }) { - affected_rows - } -} -`; diff --git a/targets/frontend/src/pages/api/password.gql.js b/targets/frontend/src/pages/api/password.gql.js deleted file mode 100644 index d85d7d622..000000000 --- a/targets/frontend/src/pages/api/password.gql.js +++ /dev/null @@ -1,55 +0,0 @@ -export const activateUserMutation = ` -mutation activateUser($secret_token: uuid!, $now: timestamptz!, $password: String!) { - update_user: update_auth_users( - where: { - _and: { - secret_token: { _eq: $secret_token} , - secret_token_expires_at: {_gt: $now } - active: {_eq: false} - } - } - _set: { - active: true - password: $password - } - ){ - affected_rows - } -}`; - -export const changePasswordMutation = ` -mutation updatePassword($secret_token: uuid!, $now: timestamptz!, $password: String!) { - update_user: update_auth_users( - where: { - _and: { - secret_token: { _eq: $secret_token} , - secret_token_expires_at: {_gt: $now } - } - } - _set: { - active: true, - password: $password - } - ){ - affected_rows - } -}`; -export const getOldPassword = ` -query getPassword($id: uuid!) { - user: auth_users_by_pk(id: $id) { password, email } -} -`; - -export const changeMyPasswordMutation = ` -mutation updateMyPassword($id: uuid!, $password: String!) { - update_user: update_auth_users_by_pk( - _set: { - password: $password - } - pk_columns: { - id: $id - } - ){ - id - } -}`; diff --git a/targets/frontend/src/pages/api/refresh_token.gql.js b/targets/frontend/src/pages/api/refresh_token.gql.js deleted file mode 100644 index 6bc11bd6e..000000000 --- a/targets/frontend/src/pages/api/refresh_token.gql.js +++ /dev/null @@ -1,53 +0,0 @@ -export const getRefreshTokenQuery = ` -query get_refresh_token( - $refresh_token: uuid!, - $current_timestampz: timestamptz!, -) { - refresh_tokens: auth_refresh_tokens ( - where: { - _and: [{ - refresh_token: { _eq: $refresh_token } - }, { - user: { active: { _eq: true }} - }, { - user: { deleted: { _eq: false }} - }, { - expires_at: { _gte: $current_timestampz } - }] - } - ) { - user { - id - active - name - default_role - roles: user_roles { - role - } - } - } -} -`; - -// delete current refresh token, generate a new, -// insert the new refresh_token in the database - -export const deletePreviousRefreshTokenMutation = ` - mutation ( - $old_refresh_token: uuid!, - $new_refresh_token_data: auth_refresh_tokens_insert_input! - ) { - delete_refresh_token: delete_auth_refresh_tokens ( - where: { - refresh_token: { _eq: $old_refresh_token } - } - ) { - affected_rows - } - insert_refresh_token: insert_auth_refresh_tokens ( - objects: [$new_refresh_token_data] - ) { - affected_rows - } - } - `; diff --git a/targets/frontend/src/pages/api/refresh_token.js b/targets/frontend/src/pages/api/refresh_token.js deleted file mode 100644 index a5b9deb96..000000000 --- a/targets/frontend/src/pages/api/refresh_token.js +++ /dev/null @@ -1,97 +0,0 @@ -import Boom from "@hapi/boom"; -import { z } from "zod"; -import { gqlClient } from "@shared/utils"; -import { createErrorFor } from "src/lib/apiError"; -import { generateJwtToken } from "src/lib/auth/jwt"; -import { getExpiryDate } from "src/lib/duration"; -import { v4 as uuidv4 } from "uuid"; -import { REFRESH_TOKEN_EXPIRES, JWT_TOKEN_EXPIRES } from "../../config"; -import { setJwtCookie } from "src/lib/auth/cookie"; -import { - deletePreviousRefreshTokenMutation, - getRefreshTokenQuery, -} from "./refresh_token.gql"; - -export default async function refreshToken(req, res) { - const apiError = createErrorFor(res); - try { - console.log("[api/refresh_token.js] refreshToken"); - const schema = z.object({ - refresh_token: z.string().uuid(), - }); - - let value; - - let { error, data } = schema.safeParse(req.query); - - value = data; - - if (error) { - const temp = schema.safeParse(req.body); - error = temp.error; - value = temp.data; - } - - if (error) { - const temp = schema.safeParse(req.cookies); - error = temp.error; - value = temp.data; - } - - if (!value.refresh_token) { - return apiError(Boom.unauthorized("Invalid 'refresh_token'")); - } - - const { refresh_token } = value; - - let result = await gqlClient() - .query(getRefreshTokenQuery, { - current_timestampz: new Date(), - refresh_token, - }) - .toPromise(); - - if (result.error) { - console.error(result.error); - return apiError(Boom.unauthorized("Invalid 'refresh_token'")); - } - - if (result.data.refresh_tokens.length === 0) { - console.error("Incorrect user id or refresh token", refresh_token); - return apiError(Boom.unauthorized("Invalid 'refresh_token'")); - } - - const { user } = result.data[`refresh_tokens`][0]; - - const new_refresh_token = uuidv4(); - - result = await gqlClient() - .mutation(deletePreviousRefreshTokenMutation, { - new_refresh_token_data: { - expires_at: getExpiryDate(REFRESH_TOKEN_EXPIRES), - refresh_token: new_refresh_token, - user_id: user.id, - }, - old_refresh_token: refresh_token, - }) - .toPromise(); - - if (result.error) { - console.error(result.error); - return apiError(Boom.unauthorized("Invalid 'refresh_token'")); - } - - const jwt_token = generateJwtToken(user); - - setJwtCookie(res, new_refresh_token, jwt_token); - - res.json({ - jwt_token, - jwt_token_expiry: getExpiryDate(JWT_TOKEN_EXPIRES), - refresh_token: new_refresh_token, - }); - } catch (e) { - console.error(e); - return apiError(Boom.badImplementation(e.message)); - } -} diff --git a/targets/frontend/src/pages/api/renew_password.js b/targets/frontend/src/pages/api/renew_password.js deleted file mode 100644 index 70a4438f3..000000000 --- a/targets/frontend/src/pages/api/renew_password.js +++ /dev/null @@ -1,9 +0,0 @@ -import { createRequestHandler } from "./activate_account"; -import { changePasswordMutation } from "./password.gql"; - -export default createRequestHandler({ - error_message: "The secret token has expired or there is no account.", - mutation: changePasswordMutation, - sendConfirmation: true, - success_message: "password changed !", -}); diff --git a/targets/frontend/src/pages/api/reset_password.js b/targets/frontend/src/pages/api/reset_password.js deleted file mode 100644 index 2e4cdf736..000000000 --- a/targets/frontend/src/pages/api/reset_password.js +++ /dev/null @@ -1,76 +0,0 @@ -import Boom from "@hapi/boom"; -import { z } from "zod"; -import { gqlClient } from "@shared/utils"; -import { createErrorFor } from "src/lib/apiError"; -import { getExpiryDate } from "src/lib/duration"; -import { v4 as uuidv4 } from "uuid"; -import { ACTIVATION_TOKEN_EXPIRES } from "../../config"; - -export default async function reset_password(req, res) { - const apiError = createErrorFor(res); - - if (req.method === "GET") { - res.setHeader("Allow", ["POST"]); - return apiError(Boom.methodNotAllowed("GET method not allowed")); - } - - const schema = z.object({ - email: z.string().email(), - }); - - const { error, data: value } = schema.safeParse(req.body); - - if (error) { - return apiError(Boom.badRequest(error.details[0].message)); - } - - const { email } = value; - const secret_token = uuidv4(); - const result = await gqlClient() - .mutation(udpateSecretTokenMutation, { - email, - expires: getExpiryDate(ACTIVATION_TOKEN_EXPIRES), - secret_token, - }) - .toPromise(); - - if (result.error) { - // silently fail to not disclose if user exists or not - console.error(result.error); - res.json({ message: "reset password" }); - return; - } - - await gqlClient() - .mutation(emailPasswordRequestMutation, { email, secret_token }) - .toPromise(); - - console.log("[reset_password]", email); - res.json({ message: "reset password" }); -} - -const udpateSecretTokenMutation = ` -mutation updateSecretTokenMutation( - $email: citext!, - $expires: timestamptz!, - $secret_token: uuid -) { - update_user: update_auth_users( - where: { - email: { _eq: $email} , - } - _set: { - secret_token_expires_at: $expires - secret_token: $secret_token - } - ){ - affected_rows - } -} -`; - -const emailPasswordRequestMutation = ` -mutation email($email: citext!, $secret_token: uuid!) { - email_password_request(email: $email, secret_token:$secret_token) -} -`; diff --git a/targets/frontend/src/pages/api/sitemap.ts b/targets/frontend/src/pages/api/sitemap.ts index d6fb863a2..019c33bf2 100644 --- a/targets/frontend/src/pages/api/sitemap.ts +++ b/targets/frontend/src/pages/api/sitemap.ts @@ -200,7 +200,7 @@ async function getGlossary() { slug, modified: updated_at } }`; - const terms = await gqlClient().query(gqlListGlossryTerm).toPromise(); + const terms = await gqlClient().query(gqlListGlossryTerm, {}).toPromise(); if (terms.error) { throw terms.error; } diff --git a/targets/frontend/src/pages/api/storage/[path].ts b/targets/frontend/src/pages/api/storage/[path].ts index 928c21bf9..483394e64 100644 --- a/targets/frontend/src/pages/api/storage/[path].ts +++ b/targets/frontend/src/pages/api/storage/[path].ts @@ -1,24 +1,13 @@ import Boom from "@hapi/boom"; -import { verify } from "jsonwebtoken"; import { NextApiRequest, NextApiResponse } from "next"; import { createErrorFor } from "src/lib/apiError"; import { deleteApiFile } from "src/lib/upload"; -const jwtSecret = JSON.parse( - process.env.HASURA_GRAPHQL_JWT_SECRET ?? - '{"type":"HS256","key":"a_pretty_long_secret_key_that_should_be_at_least_32_char"}' -); - export default async function deleteFiles( req: NextApiRequest, res: NextApiResponse ) { const apiError = createErrorFor(res); - const { jwt: token } = req.cookies; - - if (!token || !verify(token, jwtSecret.key, { algorithms: jwtSecret.type })) { - return apiError(Boom.badRequest("wrong token")); - } if (req.method !== "DELETE") { res.setHeader("Allow", ["DELETE"]); return apiError(Boom.methodNotAllowed(`${req.method} method not allowed`)); diff --git a/targets/frontend/src/pages/api/storage/index.ts b/targets/frontend/src/pages/api/storage/index.ts index aea5c6954..7c1c09613 100644 --- a/targets/frontend/src/pages/api/storage/index.ts +++ b/targets/frontend/src/pages/api/storage/index.ts @@ -1,24 +1,13 @@ import Boom from "@hapi/boom"; import formidable, { IncomingForm } from "formidable"; -import { verify } from "jsonwebtoken"; import { createErrorFor } from "src/lib/apiError"; import { isUploadFileSafe } from "src/lib/secu"; import { NextApiRequest, NextApiResponse } from "next"; import { getApiAllFiles, uploadApiFiles } from "src/lib/upload"; import fs from "fs"; -const jwtSecret = JSON.parse( - process.env.HASURA_GRAPHQL_JWT_SECRET ?? - '{"type":"HS256","key":"a_pretty_long_secret_key_that_should_be_at_least_32_char"}' -); - async function endPoint(req: NextApiRequest, res: NextApiResponse) { const apiError = createErrorFor(res); - const { jwt: token } = req.cookies; - - if (!token || !verify(token, jwtSecret.key, { algorithms: jwtSecret.type })) { - return apiError(Boom.badRequest("wrong token")); - } switch (req.method) { case "POST": diff --git a/targets/frontend/src/pages/api/users/activate.ts b/targets/frontend/src/pages/api/users/activate.ts new file mode 100644 index 000000000..c3352e218 --- /dev/null +++ b/targets/frontend/src/pages/api/users/activate.ts @@ -0,0 +1,31 @@ +import { NextApiRequest, NextApiResponse } from "next"; +import { activateUser } from "src/modules/authentification/activateUser"; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + if (req.method !== "POST") { + res.status(405).json({ message: "Method not allowed" }); + return; + } + + const token = req.body.token; + const password = req.body.password; + + if (!token || !password) { + res.status(400).json({ message: "Missing a variable" }); + return; + } + + try { + await activateUser(token, password); + } catch (error: any) { + res.status(500).json({ message: error.message }); + return; + } + + return res.json({ + message: "Success", + }); +} diff --git a/targets/frontend/src/pages/api/users/create.ts b/targets/frontend/src/pages/api/users/create.ts new file mode 100644 index 000000000..4948c42aa --- /dev/null +++ b/targets/frontend/src/pages/api/users/create.ts @@ -0,0 +1,53 @@ +import { getServerSession } from "next-auth/next"; +import { authOptions } from "../auth/[...nextauth]"; +import { NextApiRequest, NextApiResponse } from "next"; +import { verifyToken } from "src/modules/authentification/utils/jwt"; +import { createUser } from "src/modules/authentification/createUser"; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + if (req.method !== "POST") { + res.status(405).json({ message: "Method not allowed" }); + return; + } + + const name = req.body.name; + const email = req.body.email; + + if (!name || !email) { + res.status(400).json({ message: "Missing a variable" }); + return; + } + + const session = await getServerSession(req, res, authOptions); + + if (!session) { + res.status(401).json({ message: "You must be logged in." }); + return; + } + + const isAccessTokenValid = verifyToken(session.user.accessToken); + + const isRoleValid = session.user.role === "super"; + + if (!isAccessTokenValid || !isRoleValid) { + res.status(401).json({ message: "You are not authorized." }); + return; + } + + try { + const result = await createUser(name, email); + if (!result) { + res.status(500).json({ message: "Error during user creation" }); + return; + } + } catch (error: any) { + res.status(500).json({ message: JSON.stringify(error) }); + return; + } + return res.json({ + message: "Success", + }); +} diff --git a/targets/frontend/src/pages/api/users/delete.ts b/targets/frontend/src/pages/api/users/delete.ts new file mode 100644 index 000000000..d1f77ca9c --- /dev/null +++ b/targets/frontend/src/pages/api/users/delete.ts @@ -0,0 +1,49 @@ +import { getServerSession } from "next-auth/next"; +import { authOptions } from "../auth/[...nextauth]"; +import { NextApiRequest, NextApiResponse } from "next"; +import { verifyToken } from "src/modules/authentification/utils/jwt"; +import { deleteUser } from "src/modules/authentification/deleteUser"; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + if (req.method !== "DELETE") { + res.status(405).json({ message: "Method not allowed" }); + return; + } + + const userId = req.body.userId; + + if (!userId) { + res.status(400).json({ message: "Missing user id" }); + return; + } + + const session = await getServerSession(req, res, authOptions); + + if (!session) { + res.status(401).json({ message: "You must be logged in." }); + return; + } + + const isAccessTokenValid = verifyToken(session.user.accessToken); + + const isRoleValid = session.user.role === "super"; + + if (!isAccessTokenValid || !isRoleValid) { + res.status(401).json({ message: "You are not authorized." }); + return; + } + + const result = await deleteUser(userId); + + if (!result) { + res.status(500).json({ message: "Error deleting user" }); + return; + } + + return res.json({ + message: "Success", + }); +} diff --git a/targets/frontend/src/pages/api/users/password/change.ts b/targets/frontend/src/pages/api/users/password/change.ts new file mode 100644 index 000000000..52012d77d --- /dev/null +++ b/targets/frontend/src/pages/api/users/password/change.ts @@ -0,0 +1,54 @@ +import { getServerSession } from "next-auth/next"; +import { authOptions } from "../../auth/[...nextauth]"; +import { NextApiRequest, NextApiResponse } from "next"; +import { verifyToken } from "src/modules/authentification/utils/jwt"; +import { changePassword } from "src/modules/authentification/changePassword"; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + if (req.method !== "POST") { + res.status(405).json({ message: "Method not allowed" }); + return; + } + + const newPassword = req.body.newPassword; + const oldPassword = req.body.oldPassword; + + if (!newPassword || !oldPassword) { + res.status(400).json({ message: "Missing a variable" }); + return; + } + + const session = await getServerSession(req, res, authOptions); + + if (!session) { + res.status(401).json({ message: "You must be logged in." }); + return; + } + + const isAccessTokenValid = verifyToken(session.user.accessToken); + + const isRoleValid = session.user.role === "super"; + + if (!isAccessTokenValid || !isRoleValid) { + res.status(401).json({ message: "You are not authorized." }); + return; + } + + const result = await changePassword( + session.user.id, + oldPassword, + newPassword + ); + + if (!result) { + res.status(500).json({ message: "Error during password modification" }); + return; + } + + return res.json({ + message: "Success", + }); +} diff --git a/targets/frontend/src/pages/api/users/password/reset.ts b/targets/frontend/src/pages/api/users/password/reset.ts new file mode 100644 index 000000000..14e363cc3 --- /dev/null +++ b/targets/frontend/src/pages/api/users/password/reset.ts @@ -0,0 +1,30 @@ +import { NextApiRequest, NextApiResponse } from "next"; +import { resetPassword } from "src/modules/authentification/resetPassword"; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + if (req.method !== "POST") { + res.status(405).json({ message: "Method not allowed" }); + return; + } + + const email = req.body.email; + + if (!email) { + res.status(400).json({ message: "Missing a variable" }); + return; + } + + try { + await resetPassword(email); + } catch (error: any) { + res.status(500).json({ message: error.message }); + return; + } + + return res.json({ + message: "Success", + }); +} diff --git a/targets/frontend/src/pages/api/validation.js b/targets/frontend/src/pages/api/validation.ts similarity index 60% rename from targets/frontend/src/pages/api/validation.js rename to targets/frontend/src/pages/api/validation.ts index ddcc91415..9587c13cf 100644 --- a/targets/frontend/src/pages/api/validation.js +++ b/targets/frontend/src/pages/api/validation.ts @@ -1,4 +1,4 @@ -import { passwordValidation } from "../../lib/auth/auth.const"; +import { passwordValidation } from "../../modules/authentification/utils/regex"; import { z } from "zod"; export const passwordSchema = z diff --git a/targets/frontend/src/pages/change_password.tsx b/targets/frontend/src/pages/change_password.tsx index d00f5203f..ac0e10833 100644 --- a/targets/frontend/src/pages/change_password.tsx +++ b/targets/frontend/src/pages/change_password.tsx @@ -1,57 +1,63 @@ -import Link from "next/link"; import { useRouter } from "next/router"; import { useState } from "react"; import { PasswordLayout } from "src/components/layout/password.layout"; import { PasswordForm } from "src/components/user/PasswordForm"; -import { request } from "src/lib/request"; import { Typography } from "@mui/material"; +import { Button } from "src/components/button"; export default function ChangePasswordPage() { const router = useRouter(); - const { activate, token } = router.query; - let title = "Nouveau mot de passe"; - let url = "/api/renew_password"; - if (activate) { - title = "Activer votre compte"; - url = "/api/activate_account"; - } + const { token } = router.query; const [success, setSuccess] = useState(false); - let loading = false; + const [loading, setLoading] = useState(false); async function updatePassword({ password }: { password: string }) { - loading = true; + setLoading(true); try { - await request(url, { body: { password, token } }); + const result = await fetch(`/api/users/activate`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ password, token }), + }); + + const resultJson = await result.json(); + + if (!result.ok) { + alert(`Un problème est survenu, l'erreur est : ${resultJson.message}`); + return; + } setSuccess(true); } catch (error) { console.error(error); + alert("Une erreur est survenue..."); + } finally { + setLoading(false); } - loading = false; } if (success) { return ( - - {activate ? ( - - Votre compte a été activé. Suivez le lien fourni pour vous - connecter. - - ) : ( - - Votre mot de passe a été ré-initialisé, suivez le lien fourni pour - vous connecter. - - )} - + + + Votre mot passe a été mis à jour. Suivez le lien fourni pour vous + connecter. + + ); } return ( - - + + ); } diff --git a/targets/frontend/src/pages/contenus/[id].tsx b/targets/frontend/src/pages/contenus/[id].tsx index 9a958a735..287219f3e 100644 --- a/targets/frontend/src/pages/contenus/[id].tsx +++ b/targets/frontend/src/pages/contenus/[id].tsx @@ -4,14 +4,12 @@ import React, { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { Button } from "src/components/button"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { previewContentAction } from "src/lib/preview/preview.gql"; import { useMutation, useQuery } from "urql"; import { Card, Stack } from "@mui/material"; -import getDocumentQuery from "./getDocument.query.graphql"; -import updateDocumentMutation from "./updateDocument.mutation.graphql"; +import getDocumentQuery from "../../lib/contenus/getDocument.query.graphql"; +import updateDocumentMutation from "../../lib/contenus/updateDocument.mutation.graphql"; import { FixedSnackBar } from "../../components/utils/SnackBar"; import CodeEditor from "../../components/editor/CodeEditor"; @@ -122,4 +120,4 @@ export function DocumentPage() { ); } -export default withCustomUrqlClient(withUserProvider(DocumentPage)); +export default DocumentPage; diff --git a/targets/frontend/src/pages/contenus/create/[[...source]].tsx b/targets/frontend/src/pages/contenus/create/[[...source]].tsx index 6d6751d6b..092215989 100644 --- a/targets/frontend/src/pages/contenus/create/[[...source]].tsx +++ b/targets/frontend/src/pages/contenus/create/[[...source]].tsx @@ -5,8 +5,6 @@ import { useRouter } from "next/router"; import { HighlightsForm } from "src/components/highlights"; import { Layout } from "src/components/layout/auth.layout"; import { Stack } from "src/components/layout/Stack"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { Content } from "src/types"; import { useMutation } from "urql"; import { @@ -109,4 +107,4 @@ export function CreateDocumentPage() { ); } -export default withCustomUrqlClient(withUserProvider(CreateDocumentPage)); +export default CreateDocumentPage; diff --git a/targets/frontend/src/pages/contenus/edit/[id].tsx b/targets/frontend/src/pages/contenus/edit/[id].tsx index 335436fa5..5193bb325 100644 --- a/targets/frontend/src/pages/contenus/edit/[id].tsx +++ b/targets/frontend/src/pages/contenus/edit/[id].tsx @@ -8,9 +8,6 @@ import { Dialog } from "src/components/dialog"; import { EditorialContentForm } from "src/components/editorialContent"; import { HighlightsForm } from "src/components/highlights"; import { Layout } from "src/components/layout/auth.layout"; -import { PrequalifiedEdition } from "src/modules/prequalified"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { previewContentAction } from "src/lib/preview/preview.gql"; import { Content, @@ -260,4 +257,4 @@ export function EditInformationPage() { ); } -export default withCustomUrqlClient(withUserProvider(EditInformationPage)); +export default EditInformationPage; diff --git a/targets/frontend/src/pages/contenus/fiches-sp.tsx b/targets/frontend/src/pages/contenus/fiches-sp.tsx index 913d19af1..9af71a409 100644 --- a/targets/frontend/src/pages/contenus/fiches-sp.tsx +++ b/targets/frontend/src/pages/contenus/fiches-sp.tsx @@ -1,8 +1,6 @@ import { createContext, useState } from "react"; import { FichesServicePublicContainer } from "src/components/fiches-sp/fichesSpContainer"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; export type SelectionContextInterface = { selectedItems: string[]; @@ -33,4 +31,4 @@ function FichesServicePublicPage() { ); } -export default withCustomUrqlClient(withUserProvider(FichesServicePublicPage)); +export default FichesServicePublicPage; diff --git a/targets/frontend/src/pages/contenus/index.tsx b/targets/frontend/src/pages/contenus/index.tsx index 568a54563..99e67c4aa 100644 --- a/targets/frontend/src/pages/contenus/index.tsx +++ b/targets/frontend/src/pages/contenus/index.tsx @@ -3,8 +3,6 @@ import { createContext, useContext, useState } from "react"; import { DocumentListContainer } from "src/components/documents/Container"; import { DEFAULT_ITEMS_PER_PAGE } from "src/components/documents/SearchFilters"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; type ContentQueryParam = { available?: string; @@ -53,4 +51,4 @@ export function DocumentsPage() { ); } -export default withCustomUrqlClient(withUserProvider(DocumentsPage)); +export default DocumentsPage; diff --git a/targets/frontend/src/pages/contributions/answers/[answerId].tsx b/targets/frontend/src/pages/contributions/answers/[answerId].tsx index 81670480e..6a4592363 100644 --- a/targets/frontend/src/pages/contributions/answers/[answerId].tsx +++ b/targets/frontend/src/pages/contributions/answers/[answerId].tsx @@ -3,8 +3,6 @@ import { ContributionsAnswer } from "src/components/contributions"; import { ContributionAnswerReferences } from "src/modules/references/ContributionAnswerReferences"; import { Layout } from "src/components/layout/auth.layout"; import { ReferencesTabs } from "src/components/references"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; export function EditInformationPage() { const router = useRouter(); @@ -22,4 +20,4 @@ export function EditInformationPage() { ); } -export default withCustomUrqlClient(withUserProvider(EditInformationPage)); +export default EditInformationPage; diff --git a/targets/frontend/src/pages/contributions/index.tsx b/targets/frontend/src/pages/contributions/index.tsx index e089176be..c3d597b0f 100644 --- a/targets/frontend/src/pages/contributions/index.tsx +++ b/targets/frontend/src/pages/contributions/index.tsx @@ -1,6 +1,4 @@ import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { QuestionList } from "../../components/contributions"; @@ -12,4 +10,4 @@ export function ContributionsPage() { ); } -export default withCustomUrqlClient(withUserProvider(ContributionsPage)); +export default ContributionsPage; diff --git a/targets/frontend/src/pages/contributions/questions/[questionId].tsx b/targets/frontend/src/pages/contributions/questions/[questionId].tsx index 914da0bf9..fc087839f 100644 --- a/targets/frontend/src/pages/contributions/questions/[questionId].tsx +++ b/targets/frontend/src/pages/contributions/questions/[questionId].tsx @@ -1,8 +1,6 @@ import { useRouter } from "next/router"; import { EditQuestion } from "src/components/contributions"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; export function EditAnswerPage() { const router = useRouter(); @@ -15,4 +13,4 @@ export function EditAnswerPage() { ); } -export default withCustomUrqlClient(withUserProvider(EditAnswerPage)); +export default EditAnswerPage; diff --git a/targets/frontend/src/pages/duplicates.tsx b/targets/frontend/src/pages/duplicates.tsx index 58866576f..7c75f268b 100644 --- a/targets/frontend/src/pages/duplicates.tsx +++ b/targets/frontend/src/pages/duplicates.tsx @@ -10,8 +10,6 @@ import { getDuplicateQuery } from "src/components/home/DuplicateItems"; import { Layout } from "src/components/layout/auth.layout"; import { Stack } from "src/components/layout/Stack"; import { Table, Td, Th, Tr } from "src/components/table"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { RELATIONS } from "src/lib/relations"; import { Alert, CircularProgress } from "@mui/material"; import { useQuery } from "urql"; @@ -110,4 +108,4 @@ export function DuplicateContentPage(): JSX.Element { ); } -export default withCustomUrqlClient(withUserProvider(DuplicateContentPage)); +export default DuplicateContentPage; diff --git a/targets/frontend/src/pages/fichiers.tsx b/targets/frontend/src/pages/fichiers.tsx index 454ec53aa..94d93e8a6 100644 --- a/targets/frontend/src/pages/fichiers.tsx +++ b/targets/frontend/src/pages/fichiers.tsx @@ -9,8 +9,6 @@ import { import { CopyButton } from "src/components/button/CopyButton"; import { Layout } from "src/components/layout/auth.layout"; import { DropZone } from "src/components/storage/DropZone"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { useDebouncedState } from "src/hooks/"; import { timeSince } from "src/lib/duration"; import { request } from "src/lib/request"; @@ -242,7 +240,7 @@ function FilesPage() { {" "} | Mise en ligne il y a{" "} - {timeSince(file.lastModified)} + {timeSince(file.lastModified.toString())} @@ -279,7 +277,7 @@ function FilesPage() { ); } -export default withCustomUrqlClient(withUserProvider(FilesPage)); +export default FilesPage; const buttonProps = { outline: true, diff --git a/targets/frontend/src/pages/ghost-documents.tsx b/targets/frontend/src/pages/ghost-documents.tsx index fc29581c2..55bab40f0 100644 --- a/targets/frontend/src/pages/ghost-documents.tsx +++ b/targets/frontend/src/pages/ghost-documents.tsx @@ -7,8 +7,6 @@ import { } from "src/components/home/InvisibleLinkedDocument"; import { Layout } from "src/components/layout/auth.layout"; import { Table, Td, Th, Tr } from "src/components/table"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { Chip, CircularProgress, TableHead, TableRow } from "@mui/material"; import { useQuery } from "urql"; import { FixedSnackBar } from "../components/utils/SnackBar"; @@ -93,4 +91,4 @@ export function DuplicateContentPage(): JSX.Element { ); } -export default withCustomUrqlClient(withUserProvider(DuplicateContentPage)); +export default DuplicateContentPage; diff --git a/targets/frontend/src/pages/glossary/edit/[[...id]].js b/targets/frontend/src/pages/glossary/edit/[[...id]].js index b387c45a0..0b3a96f4e 100644 --- a/targets/frontend/src/pages/glossary/edit/[[...id]].js +++ b/targets/frontend/src/pages/glossary/edit/[[...id]].js @@ -5,8 +5,6 @@ import { Button } from "src/components/button"; import { Dialog } from "src/components/dialog"; import { TermForm } from "src/components/glossary/TermForm"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { Box, CircularProgress as Spinner, Stack } from "@mui/material"; import { useMutation, useQuery } from "urql"; @@ -121,4 +119,4 @@ export function EditTermPage() { ); } -export default withCustomUrqlClient(withUserProvider(EditTermPage)); +export default EditTermPage; diff --git a/targets/frontend/src/pages/glossary/index.js b/targets/frontend/src/pages/glossary/index.js index 98c951dbd..822f85323 100644 --- a/targets/frontend/src/pages/glossary/index.js +++ b/targets/frontend/src/pages/glossary/index.js @@ -5,8 +5,6 @@ import { Button, IconButton } from "src/components/button"; import { TermList } from "src/components/glossary/TermList"; import { Layout } from "src/components/layout/auth.layout"; import { Stack } from "src/components/layout/Stack"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { useDebouncedState } from "src/hooks/"; import { Box, @@ -164,7 +162,7 @@ export function GlossaryPage() { ); } -export default withCustomUrqlClient(withUserProvider(GlossaryPage)); +export default GlossaryPage; const AddATermButton = () => ( @@ -174,13 +172,3 @@ const AddATermButton = () => ( ); - -const linkStyles = { - ":hover": { - color: "primary", - }, - ":visited": { - color: "text", - }, - color: "text", -}; diff --git a/targets/frontend/src/pages/healthz.js b/targets/frontend/src/pages/healthz.tsx similarity index 100% rename from targets/frontend/src/pages/healthz.js rename to targets/frontend/src/pages/healthz.tsx diff --git a/targets/frontend/src/pages/index.tsx b/targets/frontend/src/pages/index.tsx index e98d49ee4..bd93114c9 100644 --- a/targets/frontend/src/pages/index.tsx +++ b/targets/frontend/src/pages/index.tsx @@ -2,8 +2,6 @@ import { DuplicateContent } from "src/components/home/DuplicateItems"; import { GhostLinkedDocuments } from "src/components/home/InvisibleLinkedDocument"; import { UnThemedContent } from "src/components/home/UnThemedContent"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { Stack, Typography } from "@mui/material"; export function IndexPage() { @@ -21,4 +19,4 @@ export function IndexPage() { ); } -export default withCustomUrqlClient(withUserProvider(IndexPage)); +export default IndexPage; diff --git a/targets/frontend/src/pages/informations/[id].tsx b/targets/frontend/src/pages/informations/[id].tsx index fff694fdd..01c66ec14 100644 --- a/targets/frontend/src/pages/informations/[id].tsx +++ b/targets/frontend/src/pages/informations/[id].tsx @@ -1,8 +1,6 @@ import { useRouter } from "next/router"; import { InformationsEdit } from "src/modules/informations"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { ReferencesTabs } from "src/components/references"; import { ContributionAnswerReferences } from "src/modules/references/ContributionAnswerReferences"; @@ -22,4 +20,4 @@ export function EditAnswerPage() { ); } -export default withCustomUrqlClient(withUserProvider(EditAnswerPage)); +export default EditAnswerPage; diff --git a/targets/frontend/src/pages/informations/creation.tsx b/targets/frontend/src/pages/informations/creation.tsx index cd0bd5e6f..69ca4bca5 100644 --- a/targets/frontend/src/pages/informations/creation.tsx +++ b/targets/frontend/src/pages/informations/creation.tsx @@ -1,7 +1,5 @@ import { InformationsCreate } from "src/modules/informations"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; export function EditAnswerPage() { return ( @@ -11,4 +9,4 @@ export function EditAnswerPage() { ); } -export default withCustomUrqlClient(withUserProvider(EditAnswerPage)); +export default EditAnswerPage; diff --git a/targets/frontend/src/pages/informations/index.tsx b/targets/frontend/src/pages/informations/index.tsx index 34ddd42f9..93b72f173 100644 --- a/targets/frontend/src/pages/informations/index.tsx +++ b/targets/frontend/src/pages/informations/index.tsx @@ -1,8 +1,6 @@ import { QuestionList } from "src/modules/informations"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; export function InformationsPage() { return ( @@ -12,4 +10,4 @@ export function InformationsPage() { ); } -export default withCustomUrqlClient(withUserProvider(InformationsPage)); +export default InformationsPage; diff --git a/targets/frontend/src/pages/kali/blocks.js b/targets/frontend/src/pages/kali/blocks.js index 583216a41..5cd8dfb20 100644 --- a/targets/frontend/src/pages/kali/blocks.js +++ b/targets/frontend/src/pages/kali/blocks.js @@ -4,8 +4,6 @@ import { IoMdSave } from "react-icons/io"; import { Button } from "src/components/button"; import { Layout } from "src/components/layout/auth.layout"; import { Stack } from "src/components/layout/Stack"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { Card, Select, Alert, InputLabel, MenuItem } from "@mui/material"; import { useMutation, useQuery } from "urql"; import { theme as th } from "../../theme"; @@ -253,4 +251,4 @@ export function KaliBlocksPage() { ); } -export default withCustomUrqlClient(withUserProvider(KaliBlocksPage)); +export default KaliBlocksPage; diff --git a/targets/frontend/src/pages/login.js b/targets/frontend/src/pages/login.tsx similarity index 51% rename from targets/frontend/src/pages/login.js rename to targets/frontend/src/pages/login.tsx index 9618720a5..79e6a3db7 100644 --- a/targets/frontend/src/pages/login.js +++ b/targets/frontend/src/pages/login.tsx @@ -2,8 +2,9 @@ import Head from "next/head"; import { useRouter } from "next/router"; import { Header } from "src/components/layout/header"; import LoginForm from "src/components/login"; -import { request } from "src/lib/request"; import { Box } from "@mui/material"; +import { signIn } from "next-auth/react"; +import { UseFormSetError } from "react-hook-form"; export default function LoginPage() { const router = useRouter(); @@ -12,17 +13,30 @@ export default function LoginPage() { router.push("/reset_password"); }; - const goAdmin = () => { - router.push("/"); - }; - - const authenticate = ({ email, password }) => { - return request("/api/login", { - body: { password, username: email }, - headers: { - "Cache-Control": "no-cache", - }, + const onLogin = async ( + email: string, + password: string, + setError: UseFormSetError + ) => { + const response = await signIn("credentials", { + redirect: false, + email, + password, + }).catch((error) => { + return { error: error.message }; }); + if (!response || response.error) { + setError( + "password", + { + message: response?.error ?? "Erreur non identifiée", + type: "manual", + }, + { shouldFocus: true } + ); + return; + } + router.push("/"); }; return ( @@ -39,11 +53,7 @@ export default function LoginPage() { }} > - + diff --git a/targets/frontend/src/pages/mises-a-jour.tsx b/targets/frontend/src/pages/mises-a-jour.tsx index 786f2c6ce..a7a40b944 100644 --- a/targets/frontend/src/pages/mises-a-jour.tsx +++ b/targets/frontend/src/pages/mises-a-jour.tsx @@ -1,7 +1,5 @@ import React from "react"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { Export } from "src/modules/export"; export function UpdatePage(): JSX.Element { @@ -12,4 +10,4 @@ export function UpdatePage(): JSX.Element { ); } -export default withCustomUrqlClient(withUserProvider(UpdatePage)); +export default UpdatePage; diff --git a/targets/frontend/src/pages/models/[modelId].tsx b/targets/frontend/src/pages/models/[modelId].tsx index ced5f0f40..6fd4cca57 100644 --- a/targets/frontend/src/pages/models/[modelId].tsx +++ b/targets/frontend/src/pages/models/[modelId].tsx @@ -1,8 +1,6 @@ import { ModelEdition } from "src/modules/models"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { useRouter } from "next/router"; import { ReferencesTabs } from "src/components/references"; import { ContributionAnswerReferences } from "src/modules/references/ContributionAnswerReferences"; @@ -23,4 +21,4 @@ export function ModelEditionPage() { ); } -export default withCustomUrqlClient(withUserProvider(ModelEditionPage)); +export default ModelEditionPage; diff --git a/targets/frontend/src/pages/models/creation.tsx b/targets/frontend/src/pages/models/creation.tsx index 22479adbc..114257784 100644 --- a/targets/frontend/src/pages/models/creation.tsx +++ b/targets/frontend/src/pages/models/creation.tsx @@ -1,8 +1,6 @@ import { ModelCreation } from "src/modules/models"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; export function ModelCreationPage() { return ( @@ -12,4 +10,4 @@ export function ModelCreationPage() { ); } -export default withCustomUrqlClient(withUserProvider(ModelCreationPage)); +export default ModelCreationPage; diff --git a/targets/frontend/src/pages/models/index.tsx b/targets/frontend/src/pages/models/index.tsx index 1120834e0..0f57ef08c 100644 --- a/targets/frontend/src/pages/models/index.tsx +++ b/targets/frontend/src/pages/models/index.tsx @@ -1,8 +1,6 @@ import { ModelList } from "src/modules/models"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; export function ModelsPage() { return ( @@ -12,4 +10,4 @@ export function ModelsPage() { ); } -export default withCustomUrqlClient(withUserProvider(ModelsPage)); +export default ModelsPage; diff --git a/targets/frontend/src/pages/prequalified/[id].tsx b/targets/frontend/src/pages/prequalified/[id].tsx index b1493abc7..676568d46 100644 --- a/targets/frontend/src/pages/prequalified/[id].tsx +++ b/targets/frontend/src/pages/prequalified/[id].tsx @@ -1,7 +1,5 @@ import { PrequalifiedEdition } from "src/modules/prequalified"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { useRouter } from "next/router"; export function PrequalifiedPage() { @@ -14,4 +12,4 @@ export function PrequalifiedPage() { ); } -export default withCustomUrqlClient(withUserProvider(PrequalifiedPage)); +export default PrequalifiedPage; diff --git a/targets/frontend/src/pages/prequalified/create.tsx b/targets/frontend/src/pages/prequalified/create.tsx index 486e5ea23..8f686d646 100644 --- a/targets/frontend/src/pages/prequalified/create.tsx +++ b/targets/frontend/src/pages/prequalified/create.tsx @@ -1,7 +1,5 @@ import { PrequalifiedCreate } from "src/modules/prequalified"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; export function PrequalifiedNewPage() { return ( @@ -11,4 +9,4 @@ export function PrequalifiedNewPage() { ); } -export default withCustomUrqlClient(withUserProvider(PrequalifiedNewPage)); +export default PrequalifiedNewPage; diff --git a/targets/frontend/src/pages/prequalified/index.tsx b/targets/frontend/src/pages/prequalified/index.tsx index a3336aa7b..bcc941d52 100644 --- a/targets/frontend/src/pages/prequalified/index.tsx +++ b/targets/frontend/src/pages/prequalified/index.tsx @@ -1,7 +1,5 @@ import { PrequalifiedList } from "src/modules/prequalified"; import { Layout } from "src/components/layout/auth.layout"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; export function PrequalifiedPage() { return ( @@ -11,4 +9,4 @@ export function PrequalifiedPage() { ); } -export default withCustomUrqlClient(withUserProvider(PrequalifiedPage)); +export default PrequalifiedPage; diff --git a/targets/frontend/src/pages/reset_password.js b/targets/frontend/src/pages/reset_password.tsx similarity index 54% rename from targets/frontend/src/pages/reset_password.js rename to targets/frontend/src/pages/reset_password.tsx index 195bae59c..00812e182 100644 --- a/targets/frontend/src/pages/reset_password.js +++ b/targets/frontend/src/pages/reset_password.tsx @@ -1,12 +1,12 @@ -import Link from "next/link"; import { useState } from "react"; import { useForm } from "react-hook-form"; import { Button } from "src/components/button"; import { FormErrorMessage } from "src/components/forms/ErrorMessage"; import { PasswordLayout } from "src/components/layout/password.layout"; import { Stack } from "src/components/layout/Stack"; -import { request } from "src/lib/request"; import { TextField as Field } from "@mui/material"; +import { useRouter } from "next/router"; +import { emailValidation } from "src/modules/authentification/utils/regex"; export default function ResetPasswordPage() { const [success, setSuccess] = useState(false); @@ -18,50 +18,74 @@ export default function ResetPasswordPage() { formState: { errors }, } = useForm(); const hasError = Object.keys(errors).length > 0; - let loading = false; + const [loading, setLoading] = useState(false); + const router = useRouter(); - async function resetPassword(data) { - console.log(data); - loading = true; + async function resetPassword({ email }: any) { + setLoading(true); try { - await request("/api/reset_password", { body: data }); + const result = await fetch(`/api/users/password/reset`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ email }), + }); + + const resultJson = await result.json(); + + if (!result.ok) { + setError( + "email", + { + message: `Un problème est survenu, l'erreur est : ${resultJson.message}`, + type: "validate", + }, + { shouldFocus: true } + ); + return; + } setSuccess(true); } catch (error) { console.error(error); setError( "email", { - message: "désolé, une erreur est survenue :(", + message: "Désolé, une erreur est survenue :(", type: "validate", }, { shouldFocus: true } ); + } finally { + setLoading(false); } - loading = false; } if (success) { return ( -

+

Nous venons de vous envoyer un lien pour ré-initialiser votre mot de - passe par mail. Vous pouvez consulter votre boîte mail et suivre les - instructions pour définir un nouveau mot de passe. + passe par mail. +

+ Vous pouvez consulter votre boîte mail et suivre les instructions pour + définir un nouveau mot de passe.

- +
); } return ( - +

Vous avez perdu votre mot de passe ? @@ -70,17 +94,22 @@ export default function ResetPasswordPage() { lien pour ré-initialiser votre mot de passe.

-
diff --git a/targets/frontend/src/pages/themes/[[...id]].js b/targets/frontend/src/pages/themes/[[...id]].js index 6d643ff7e..e8957b8be 100644 --- a/targets/frontend/src/pages/themes/[[...id]].js +++ b/targets/frontend/src/pages/themes/[[...id]].js @@ -7,8 +7,6 @@ import { Layout } from "src/components/layout/auth.layout"; import { Stack } from "src/components/layout/Stack"; import { List } from "src/components/themes/List"; import { MapModal } from "src/components/themes/MapModal"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { RELATIONS } from "src/lib/relations"; import { Box, Card, CircularProgress } from "@mui/material"; import { useMutation, useQuery } from "urql"; @@ -51,22 +49,17 @@ query getRootThemes { `; const updateThemesPositionMutation = ` -mutation updateThemesPosition( - $objects: [document_relations_insert_input!]! -) { - insert_document_relations( - objects: $objects, - on_conflict: { - constraint: document_relations_pkey, - update_columns: data - } - ) { - returning { - position: data(path: "position") - id + mutation updateThemesPosition($objects: [document_relations_insert_input!]!) { + insert_document_relations( + objects: $objects + on_conflict: { constraint: document_relations_pkey, update_columns: data } + ) { + returning { + position: data(path: "position") + id + } } } -} `; const context = { additionalTypenames: ["documents", "document_relations"] }; @@ -181,7 +174,7 @@ export function ThemePage() { ); } -export default withCustomUrqlClient(withUserProvider(ThemePage)); +export default ThemePage; const AddAThemeButton = ({ themeId }) => ( diff --git a/targets/frontend/src/pages/themes/[id]/create.js b/targets/frontend/src/pages/themes/[id]/create.js index 17967c33b..d60d50704 100644 --- a/targets/frontend/src/pages/themes/[id]/create.js +++ b/targets/frontend/src/pages/themes/[id]/create.js @@ -8,8 +8,6 @@ import { formatContentsMutation, updateContentsMutation, } from "src/components/themes/updateContentsMutation"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { RELATIONS } from "src/lib/relations"; import { CircularProgress as Spinner } from "@mui/material"; import { useMutation, useQuery } from "urql"; @@ -142,4 +140,4 @@ export function CreateThemePage() { ); } -export default withCustomUrqlClient(withUserProvider(CreateThemePage)); +export default CreateThemePage; diff --git a/targets/frontend/src/pages/themes/create.js b/targets/frontend/src/pages/themes/create.js index 66c6c6860..fa9c1653b 100644 --- a/targets/frontend/src/pages/themes/create.js +++ b/targets/frontend/src/pages/themes/create.js @@ -1,5 +1,3 @@ -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { CreateThemePage } from "src/pages/themes/[id]/create"; -export default withCustomUrqlClient(withUserProvider(CreateThemePage)); +export default CreateThemePage; diff --git a/targets/frontend/src/pages/themes/edit/[id].js b/targets/frontend/src/pages/themes/edit/[id].js index dc6fe92bb..547501241 100644 --- a/targets/frontend/src/pages/themes/edit/[id].js +++ b/targets/frontend/src/pages/themes/edit/[id].js @@ -10,8 +10,6 @@ import { formatContentsMutation, updateContentsMutation, } from "src/components/themes/updateContentsMutation"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { RELATIONS } from "src/lib/relations"; import { Alert, Box, CircularProgress as Spinner, Stack } from "@mui/material"; import { useMutation, useQuery } from "urql"; @@ -207,4 +205,4 @@ export function EditThemePage() { ); } -export default withCustomUrqlClient(withUserProvider(EditThemePage)); +export default EditThemePage; diff --git a/targets/frontend/src/pages/unthemed.js b/targets/frontend/src/pages/unthemed.js index b5cc2b9e2..3e88038b1 100644 --- a/targets/frontend/src/pages/unthemed.js +++ b/targets/frontend/src/pages/unthemed.js @@ -9,8 +9,6 @@ import { } from "src/components/home/UnThemedContent"; import { Layout } from "src/components/layout/auth.layout"; import { Stack } from "src/components/layout/Stack"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; import { RELATIONS } from "src/lib/relations"; import { Box, CircularProgress, Alert, List, ListItem } from "@mui/material"; import { useMutation, useQuery } from "urql"; @@ -103,7 +101,7 @@ export function UnthemedPage() { title={title} > item.role !== role)) { - rolePromise = saveRole({ id: user.id, role }); - } - rolePromise - .then(() => saveUser({ email, id: user.id, name })) - .then((result) => { - if (!result.error) { - router.push("/users"); - } - }); - } - return ( - - {user && ( - - )} - - ); -} - -export default withCustomUrqlClient(withUserProvider(EditUserPage)); diff --git a/targets/frontend/src/pages/user/edit/[id].js b/targets/frontend/src/pages/user/edit/[id].js deleted file mode 100644 index 84b832802..000000000 --- a/targets/frontend/src/pages/user/edit/[id].js +++ /dev/null @@ -1,92 +0,0 @@ -import { useRouter } from "next/router"; -import PropTypes from "prop-types"; -import { Layout } from "src/components/layout/auth.layout"; -import { UserForm } from "src/components/user/UserForm"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; -import { useUser } from "src/hooks/useUser"; -import { useMutation } from "urql"; - -const getUserQuery = ` -query getUser($id: uuid!) { - user:auth_users_by_pk(id: $id) { - __typename - id - email - name - active - default_role - roles: user_roles { - role - } - } -} -`; - -const saveUserMutation = ` -mutation saveUser($id: uuid!, $name:String!, $email: citext!) { - update_auth_users_by_pk( - _set: { - name: $name, - email: $email, - }, - pk_columns: { id: $id} - ){ __typename } -} -`; - -const saveRoleMutation = ` -mutation saveRole($id: uuid!, $role:String!) { - update_auth_user_roles(_set: {role: $role}, where: { - user_id: {_eq: $id} - }){ - returning { __typename } - } -} -`; - -export function EditUserPage({ user }) { - const router = useRouter(); - const { isAdmin } = useUser(); - const [userResult, saveUser] = useMutation(saveUserMutation); - const [roleResult, saveRole] = useMutation(saveRoleMutation); - function handleSubmit(data) { - const { name, email, default_role } = data; - let rolePromise = Promise.resolve(); - if (user.roles.every(({ role }) => role !== default_role)) { - rolePromise = saveRole({ id: user.id, role: default_role }); - } - rolePromise - .then(() => saveUser({ email, id: user.id, name })) - .then((result) => { - if (!result.error) { - router.push("/users"); - } - }); - } - return ( - - - - ); -} - -EditUserPage.getInitialProps = async function ({ urqlClient, query }) { - const { id } = query; - const result = await urqlClient.query(getUserQuery, { id }).toPromise(); - - if (result.error) { - const error = new Error("user not found"); - error.statusCode = 404; - return Promise.reject(error); - } - return { user: result.data.user }; -}; - -export default withCustomUrqlClient(withUserProvider(EditUserPage)); diff --git a/targets/frontend/src/pages/user/new.js b/targets/frontend/src/pages/user/new.js deleted file mode 100644 index 8bcbed35b..000000000 --- a/targets/frontend/src/pages/user/new.js +++ /dev/null @@ -1,68 +0,0 @@ -import { useRouter } from "next/router"; -import { Layout } from "src/components/layout/auth.layout"; -import { Stack } from "src/components/layout/Stack"; -import { UserForm } from "src/components/user/UserForm"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; -import { getExpiryDate } from "src/lib/duration"; -import { useMutation } from "urql"; -import { Alert } from "@mui/material"; -import { ACTIVATION_TOKEN_EXPIRES } from "../../config"; - -const registerUserMutation = ` -mutation registerUser($user: auth_users_insert_input! ) { - user: insert_auth_users_one( object: $user ) { - id - email - __typename - } -} -`; - -const emailAccountMutation = ` -mutation email($email: citext!) { - email_account_activation(email: $email) -} -`; - -function prepareMutationData(input) { - return { - user: { - ...input, - secret_token_expires_at: getExpiryDate(ACTIVATION_TOKEN_EXPIRES), - user_roles: { data: { role: input.default_role } }, - }, - }; -} - -export function UserPage() { - const router = useRouter(); - const [result, registerUser] = useMutation(registerUserMutation); - const [, emailAccount] = useMutation(emailAccountMutation); - const { fetching, error } = result; - - function handleCreate(data) { - registerUser(prepareMutationData(data)).then((result) => { - if (!result.error) { - router.push("/users"); - const { email } = result.data.user; - emailAccount({ email }); - } - }); - } - - return ( - - - {error && ( - -
{JSON.stringify(error, 0, 2)}
-
- )} - -
-
- ); -} - -export default withCustomUrqlClient(withUserProvider(UserPage)); diff --git a/targets/frontend/src/pages/user/password.js b/targets/frontend/src/pages/user/password.js deleted file mode 100644 index a60c333d5..000000000 --- a/targets/frontend/src/pages/user/password.js +++ /dev/null @@ -1,25 +0,0 @@ -import { useRouter } from "next/router"; -import { Layout } from "src/components/layout/auth.layout"; -import { PasswordForm } from "src/components/user/PasswordForm"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; -import { request } from "src/lib/request"; - -export function ChangeMyPasswordPage() { - const router = useRouter(); - async function handleChangePasword({ id, oldPassword, password }) { - await request("/api/change_password", { - body: { id, oldPassword, password }, - }); - - router.push("/user/account"); - } - - return ( - - - - ); -} - -export default withCustomUrqlClient(withUserProvider(ChangeMyPasswordPage)); diff --git a/targets/frontend/src/pages/users.js b/targets/frontend/src/pages/users.js deleted file mode 100644 index b4c74f337..000000000 --- a/targets/frontend/src/pages/users.js +++ /dev/null @@ -1,34 +0,0 @@ -import { Button } from "@mui/material"; -import Link from "next/link"; -import { IoIosAdd } from "react-icons/io"; -import { Layout } from "src/components/layout/auth.layout"; -import { Stack } from "src/components/layout/Stack"; -import { UserList } from "src/components/user/List"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; -import { Box } from "@mui/material"; - -export function UserPage() { - return ( - - - - - - - - - - - ); -} - -export default withCustomUrqlClient(withUserProvider(UserPage)); diff --git a/targets/frontend/src/pages/user/account.js b/targets/frontend/src/pages/users/account.tsx similarity index 59% rename from targets/frontend/src/pages/user/account.js rename to targets/frontend/src/pages/users/account.tsx index 5ee754509..43d494c46 100644 --- a/targets/frontend/src/pages/user/account.js +++ b/targets/frontend/src/pages/users/account.tsx @@ -1,20 +1,18 @@ import { Button } from "src/components/button"; import { Layout } from "src/components/layout/auth.layout"; -import { Stack } from "src/components/layout/Stack"; -import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; -import { withUserProvider } from "src/hoc/UserProvider"; -import { useUser } from "src/hooks/useUser"; +import { useSession } from "next-auth/react"; import { useRouter } from "next/router"; import { Box } from "@mui/material"; export function UserPage() { - const { user } = useUser(); + const { data } = useSession(); + const user = data?.user; const router = useRouter(); return ( {user && ( - +

Nom d’utilisateur

{user.name}

@@ -25,7 +23,7 @@ export function UserPage() {

role

-

{user.roles[0].role}

+

{user.role}

- - -
+
)} ); } -export default withCustomUrqlClient(withUserProvider(UserPage)); +export default UserPage; diff --git a/targets/frontend/src/pages/users/index.tsx b/targets/frontend/src/pages/users/index.tsx new file mode 100644 index 000000000..fe4674868 --- /dev/null +++ b/targets/frontend/src/pages/users/index.tsx @@ -0,0 +1,53 @@ +import { Button } from "@mui/material"; +import { IoIosAdd } from "react-icons/io"; +import { Layout } from "src/components/layout/auth.layout"; +import { Stack } from "src/components/layout/Stack"; +import { UserList } from "src/components/user/List"; +import { Box } from "@mui/material"; +import { useRouter } from "next/router"; + +export function UserPage() { + const router = useRouter(); + + const onDeleteUser = async (userId: string) => { + const result = await fetch(`/api/users/delete`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ userId }), + }); + + const resultJson = await result.json(); + + if (!result.ok) { + alert(`Un problème est survenu, l'erreur est : ${resultJson.message}`); + return false; + } + + alert("L'utilisateur a été supprimé avec succès"); + + return true; + }; + + return ( + + + + + + + + + ); +} + +export default UserPage; diff --git a/targets/frontend/src/pages/users/new.tsx b/targets/frontend/src/pages/users/new.tsx new file mode 100644 index 000000000..ecbbf4e66 --- /dev/null +++ b/targets/frontend/src/pages/users/new.tsx @@ -0,0 +1,37 @@ +import { useRouter } from "next/router"; +import { Layout } from "src/components/layout/auth.layout"; +import { Stack } from "src/components/layout/Stack"; +import { UserForm } from "src/components/user/UserForm"; + +export function UserPage() { + const router = useRouter(); + + async function handleCreate({ name, email }: any) { + const result = await fetch(`/api/users/create`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ name, email }), + }); + + const resultJson = await result.json(); + + if (!result.ok) { + alert(`Un problème est survenu, l'erreur est : ${resultJson.message}`); + return; + } + + router.push("/users"); + } + + return ( + + + + + + ); +} + +export default UserPage; diff --git a/targets/frontend/src/pages/users/password.tsx b/targets/frontend/src/pages/users/password.tsx new file mode 100644 index 000000000..5843ab972 --- /dev/null +++ b/targets/frontend/src/pages/users/password.tsx @@ -0,0 +1,34 @@ +import { useRouter } from "next/router"; +import { Layout } from "src/components/layout/auth.layout"; +import { PasswordForm } from "src/components/user/PasswordForm"; + +export function ChangeMyPasswordPage() { + const router = useRouter(); + + const handleChangePasword = async ({ oldPassword, password }: any) => { + const result = await fetch(`/api/users/password/change`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ oldPassword, newPassword: password }), + }); + + const resultJson = await result.json(); + + if (!result.ok) { + alert(`Un problème est survenu, l'erreur est : ${resultJson.message}`); + return; + } + + router.push("/users/account"); + }; + + return ( + + + + ); +} + +export default ChangeMyPasswordPage; diff --git a/targets/frontend/src/index.d.ts b/targets/frontend/src/types/graphql.d.ts similarity index 100% rename from targets/frontend/src/index.d.ts rename to targets/frontend/src/types/graphql.d.ts diff --git a/targets/frontend/src/types/next-auth.d.ts b/targets/frontend/src/types/next-auth.d.ts new file mode 100644 index 000000000..3622745df --- /dev/null +++ b/targets/frontend/src/types/next-auth.d.ts @@ -0,0 +1,17 @@ +import NextAuth from "next-auth"; +import { UserSignedIn } from "src/modules/authentification/signIn"; + +declare module "next-auth" { + /** + * Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context + */ + interface Session { + user: { + name: string; + email: string; + accessToken: string; + id: string; + role: "super" | "user"; + }; + } +} diff --git a/targets/frontend/tsconfig.json b/targets/frontend/tsconfig.json index 81c7fe09d..96719657b 100644 --- a/targets/frontend/tsconfig.json +++ b/targets/frontend/tsconfig.json @@ -14,7 +14,6 @@ "jsx": "preserve", "baseUrl": ".", "incremental": true, - "tsBuildInfoFile": ".next/cache/ts", "noEmit": true }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "node_modules/@types"], diff --git a/targets/hasura/metadata/actions.graphql b/targets/hasura/metadata/actions.graphql index 0270cd137..081545811 100644 --- a/targets/hasura/metadata/actions.graphql +++ b/targets/hasura/metadata/actions.graphql @@ -1,22 +1,3 @@ -type Mutation { - email_account_activation( - email: citext! - ): Status -} - -type Mutation { - email_password_request( - email: citext! - secret_token: uuid! - ): Status -} - -type Query { - pipeline_status( - pipelineId: String! - ): PipelineStatus -} - type Mutation { preview_document( cdtnId: String! @@ -40,12 +21,6 @@ type Query { ): RecentKaliReferenceOutput } -type Mutation { - updatePipeline( - environment: String! - ): UpdatePipelineOutput -} - input PreviewDocument { cdtn_id: String document: jsonb diff --git a/targets/hasura/metadata/actions.yaml b/targets/hasura/metadata/actions.yaml index 8acfd6e16..e3c8ba4ce 100644 --- a/targets/hasura/metadata/actions.yaml +++ b/targets/hasura/metadata/actions.yaml @@ -1,34 +1,4 @@ actions: - - name: email_account_activation - definition: - kind: asynchronous - handler: '{{API_URL}}/actions/email_account_activation' - forward_client_headers: true - headers: - - name: actions-secret - value_from_env: ACTIONS_SECRET - permissions: - - role: user - - role: super - - name: email_password_request - definition: - kind: asynchronous - handler: '{{API_URL}}/actions/email_password_request' - forward_client_headers: true - headers: - - name: actions-secret - value_from_env: ACTIONS_SECRET - permissions: - - role: public - - name: pipeline_status - definition: - kind: "" - handler: '{{API_URL}}/actions/pipeline_status' - headers: - - name: actions-secret - value_from_env: ACTIONS_SECRET - permissions: - - role: user - name: preview_document definition: kind: synchronous @@ -56,17 +26,6 @@ actions: permissions: - role: user - role: super - - name: updatePipeline - definition: - kind: synchronous - handler: '{{API_URL}}/actions/trigger_pipeline' - forward_client_headers: true - headers: - - name: secret - value_from_env: ACTIONS_SECRET - permissions: - - role: super - - role: user custom_types: enums: [] input_objects: diff --git a/targets/hasura/metadata/databases/default/tables/auth_refresh_tokens.yaml b/targets/hasura/metadata/databases/default/tables/auth_refresh_tokens.yaml index 54e6173a0..763dc4711 100644 --- a/targets/hasura/metadata/databases/default/tables/auth_refresh_tokens.yaml +++ b/targets/hasura/metadata/databases/default/tables/auth_refresh_tokens.yaml @@ -1,7 +1,3 @@ table: name: refresh_tokens schema: auth -object_relationships: - - name: user - using: - foreign_key_constraint_on: user_id diff --git a/targets/hasura/metadata/databases/default/tables/auth_user_roles.yaml b/targets/hasura/metadata/databases/default/tables/auth_user_roles.yaml index 4b6840da4..79f192e1c 100644 --- a/targets/hasura/metadata/databases/default/tables/auth_user_roles.yaml +++ b/targets/hasura/metadata/databases/default/tables/auth_user_roles.yaml @@ -1,13 +1,6 @@ table: name: user_roles schema: auth -object_relationships: - - name: roleByRole - using: - foreign_key_constraint_on: role - - name: user - using: - foreign_key_constraint_on: user_id insert_permissions: - role: super permission: diff --git a/targets/hasura/metadata/databases/default/tables/auth_users.yaml b/targets/hasura/metadata/databases/default/tables/auth_users.yaml index 29fb58c87..18f19f665 100644 --- a/targets/hasura/metadata/databases/default/tables/auth_users.yaml +++ b/targets/hasura/metadata/databases/default/tables/auth_users.yaml @@ -1,89 +1,33 @@ table: name: users schema: auth -object_relationships: - - name: role - using: - foreign_key_constraint_on: default_role -array_relationships: - - name: refresh_tokens - using: - foreign_key_constraint_on: - column: user_id - table: - name: refresh_tokens - schema: auth - - name: user_roles - using: - foreign_key_constraint_on: - column: user_id - table: - name: user_roles - schema: auth -insert_permissions: - - role: super - permission: - check: {} - columns: - - active - - created_at - - default_role - - email - - id - - name - - secret_token - - secret_token_expires_at - - updated_at +configuration: + column_config: + created_at: + custom_name: createdAt + is_active: + custom_name: isActive + is_deleted: + custom_name: isDeleted + updated_at: + custom_name: updatedAt + custom_column_names: + created_at: createdAt + is_active: isActive + is_deleted: isDeleted + updated_at: updatedAt + custom_root_fields: {} select_permissions: - role: super permission: columns: - - active - - created_at - - default_role - - deleted - - email - - id - - name - - updated_at - filter: {} - allow_aggregations: true - - role: user - permission: - columns: - - active - - created_at - - default_role - - email - - id - - name - - updated_at - filter: - id: - _eq: X-Hasura-User-Id -update_permissions: - - role: super - permission: - columns: - - active - created_at - - default_role - - deleted - email - id + - is_active + - is_deleted - name - - password - - secret_token - - secret_token_expires_at + - role - updated_at filter: {} - check: null - - role: user - permission: - columns: - - email - - name - filter: - id: - _eq: X-Hasura-User-Id - check: null + comment: "" diff --git a/targets/hasura/metadata/databases/default/tables/contribution_answer_comments.yaml b/targets/hasura/metadata/databases/default/tables/contribution_answer_comments.yaml index 2fb614996..431f53f72 100644 --- a/targets/hasura/metadata/databases/default/tables/contribution_answer_comments.yaml +++ b/targets/hasura/metadata/databases/default/tables/contribution_answer_comments.yaml @@ -11,7 +11,9 @@ object_relationships: insert_permissions: - role: super permission: - check: {} + check: + user_id: + _eq: X-Hasura-User-Id columns: - answer_id - content diff --git a/targets/hasura/metadata/databases/default/tables/public_document_relations.yaml b/targets/hasura/metadata/databases/default/tables/public_document_relations.yaml index 8975e11d0..4afbdef41 100644 --- a/targets/hasura/metadata/databases/default/tables/public_document_relations.yaml +++ b/targets/hasura/metadata/databases/default/tables/public_document_relations.yaml @@ -28,16 +28,6 @@ insert_permissions: - type - data select_permissions: - - role: public - permission: - columns: - - id - - document_a - - document_b - - type - - data - filter: {} - allow_aggregations: true - role: super permission: columns: diff --git a/targets/hasura/metadata/databases/default/tables/public_documents.yaml b/targets/hasura/metadata/databases/default/tables/public_documents.yaml index fc97bfd26..c5516fe2b 100644 --- a/targets/hasura/metadata/databases/default/tables/public_documents.yaml +++ b/targets/hasura/metadata/databases/default/tables/public_documents.yaml @@ -52,24 +52,6 @@ insert_permissions: - title - updated_at select_permissions: - - role: public - permission: - columns: - - cdtn_id - - initial_id - - title - - meta_description - - source - - slug - - text - - document - - is_published - - is_searchable - - created_at - - updated_at - - is_available - filter: {} - allow_aggregations: true - role: super permission: columns: diff --git a/targets/hasura/metadata/databases/default/tables/public_glossary.yaml b/targets/hasura/metadata/databases/default/tables/public_glossary.yaml index 070d802d0..a0fa10fd8 100644 --- a/targets/hasura/metadata/databases/default/tables/public_glossary.yaml +++ b/targets/hasura/metadata/databases/default/tables/public_glossary.yaml @@ -29,19 +29,6 @@ insert_permissions: - updated_at - id select_permissions: - - role: public - permission: - columns: - - abbreviations - - references - - variants - - definition - - slug - - term - - created_at - - updated_at - - id - filter: {} - role: super permission: columns: diff --git a/targets/hasura/metadata/databases/default/tables/public_kali_blocks.yaml b/targets/hasura/metadata/databases/default/tables/public_kali_blocks.yaml index b7a262709..ca62893ca 100644 --- a/targets/hasura/metadata/databases/default/tables/public_kali_blocks.yaml +++ b/targets/hasura/metadata/databases/default/tables/public_kali_blocks.yaml @@ -19,14 +19,6 @@ insert_permissions: - idcc - blocks select_permissions: - - role: public - permission: - columns: - - id - - title - - idcc - - blocks - filter: {} - role: super permission: columns: diff --git a/targets/hasura/metadata/databases/default/tables/public_package_version.yaml b/targets/hasura/metadata/databases/default/tables/public_package_version.yaml index 7ce1bce7a..f1da487ea 100644 --- a/targets/hasura/metadata/databases/default/tables/public_package_version.yaml +++ b/targets/hasura/metadata/databases/default/tables/public_package_version.yaml @@ -2,14 +2,6 @@ table: name: package_version schema: public select_permissions: - - role: public - permission: - columns: - - repository - - version - - created_at - - updated_at - filter: {} - role: super permission: columns: diff --git a/targets/hasura/metadata/databases/default/tables/public_roles.yaml b/targets/hasura/metadata/databases/default/tables/public_roles.yaml index 53f00deae..2b641c2cf 100644 --- a/targets/hasura/metadata/databases/default/tables/public_roles.yaml +++ b/targets/hasura/metadata/databases/default/tables/public_roles.yaml @@ -1,21 +1,6 @@ table: name: roles schema: public -array_relationships: - - name: user_roles - using: - foreign_key_constraint_on: - column: role - table: - name: user_roles - schema: auth - - name: users - using: - foreign_key_constraint_on: - column: default_role - table: - name: users - schema: auth select_permissions: - role: super permission: diff --git a/targets/hasura/metadata/databases/default/tables/tables.yaml b/targets/hasura/metadata/databases/default/tables/tables.yaml index c73da929f..b41ee2bb8 100644 --- a/targets/hasura/metadata/databases/default/tables/tables.yaml +++ b/targets/hasura/metadata/databases/default/tables/tables.yaml @@ -1,6 +1,4 @@ - "!include agreement_agreements.yaml" -- "!include auth_refresh_tokens.yaml" -- "!include auth_user_roles.yaml" - "!include auth_users.yaml" - "!include contribution_agreement_messages.yaml" - "!include contribution_answer_cdtn_references.yaml" @@ -34,8 +32,6 @@ - "!include public_kali_blocks.yaml" - "!include public_legi_articles.yaml" - "!include public_package_version.yaml" -- "!include public_pipelines.yaml" -- "!include public_roles.yaml" - "!include public_service_public_contents.yaml" - "!include public_sources.yaml" - "!include search_prequalified.yaml" diff --git a/targets/hasura/migrations/default/1710942991576_drop_table_auth_refresh_tokens/down.sql b/targets/hasura/migrations/default/1710942991576_drop_table_auth_refresh_tokens/down.sql new file mode 100644 index 000000000..80f063fbb --- /dev/null +++ b/targets/hasura/migrations/default/1710942991576_drop_table_auth_refresh_tokens/down.sql @@ -0,0 +1,3 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- DROP table "auth"."refresh_tokens"; diff --git a/targets/hasura/migrations/default/1710942991576_drop_table_auth_refresh_tokens/up.sql b/targets/hasura/migrations/default/1710942991576_drop_table_auth_refresh_tokens/up.sql new file mode 100644 index 000000000..b41d15d69 --- /dev/null +++ b/targets/hasura/migrations/default/1710942991576_drop_table_auth_refresh_tokens/up.sql @@ -0,0 +1 @@ +DROP table "auth"."refresh_tokens"; diff --git a/targets/hasura/migrations/default/1710943179800_delete_fk_auth_user_roles_user_roles_user_id_fkey/down.sql b/targets/hasura/migrations/default/1710943179800_delete_fk_auth_user_roles_user_roles_user_id_fkey/down.sql new file mode 100644 index 000000000..c19966320 --- /dev/null +++ b/targets/hasura/migrations/default/1710943179800_delete_fk_auth_user_roles_user_roles_user_id_fkey/down.sql @@ -0,0 +1,5 @@ +alter table "auth"."user_roles" + add constraint "user_roles_user_id_fkey" + foreign key ("user_id") + references "auth"."users" + ("id") on update restrict on delete cascade; diff --git a/targets/hasura/migrations/default/1710943179800_delete_fk_auth_user_roles_user_roles_user_id_fkey/up.sql b/targets/hasura/migrations/default/1710943179800_delete_fk_auth_user_roles_user_roles_user_id_fkey/up.sql new file mode 100644 index 000000000..d8159a10e --- /dev/null +++ b/targets/hasura/migrations/default/1710943179800_delete_fk_auth_user_roles_user_roles_user_id_fkey/up.sql @@ -0,0 +1 @@ +alter table "auth"."user_roles" drop constraint "user_roles_user_id_fkey"; diff --git a/targets/hasura/migrations/default/1710943186197_delete_fk_auth_user_roles_user_roles_role_fkey/down.sql b/targets/hasura/migrations/default/1710943186197_delete_fk_auth_user_roles_user_roles_role_fkey/down.sql new file mode 100644 index 000000000..812b2f2c3 --- /dev/null +++ b/targets/hasura/migrations/default/1710943186197_delete_fk_auth_user_roles_user_roles_role_fkey/down.sql @@ -0,0 +1,5 @@ +alter table "auth"."user_roles" + add constraint "user_roles_role_fkey" + foreign key ("role") + references "public"."roles" + ("role") on update restrict on delete cascade; diff --git a/targets/hasura/migrations/default/1710943186197_delete_fk_auth_user_roles_user_roles_role_fkey/up.sql b/targets/hasura/migrations/default/1710943186197_delete_fk_auth_user_roles_user_roles_role_fkey/up.sql new file mode 100644 index 000000000..fb2a8a903 --- /dev/null +++ b/targets/hasura/migrations/default/1710943186197_delete_fk_auth_user_roles_user_roles_role_fkey/up.sql @@ -0,0 +1 @@ +alter table "auth"."user_roles" drop constraint "user_roles_role_fkey"; diff --git a/targets/hasura/migrations/default/1710943195146_alter_table_auth_user_roles_drop_constraint_user_roles_user_id_role_key/down.sql b/targets/hasura/migrations/default/1710943195146_alter_table_auth_user_roles_drop_constraint_user_roles_user_id_role_key/down.sql new file mode 100644 index 000000000..b547770ee --- /dev/null +++ b/targets/hasura/migrations/default/1710943195146_alter_table_auth_user_roles_drop_constraint_user_roles_user_id_role_key/down.sql @@ -0,0 +1 @@ +alter table "auth"."user_roles" add constraint "user_roles_user_id_role_key" unique ("user_id", "role"); diff --git a/targets/hasura/migrations/default/1710943195146_alter_table_auth_user_roles_drop_constraint_user_roles_user_id_role_key/up.sql b/targets/hasura/migrations/default/1710943195146_alter_table_auth_user_roles_drop_constraint_user_roles_user_id_role_key/up.sql new file mode 100644 index 000000000..1a45d9ae5 --- /dev/null +++ b/targets/hasura/migrations/default/1710943195146_alter_table_auth_user_roles_drop_constraint_user_roles_user_id_role_key/up.sql @@ -0,0 +1 @@ +alter table "auth"."user_roles" drop constraint "user_roles_user_id_role_key"; diff --git a/targets/hasura/migrations/default/1710943204983_drop_table_auth_user_roles/down.sql b/targets/hasura/migrations/default/1710943204983_drop_table_auth_user_roles/down.sql new file mode 100644 index 000000000..3f549559b --- /dev/null +++ b/targets/hasura/migrations/default/1710943204983_drop_table_auth_user_roles/down.sql @@ -0,0 +1,3 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- DROP table "auth"."user_roles"; diff --git a/targets/hasura/migrations/default/1710943204983_drop_table_auth_user_roles/up.sql b/targets/hasura/migrations/default/1710943204983_drop_table_auth_user_roles/up.sql new file mode 100644 index 000000000..5d79dc498 --- /dev/null +++ b/targets/hasura/migrations/default/1710943204983_drop_table_auth_user_roles/up.sql @@ -0,0 +1 @@ +DROP table "auth"."user_roles"; diff --git a/targets/hasura/migrations/default/1710943530563_delete_fk_auth_users_users_default_role_fkey/down.sql b/targets/hasura/migrations/default/1710943530563_delete_fk_auth_users_users_default_role_fkey/down.sql new file mode 100644 index 000000000..783343aaa --- /dev/null +++ b/targets/hasura/migrations/default/1710943530563_delete_fk_auth_users_users_default_role_fkey/down.sql @@ -0,0 +1,5 @@ +alter table "auth"."users" + add constraint "users_default_role_fkey" + foreign key ("default_role") + references "public"."roles" + ("role") on update cascade on delete restrict; diff --git a/targets/hasura/migrations/default/1710943530563_delete_fk_auth_users_users_default_role_fkey/up.sql b/targets/hasura/migrations/default/1710943530563_delete_fk_auth_users_users_default_role_fkey/up.sql new file mode 100644 index 000000000..c747fa62e --- /dev/null +++ b/targets/hasura/migrations/default/1710943530563_delete_fk_auth_users_users_default_role_fkey/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" drop constraint "users_default_role_fkey"; diff --git a/targets/hasura/migrations/default/1710943562140_drop_table_public_roles/down.sql b/targets/hasura/migrations/default/1710943562140_drop_table_public_roles/down.sql new file mode 100644 index 000000000..f00cd715e --- /dev/null +++ b/targets/hasura/migrations/default/1710943562140_drop_table_public_roles/down.sql @@ -0,0 +1,3 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- DROP table "public"."roles"; diff --git a/targets/hasura/migrations/default/1710943562140_drop_table_public_roles/up.sql b/targets/hasura/migrations/default/1710943562140_drop_table_public_roles/up.sql new file mode 100644 index 000000000..ed60a2e49 --- /dev/null +++ b/targets/hasura/migrations/default/1710943562140_drop_table_public_roles/up.sql @@ -0,0 +1 @@ +DROP table "public"."roles"; diff --git a/targets/hasura/migrations/default/1710945049362_drop_table_public_pipelines/down.sql b/targets/hasura/migrations/default/1710945049362_drop_table_public_pipelines/down.sql new file mode 100644 index 000000000..966da9936 --- /dev/null +++ b/targets/hasura/migrations/default/1710945049362_drop_table_public_pipelines/down.sql @@ -0,0 +1,3 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- DROP table "public"."pipelines"; diff --git a/targets/hasura/migrations/default/1710945049362_drop_table_public_pipelines/up.sql b/targets/hasura/migrations/default/1710945049362_drop_table_public_pipelines/up.sql new file mode 100644 index 000000000..cd13fdb52 --- /dev/null +++ b/targets/hasura/migrations/default/1710945049362_drop_table_public_pipelines/up.sql @@ -0,0 +1 @@ +DROP table "public"."pipelines"; diff --git a/targets/hasura/migrations/default/1710946501277_alter_table_auth_users_update_comment/down.sql b/targets/hasura/migrations/default/1710946501277_alter_table_auth_users_update_comment/down.sql new file mode 100644 index 000000000..b697a3858 --- /dev/null +++ b/targets/hasura/migrations/default/1710946501277_alter_table_auth_users_update_comment/down.sql @@ -0,0 +1 @@ +comment on table "auth"."users" is NULL; diff --git a/targets/hasura/migrations/default/1710946501277_alter_table_auth_users_update_comment/up.sql b/targets/hasura/migrations/default/1710946501277_alter_table_auth_users_update_comment/up.sql new file mode 100644 index 000000000..81d4188b0 --- /dev/null +++ b/targets/hasura/migrations/default/1710946501277_alter_table_auth_users_update_comment/up.sql @@ -0,0 +1 @@ +comment on table "auth"."users" is E'Users table'; diff --git a/targets/hasura/migrations/default/1710947045361_alter_table_auth_users_alter_column_default_role/down.sql b/targets/hasura/migrations/default/1710947045361_alter_table_auth_users_alter_column_default_role/down.sql new file mode 100644 index 000000000..6d67f91f0 --- /dev/null +++ b/targets/hasura/migrations/default/1710947045361_alter_table_auth_users_alter_column_default_role/down.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "role" to "default_role"; diff --git a/targets/hasura/migrations/default/1710947045361_alter_table_auth_users_alter_column_default_role/up.sql b/targets/hasura/migrations/default/1710947045361_alter_table_auth_users_alter_column_default_role/up.sql new file mode 100644 index 000000000..89aaa6244 --- /dev/null +++ b/targets/hasura/migrations/default/1710947045361_alter_table_auth_users_alter_column_default_role/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "default_role" to "role"; diff --git a/targets/hasura/migrations/default/1710947065729_alter_table_auth_users_alter_column_deleted/down.sql b/targets/hasura/migrations/default/1710947065729_alter_table_auth_users_alter_column_deleted/down.sql new file mode 100644 index 000000000..371aa160e --- /dev/null +++ b/targets/hasura/migrations/default/1710947065729_alter_table_auth_users_alter_column_deleted/down.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "is_deleted" to "deleted"; diff --git a/targets/hasura/migrations/default/1710947065729_alter_table_auth_users_alter_column_deleted/up.sql b/targets/hasura/migrations/default/1710947065729_alter_table_auth_users_alter_column_deleted/up.sql new file mode 100644 index 000000000..cc61b9483 --- /dev/null +++ b/targets/hasura/migrations/default/1710947065729_alter_table_auth_users_alter_column_deleted/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "deleted" to "is_deleted"; diff --git a/targets/hasura/migrations/default/1710947130787_alter_table_auth_users_alter_column_secret_token/down.sql b/targets/hasura/migrations/default/1710947130787_alter_table_auth_users_alter_column_secret_token/down.sql new file mode 100644 index 000000000..1795d24da --- /dev/null +++ b/targets/hasura/migrations/default/1710947130787_alter_table_auth_users_alter_column_secret_token/down.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "refresh_token" to "secret_token"; diff --git a/targets/hasura/migrations/default/1710947130787_alter_table_auth_users_alter_column_secret_token/up.sql b/targets/hasura/migrations/default/1710947130787_alter_table_auth_users_alter_column_secret_token/up.sql new file mode 100644 index 000000000..a6a048355 --- /dev/null +++ b/targets/hasura/migrations/default/1710947130787_alter_table_auth_users_alter_column_secret_token/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "secret_token" to "refresh_token"; diff --git a/targets/hasura/migrations/default/1710947143482_alter_table_auth_users_alter_column_active/down.sql b/targets/hasura/migrations/default/1710947143482_alter_table_auth_users_alter_column_active/down.sql new file mode 100644 index 000000000..ee185e16f --- /dev/null +++ b/targets/hasura/migrations/default/1710947143482_alter_table_auth_users_alter_column_active/down.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "is_active" to "active"; diff --git a/targets/hasura/migrations/default/1710947143482_alter_table_auth_users_alter_column_active/up.sql b/targets/hasura/migrations/default/1710947143482_alter_table_auth_users_alter_column_active/up.sql new file mode 100644 index 000000000..a30daae7a --- /dev/null +++ b/targets/hasura/migrations/default/1710947143482_alter_table_auth_users_alter_column_active/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "active" to "is_active"; diff --git a/targets/hasura/migrations/default/1710947167029_alter_table_auth_users_alter_column_secret_token_expires_at/down.sql b/targets/hasura/migrations/default/1710947167029_alter_table_auth_users_alter_column_secret_token_expires_at/down.sql new file mode 100644 index 000000000..76e2c1a9e --- /dev/null +++ b/targets/hasura/migrations/default/1710947167029_alter_table_auth_users_alter_column_secret_token_expires_at/down.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "refresh_token_expires_at" to "secret_token_expires_at"; diff --git a/targets/hasura/migrations/default/1710947167029_alter_table_auth_users_alter_column_secret_token_expires_at/up.sql b/targets/hasura/migrations/default/1710947167029_alter_table_auth_users_alter_column_secret_token_expires_at/up.sql new file mode 100644 index 000000000..2fe5da55b --- /dev/null +++ b/targets/hasura/migrations/default/1710947167029_alter_table_auth_users_alter_column_secret_token_expires_at/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "secret_token_expires_at" to "refresh_token_expires_at"; diff --git a/targets/hasura/migrations/default/1710947221940_alter_table_auth_users_add_column_access_token/down.sql b/targets/hasura/migrations/default/1710947221940_alter_table_auth_users_add_column_access_token/down.sql new file mode 100644 index 000000000..5949fc520 --- /dev/null +++ b/targets/hasura/migrations/default/1710947221940_alter_table_auth_users_add_column_access_token/down.sql @@ -0,0 +1,5 @@ +alter table "auth"."users" drop column "access_token" cascade +alter table "auth"."users" drop column "access_token"; +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- CREATE EXTENSION IF NOT EXISTS pgcrypto; diff --git a/targets/hasura/migrations/default/1710947221940_alter_table_auth_users_add_column_access_token/up.sql b/targets/hasura/migrations/default/1710947221940_alter_table_auth_users_add_column_access_token/up.sql new file mode 100644 index 000000000..65310ca4c --- /dev/null +++ b/targets/hasura/migrations/default/1710947221940_alter_table_auth_users_add_column_access_token/up.sql @@ -0,0 +1,3 @@ +CREATE EXTENSION IF NOT EXISTS pgcrypto; +alter table "auth"."users" add column "access_token" uuid + null default gen_random_uuid(); diff --git a/targets/hasura/migrations/default/1710947243237_alter_table_auth_users_alter_column_refresh_token/down.sql b/targets/hasura/migrations/default/1710947243237_alter_table_auth_users_alter_column_refresh_token/down.sql new file mode 100644 index 000000000..df8f77a8a --- /dev/null +++ b/targets/hasura/migrations/default/1710947243237_alter_table_auth_users_alter_column_refresh_token/down.sql @@ -0,0 +1 @@ +alter table "auth"."users" alter column "refresh_token" set default public.gen_random_uuid(); diff --git a/targets/hasura/migrations/default/1710947243237_alter_table_auth_users_alter_column_refresh_token/up.sql b/targets/hasura/migrations/default/1710947243237_alter_table_auth_users_alter_column_refresh_token/up.sql new file mode 100644 index 000000000..9c5cc6c62 --- /dev/null +++ b/targets/hasura/migrations/default/1710947243237_alter_table_auth_users_alter_column_refresh_token/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" alter column "refresh_token" set default gen_random_uuid(); diff --git a/targets/hasura/migrations/default/1710947451028_alter_table_auth_users_alter_column_refresh_token_expires_at/down.sql b/targets/hasura/migrations/default/1710947451028_alter_table_auth_users_alter_column_refresh_token_expires_at/down.sql new file mode 100644 index 000000000..c45ae45fa --- /dev/null +++ b/targets/hasura/migrations/default/1710947451028_alter_table_auth_users_alter_column_refresh_token_expires_at/down.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "expires_at" to "refresh_token_expires_at"; diff --git a/targets/hasura/migrations/default/1710947451028_alter_table_auth_users_alter_column_refresh_token_expires_at/up.sql b/targets/hasura/migrations/default/1710947451028_alter_table_auth_users_alter_column_refresh_token_expires_at/up.sql new file mode 100644 index 000000000..709da0407 --- /dev/null +++ b/targets/hasura/migrations/default/1710947451028_alter_table_auth_users_alter_column_refresh_token_expires_at/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "refresh_token_expires_at" to "expires_at"; diff --git a/targets/hasura/migrations/default/1711289415888_alter_table_auth_users_alter_column_expires_at/down.sql b/targets/hasura/migrations/default/1711289415888_alter_table_auth_users_alter_column_expires_at/down.sql new file mode 100644 index 000000000..670d09b8b --- /dev/null +++ b/targets/hasura/migrations/default/1711289415888_alter_table_auth_users_alter_column_expires_at/down.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "expires_in" to "expires_at"; diff --git a/targets/hasura/migrations/default/1711289415888_alter_table_auth_users_alter_column_expires_at/up.sql b/targets/hasura/migrations/default/1711289415888_alter_table_auth_users_alter_column_expires_at/up.sql new file mode 100644 index 000000000..c1942b81c --- /dev/null +++ b/targets/hasura/migrations/default/1711289415888_alter_table_auth_users_alter_column_expires_at/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" rename column "expires_at" to "expires_in"; diff --git a/targets/hasura/migrations/default/1711289911681_alter_table_auth_users_alter_column_refresh_token/down.sql b/targets/hasura/migrations/default/1711289911681_alter_table_auth_users_alter_column_refresh_token/down.sql new file mode 100644 index 000000000..8f14b0a39 --- /dev/null +++ b/targets/hasura/migrations/default/1711289911681_alter_table_auth_users_alter_column_refresh_token/down.sql @@ -0,0 +1,2 @@ +alter table "auth"."users" alter column "refresh_token" set default gen_random_uuid(); +ALTER TABLE "auth"."users" ALTER COLUMN "refresh_token" TYPE uuid; diff --git a/targets/hasura/migrations/default/1711289911681_alter_table_auth_users_alter_column_refresh_token/up.sql b/targets/hasura/migrations/default/1711289911681_alter_table_auth_users_alter_column_refresh_token/up.sql new file mode 100644 index 000000000..d853cc845 --- /dev/null +++ b/targets/hasura/migrations/default/1711289911681_alter_table_auth_users_alter_column_refresh_token/up.sql @@ -0,0 +1,2 @@ +ALTER TABLE "auth"."users" ALTER COLUMN "refresh_token" TYPE text; +ALTER TABLE "auth"."users" ALTER COLUMN "refresh_token" drop default; diff --git a/targets/hasura/migrations/default/1711289930124_alter_table_auth_users_alter_column_refresh_token/down.sql b/targets/hasura/migrations/default/1711289930124_alter_table_auth_users_alter_column_refresh_token/down.sql new file mode 100644 index 000000000..c221e2b4e --- /dev/null +++ b/targets/hasura/migrations/default/1711289930124_alter_table_auth_users_alter_column_refresh_token/down.sql @@ -0,0 +1,2 @@ +alter table "auth"."users" drop constraint "users_refresh_token_key"; +alter table "auth"."users" alter column "refresh_token" set not null; diff --git a/targets/hasura/migrations/default/1711289930124_alter_table_auth_users_alter_column_refresh_token/up.sql b/targets/hasura/migrations/default/1711289930124_alter_table_auth_users_alter_column_refresh_token/up.sql new file mode 100644 index 000000000..4976738f8 --- /dev/null +++ b/targets/hasura/migrations/default/1711289930124_alter_table_auth_users_alter_column_refresh_token/up.sql @@ -0,0 +1,2 @@ +alter table "auth"."users" alter column "refresh_token" drop not null; +alter table "auth"."users" add constraint "users_refresh_token_key" unique ("refresh_token"); diff --git a/targets/hasura/migrations/default/1711289953743_alter_table_auth_users_alter_column_access_token/down.sql b/targets/hasura/migrations/default/1711289953743_alter_table_auth_users_alter_column_access_token/down.sql new file mode 100644 index 000000000..a5ab4a7bf --- /dev/null +++ b/targets/hasura/migrations/default/1711289953743_alter_table_auth_users_alter_column_access_token/down.sql @@ -0,0 +1,3 @@ +alter table "auth"."users" drop constraint "users_access_token_key"; +alter table "auth"."users" alter column "access_token" set default gen_random_uuid(); +ALTER TABLE "auth"."users" ALTER COLUMN "access_token" TYPE uuid; diff --git a/targets/hasura/migrations/default/1711289953743_alter_table_auth_users_alter_column_access_token/up.sql b/targets/hasura/migrations/default/1711289953743_alter_table_auth_users_alter_column_access_token/up.sql new file mode 100644 index 000000000..1f14d9f93 --- /dev/null +++ b/targets/hasura/migrations/default/1711289953743_alter_table_auth_users_alter_column_access_token/up.sql @@ -0,0 +1,3 @@ +ALTER TABLE "auth"."users" ALTER COLUMN "access_token" TYPE text; +ALTER TABLE "auth"."users" ALTER COLUMN "access_token" drop default; +alter table "auth"."users" add constraint "users_access_token_key" unique ("access_token"); diff --git a/targets/hasura/migrations/default/1711469151306_alter_table_auth_users_drop_column_access_token/down.sql b/targets/hasura/migrations/default/1711469151306_alter_table_auth_users_drop_column_access_token/down.sql new file mode 100644 index 000000000..4fb9ef420 --- /dev/null +++ b/targets/hasura/migrations/default/1711469151306_alter_table_auth_users_drop_column_access_token/down.sql @@ -0,0 +1,4 @@ +comment on column "auth"."users"."access_token" is E'Users table'; +alter table "auth"."users" add constraint "users_access_token_key" unique (access_token); +alter table "auth"."users" alter column "access_token" drop not null; +alter table "auth"."users" add column "access_token" text; diff --git a/targets/hasura/migrations/default/1711469151306_alter_table_auth_users_drop_column_access_token/up.sql b/targets/hasura/migrations/default/1711469151306_alter_table_auth_users_drop_column_access_token/up.sql new file mode 100644 index 000000000..681e804d4 --- /dev/null +++ b/targets/hasura/migrations/default/1711469151306_alter_table_auth_users_drop_column_access_token/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" drop column "access_token" cascade; diff --git a/targets/hasura/migrations/default/1711469221795_alter_table_auth_users_add_column_access_token/down.sql b/targets/hasura/migrations/default/1711469221795_alter_table_auth_users_add_column_access_token/down.sql new file mode 100644 index 000000000..db7dfb238 --- /dev/null +++ b/targets/hasura/migrations/default/1711469221795_alter_table_auth_users_add_column_access_token/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "auth"."users" add column "access_token" text +-- null unique; diff --git a/targets/hasura/migrations/default/1711469221795_alter_table_auth_users_add_column_access_token/up.sql b/targets/hasura/migrations/default/1711469221795_alter_table_auth_users_add_column_access_token/up.sql new file mode 100644 index 000000000..8e3e0c098 --- /dev/null +++ b/targets/hasura/migrations/default/1711469221795_alter_table_auth_users_add_column_access_token/up.sql @@ -0,0 +1,2 @@ +alter table "auth"."users" add column "access_token" text + null unique; diff --git a/targets/hasura/migrations/default/1711541152381_alter_table_auth_users_drop_column_refresh_token/down.sql b/targets/hasura/migrations/default/1711541152381_alter_table_auth_users_drop_column_refresh_token/down.sql new file mode 100644 index 000000000..5b7508bf5 --- /dev/null +++ b/targets/hasura/migrations/default/1711541152381_alter_table_auth_users_drop_column_refresh_token/down.sql @@ -0,0 +1,4 @@ +comment on column "auth"."users"."refresh_token" is E'Users table'; +alter table "auth"."users" add constraint "users_refresh_token_key" unique (refresh_token); +alter table "auth"."users" alter column "refresh_token" drop not null; +alter table "auth"."users" add column "refresh_token" text; diff --git a/targets/hasura/migrations/default/1711541152381_alter_table_auth_users_drop_column_refresh_token/up.sql b/targets/hasura/migrations/default/1711541152381_alter_table_auth_users_drop_column_refresh_token/up.sql new file mode 100644 index 000000000..514154f60 --- /dev/null +++ b/targets/hasura/migrations/default/1711541152381_alter_table_auth_users_drop_column_refresh_token/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" drop column "refresh_token" cascade; diff --git a/targets/hasura/migrations/default/1711541174570_alter_table_auth_users_drop_column_access_token/down.sql b/targets/hasura/migrations/default/1711541174570_alter_table_auth_users_drop_column_access_token/down.sql new file mode 100644 index 000000000..4fb9ef420 --- /dev/null +++ b/targets/hasura/migrations/default/1711541174570_alter_table_auth_users_drop_column_access_token/down.sql @@ -0,0 +1,4 @@ +comment on column "auth"."users"."access_token" is E'Users table'; +alter table "auth"."users" add constraint "users_access_token_key" unique (access_token); +alter table "auth"."users" alter column "access_token" drop not null; +alter table "auth"."users" add column "access_token" text; diff --git a/targets/hasura/migrations/default/1711541174570_alter_table_auth_users_drop_column_access_token/up.sql b/targets/hasura/migrations/default/1711541174570_alter_table_auth_users_drop_column_access_token/up.sql new file mode 100644 index 000000000..681e804d4 --- /dev/null +++ b/targets/hasura/migrations/default/1711541174570_alter_table_auth_users_drop_column_access_token/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" drop column "access_token" cascade; diff --git a/targets/hasura/migrations/default/1711541187969_alter_table_auth_users_drop_column_expires_in/down.sql b/targets/hasura/migrations/default/1711541187969_alter_table_auth_users_drop_column_expires_in/down.sql new file mode 100644 index 000000000..c6ed1961f --- /dev/null +++ b/targets/hasura/migrations/default/1711541187969_alter_table_auth_users_drop_column_expires_in/down.sql @@ -0,0 +1,4 @@ +comment on column "auth"."users"."expires_in" is E'Users table'; +alter table "auth"."users" alter column "expires_in" set default now(); +alter table "auth"."users" alter column "expires_in" drop not null; +alter table "auth"."users" add column "expires_in" timestamptz; diff --git a/targets/hasura/migrations/default/1711541187969_alter_table_auth_users_drop_column_expires_in/up.sql b/targets/hasura/migrations/default/1711541187969_alter_table_auth_users_drop_column_expires_in/up.sql new file mode 100644 index 000000000..d228dca32 --- /dev/null +++ b/targets/hasura/migrations/default/1711541187969_alter_table_auth_users_drop_column_expires_in/up.sql @@ -0,0 +1 @@ +alter table "auth"."users" drop column "expires_in" cascade; diff --git a/targets/hasura/migrations/default/1711541218864_drop_index_users_access_token_key/down.sql b/targets/hasura/migrations/default/1711541218864_drop_index_users_access_token_key/down.sql new file mode 100644 index 000000000..c7ea2c736 --- /dev/null +++ b/targets/hasura/migrations/default/1711541218864_drop_index_users_access_token_key/down.sql @@ -0,0 +1,2 @@ +CREATE INDEX "users_access_token_key" on + "auth"."users" using btree ("access_token"); diff --git a/targets/hasura/migrations/default/1711541218864_drop_index_users_access_token_key/up.sql b/targets/hasura/migrations/default/1711541218864_drop_index_users_access_token_key/up.sql new file mode 100644 index 000000000..1055b8a27 --- /dev/null +++ b/targets/hasura/migrations/default/1711541218864_drop_index_users_access_token_key/up.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS "auth"."users_access_token_key"; diff --git a/targets/ingester/package.json b/targets/ingester/package.json index 1501e2bf0..ed0c2c5a6 100644 --- a/targets/ingester/package.json +++ b/targets/ingester/package.json @@ -44,7 +44,7 @@ "lint-staged": "^12.0.0", "ts-jest": "^27.0.5", "ts-node": "10.8.0", - "typescript": "^4.4.3" + "typescript": "^5.4.3" }, "license": "MIT", "main": "dist/index.js", diff --git a/targets/ingester/src/articles/kali/load-supported-agreements.ts b/targets/ingester/src/articles/kali/load-supported-agreements.ts index dd9e3de24..3eaf3f362 100644 --- a/targets/ingester/src/articles/kali/load-supported-agreements.ts +++ b/targets/ingester/src/articles/kali/load-supported-agreements.ts @@ -22,7 +22,7 @@ query LoadAgreements { export const loadSupportedAgreements = async (): Promise => { const result = await gqlClient() - .query(loadSupportedAgreementsQuery) + .query(loadSupportedAgreementsQuery, {}) .toPromise(); if (result.error) { diff --git a/targets/ingester/src/lib/fetchContributions/ContributionRepository.ts b/targets/ingester/src/lib/fetchContributions/ContributionRepository.ts index 585c320bf..80e51fb35 100644 --- a/targets/ingester/src/lib/fetchContributions/ContributionRepository.ts +++ b/targets/ingester/src/lib/fetchContributions/ContributionRepository.ts @@ -1,5 +1,4 @@ import { gqlClient } from "@shared/utils"; -import type { Client } from "@urql/core/dist/types/client"; import { fetchAllContributions } from "./query"; import type { QuestionRaw } from "./types"; @@ -9,13 +8,9 @@ export interface ContributionRepository { } export class ContributionDatabase implements ContributionRepository { - constructor() { - this.client = gqlClient(); - } - public async fetchAll(): Promise { const res = await gqlClient() - .query<{ questions: QuestionRaw[] }>(fetchAllContributions) + .query<{ questions: QuestionRaw[] }>(fetchAllContributions, {}) .toPromise(); if (res.error) { throw res.error; @@ -25,6 +20,4 @@ export class ContributionDatabase implements ContributionRepository { } return res.data.questions; } - - private readonly client: Client; } diff --git a/targets/ingester/src/lib/hasura-mutations-queries.ts b/targets/ingester/src/lib/hasura-mutations-queries.ts index 827440193..bb692f1ec 100644 --- a/targets/ingester/src/lib/hasura-mutations-queries.ts +++ b/targets/ingester/src/lib/hasura-mutations-queries.ts @@ -18,11 +18,14 @@ interface PackageVersionResult { } const updateDocumentAvailability = ` -mutation update_documents($source: String!) { - documents: update_documents(_set: {is_available: false}, where: {source: {_eq: $source}, is_available: {_eq: true}}) { - affected_rows + mutation update_documents($source: String!) { + documents: update_documents( + _set: { is_available: false } + where: { source: { _eq: $source }, is_available: { _eq: true } } + ) { + affected_rows + } } -} `; interface UpdateDocumentAvailabilityResult { @@ -32,36 +35,60 @@ interface UpdateDocumentAvailabilityResult { } const insertDocumentsMutation = ` -mutation insert_documents($documents: [documents_insert_input!]!) { - documents: insert_documents(objects: $documents, on_conflict: { - constraint: documents_pkey, - update_columns: [title, source, slug, text, document, is_available, is_searchable] - }) { - returning {cdtn_id} + mutation insert_documents($documents: [documents_insert_input!]!) { + documents: insert_documents( + objects: $documents + on_conflict: { + constraint: documents_pkey + update_columns: [ + title + source + slug + text + document + is_available + is_searchable + ] + } + ) { + returning { + cdtn_id + } + } } -} `; const insertDocumentsWithoutSlugMutation = ` -mutation insert_documents($documents: [documents_insert_input!]!) { - documents: insert_documents(objects: $documents, on_conflict: { - constraint: documents_pkey, - update_columns: [title, source, text, document, is_available, is_searchable] - }) { - returning {cdtn_id} + mutation insert_documents($documents: [documents_insert_input!]!) { + documents: insert_documents( + objects: $documents + on_conflict: { + constraint: documents_pkey + update_columns: [ + title + source + text + document + is_available + is_searchable + ] + } + ) { + returning { + cdtn_id + } + } } -} `; const updatePublishStatusDocumentsMutation = ` -mutation update_published_status_documents($updates: [documents_updates!]!) { - update_documents_many(updates: $updates) { - returning { - cdtn_id + mutation update_published_status_documents($updates: [documents_updates!]!) { + update_documents_many(updates: $updates) { + returning { + cdtn_id + } } } -} - `; interface InsertdocumentResult { @@ -69,14 +96,15 @@ interface InsertdocumentResult { } const insertPackageVersionMutation = ` -mutation insert_package_version($object:package_version_insert_input!) { - version: insert_package_version_one(object: $object, on_conflict: { - constraint: package_version_pkey, - update_columns: version - }) { - repository, version + mutation insert_package_version($object: package_version_insert_input!) { + version: insert_package_version_one( + object: $object + on_conflict: { constraint: package_version_pkey, update_columns: version } + ) { + repository + version + } } -} `; interface UpsertPackageVersionResult { diff --git a/targets/ingester/src/transform/fichesServicePublic/fetchAgreementsWithKaliId.ts b/targets/ingester/src/transform/fichesServicePublic/fetchAgreementsWithKaliId.ts index 4447f1d65..8391d98f1 100644 --- a/targets/ingester/src/transform/fichesServicePublic/fetchAgreementsWithKaliId.ts +++ b/targets/ingester/src/transform/fichesServicePublic/fetchAgreementsWithKaliId.ts @@ -24,7 +24,7 @@ interface HasuraReturn { export async function fetchAgreementsWithKaliId() { const res = await gqlClient() - .query(getAgreementsWithKaliId) + .query(getAgreementsWithKaliId, {}) .toPromise(); if (res.error) { throw res.error; diff --git a/targets/ingester/src/transform/fichesServicePublic/index.ts b/targets/ingester/src/transform/fichesServicePublic/index.ts index 3effae323..84b361992 100644 --- a/targets/ingester/src/transform/fichesServicePublic/index.ts +++ b/targets/ingester/src/transform/fichesServicePublic/index.ts @@ -42,7 +42,7 @@ export default async function getFichesServicePublic(pkgName: string) { const resolveCdtReference = createReferenceResolver(cdt); const results = await gqlClient() - .query(getFicheIdsQuery) + .query(getFicheIdsQuery, {}) .toPromise(); if (results.error) { diff --git a/yarn.lock b/yarn.lock index 25bc875bf..c8f97ad33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17,6 +17,18 @@ __metadata: languageName: node linkType: hard +"@0no-co/graphql.web@npm:^1.0.5": + version: 1.0.6 + resolution: "@0no-co/graphql.web@npm:1.0.6" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 + peerDependenciesMeta: + graphql: + optional: true + checksum: a83e3d9b10cd7259fd5c9b6f548c602aecb343c9fba1a5dc628369b8638c69505b62281ac7b5f52284f5188f4d899096d8acd2a8cea8b3f7afce8f44e469f1cb + languageName: node + linkType: hard + "@adobe/css-tools@npm:^4.0.1": version: 4.2.0 resolution: "@adobe/css-tools@npm:4.2.0" @@ -1579,6 +1591,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.20.13": + version: 7.24.4 + resolution: "@babel/runtime@npm:7.24.4" + dependencies: + regenerator-runtime: ^0.14.0 + checksum: 2f27d4c0ffac7ae7999ac0385e1106f2a06992a8bdcbf3da06adcac7413863cd08c198c2e4e970041bbea849e17f02e1df18875539b6afba76c781b6b59a07c3 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.22.15": version: 7.23.1 resolution: "@babel/runtime@npm:7.23.1" @@ -1953,15 +1974,6 @@ __metadata: languageName: node linkType: hard -"@graphql-typed-document-node/core@npm:^3.1.1": - version: 3.2.0 - resolution: "@graphql-typed-document-node/core@npm:3.2.0" - peerDependencies: - graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: fa44443accd28c8cf4cb96aaaf39d144a22e8b091b13366843f4e97d19c7bfeaf609ce3c7603a4aeffe385081eaf8ea245d078633a7324c11c5ec4b2011bb76d - languageName: node - linkType: hard - "@hapi/boom@npm:9.x.x, @hapi/boom@npm:^9.1.4": version: 9.1.4 resolution: "@hapi/boom@npm:9.1.4" @@ -2140,7 +2152,7 @@ __metadata: languageName: node linkType: hard -"@jest/core@npm:^27.0.6, @jest/core@npm:^27.5.1": +"@jest/core@npm:^27.5.1": version: 27.5.1 resolution: "@jest/core@npm:27.5.1" dependencies: @@ -3918,81 +3930,81 @@ __metadata: languageName: node linkType: hard -"@next/env@npm:14.0.1": - version: 14.0.1 - resolution: "@next/env@npm:14.0.1" - checksum: 1fab6732f877c3702fce12396f16046f9b7a59c70b0d0b3db713995eed431706d12175530709d21c613682865ce82ef965a5719a43d6bc84142462a8ed558cda +"@next/env@npm:14.1.4": + version: 14.1.4 + resolution: "@next/env@npm:14.1.4" + checksum: 2f3ea0c9820546cc10acc5b01b1f1eadc702ceb20a5c63f6e77a75c9a721388980a8242d10476fb16d17d8dfb1477cd8586fe5e8c396732a4c15493b3ccc096e languageName: node linkType: hard -"@next/eslint-plugin-next@npm:14.0.1": - version: 14.0.1 - resolution: "@next/eslint-plugin-next@npm:14.0.1" +"@next/eslint-plugin-next@npm:14.1.4": + version: 14.1.4 + resolution: "@next/eslint-plugin-next@npm:14.1.4" dependencies: - glob: 7.1.7 - checksum: 2bb3cd1035414a1cf645772297224bf50cb81947c2aae8a8c0caee20f2b8f1931dab0f16c0dabfb08eb61a247a0006b57d98dd81ae02558470808f1e22fa7665 + glob: 10.3.10 + checksum: 1609432d9e28910e2a7b74242d3181b106af12fff241b5f61b82b467d1d16c812a71a94cdd040e0338575ed55ddc016ecd6c58d08c8b8eb031f030fdd778c8d2 languageName: node linkType: hard -"@next/swc-darwin-arm64@npm:14.0.1": - version: 14.0.1 - resolution: "@next/swc-darwin-arm64@npm:14.0.1" +"@next/swc-darwin-arm64@npm:14.1.4": + version: 14.1.4 + resolution: "@next/swc-darwin-arm64@npm:14.1.4" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@next/swc-darwin-x64@npm:14.0.1": - version: 14.0.1 - resolution: "@next/swc-darwin-x64@npm:14.0.1" +"@next/swc-darwin-x64@npm:14.1.4": + version: 14.1.4 + resolution: "@next/swc-darwin-x64@npm:14.1.4" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@next/swc-linux-arm64-gnu@npm:14.0.1": - version: 14.0.1 - resolution: "@next/swc-linux-arm64-gnu@npm:14.0.1" +"@next/swc-linux-arm64-gnu@npm:14.1.4": + version: 14.1.4 + resolution: "@next/swc-linux-arm64-gnu@npm:14.1.4" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-arm64-musl@npm:14.0.1": - version: 14.0.1 - resolution: "@next/swc-linux-arm64-musl@npm:14.0.1" +"@next/swc-linux-arm64-musl@npm:14.1.4": + version: 14.1.4 + resolution: "@next/swc-linux-arm64-musl@npm:14.1.4" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@next/swc-linux-x64-gnu@npm:14.0.1": - version: 14.0.1 - resolution: "@next/swc-linux-x64-gnu@npm:14.0.1" +"@next/swc-linux-x64-gnu@npm:14.1.4": + version: 14.1.4 + resolution: "@next/swc-linux-x64-gnu@npm:14.1.4" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-x64-musl@npm:14.0.1": - version: 14.0.1 - resolution: "@next/swc-linux-x64-musl@npm:14.0.1" +"@next/swc-linux-x64-musl@npm:14.1.4": + version: 14.1.4 + resolution: "@next/swc-linux-x64-musl@npm:14.1.4" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@next/swc-win32-arm64-msvc@npm:14.0.1": - version: 14.0.1 - resolution: "@next/swc-win32-arm64-msvc@npm:14.0.1" +"@next/swc-win32-arm64-msvc@npm:14.1.4": + version: 14.1.4 + resolution: "@next/swc-win32-arm64-msvc@npm:14.1.4" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@next/swc-win32-ia32-msvc@npm:14.0.1": - version: 14.0.1 - resolution: "@next/swc-win32-ia32-msvc@npm:14.0.1" +"@next/swc-win32-ia32-msvc@npm:14.1.4": + version: 14.1.4 + resolution: "@next/swc-win32-ia32-msvc@npm:14.1.4" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@next/swc-win32-x64-msvc@npm:14.0.1": - version: 14.0.1 - resolution: "@next/swc-win32-x64-msvc@npm:14.0.1" +"@next/swc-win32-x64-msvc@npm:14.1.4": + version: 14.1.4 + resolution: "@next/swc-win32-x64-msvc@npm:14.1.4" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -4445,6 +4457,13 @@ __metadata: languageName: node linkType: hard +"@panva/hkdf@npm:^1.0.2": + version: 1.1.1 + resolution: "@panva/hkdf@npm:1.1.1" + checksum: f0dd12903751d8792420353f809ed3c7de860cf506399759fff5f59f7acfef8a77e2b64012898cee7e5b047708fa0bd91dff5ef55a502bf8ea11aad9842160da + languageName: node + linkType: hard + "@parcel/watcher@npm:2.0.4": version: 2.0.4 resolution: "@parcel/watcher@npm:2.0.4" @@ -4774,7 +4793,7 @@ __metadata: dependencies: "@socialgouv/kali-data-types": ^2.127.0 "@socialgouv/legi-data-types": ^2.73.1 - typescript: ^4.9.5 + typescript: ^5.4.3 languageName: unknown linkType: soft @@ -4789,11 +4808,11 @@ __metadata: "@swc/jest": ^0.2.29 "@types/uuid": ^9.0.5 "@types/xxhashjs": ^0.2.2 - "@urql/core": ^2.4.3 - graphql: ^16.3.0 - isomorphic-unfetch: ^3.1.0 + "@urql/core": ^4.3.0 + graphql: ^16.8.1 + isomorphic-unfetch: ^4.0.2 jest: ^29.7.0 - typescript: ^5.3.3 + typescript: ^5.4.3 uuid: ^9.0.1 winston: 3.3.3 xxhashjs: ^0.2.2 @@ -5616,15 +5635,6 @@ __metadata: languageName: node linkType: hard -"@socialgouv/matomo-next@npm:^1.2.2": - version: 1.6.1 - resolution: "@socialgouv/matomo-next@npm:1.6.1" - peerDependencies: - next: ">= 9.5.5" - checksum: 748d2b7792f002afc4ed9660616ff23f826b6fea5b3b02d90db1668eb81e17410940320f8b50c63c282264735bd673341012632d95a5cd41937914e880c4eecd - languageName: node - linkType: hard - "@socialgouv/react-accessible-accordion@npm:4.1.1": version: 4.1.1 resolution: "@socialgouv/react-accessible-accordion@npm:4.1.1" @@ -6380,13 +6390,6 @@ __metadata: languageName: node linkType: hard -"@types/cookie@npm:^0.5.2": - version: 0.5.2 - resolution: "@types/cookie@npm:0.5.2" - checksum: 4a1e46379d877f5a3cc687a9799dd72e5f7e68c4764d45cb469789dec92b4b4a7a5bb8b10a08c90be15939fa7b9b402f87ed339dfac0cabf43699c5189880e88 - languageName: node - linkType: hard - "@types/cookiejar@npm:*": version: 2.1.2 resolution: "@types/cookiejar@npm:2.1.2" @@ -6484,12 +6487,12 @@ __metadata: languageName: node linkType: hard -"@types/http-proxy@npm:^1.17.5": - version: 1.17.12 - resolution: "@types/http-proxy@npm:1.17.12" +"@types/http-proxy@npm:^1.17.10": + version: 1.17.14 + resolution: "@types/http-proxy@npm:1.17.14" dependencies: "@types/node": "*" - checksum: 89700c8e3c8f2c59c87c8db8e7a070c97a3b30a4a38223aca6b8b817e6f2ca931f5a500e16ecadc1ebcfed2676cc60e073d8f887e621d84420298728ec6fd000 + checksum: 491320bce3565bbb6c7d39d25b54bce626237cfb6b09e60ee7f77b56ae7c6cbad76f08d47fe01eaa706781124ee3dfad9bb737049254491efd98ed1f014c4e83 languageName: node linkType: hard @@ -6558,6 +6561,16 @@ __metadata: languageName: node linkType: hard +"@types/jest@npm:^29.5.12": + version: 29.5.12 + resolution: "@types/jest@npm:29.5.12" + dependencies: + expect: ^29.0.0 + pretty-format: ^29.0.0 + checksum: 19b1efdeed9d9a60a81edc8226cdeae5af7479e493eaed273e01243891c9651f7b8b4c08fc633a7d0d1d379b091c4179bbaa0807af62542325fd72f2dd17ce1c + languageName: node + linkType: hard + "@types/jsdom@npm:^20.0.0": version: 20.0.1 resolution: "@types/jsdom@npm:20.0.1" @@ -6583,12 +6596,12 @@ __metadata: languageName: node linkType: hard -"@types/jsonwebtoken@npm:^9.0.3": - version: 9.0.3 - resolution: "@types/jsonwebtoken@npm:9.0.3" +"@types/jsonwebtoken@npm:^9.0.6": + version: 9.0.6 + resolution: "@types/jsonwebtoken@npm:9.0.6" dependencies: "@types/node": "*" - checksum: 2debf3adb19b827a023205234ec439b7258aee6ca9273472abe360738a84f08db78c6e853172e842ec303169ec0bb2df39701ab9a13b9e7868fe284ef9136567 + checksum: a568e7cb1c703bcb015eff8bf5996e276e748d2b39ddc47edf5ddccd1378f5792179c43302a1c803e47a54b0220f9ecaae445ec444d28bf81b88856f899e85b9 languageName: node linkType: hard @@ -6689,6 +6702,15 @@ __metadata: languageName: node linkType: hard +"@types/nodemailer@npm:^6.4.14": + version: 6.4.14 + resolution: "@types/nodemailer@npm:6.4.14" + dependencies: + "@types/node": "*" + checksum: 5f61f01dd736b17f431d1e8b320322f86460604b45df947fc4bc8999d7c7719405e349f7abba86e4fb100a464a30b52615d00dac03d9cb37562ff04487ebd310 + languageName: node + linkType: hard + "@types/normalize-package-data@npm:^2.4.0": version: 2.4.1 resolution: "@types/normalize-package-data@npm:2.4.1" @@ -6752,7 +6774,16 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.0.11": +"@types/react-dom@npm:18.2.0": + version: 18.2.0 + resolution: "@types/react-dom@npm:18.2.0" + dependencies: + "@types/react": "*" + checksum: 9212b3793707a763f10e2c608f6ccb5f729029da6cb84204f333634d3d7baafbc1b20b7faf7cf788a8fd385050a1fb579902031f9462473ef10607116f33f33c + languageName: node + linkType: hard + +"@types/react-dom@npm:^18.0.0": version: 18.2.6 resolution: "@types/react-dom@npm:18.2.6" dependencies: @@ -6781,14 +6812,14 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:^17.0.24": - version: 17.0.62 - resolution: "@types/react@npm:17.0.62" +"@types/react@npm:18.2.0": + version: 18.2.0 + resolution: "@types/react@npm:18.2.0" dependencies: "@types/prop-types": "*" "@types/scheduler": "*" csstype: ^3.0.2 - checksum: 428a5aff44824ef504e9a9259b5894fe44a5db1c344b536990f07e132900ff5b34cbef0be77a84f30f37be1f88fc8b56dce328f568de8d65de3bfe414c05b2e1 + checksum: db3d92b423150222a666329f7aa3023e3e942044700557b8a7d161530847e621aec9f56c9e7f71761b06dd164c8a7b17ad52355863efe80963dffa5537e8e5fd languageName: node linkType: hard @@ -7166,49 +7197,33 @@ __metadata: languageName: node linkType: hard -"@urql/core@npm:>=2.3.6": - version: 4.0.10 - resolution: "@urql/core@npm:4.0.10" +"@urql/core@npm:>=4.1.0, @urql/core@npm:^5.0.0": + version: 5.0.0 + resolution: "@urql/core@npm:5.0.0" dependencies: - "@0no-co/graphql.web": ^1.0.1 + "@0no-co/graphql.web": ^1.0.5 wonka: ^6.3.2 - checksum: adeb666c632acbd85dbb6d48aab81b8ec26e839ff525b71a93e6d0cc1632bab49b4615585527ccc8b98fbf5c2e1a9f5c20bdd92d3f89d573803f069d97ea09eb + checksum: a7e546486c5a940128ed7c1c88b41b1d7d501725137f6e3050258717ed71d1172d21039de2a34aa0713adb264c95c5857029be6de0fafabbc541bb364255e055 languageName: node linkType: hard -"@urql/core@npm:^2.4.3, @urql/core@npm:^2.6.1": - version: 2.6.1 - resolution: "@urql/core@npm:2.6.1" - dependencies: - "@graphql-typed-document-node/core": ^3.1.1 - wonka: ^4.0.14 - peerDependencies: - graphql: ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: d3bdc343d77b2473c1fbc02bd8669376e46f00ac93efb387e7df7783b62b201096531f3021668e696b40bbf6c5cbb6bcdc79905e16b9c4603baf6174a4949153 - languageName: node - linkType: hard - -"@urql/devtools@npm:^2.0.3": - version: 2.0.3 - resolution: "@urql/devtools@npm:2.0.3" +"@urql/core@npm:^4.3.0": + version: 4.3.0 + resolution: "@urql/core@npm:4.3.0" dependencies: - wonka: ">= 4.0.9" - peerDependencies: - "@urql/core": ">= 1.14.0" - graphql: ">= 0.11.0" - checksum: 9b4a46dd0b6cca5296667bc0e658212c3101cd1c0d01dcc0be736e5b5159beaf6aa982115dd7546ff5425ed91e1688132a82a8f101bf8ad560245b97bb533f59 + "@0no-co/graphql.web": ^1.0.1 + wonka: ^6.3.2 + checksum: 706e4f28390a1ee441588bfb2ab1517e620c2b63ed26756e8e5dd808acb6c871b1d0d760d569b162af773bff05df3d90fed753963ce70806fa8ca1f7a37bb7e9 languageName: node linkType: hard -"@urql/exchange-auth@npm:^0.1.6": - version: 0.1.7 - resolution: "@urql/exchange-auth@npm:0.1.7" +"@urql/exchange-auth@npm:^2.1.6": + version: 2.1.6 + resolution: "@urql/exchange-auth@npm:2.1.6" dependencies: - "@urql/core": ">=2.3.6" - wonka: ^4.0.14 - peerDependencies: - graphql: ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 36036f02d7873f9fd9385b16f1980a85918307cf23ffad83152bd67aa93b16a405c44f2e5c2b378fdef1837c33dfcc9b0db22143127a43a63da2c3c378c0600e + "@urql/core": ">=4.1.0" + wonka: ^6.3.2 + checksum: 180694184d36c32ad8d408a508886f338aca34117c57874e509e6a20e8f4b4fba7aa8770b63722873e634b69e85b6e7ddab9605187da2dda65f160d18e4e1959 languageName: node linkType: hard @@ -7436,7 +7451,7 @@ __metadata: "@socialgouv/kali-data-types": 2.127.0 "@socialgouv/legi-data-types": 2.73.1 "@types/diff": ^5.0.3 - "@types/jest": 27.4.0 + "@types/jest": ^29.5.12 "@types/memoizee": 0.4.6 "@types/node": 16.11.11 "@types/semver": 7.3.8 @@ -7445,16 +7460,16 @@ __metadata: axios: ^1.5.0 builtin-modules: 3.2.0 diff: ^5.1.0 - jest: 27.0.6 + jest: ^29.7.0 lint-staged: 12.0.0 memoizee: 0.4.15 node-xlsx: ^0.23.0 p-map: 4 semver: 7.3.5 simple-git: ^3.19.1 - ts-jest: 27.0.5 + ts-jest: ^29.1.2 ts-node: 10.8.0 - typescript: 4.7.2 + typescript: ^5.4.3 unist-util-parents: 1.0.3 unist-util-select: 4.0.1 languageName: unknown @@ -8622,13 +8637,20 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001406, caniuse-lite@npm:^1.0.30001503": +"caniuse-lite@npm:^1.0.30001503": version: 1.0.30001508 resolution: "caniuse-lite@npm:1.0.30001508" checksum: 0a083ed92194d87e608fc35cac65830a27900249729eb8a68e270f866f2c4f83396c2e54eb47b0ef71360682174dd74e2e68eac0b8d407d125611c7bc12488eb languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001579": + version: 1.0.30001605 + resolution: "caniuse-lite@npm:1.0.30001605" + checksum: 8af1ae364c4f4c0796e7fd1aa195dfae2d9c3011c61f0907030201e4fc31a12e81407a13cca621a3b7f6a1eb0217ee9c681fb15670074c204a54edfab798d5c9 + languageName: node + linkType: hard + "case-anything@npm:^2.1.10": version: 2.1.13 resolution: "case-anything@npm:2.1.13" @@ -9348,20 +9370,13 @@ __metadata: languageName: node linkType: hard -"cookie@npm:0.5.0": +"cookie@npm:0.5.0, cookie@npm:^0.5.0": version: 0.5.0 resolution: "cookie@npm:0.5.0" checksum: 1f4bd2ca5765f8c9689a7e8954183f5332139eb72b6ff783d8947032ec1fdf43109852c178e21a953a30c0dd42257828185be01b49d1eb1a67fd054ca588a180 languageName: node linkType: hard -"cookie@npm:^0.4.1": - version: 0.4.2 - resolution: "cookie@npm:0.4.2" - checksum: a00833c998bedf8e787b4c342defe5fa419abd96b32f4464f718b91022586b8f1bafbddd499288e75c037642493c83083da426c6a9080d309e3bd90fd11baa9b - languageName: node - linkType: hard - "cookiejar@npm:^2.1.4": version: 2.1.4 resolution: "cookiejar@npm:2.1.4" @@ -9964,6 +9979,13 @@ __metadata: languageName: node linkType: hard +"data-uri-to-buffer@npm:^4.0.0": + version: 4.0.1 + resolution: "data-uri-to-buffer@npm:4.0.1" + checksum: 0d0790b67ffec5302f204c2ccca4494f70b4e2d940fea3d36b09f0bb2b8539c2e86690429eb1f1dc4bcc9e4df0644193073e63d9ee48ac9fce79ec1506e4aa4c + languageName: node + linkType: hard + "data-urls@npm:^2.0.0": version: 2.0.0 resolution: "data-urls@npm:2.0.0" @@ -10989,11 +11011,11 @@ __metadata: languageName: node linkType: hard -"eslint-config-next@npm:14.0.1": - version: 14.0.1 - resolution: "eslint-config-next@npm:14.0.1" +"eslint-config-next@npm:14.1.4": + version: 14.1.4 + resolution: "eslint-config-next@npm:14.1.4" dependencies: - "@next/eslint-plugin-next": 14.0.1 + "@next/eslint-plugin-next": 14.1.4 "@rushstack/eslint-patch": ^1.3.3 "@typescript-eslint/parser": ^5.4.2 || ^6.0.0 eslint-import-resolver-node: ^0.3.6 @@ -11008,7 +11030,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: c70d6b68a6d0f2293cc41d171b38bda04ebc3337148db9eac361582de20e0bb1037bf080bb1723bc6cdae14c4953e5fce271e564bfc444f077fd3a3b64c82cc0 + checksum: 74cbaa5514a7a072731c7df01581017221538010691bb4a30d7bffac29cf2e1560d6aed3f9b97f3bee94113aace5c530b91159504f394dd0175e30c654457246 languageName: node linkType: hard @@ -11492,7 +11514,7 @@ __metadata: rimraf: 3.0.2 supertest: ^6.2.2 timekeeper: ^2.2.0 - typescript: 4.6.2 + typescript: ^5.4.3 unified: ^9.2.2 zod: ^3.14.2 languageName: unknown @@ -11661,6 +11683,16 @@ __metadata: languageName: node linkType: hard +"fetch-blob@npm:^3.1.2, fetch-blob@npm:^3.1.4": + version: 3.2.0 + resolution: "fetch-blob@npm:3.2.0" + dependencies: + node-domexception: ^1.0.0 + web-streams-polyfill: ^3.0.3 + checksum: f19bc28a2a0b9626e69fd7cf3a05798706db7f6c7548da657cbf5026a570945f5eeaedff52007ea35c8bcd3d237c58a20bf1543bc568ab2422411d762dd3d5bf + languageName: node + linkType: hard + "figures@npm:3.2.0, figures@npm:^3.0.0": version: 3.2.0 resolution: "figures@npm:3.2.0" @@ -11890,6 +11922,15 @@ __metadata: languageName: node linkType: hard +"formdata-polyfill@npm:^4.0.10": + version: 4.0.10 + resolution: "formdata-polyfill@npm:4.0.10" + dependencies: + fetch-blob: ^3.1.2 + checksum: 82a34df292afadd82b43d4a740ce387bc08541e0a534358425193017bf9fb3567875dc5f69564984b1da979979b70703aa73dee715a17b6c229752ae736dd9db + languageName: node + linkType: hard + "formidable@npm:^2.0.0, formidable@npm:^2.1.2": version: 2.1.2 resolution: "formidable@npm:2.1.2" @@ -11947,7 +11988,6 @@ __metadata: "@socialgouv/cdtn-sources": ^4.52.1 "@socialgouv/cdtn-ui": ^4.92.0 "@socialgouv/cdtn-utils": ^4.121.1 - "@socialgouv/matomo-next": ^1.2.2 "@testing-library/jest-dom": ^5.16.5 "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.5.1 @@ -11963,52 +12003,48 @@ __metadata: "@tiptap/pm": ^2.1.12 "@tiptap/react": ^2.1.12 "@tiptap/starter-kit": ^2.1.12 - "@types/cookie": ^0.5.2 "@types/formidable": ^2.0.5 "@types/jest": ^27.4.0 - "@types/jsonwebtoken": ^9.0.3 + "@types/jsonwebtoken": ^9.0.6 "@types/lodash.get": ^4.4.7 - "@types/react": ^17.0.24 - "@types/react-dom": ^18.0.11 - "@urql/devtools": ^2.0.3 - "@urql/exchange-auth": ^0.1.6 + "@types/nodemailer": ^6.4.14 + "@types/react": 18.2.0 + "@types/react-dom": 18.2.0 + "@urql/exchange-auth": ^2.1.6 ace-builds: ^1.31.1 argon2: ^0.30.3 - cookie: ^0.4.1 d3: ^6.7.0 d3-hierarchy: ^2.0.0 date-fns: ^2.23.0 diff: ^5.0.0 eslint: ^8.41.0 - eslint-config-next: 14.0.1 + eslint-config-next: 14.1.4 formidable: ^2.0.0 - graphql: ^16.0.0 + graphql: ^16.8.1 graphql-tag: ^2.12.6 - http-proxy-middleware: 2.0.1 - isomorphic-unfetch: ^3.1.0 + http-proxy-middleware: ^3.0.0 jest: ^29.5.0 jest-environment-jsdom: ^29.5.0 - jsonwebtoken: ^8.5.1 + jsonwebtoken: ^9.0.2 lint-staged: ^12.0.0 mammoth: ^1.6.0 memoizee: ^0.4.15 micromark: ^2.11.4 mime-types: ^2.1.35 - next: 14.0.1 - next-urql: ^3.2.1 - nodemailer: ^6.6.5 + next: 14.1.4 + next-auth: ^4.24.7 + nodemailer: ^6.9.13 p-limit: ^4.0.0 polished: ^4.1.3 pretty-bytes: ^5.6.0 prop-types: ^15.7.2 - react: ^18.2.0 + react: 18.2.0 react-ace: ^10.1.0 react-autosuggest: ^10.1.0 - react-dom: ^18.2.0 + react-dom: 18.2.0 react-dropzone: 14.2.3 react-hook-form: ^7.43.9 react-icons: ^4.2.0 - react-is: ^17.0.2 react-sortable-hoc: ^2.0.0 rehype-raw: ^5.1.0 rehype-stringify: ^8.0.0 @@ -12019,11 +12055,10 @@ __metadata: sharp: ^0.32.6 strip-markdown: ^4.2.0 swr: ^1.0.1 - typescript: ^4.9.5 + typescript: ^5.4.3 unified: ^9.2.2 - urql: ^2.0.5 + urql: ^4.0.6 uuid: ^8.3.2 - wonka: ^4.0.15 zod: 3.21.4 languageName: unknown linkType: soft @@ -12436,10 +12471,18 @@ __metadata: languageName: node linkType: hard -"glob-to-regexp@npm:^0.4.1": - version: 0.4.1 - resolution: "glob-to-regexp@npm:0.4.1" - checksum: e795f4e8f06d2a15e86f76e4d92751cf8bbfcf0157cea5c2f0f35678a8195a750b34096b1256e436f0cebc1883b5ff0888c47348443e69546a5a87f9e1eb1167 +"glob@npm:10.3.10": + version: 10.3.10 + resolution: "glob@npm:10.3.10" + dependencies: + foreground-child: ^3.1.0 + jackspeak: ^2.3.5 + minimatch: ^9.0.1 + minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 + path-scurry: ^1.10.1 + bin: + glob: dist/esm/bin.mjs + checksum: 4f2fe2511e157b5a3f525a54092169a5f92405f24d2aed3142f4411df328baca13059f4182f1db1bf933e2c69c0bd89e57ae87edd8950cba8c7ccbe84f721cf3 languageName: node linkType: hard @@ -12457,20 +12500,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:7.1.7": - version: 7.1.7 - resolution: "glob@npm:7.1.7" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^3.0.4 - once: ^1.3.0 - path-is-absolute: ^1.0.0 - checksum: b61f48973bbdcf5159997b0874a2165db572b368b931135832599875919c237fc05c12984e38fe828e69aa8a921eb0e8a4997266211c517c9cfaae8a93988bb8 - languageName: node - linkType: hard - "glob@npm:^10.2.2": version: 10.3.0 resolution: "glob@npm:10.3.0" @@ -12667,7 +12696,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 @@ -12699,14 +12728,7 @@ __metadata: languageName: node linkType: hard -"graphql@npm:^16.0.0": - version: 16.7.1 - resolution: "graphql@npm:16.7.1" - checksum: c924d8428daf0e96a5ea43e9bc3cd1b6802899907d284478ac8f705c8fd233a0a51eef915f7569fb5de8acb2e85b802ccc6c85c2b157ad805c1e9adba5a299bd - languageName: node - linkType: hard - -"graphql@npm:^16.3.0": +"graphql@npm:^16.8.1": version: 16.8.1 resolution: "graphql@npm:16.8.1" checksum: 8d304b7b6f708c8c5cc164b06e92467dfe36aff6d4f2cf31dd19c4c2905a0e7b89edac4b7e225871131fd24e21460836b369de0c06532644d15b461d55b1ccc0 @@ -13106,16 +13128,17 @@ __metadata: languageName: node linkType: hard -"http-proxy-middleware@npm:2.0.1": - version: 2.0.1 - resolution: "http-proxy-middleware@npm:2.0.1" +"http-proxy-middleware@npm:^3.0.0": + version: 3.0.0 + resolution: "http-proxy-middleware@npm:3.0.0" dependencies: - "@types/http-proxy": ^1.17.5 + "@types/http-proxy": ^1.17.10 + debug: ^4.3.4 http-proxy: ^1.18.1 is-glob: ^4.0.1 is-plain-obj: ^3.0.0 - micromatch: ^4.0.2 - checksum: 0de65bc6644b6efae5d26cd3bec071ceaeb92f26856ffee5ecdde9c702ea1435936e7dfb09da2ac0883eada80fdc993e9925902fc10bf6625565d6365f8cb30f + micromatch: ^4.0.5 + checksum: 2c286f0604f7a08af707a8df8e6f043fca022e55df6f7f843ea48081c9288277fc7fd7196446a7c8e8568dd1db8bf89f1555b2bc8a11bda87123f9f28aebd3a5 languageName: node linkType: hard @@ -13357,7 +13380,7 @@ __metadata: tar-fs: 2.1.1 ts-jest: ^27.0.5 ts-node: 10.8.0 - typescript: ^4.4.3 + typescript: ^5.4.3 unist-util-filter: ^2.0.3 unist-util-find: 1.0.2 unist-util-flat-filter: 1.0.0 @@ -14112,13 +14135,13 @@ __metadata: languageName: node linkType: hard -"isomorphic-unfetch@npm:^3.1.0": - version: 3.1.0 - resolution: "isomorphic-unfetch@npm:3.1.0" +"isomorphic-unfetch@npm:^4.0.2": + version: 4.0.2 + resolution: "isomorphic-unfetch@npm:4.0.2" dependencies: - node-fetch: ^2.6.1 - unfetch: ^4.2.0 - checksum: 82b92fe4ec2823a81ab0fc0d11bd94d710e6f9a940d56b3cba31896d4345ec9ffc7949f4ff31ebcae84f6b95f7ebf3474c4c7452b834eb4078ea3f2c37e459c5 + node-fetch: ^3.2.0 + unfetch: ^5.0.0 + checksum: a5c22569f18a897c333aa2d7c0042214e1d26fc502b7b7dd451aca81f34a56557cb48faf63a3ad5c6534d610c043ef36b9e999211a2c0665eabdca9e9c86e398 languageName: node linkType: hard @@ -14213,6 +14236,19 @@ __metadata: languageName: node linkType: hard +"jackspeak@npm:^2.3.5": + version: 2.3.6 + resolution: "jackspeak@npm:2.3.6" + dependencies: + "@isaacs/cliui": ^8.0.2 + "@pkgjs/parseargs": ^0.11.0 + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 57d43ad11eadc98cdfe7496612f6bbb5255ea69fe51ea431162db302c2a11011642f50cfad57288bd0aea78384a0612b16e131944ad8ecd09d619041c8531b54 + languageName: node + linkType: hard + "jake@npm:^10.8.5": version: 10.8.7 resolution: "jake@npm:10.8.7" @@ -14342,7 +14378,7 @@ __metadata: languageName: node linkType: hard -"jest-cli@npm:^27.0.6, jest-cli@npm:^27.5.1": +"jest-cli@npm:^27.5.1": version: 27.5.1 resolution: "jest-cli@npm:27.5.1" dependencies: @@ -15405,31 +15441,31 @@ __metadata: languageName: node linkType: hard -"jest-util@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-util@npm:29.5.0" +"jest-util@npm:^29.0.0, jest-util@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-util@npm:29.7.0" dependencies: - "@jest/types": ^29.5.0 + "@jest/types": ^29.6.3 "@types/node": "*" chalk: ^4.0.0 ci-info: ^3.2.0 graceful-fs: ^4.2.9 picomatch: ^2.2.3 - checksum: fd9212950d34d2ecad8c990dda0d8ea59a8a554b0c188b53ea5d6c4a0829a64f2e1d49e6e85e812014933d17426d7136da4785f9cf76fff1799de51b88bc85d3 + checksum: 042ab4980f4ccd4d50226e01e5c7376a8556b472442ca6091a8f102488c0f22e6e8b89ea874111d2328a2080083bf3225c86f3788c52af0bd0345a00eb57a3ca languageName: node linkType: hard -"jest-util@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-util@npm:29.7.0" +"jest-util@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-util@npm:29.5.0" dependencies: - "@jest/types": ^29.6.3 + "@jest/types": ^29.5.0 "@types/node": "*" chalk: ^4.0.0 ci-info: ^3.2.0 graceful-fs: ^4.2.9 picomatch: ^2.2.3 - checksum: 042ab4980f4ccd4d50226e01e5c7376a8556b472442ca6091a8f102488c0f22e6e8b89ea874111d2328a2080083bf3225c86f3788c52af0bd0345a00eb57a3ca + checksum: fd9212950d34d2ecad8c990dda0d8ea59a8a554b0c188b53ea5d6c4a0829a64f2e1d49e6e85e812014933d17426d7136da4785f9cf76fff1799de51b88bc85d3 languageName: node linkType: hard @@ -15557,24 +15593,6 @@ __metadata: languageName: node linkType: hard -"jest@npm:27.0.6": - version: 27.0.6 - resolution: "jest@npm:27.0.6" - dependencies: - "@jest/core": ^27.0.6 - import-local: ^3.0.2 - jest-cli: ^27.0.6 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - bin: - jest: bin/jest.js - checksum: 60de979335cf28c03f8fdf8ba7aee240d72e11d2b918e50ed31a835b08debf593bca6ad058d3c323ffb670dcd8d5c060c22e0ec9a716fdb40ffa2134db7d6aca - languageName: node - linkType: hard - "jest@npm:27.5.1, jest@npm:^27.1.1": version: 27.5.1 resolution: "jest@npm:27.5.1" @@ -15644,6 +15662,13 @@ __metadata: languageName: node linkType: hard +"jose@npm:^4.15.5": + version: 4.15.5 + resolution: "jose@npm:4.15.5" + checksum: 7dde76447c7707bd4b448f914b216f3858e701aa83f00447434252461af5b9e159dcbffb88badea3f9616739526763581267c9560622f0a058df8d68c86d7f79 + languageName: node + linkType: hard + "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -15818,7 +15843,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:2.x, json5@npm:^2.2.2": +"json5@npm:2.x, json5@npm:^2.2.2, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: @@ -15877,9 +15902,9 @@ __metadata: languageName: node linkType: hard -"jsonwebtoken@npm:^8.5.1": - version: 8.5.1 - resolution: "jsonwebtoken@npm:8.5.1" +"jsonwebtoken@npm:^9.0.2": + version: 9.0.2 + resolution: "jsonwebtoken@npm:9.0.2" dependencies: jws: ^3.2.2 lodash.includes: ^4.3.0 @@ -15890,8 +15915,8 @@ __metadata: lodash.isstring: ^4.0.1 lodash.once: ^4.0.0 ms: ^2.1.1 - semver: ^5.6.0 - checksum: 93c9e3f23c59b758ac88ba15f4e4753b3749dfce7a6f7c40fb86663128a1e282db085eec852d4e0cbca4cefdcd3a8275ee255dbd08fcad0df26ad9f6e4cc853a + semver: ^7.5.4 + checksum: fc739a6a8b33f1974f9772dca7f8493ca8df4cc31c5a09dcfdb7cff77447dcf22f4236fb2774ef3fe50df0abeb8e1c6f4c41eba82f500a804ab101e2fbc9d61a languageName: node linkType: hard @@ -16427,7 +16452,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:4.x, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:^4.5.1, lodash@npm:^4.7.0": +"lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:^4.5.1, lodash@npm:^4.7.0": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -16523,6 +16548,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^10.2.0": + version: 10.2.0 + resolution: "lru-cache@npm:10.2.0" + checksum: eee7ddda4a7475deac51ac81d7dd78709095c6fa46e8350dc2d22462559a1faa3b81ed931d5464b13d48cbd7e08b46100b6f768c76833912bc444b99c37e25db + languageName: node + linkType: hard + "lru-cache@npm:^4.0.1": version: 4.1.5 resolution: "lru-cache@npm:4.1.5" @@ -16892,7 +16924,7 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": +"micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": version: 4.0.5 resolution: "micromatch@npm:4.0.5" dependencies: @@ -17124,6 +17156,13 @@ __metadata: languageName: node linkType: hard +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0": + version: 7.0.4 + resolution: "minipass@npm:7.0.4" + checksum: 87585e258b9488caf2e7acea242fd7856bbe9a2c84a7807643513a338d66f368c7d518200ad7b70a508664d408aa000517647b2930c259a8b1f9f0984f344a21 + languageName: node + linkType: hard + "minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": version: 2.1.2 resolution: "minizlib@npm:2.1.2" @@ -17294,6 +17333,31 @@ __metadata: languageName: node linkType: hard +"next-auth@npm:^4.24.7": + version: 4.24.7 + resolution: "next-auth@npm:4.24.7" + dependencies: + "@babel/runtime": ^7.20.13 + "@panva/hkdf": ^1.0.2 + cookie: ^0.5.0 + jose: ^4.15.5 + oauth: ^0.9.15 + openid-client: ^5.4.0 + preact: ^10.6.3 + preact-render-to-string: ^5.1.19 + uuid: ^8.3.2 + peerDependencies: + next: ^12.2.5 || ^13 || ^14 + nodemailer: ^6.6.5 + react: ^17.0.2 || ^18 + react-dom: ^17.0.2 || ^18 + peerDependenciesMeta: + nodemailer: + optional: true + checksum: e7849ecf86394d86f08730b96f869c9353b6cc003794fcd953db2949f1ab06a2ce4f7a67312fdb8c7b3bbe7e99a8a215f11ef4eba5ec93f6c3e8ac1954e8b3e6 + languageName: node + linkType: hard + "next-tick@npm:1, next-tick@npm:^1.1.0": version: 1.1.0 resolution: "next-tick@npm:1.1.0" @@ -17301,38 +17365,26 @@ __metadata: languageName: node linkType: hard -"next-urql@npm:^3.2.1": - version: 3.3.3 - resolution: "next-urql@npm:3.3.3" +"next@npm:14.1.4": + version: 14.1.4 + resolution: "next@npm:14.1.4" dependencies: - react-ssr-prepass: ^1.4.0 - peerDependencies: - react: ">=16.8.0" - urql: ^2.0.0 - checksum: fc6e164152a013ece6fb036e9a52b318c830fa32fb2e18e5eeb7d355cd2f23f70a3846f98f87862dd96d586accf74d6e7de8fce7e18b004f6bef3a1a9d11b901 - languageName: node - linkType: hard - -"next@npm:14.0.1": - version: 14.0.1 - resolution: "next@npm:14.0.1" - dependencies: - "@next/env": 14.0.1 - "@next/swc-darwin-arm64": 14.0.1 - "@next/swc-darwin-x64": 14.0.1 - "@next/swc-linux-arm64-gnu": 14.0.1 - "@next/swc-linux-arm64-musl": 14.0.1 - "@next/swc-linux-x64-gnu": 14.0.1 - "@next/swc-linux-x64-musl": 14.0.1 - "@next/swc-win32-arm64-msvc": 14.0.1 - "@next/swc-win32-ia32-msvc": 14.0.1 - "@next/swc-win32-x64-msvc": 14.0.1 + "@next/env": 14.1.4 + "@next/swc-darwin-arm64": 14.1.4 + "@next/swc-darwin-x64": 14.1.4 + "@next/swc-linux-arm64-gnu": 14.1.4 + "@next/swc-linux-arm64-musl": 14.1.4 + "@next/swc-linux-x64-gnu": 14.1.4 + "@next/swc-linux-x64-musl": 14.1.4 + "@next/swc-win32-arm64-msvc": 14.1.4 + "@next/swc-win32-ia32-msvc": 14.1.4 + "@next/swc-win32-x64-msvc": 14.1.4 "@swc/helpers": 0.5.2 busboy: 1.6.0 - caniuse-lite: ^1.0.30001406 + caniuse-lite: ^1.0.30001579 + graceful-fs: ^4.2.11 postcss: 8.4.31 styled-jsx: 5.1.1 - watchpack: 2.4.0 peerDependencies: "@opentelemetry/api": ^1.1.0 react: ^18.2.0 @@ -17364,7 +17416,7 @@ __metadata: optional: true bin: next: dist/bin/next - checksum: d142407f47012eb57ba3932f91453960c79d7df2fef03ded581f32195b98a4378e13c49709f498a112d142109a8edd73f40357ee102a6bd4d7b1f76de9f0877a + checksum: 2886bc6a8440d54adad4cc53bc3d89c9947c34f8b0142919a505ae1dcba45e640967f48ee551b875c1fc310234210aa64aa526c49ec7568da76afae5255f837f languageName: node linkType: hard @@ -17404,6 +17456,13 @@ __metadata: languageName: node linkType: hard +"node-domexception@npm:^1.0.0": + version: 1.0.0 + resolution: "node-domexception@npm:1.0.0" + checksum: ee1d37dd2a4eb26a8a92cd6b64dfc29caec72bff5e1ed9aba80c294f57a31ba4895a60fd48347cf17dd6e766da0ae87d75657dfd1f384ebfa60462c2283f5c7f + languageName: node + linkType: hard + "node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.5, node-fetch@npm:^2.6.6, node-fetch@npm:^2.6.7": version: 2.6.11 resolution: "node-fetch@npm:2.6.11" @@ -17418,6 +17477,17 @@ __metadata: languageName: node linkType: hard +"node-fetch@npm:^3.2.0": + version: 3.3.2 + resolution: "node-fetch@npm:3.3.2" + dependencies: + data-uri-to-buffer: ^4.0.0 + fetch-blob: ^3.1.4 + formdata-polyfill: ^4.0.10 + checksum: 06a04095a2ddf05b0830a0d5302699704d59bda3102894ea64c7b9d4c865ecdff2d90fd042df7f5bc40337266961cb6183dcc808ea4f3000d024f422b462da92 + languageName: node + linkType: hard + "node-gyp-build@npm:^4.3.0": version: 4.6.0 resolution: "node-gyp-build@npm:4.6.0" @@ -17475,10 +17545,10 @@ __metadata: languageName: node linkType: hard -"nodemailer@npm:^6.6.5": - version: 6.9.3 - resolution: "nodemailer@npm:6.9.3" - checksum: 3bea8316652c0578515d9146d2f24660e4855807520153f061d39af76b440a4f61b4e70f10fed35f8f12f115f6aea1aeb483ea7ba0337c0e3e675f117c41c611 +"nodemailer@npm:^6.9.13": + version: 6.9.13 + resolution: "nodemailer@npm:6.9.13" + checksum: 1b591ef480be2ff69480127cbff819e6593b1ef263b6f920e1a4e83e40280582daf7a14a809ef92f9828e2a70bdb3ce22b11924e209f2afe4975f9ff37e08e9d languageName: node linkType: hard @@ -17876,6 +17946,13 @@ __metadata: languageName: node linkType: hard +"oauth@npm:^0.9.15": + version: 0.9.15 + resolution: "oauth@npm:0.9.15" + checksum: 957c0d8d85300398dcb0e293953650c0fc3facc795bee8228238414f19f59cef5fd4ee8d17a972c142924c10c5f6ec50ef80f77f4a6cc6e3c98f9d22c027801c + languageName: node + linkType: hard + "object-assign@npm:^3.0.0": version: 3.0.0 resolution: "object-assign@npm:3.0.0" @@ -17890,6 +17967,13 @@ __metadata: languageName: node linkType: hard +"object-hash@npm:^2.2.0": + version: 2.2.0 + resolution: "object-hash@npm:2.2.0" + checksum: 55ba841e3adce9c4f1b9b46b41983eda40f854e0d01af2802d3ae18a7085a17168d6b81731d43fdf1d6bcbb3c9f9c56d22c8fea992203ad90a38d7d919bc28f1 + languageName: node + linkType: hard + "object-inspect@npm:1.11.0": version: 1.11.0 resolution: "object-inspect@npm:1.11.0" @@ -18046,6 +18130,13 @@ __metadata: languageName: node linkType: hard +"oidc-token-hash@npm:^5.0.3": + version: 5.0.3 + resolution: "oidc-token-hash@npm:5.0.3" + checksum: 35fa19aea9ff2c509029ec569d74b778c8a215b92bd5e6e9bc4ebbd7ab035f44304ff02430a6397c3fb7c1d15ebfa467807ca0bcd31d06ba610b47798287d303 + languageName: node + linkType: hard + "on-finished@npm:2.4.1": version: 2.4.1 resolution: "on-finished@npm:2.4.1" @@ -18114,6 +18205,18 @@ __metadata: languageName: node linkType: hard +"openid-client@npm:^5.4.0": + version: 5.6.5 + resolution: "openid-client@npm:5.6.5" + dependencies: + jose: ^4.15.5 + lru-cache: ^6.0.0 + object-hash: ^2.2.0 + oidc-token-hash: ^5.0.3 + checksum: 2240079f761173b10635ce5fefbac04b6820f54e00d588ab2afdddb6c0f0ab6568e663cf1ab6a4a2297fbdbb73e42d78b8190f91dba7e1b80d287b2127fcbc7c + languageName: node + linkType: hard + "opn-cli@npm:^3.1.0": version: 3.1.0 resolution: "opn-cli@npm:3.1.0" @@ -18612,6 +18715,16 @@ __metadata: languageName: node linkType: hard +"path-scurry@npm:^1.10.1": + version: 1.10.2 + resolution: "path-scurry@npm:1.10.2" + dependencies: + lru-cache: ^10.2.0 + minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 + checksum: 6739b4290f7d1a949c61c758b481c07ac7d1a841964c68cf5e1fa153d7e18cbde4872b37aadf9c5173c800d627f219c47945859159de36c977dd82419997b9b8 + languageName: node + linkType: hard + "path-scurry@npm:^1.7.0": version: 1.9.2 resolution: "path-scurry@npm:1.9.2" @@ -18786,6 +18899,24 @@ __metadata: languageName: node linkType: hard +"preact-render-to-string@npm:^5.1.19": + version: 5.2.6 + resolution: "preact-render-to-string@npm:5.2.6" + dependencies: + pretty-format: ^3.8.0 + peerDependencies: + preact: ">=10" + checksum: be8d5d8fb502d422c503e68af7bcccb6facd942f3ae9a4d093ebe3f1d4f0b15c540624bdac434d53a2a8e8fb7afa4606383414e937c40933ca43445470a026ff + languageName: node + linkType: hard + +"preact@npm:^10.6.3": + version: 10.20.1 + resolution: "preact@npm:10.20.1" + checksum: af5ed9bdf44bfa5487479c09fa971a32902987f277c74d6244f9d9466ccd5c1efd3a0949e7dc2227177623878b1adafcc5c50cee6617a84f72d1cebe55ff76ba + languageName: node + linkType: hard + "prebuild-install@npm:^7.1.1": version: 7.1.1 resolution: "prebuild-install@npm:7.1.1" @@ -18900,6 +19031,13 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:^3.8.0": + version: 3.8.0 + resolution: "pretty-format@npm:3.8.0" + checksum: 21a114d43ef06978f8f7f6212be4649b0b094f05d9b30e14e37550bf35c8ca24d8adbca9e5adc4cc15d9eaf7a1e7a30478a4dc37b30982bfdf0292a5b385484c + languageName: node + linkType: hard + "proc-log@npm:^2.0.0, proc-log@npm:^2.0.1": version: 2.0.1 resolution: "proc-log@npm:2.0.1" @@ -19455,7 +19593,7 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^18.2.0": +"react-dom@npm:18.2.0": version: 18.2.0 resolution: "react-dom@npm:18.2.0" dependencies: @@ -19536,7 +19674,7 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^17.0.1, react-is@npm:^17.0.2": +"react-is@npm:^17.0.1": version: 17.0.2 resolution: "react-is@npm:17.0.2" checksum: 9d6d111d8990dc98bc5402c1266a808b0459b5d54830bbea24c12d908b536df7883f268a7868cfaedde3dd9d4e0d574db456f84d2e6df9c4526f99bb4b5344d8 @@ -19600,15 +19738,6 @@ __metadata: languageName: node linkType: hard -"react-ssr-prepass@npm:^1.4.0": - version: 1.5.0 - resolution: "react-ssr-prepass@npm:1.5.0" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: efe89b9f8b2053474613f56dfdbeb41d8ee2e572bf819a39377d95d3e4a9acf8a4a16e28d8d8034cb9ac2b316d11dc9e62217743e4322046d08175eb3b4fed3e - languageName: node - linkType: hard - "react-style-singleton@npm:^2.2.1": version: 2.2.1 resolution: "react-style-singleton@npm:2.2.1" @@ -19662,7 +19791,7 @@ __metadata: languageName: node linkType: hard -"react@npm:^18.2.0": +"react@npm:18.2.0": version: 18.2.0 resolution: "react@npm:18.2.0" dependencies: @@ -21918,15 +22047,15 @@ __metadata: languageName: node linkType: hard -"ts-jest@npm:27.0.5": - version: 27.0.5 - resolution: "ts-jest@npm:27.0.5" +"ts-jest@npm:^27.0.5": + version: 27.1.5 + resolution: "ts-jest@npm:27.1.5" dependencies: bs-logger: 0.x fast-json-stable-stringify: 2.x jest-util: ^27.0.0 json5: 2.x - lodash: 4.x + lodash.memoize: 4.x make-error: 1.x semver: 7.x yargs-parser: 20.x @@ -21943,34 +22072,36 @@ __metadata: optional: true babel-jest: optional: true + esbuild: + optional: true bin: ts-jest: cli.js - checksum: fd53cdb6f913cbe802799d2b491f70f33c52c840c4b8483cecf600ff360efbd00c8d7ed9eb0dd677219f330ee38928b7b9890e9853e9f4d3574b9d8e1dcf4a30 + checksum: 3ef51c538b82f49b3f529331c1a017871a2f90e7a9a6e69333304755036d121818c6b120e2ce32dd161ff8bb2487efec0c790753ecd39b46a9ed1ce0d241464c languageName: node linkType: hard -"ts-jest@npm:^27.0.5": - version: 27.1.5 - resolution: "ts-jest@npm:27.1.5" +"ts-jest@npm:^29.1.2": + version: 29.1.2 + resolution: "ts-jest@npm:29.1.2" dependencies: bs-logger: 0.x fast-json-stable-stringify: 2.x - jest-util: ^27.0.0 - json5: 2.x + jest-util: ^29.0.0 + json5: ^2.2.3 lodash.memoize: 4.x make-error: 1.x - semver: 7.x - yargs-parser: 20.x + semver: ^7.5.3 + yargs-parser: ^21.0.1 peerDependencies: "@babel/core": ">=7.0.0-beta.0 <8" - "@types/jest": ^27.0.0 - babel-jest: ">=27.0.0 <28" - jest: ^27.0.0 - typescript: ">=3.8 <5.0" + "@jest/types": ^29.0.0 + babel-jest: ^29.0.0 + jest: ^29.0.0 + typescript: ">=4.3 <6" peerDependenciesMeta: "@babel/core": optional: true - "@types/jest": + "@jest/types": optional: true babel-jest: optional: true @@ -21978,7 +22109,7 @@ __metadata: optional: true bin: ts-jest: cli.js - checksum: 3ef51c538b82f49b3f529331c1a017871a2f90e7a9a6e69333304755036d121818c6b120e2ce32dd161ff8bb2487efec0c790753ecd39b46a9ed1ce0d241464c + checksum: a0ce0affc1b716c78c9ab55837829c42cb04b753d174a5c796bb1ddf9f0379fc20647b76fbe30edb30d9b23181908138d6b4c51ef2ae5e187b66635c295cefd5 languageName: node linkType: hard @@ -22252,27 +22383,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:4.6.2": - version: 4.6.2 - resolution: "typescript@npm:4.6.2" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 8a44ed7e6f6c4cb1ebe8cf236ecda2fb119d84dcf0fbd77e707b2dfea1bbcfc4e366493a143513ce7f57203c75da9d4e20af6fe46de89749366351046be7577c - languageName: node - linkType: hard - -"typescript@npm:4.7.2": - version: 4.7.2 - resolution: "typescript@npm:4.7.2" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 5163585e6b56410f77d5483b698d9489bbee8902c99029eb70cf6d21525a186530ce19a00951af84eefd4a131cc51d0959f5118e25e70ab61f45ac4057dbd1ef - languageName: node - linkType: hard - -"typescript@npm:^3 || ^4, typescript@npm:^4.4.3, typescript@npm:^4.9.5": +"typescript@npm:^3 || ^4": version: 4.9.5 resolution: "typescript@npm:4.9.5" bin: @@ -22282,37 +22393,17 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.3.3": - version: 5.3.3 - resolution: "typescript@npm:5.3.3" +"typescript@npm:^5.4.3": + version: 5.4.3 + resolution: "typescript@npm:5.4.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 2007ccb6e51bbbf6fde0a78099efe04dc1c3dfbdff04ca3b6a8bc717991862b39fd6126c0c3ebf2d2d98ac5e960bcaa873826bb2bb241f14277034148f41f6a2 + checksum: d74d731527e35e64d8d2dcf2f897cf8cfbc3428be0ad7c48434218ba4ae41239f53be7c90714089db1068c05cae22436af2ecba71fd36ecc5e7a9118af060198 languageName: node linkType: hard -"typescript@patch:typescript@4.6.2#~builtin": - version: 4.6.2 - resolution: "typescript@patch:typescript@npm%3A4.6.2#~builtin::version=4.6.2&hash=5d3a66" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 40b493a71747fb89fa70df104e2c4a5e284b43750af5bea024090a5261cefa387f7a9372411b13030f7bf5555cee4275443d08805642ae5c74ef76740854a4c7 - languageName: node - linkType: hard - -"typescript@patch:typescript@4.7.2#~builtin": - version: 4.7.2 - resolution: "typescript@patch:typescript@npm%3A4.7.2#~builtin::version=4.7.2&hash=65a307" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 7e2b9a9f4a70fb7616f1b0d986977f8e34a74f046202fa7f24fdee79589598277810fa216b3776c20c0683a9235872c73be34fdb93f67f98c1efaca40999422f - languageName: node - linkType: hard - -"typescript@patch:typescript@^3 || ^4#~builtin, typescript@patch:typescript@^4.4.3#~builtin, typescript@patch:typescript@^4.9.5#~builtin": +"typescript@patch:typescript@^3 || ^4#~builtin": version: 4.9.5 resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=289587" bin: @@ -22322,13 +22413,13 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@^5.3.3#~builtin": - version: 5.3.3 - resolution: "typescript@patch:typescript@npm%3A5.3.3#~builtin::version=5.3.3&hash=f3b441" +"typescript@patch:typescript@^5.4.3#~builtin": + version: 5.4.3 + resolution: "typescript@patch:typescript@npm%3A5.4.3#~builtin::version=5.4.3&hash=f3b441" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: f61375590b3162599f0f0d5b8737877ac0a7bc52761dbb585d67e7b8753a3a4c42d9a554c4cc929f591ffcf3a2b0602f65ae3ce74714fd5652623a816862b610 + checksum: 3a62fe90aa79d68c9ce38ea5edb2957e62801c733b99f0e5a2b8b50922761f68f7d9a40d28c544b449866e81185cddb93cba2496d0ff3fa52ef5b1f8bcace38c languageName: node linkType: hard @@ -22374,10 +22465,10 @@ __metadata: languageName: node linkType: hard -"unfetch@npm:^4.2.0": - version: 4.2.0 - resolution: "unfetch@npm:4.2.0" - checksum: 6a4b2557e1d921eaa80c4425ce27a404945ec26491ed06e62598f333996a91a44c7908cb26dc7c2746d735762b13276cf4aa41829b4c8f438dde63add3045d7a +"unfetch@npm:^5.0.0": + version: 5.0.0 + resolution: "unfetch@npm:5.0.0" + checksum: 005133bcdc85cefea60890af4ac265799356b69c6a7719c1330484165af7109c06b9eedd3e03d620c14dcc8b43bcf329148f4c1f06016390162f845e0d0a62c5 languageName: node linkType: hard @@ -22741,16 +22832,15 @@ __metadata: languageName: node linkType: hard -"urql@npm:^2.0.5": - version: 2.2.3 - resolution: "urql@npm:2.2.3" +"urql@npm:^4.0.6": + version: 4.0.7 + resolution: "urql@npm:4.0.7" dependencies: - "@urql/core": ^2.6.1 - wonka: ^4.0.14 + "@urql/core": ^5.0.0 + wonka: ^6.3.2 peerDependencies: - graphql: ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 react: ">= 16.8.0" - checksum: b105d10036e5cdbc92dac03bf50e81bfc946eb4909c5f2009fa7b83b5161493ac3288f97f42fd18c7bae6a5645ff18535d6746ec6d0c8cdbce5803b24a8a10a4 + checksum: a57bc4b4e60e49dd686c6a5890443c422306a07a2641b2da1a826286fd7cdcc27d69f486df3dade0e2a95659ec969cb3165f115c64749098c54c929f1a4facc8 languageName: node linkType: hard @@ -23034,16 +23124,6 @@ __metadata: languageName: node linkType: hard -"watchpack@npm:2.4.0": - version: 2.4.0 - resolution: "watchpack@npm:2.4.0" - dependencies: - glob-to-regexp: ^0.4.1 - graceful-fs: ^4.1.2 - checksum: 23d4bc58634dbe13b86093e01c6a68d8096028b664ab7139d58f0c37d962d549a940e98f2f201cecdabd6f9c340338dc73ef8bf094a2249ef582f35183d1a131 - languageName: node - linkType: hard - "wcwidth@npm:^1.0.0, wcwidth@npm:^1.0.1": version: 1.0.1 resolution: "wcwidth@npm:1.0.1" @@ -23060,6 +23140,13 @@ __metadata: languageName: node linkType: hard +"web-streams-polyfill@npm:^3.0.3": + version: 3.3.3 + resolution: "web-streams-polyfill@npm:3.3.3" + checksum: 21ab5ea08a730a2ef8023736afe16713b4f2023ec1c7085c16c8e293ee17ed085dff63a0ad8722da30c99c4ccbd4ccd1b2e79c861829f7ef2963d7de7004c2cb + languageName: node + linkType: hard + "webidl-conversions@npm:^3.0.0": version: 3.0.1 resolution: "webidl-conversions@npm:3.0.1" @@ -23298,20 +23385,13 @@ __metadata: languageName: node linkType: hard -"wonka@npm:>= 4.0.9, wonka@npm:^6.3.2": +"wonka@npm:^6.3.2": version: 6.3.2 resolution: "wonka@npm:6.3.2" checksum: e161f377a4ea17cc2b19fe8820219a9e3e2c78db5df08b820525bc2cc261184823d1bc33bd2385e632656a9676c9de6ff614b6324c441dd5fc5faa253433d032 languageName: node linkType: hard -"wonka@npm:^4.0.14, wonka@npm:^4.0.15": - version: 4.0.15 - resolution: "wonka@npm:4.0.15" - checksum: afbee7359ed2d0a9146bf682f3953cb093f47d5f827e767e6ef33cb70ca6f30631afe5fe31dbb8d6c7eaed26c4ac6426e7c13568917c017ef6f42c71139b38f7 - languageName: node - linkType: hard - "word-wrap@npm:^1.2.3, word-wrap@npm:~1.2.3": version: 1.2.3 resolution: "word-wrap@npm:1.2.3" @@ -23602,7 +23682,7 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:21.1.1, yargs-parser@npm:^21.1.1": +"yargs-parser@npm:21.1.1, yargs-parser@npm:^21.0.1, yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c