diff --git a/packages/backend/src/db/migrations/20240822111546_add_prevent_users_from_updating_their_profiles_user_management_in_config.js b/packages/backend/src/db/migrations/20240822111546_add_prevent_users_from_updating_their_profiles_user_management_in_config.js new file mode 100644 index 00000000..7d21d070 --- /dev/null +++ b/packages/backend/src/db/migrations/20240822111546_add_prevent_users_from_updating_their_profiles_user_management_in_config.js @@ -0,0 +1,12 @@ +export async function up(knex) { + await knex('config').insert({ + key: 'userManagement.preventUsersFromUpdatingTheirProfile', + value: { + data: false + } + }); +}; + +export async function down(knex) { + await knex('config').where({ key: 'userManagement.preventUsersFromUpdatingTheirProfile' }).delete(); +}; diff --git a/packages/web/src/components/AddAppConnection/index.jsx b/packages/web/src/components/AddAppConnection/index.jsx index f253831b..4cbd41be 100644 --- a/packages/web/src/components/AddAppConnection/index.jsx +++ b/packages/web/src/components/AddAppConnection/index.jsx @@ -7,6 +7,7 @@ import DialogContentText from '@mui/material/DialogContentText'; import DialogTitle from '@mui/material/DialogTitle'; import * as React from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; +import { useQueryClient } from '@tanstack/react-query'; import { AppPropType } from 'propTypes/propTypes'; import AppAuthClientsDialog from 'components/AppAuthClientsDialog/index.ee'; @@ -17,7 +18,6 @@ import useFormatMessage from 'hooks/useFormatMessage'; import { generateExternalLink } from 'helpers/translationValues'; import { Form } from './style'; import useAppAuth from 'hooks/useAppAuth'; -import { useQueryClient } from '@tanstack/react-query'; function AddAppConnection(props) { const { application, connectionId, onClose } = props; diff --git a/packages/web/src/components/LoginForm/index.jsx b/packages/web/src/components/LoginForm/index.jsx index 3611417e..bb4b3e94 100644 --- a/packages/web/src/components/LoginForm/index.jsx +++ b/packages/web/src/components/LoginForm/index.jsx @@ -12,6 +12,7 @@ import TextField from 'components/TextField'; import useFormatMessage from 'hooks/useFormatMessage'; import useCreateAccessToken from 'hooks/useCreateAccessToken'; import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar'; +import usePreventUsersFromUpdatingTheirProfile from 'hooks/usePreventUsersFromUpdatingTheirProfile'; function LoginForm() { const isCloud = useCloud(); @@ -19,6 +20,7 @@ function LoginForm() { const formatMessage = useFormatMessage(); const enqueueSnackbar = useEnqueueSnackbar(); const authentication = useAuthentication(); + const preventUsersFromUpdatingTheirProfile = usePreventUsersFromUpdatingTheirProfile(); const { mutateAsync: createAccessToken, isPending: loading } = useCreateAccessToken(); @@ -84,7 +86,7 @@ function LoginForm() { sx={{ mb: 1 }} /> - {isCloud && ( + {isCloud && !preventUsersFromUpdatingTheirProfile && ( { + try { + await updateConfig({ + variables: { + input: { + 'userManagement.preventUsersFromUpdatingTheirProfile': values.userManagement.preventUsersFromUpdatingTheirProfile, + }, + }, + }); + + await queryClient.invalidateQueries({ + queryKey: ['automatisch', 'config'], + }); + + enqueueSnackbar(formatMessage('authenticationConfig.successfullySaved'), { + variant: 'success', + SnackbarProps: { + 'data-test': 'snackbar-update-role-mappings-success', + }, + }); + } catch (error) { + throw new Error('Failed while saving!'); + } + }; + + if (isAutomatischConfigLoading) { + return null; + } + + return ( + <> + + {formatMessage('authenticationConfig.title')} + + +
+ + + {formatMessage('authenticationConfig.userManagementPreventUsersFromUpdatingTheirProfile')} + + + + + } + /> + + + {formatMessage('authenticationConfig.save')} + + +
+ + ); +} + +AuthenticationConfig.propTypes = { +}; + +export default AuthenticationConfig; diff --git a/packages/web/src/pages/Authentication/RoleMappings.jsx b/packages/web/src/pages/Authentication/RoleMappings.jsx index a2605eef..812f24a0 100644 --- a/packages/web/src/pages/Authentication/RoleMappings.jsx +++ b/packages/web/src/pages/Authentication/RoleMappings.jsx @@ -1,7 +1,6 @@ import PropTypes from 'prop-types'; import { useMutation } from '@apollo/client'; import LoadingButton from '@mui/lab/LoadingButton'; -import Divider from '@mui/material/Divider'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar'; @@ -85,7 +84,6 @@ function RoleMappings({ provider, providerLoading }) { return ( <> - {formatMessage('roleMappingsForm.title')} diff --git a/packages/web/src/pages/Authentication/SamlConfiguration.jsx b/packages/web/src/pages/Authentication/SamlConfiguration.jsx index 6a99b6bb..bc8518bd 100644 --- a/packages/web/src/pages/Authentication/SamlConfiguration.jsx +++ b/packages/web/src/pages/Authentication/SamlConfiguration.jsx @@ -75,7 +75,7 @@ function SamlConfiguration({ provider, providerLoading }) { }, }); - enqueueSnackbar(formatMessage('authenticationForm.successfullySaved'), { + enqueueSnackbar(formatMessage('samlAuthenticationForm.successfullySaved'), { variant: 'success', SnackbarProps: { 'data-test': 'snackbar-save-saml-provider-success', @@ -98,18 +98,18 @@ function SamlConfiguration({ provider, providerLoading }) { @@ -126,44 +126,44 @@ function SamlConfiguration({ provider, providerLoading }) { renderInput={(params) => ( )} /> ( )} loading={isRolesLoading} @@ -187,7 +187,7 @@ function SamlConfiguration({ provider, providerLoading }) { sx={{ boxShadow: 2 }} loading={loading} > - {formatMessage('authenticationForm.save')} + {formatMessage('samlAuthenticationForm.save')} diff --git a/packages/web/src/pages/Authentication/index.jsx b/packages/web/src/pages/Authentication/index.jsx index 7b6e6826..062bb192 100644 --- a/packages/web/src/pages/Authentication/index.jsx +++ b/packages/web/src/pages/Authentication/index.jsx @@ -2,11 +2,14 @@ import Grid from '@mui/material/Grid'; import Stack from '@mui/material/Stack'; import PageTitle from 'components/PageTitle'; import Container from 'components/Container'; +import Divider from '@mui/material/Divider'; import useFormatMessage from 'hooks/useFormatMessage'; import useSamlAuthProvider from 'hooks/useSamlAuthProvider'; +import AuthenticationConfig from './AuthenticationConfig'; import SamlConfiguration from './SamlConfiguration'; import RoleMappings from './RoleMappings'; import useAdminSamlAuthProviders from 'hooks/useAdminSamlAuthProviders.ee'; + function AuthenticationPage() { const formatMessage = useFormatMessage(); @@ -16,20 +19,37 @@ function AuthenticationPage() { const { data, isLoading: isProviderLoading } = useSamlAuthProvider({ samlAuthProviderId, }); + const provider = data?.data; return ( - + {formatMessage('authenticationPage.title')} + + + + + + + + + + + {formatMessage('samlAuthenticationPage.title')} + + + + + + diff --git a/packages/web/src/routes.jsx b/packages/web/src/routes.jsx index 1f634275..872038a7 100644 --- a/packages/web/src/routes.jsx +++ b/packages/web/src/routes.jsx @@ -29,12 +29,14 @@ import adminSettingsRoutes from './adminSettingsRoutes'; import Notifications from 'pages/Notifications'; import useAutomatischConfig from 'hooks/useAutomatischConfig'; import useAuthentication from 'hooks/useAuthentication'; +import usePreventUsersFromUpdatingTheirProfile from 'hooks/usePreventUsersFromUpdatingTheirProfile'; import useAutomatischInfo from 'hooks/useAutomatischInfo'; import Installation from 'pages/Installation'; function Routes() { const { data: automatischInfo, isSuccess } = useAutomatischInfo(); const { data: configData } = useAutomatischConfig(); + const preventUsersFromUpdatingTheirProfile = usePreventUsersFromUpdatingTheirProfile(); const { isAuthenticated } = useAuthentication(); const config = configData?.data; @@ -134,14 +136,14 @@ function Routes() { } /> - } - /> + />}