Compare commits
14 Commits
feat/user-
...
1.1.26
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4afd544c41 | ||
![]() |
307c6f7d15 | ||
![]() |
bbc6394cf3 | ||
![]() |
63c8e2e55f | ||
![]() |
b224892a39 | ||
![]() |
13edf1965c | ||
![]() |
1f220a5205 | ||
![]() |
32fb954a1c | ||
![]() |
65eadb66fa | ||
![]() |
9ce53eb8e8 | ||
![]() |
3b196f074b | ||
![]() |
f2fe584793 | ||
![]() |
287b952dad | ||
![]() |
e690066652 |
@@ -60,7 +60,12 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
||||
{view === VIEW_TYPES.FORGOT_PASSWORD && (
|
||||
<Fragment>
|
||||
<h1 style={{ textAlign: 'center' }}>Forgot Password</h1>
|
||||
<AuthorizerForgotPassword urlProps={urlProps} />
|
||||
<AuthorizerForgotPassword
|
||||
urlProps={{
|
||||
...urlProps,
|
||||
redirect_uri: `${window.location.origin}/app/reset-password`,
|
||||
}}
|
||||
/>
|
||||
<Footer>
|
||||
<Link
|
||||
to="#"
|
||||
|
@@ -1,263 +1,263 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Center,
|
||||
Flex,
|
||||
MenuItem,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Stack,
|
||||
useDisclosure,
|
||||
Text,
|
||||
useToast,
|
||||
Button,
|
||||
Center,
|
||||
Flex,
|
||||
MenuItem,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Stack,
|
||||
useDisclosure,
|
||||
Text,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import { useClient } from 'urql';
|
||||
import { FaSave } from 'react-icons/fa';
|
||||
import InputField from './InputField';
|
||||
import {
|
||||
DateInputType,
|
||||
MultiSelectInputType,
|
||||
SelectInputType,
|
||||
TextInputType,
|
||||
DateInputType,
|
||||
MultiSelectInputType,
|
||||
SelectInputType,
|
||||
TextInputType,
|
||||
} from '../constants';
|
||||
import { getObjectDiff } from '../utils';
|
||||
import { UpdateUser } from '../graphql/mutation';
|
||||
import { GetAvailableRolesQuery } from '../graphql/queries';
|
||||
|
||||
const GenderTypes = {
|
||||
Undisclosed: null,
|
||||
Male: 'Male',
|
||||
Female: 'Female',
|
||||
Undisclosed: null,
|
||||
Male: 'Male',
|
||||
Female: 'Female',
|
||||
};
|
||||
|
||||
interface userDataTypes {
|
||||
id: string;
|
||||
email: string;
|
||||
given_name: string;
|
||||
family_name: string;
|
||||
middle_name: string;
|
||||
nickname: string;
|
||||
gender: string;
|
||||
birthdate: string;
|
||||
phone_number: string;
|
||||
picture: string;
|
||||
roles: [string] | [];
|
||||
id: string;
|
||||
email: string;
|
||||
given_name: string;
|
||||
family_name: string;
|
||||
middle_name: string;
|
||||
nickname: string;
|
||||
gender: string;
|
||||
birthdate: string;
|
||||
phone_number: string;
|
||||
picture: string;
|
||||
roles: [string] | [];
|
||||
}
|
||||
|
||||
const EditUserModal = ({
|
||||
user,
|
||||
updateUserList,
|
||||
user,
|
||||
updateUserList,
|
||||
}: {
|
||||
user: userDataTypes;
|
||||
updateUserList: Function;
|
||||
user: userDataTypes;
|
||||
updateUserList: Function;
|
||||
}) => {
|
||||
const client = useClient();
|
||||
const toast = useToast();
|
||||
const [availableRoles, setAvailableRoles] = useState<string[]>([]);
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const [userData, setUserData] = useState<userDataTypes>({
|
||||
id: '',
|
||||
email: '',
|
||||
given_name: '',
|
||||
family_name: '',
|
||||
middle_name: '',
|
||||
nickname: '',
|
||||
gender: '',
|
||||
birthdate: '',
|
||||
phone_number: '',
|
||||
picture: '',
|
||||
roles: [],
|
||||
});
|
||||
React.useEffect(() => {
|
||||
setUserData(user);
|
||||
fetchAvailableRoles();
|
||||
}, []);
|
||||
const fetchAvailableRoles = async () => {
|
||||
const res = await client.query(GetAvailableRolesQuery).toPromise();
|
||||
if (res.data?._env?.ROLES && res.data?._env?.PROTECTED_ROLES) {
|
||||
setAvailableRoles([
|
||||
...res.data._env.ROLES,
|
||||
...res.data._env.PROTECTED_ROLES,
|
||||
]);
|
||||
}
|
||||
};
|
||||
const saveHandler = async () => {
|
||||
const diff = getObjectDiff(user, userData);
|
||||
const updatedUserData = diff.reduce(
|
||||
(acc: any, property: string) => ({
|
||||
...acc,
|
||||
// @ts-ignore
|
||||
[property]: userData[property],
|
||||
}),
|
||||
{},
|
||||
);
|
||||
const res = await client
|
||||
.mutation(UpdateUser, { params: { ...updatedUserData, id: userData.id } })
|
||||
.toPromise();
|
||||
if (res.error) {
|
||||
toast({
|
||||
title: 'User data update failed',
|
||||
isClosable: true,
|
||||
status: 'error',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
} else if (res.data?._update_user?.id) {
|
||||
toast({
|
||||
title: 'User data update successful',
|
||||
isClosable: true,
|
||||
status: 'success',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
}
|
||||
onClose();
|
||||
updateUserList();
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={onOpen}>Edit User Details</MenuItem>
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Edit User Details</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Stack>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Given Name:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={TextInputType.GIVEN_NAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Middle Name:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={TextInputType.MIDDLE_NAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Family Name:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={TextInputType.FAMILY_NAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Birth Date:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={DateInputType.BIRTHDATE}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Nickname:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={TextInputType.NICKNAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Gender:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={SelectInputType.GENDER}
|
||||
value={userData.gender}
|
||||
options={GenderTypes}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Phone Number:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={TextInputType.PHONE_NUMBER}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Picture:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={TextInputType.PICTURE}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Roles:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
availableRoles={availableRoles}
|
||||
inputType={MultiSelectInputType.USER_ROLES}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</ModalBody>
|
||||
const client = useClient();
|
||||
const toast = useToast();
|
||||
const [availableRoles, setAvailableRoles] = useState<string[]>([]);
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const [userData, setUserData] = useState<userDataTypes>({
|
||||
id: '',
|
||||
email: '',
|
||||
given_name: '',
|
||||
family_name: '',
|
||||
middle_name: '',
|
||||
nickname: '',
|
||||
gender: '',
|
||||
birthdate: '',
|
||||
phone_number: '',
|
||||
picture: '',
|
||||
roles: [],
|
||||
});
|
||||
React.useEffect(() => {
|
||||
setUserData(user);
|
||||
fetchAvailableRoles();
|
||||
}, []);
|
||||
const fetchAvailableRoles = async () => {
|
||||
const res = await client.query(GetAvailableRolesQuery).toPromise();
|
||||
if (res.data?._env?.ROLES && res.data?._env?.PROTECTED_ROLES) {
|
||||
setAvailableRoles([
|
||||
...res.data._env.ROLES,
|
||||
...res.data._env.PROTECTED_ROLES,
|
||||
]);
|
||||
}
|
||||
};
|
||||
const saveHandler = async () => {
|
||||
const diff = getObjectDiff(user, userData);
|
||||
const updatedUserData = diff.reduce(
|
||||
(acc: any, property: string) => ({
|
||||
...acc,
|
||||
// @ts-ignore
|
||||
[property]: userData[property],
|
||||
}),
|
||||
{},
|
||||
);
|
||||
const res = await client
|
||||
.mutation(UpdateUser, { params: { ...updatedUserData, id: userData.id } })
|
||||
.toPromise();
|
||||
if (res.error) {
|
||||
toast({
|
||||
title: 'User data update failed',
|
||||
isClosable: true,
|
||||
status: 'error',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
} else if (res.data?._update_user?.id) {
|
||||
toast({
|
||||
title: 'User data update successful',
|
||||
isClosable: true,
|
||||
status: 'success',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
}
|
||||
onClose();
|
||||
updateUserList();
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<MenuItem onClick={onOpen}>Edit User Details</MenuItem>
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Edit User Details</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Stack>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Given Name:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={TextInputType.GIVEN_NAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Middle Name:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={TextInputType.MIDDLE_NAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Family Name:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={TextInputType.FAMILY_NAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Birth Date:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={DateInputType.BIRTHDATE}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Nickname:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={TextInputType.NICKNAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Gender:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={SelectInputType.GENDER}
|
||||
value={userData.gender}
|
||||
options={GenderTypes}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Phone Number:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={TextInputType.PHONE_NUMBER}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Picture:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
inputType={TextInputType.PICTURE}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Roles:</Text>
|
||||
</Flex>
|
||||
<Center w="70%">
|
||||
<InputField
|
||||
variables={userData}
|
||||
setVariables={setUserData}
|
||||
availableRoles={availableRoles}
|
||||
inputType={MultiSelectInputType.USER_ROLES}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button
|
||||
leftIcon={<FaSave />}
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
onClick={saveHandler}
|
||||
isDisabled={false}
|
||||
>
|
||||
<Center h="100%" pt="5%">
|
||||
Save
|
||||
</Center>
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
<ModalFooter>
|
||||
<Button
|
||||
leftIcon={<FaSave />}
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
onClick={saveHandler}
|
||||
isDisabled={false}
|
||||
>
|
||||
<Center h="100%" pt="5%">
|
||||
Save
|
||||
</Center>
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditUserModal;
|
||||
|
@@ -48,6 +48,26 @@ const EmailConfigurations = ({
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? '30%' : '40%'}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="sm">SMTP Local Name:</Text>
|
||||
</Flex>
|
||||
<Center
|
||||
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||
mt={isNotSmallerScreen ? '0' : '3'}
|
||||
>
|
||||
<InputField
|
||||
borderRadius={5}
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={TextInputType.SMTP_LOCAL_NAME}
|
||||
/>
|
||||
</Center>
|
||||
</Flex>
|
||||
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||
<Flex
|
||||
w={isNotSmallerScreen ? '30%' : '40%'}
|
||||
|
@@ -1,432 +1,432 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
Input,
|
||||
Center,
|
||||
InputGroup,
|
||||
InputRightElement,
|
||||
Tag,
|
||||
TagLabel,
|
||||
TagRightIcon,
|
||||
Select,
|
||||
Textarea,
|
||||
Switch,
|
||||
Text,
|
||||
MenuButton,
|
||||
MenuList,
|
||||
MenuItemOption,
|
||||
MenuOptionGroup,
|
||||
Button,
|
||||
Menu,
|
||||
Box,
|
||||
Flex,
|
||||
Input,
|
||||
Center,
|
||||
InputGroup,
|
||||
InputRightElement,
|
||||
Tag,
|
||||
TagLabel,
|
||||
TagRightIcon,
|
||||
Select,
|
||||
Textarea,
|
||||
Switch,
|
||||
Text,
|
||||
MenuButton,
|
||||
MenuList,
|
||||
MenuItemOption,
|
||||
MenuOptionGroup,
|
||||
Button,
|
||||
Menu,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaRegClone,
|
||||
FaRegEye,
|
||||
FaRegEyeSlash,
|
||||
FaPlus,
|
||||
FaTimes,
|
||||
FaAngleDown,
|
||||
FaRegClone,
|
||||
FaRegEye,
|
||||
FaRegEyeSlash,
|
||||
FaPlus,
|
||||
FaTimes,
|
||||
FaAngleDown,
|
||||
} from 'react-icons/fa';
|
||||
import {
|
||||
ArrayInputOperations,
|
||||
ArrayInputType,
|
||||
SelectInputType,
|
||||
HiddenInputType,
|
||||
TextInputType,
|
||||
TextAreaInputType,
|
||||
SwitchInputType,
|
||||
DateInputType,
|
||||
MultiSelectInputType,
|
||||
ArrayInputOperations,
|
||||
ArrayInputType,
|
||||
SelectInputType,
|
||||
HiddenInputType,
|
||||
TextInputType,
|
||||
TextAreaInputType,
|
||||
SwitchInputType,
|
||||
DateInputType,
|
||||
MultiSelectInputType,
|
||||
} from '../constants';
|
||||
import { copyTextToClipboard } from '../utils';
|
||||
|
||||
const InputField = ({
|
||||
inputType,
|
||||
variables,
|
||||
setVariables,
|
||||
fieldVisibility,
|
||||
setFieldVisibility,
|
||||
availableRoles,
|
||||
...downshiftProps
|
||||
inputType,
|
||||
variables,
|
||||
setVariables,
|
||||
fieldVisibility,
|
||||
setFieldVisibility,
|
||||
availableRoles,
|
||||
...downshiftProps
|
||||
}: any) => {
|
||||
const props = {
|
||||
size: 'sm',
|
||||
...downshiftProps,
|
||||
};
|
||||
const [availableUserRoles, setAvailableUserRoles] =
|
||||
useState<string[]>(availableRoles);
|
||||
const [inputFieldVisibility, setInputFieldVisibility] = useState<
|
||||
Record<string, boolean>
|
||||
>({
|
||||
ROLES: false,
|
||||
DEFAULT_ROLES: false,
|
||||
PROTECTED_ROLES: false,
|
||||
ALLOWED_ORIGINS: false,
|
||||
roles: false,
|
||||
});
|
||||
const [inputData, setInputData] = useState<Record<string, string>>({
|
||||
ROLES: '',
|
||||
DEFAULT_ROLES: '',
|
||||
PROTECTED_ROLES: '',
|
||||
ALLOWED_ORIGINS: '',
|
||||
roles: '',
|
||||
});
|
||||
const updateInputHandler = (
|
||||
type: string,
|
||||
operation: any,
|
||||
role: string = '',
|
||||
) => {
|
||||
if (operation === ArrayInputOperations.APPEND) {
|
||||
if (inputData[type] !== '') {
|
||||
setVariables({
|
||||
...variables,
|
||||
[type]: [...variables[type], inputData[type]],
|
||||
});
|
||||
setInputData({ ...inputData, [type]: '' });
|
||||
}
|
||||
setInputFieldVisibility({ ...inputFieldVisibility, [type]: false });
|
||||
}
|
||||
if (operation === ArrayInputOperations.REMOVE) {
|
||||
let updatedEnvVars = variables[type].filter(
|
||||
(item: string) => item !== role,
|
||||
);
|
||||
setVariables({
|
||||
...variables,
|
||||
[type]: updatedEnvVars,
|
||||
});
|
||||
}
|
||||
};
|
||||
if (Object.values(TextInputType).includes(inputType)) {
|
||||
return (
|
||||
<InputGroup size="sm">
|
||||
<Input
|
||||
{...props}
|
||||
value={variables[inputType] ? variables[inputType] : ''}
|
||||
onChange={(
|
||||
event: Event & {
|
||||
target: HTMLInputElement;
|
||||
},
|
||||
) =>
|
||||
setVariables({
|
||||
...variables,
|
||||
[inputType]: event.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<InputRightElement
|
||||
children={<FaRegClone color="#bfbfbf" />}
|
||||
cursor="pointer"
|
||||
onClick={() => copyTextToClipboard(variables[inputType])}
|
||||
/>
|
||||
</InputGroup>
|
||||
);
|
||||
}
|
||||
if (Object.values(HiddenInputType).includes(inputType)) {
|
||||
return (
|
||||
<InputGroup size="sm">
|
||||
<Input
|
||||
{...props}
|
||||
value={variables[inputType] || ''}
|
||||
onChange={(
|
||||
event: Event & {
|
||||
target: HTMLInputElement;
|
||||
},
|
||||
) =>
|
||||
setVariables({
|
||||
...variables,
|
||||
[inputType]: event.target.value,
|
||||
})
|
||||
}
|
||||
type={!fieldVisibility[inputType] ? 'password' : 'text'}
|
||||
/>
|
||||
<InputRightElement
|
||||
right="15px"
|
||||
children={
|
||||
<Flex>
|
||||
{fieldVisibility[inputType] ? (
|
||||
<Center
|
||||
w="25px"
|
||||
margin="0 1.5%"
|
||||
cursor="pointer"
|
||||
onClick={() =>
|
||||
setFieldVisibility({
|
||||
...fieldVisibility,
|
||||
[inputType]: false,
|
||||
})
|
||||
}
|
||||
>
|
||||
<FaRegEyeSlash color="#bfbfbf" />
|
||||
</Center>
|
||||
) : (
|
||||
<Center
|
||||
w="25px"
|
||||
margin="0 1.5%"
|
||||
cursor="pointer"
|
||||
onClick={() =>
|
||||
setFieldVisibility({
|
||||
...fieldVisibility,
|
||||
[inputType]: true,
|
||||
})
|
||||
}
|
||||
>
|
||||
<FaRegEye color="#bfbfbf" />
|
||||
</Center>
|
||||
)}
|
||||
<Center
|
||||
w="25px"
|
||||
margin="0 1.5%"
|
||||
cursor="pointer"
|
||||
onClick={() => copyTextToClipboard(variables[inputType])}
|
||||
>
|
||||
<FaRegClone color="#bfbfbf" />
|
||||
</Center>
|
||||
</Flex>
|
||||
}
|
||||
/>
|
||||
</InputGroup>
|
||||
);
|
||||
}
|
||||
if (Object.values(ArrayInputType).includes(inputType)) {
|
||||
return (
|
||||
<Flex
|
||||
border="1px solid #e2e8f0"
|
||||
w="100%"
|
||||
borderRadius={5}
|
||||
paddingTop="0.5%"
|
||||
overflowX={variables[inputType].length > 3 ? 'scroll' : 'hidden'}
|
||||
overflowY="hidden"
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
{variables[inputType].map((role: string, index: number) => (
|
||||
<Box key={index} margin="0.5%" role="group">
|
||||
<Tag
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme="gray"
|
||||
minW="fit-content"
|
||||
>
|
||||
<TagLabel cursor="default">{role}</TagLabel>
|
||||
<TagRightIcon
|
||||
boxSize="12px"
|
||||
as={FaTimes}
|
||||
display="none"
|
||||
cursor="pointer"
|
||||
_groupHover={{ display: 'block' }}
|
||||
onClick={() =>
|
||||
updateInputHandler(
|
||||
inputType,
|
||||
ArrayInputOperations.REMOVE,
|
||||
role,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tag>
|
||||
</Box>
|
||||
))}
|
||||
{inputFieldVisibility[inputType] ? (
|
||||
<Box ml="1%" mb="0.75%">
|
||||
<Input
|
||||
type="text"
|
||||
size="xs"
|
||||
minW="150px"
|
||||
placeholder="add a new value"
|
||||
value={inputData[inputType] || ''}
|
||||
onChange={(e: any) => {
|
||||
setInputData({ ...inputData, [inputType]: e.target.value });
|
||||
}}
|
||||
onBlur={() =>
|
||||
updateInputHandler(inputType, ArrayInputOperations.APPEND)
|
||||
}
|
||||
onKeyPress={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
updateInputHandler(inputType, ArrayInputOperations.APPEND);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
) : (
|
||||
<Box
|
||||
marginLeft="0.5%"
|
||||
cursor="pointer"
|
||||
onClick={() =>
|
||||
setInputFieldVisibility({
|
||||
...inputFieldVisibility,
|
||||
[inputType]: true,
|
||||
})
|
||||
}
|
||||
>
|
||||
<Tag
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme="gray"
|
||||
minW="fit-content"
|
||||
>
|
||||
<FaPlus />
|
||||
</Tag>
|
||||
</Box>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
if (Object.values(SelectInputType).includes(inputType)) {
|
||||
const { options, ...rest } = props;
|
||||
return (
|
||||
<Select
|
||||
size="sm"
|
||||
{...rest}
|
||||
value={variables[inputType] ? variables[inputType] : ''}
|
||||
onChange={(e) =>
|
||||
setVariables({ ...variables, [inputType]: e.target.value })
|
||||
}
|
||||
>
|
||||
{Object.entries(options).map(([key, value]: any) => (
|
||||
<option value={value} key={key}>
|
||||
{key}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
if (Object.values(MultiSelectInputType).includes(inputType)) {
|
||||
return (
|
||||
<Flex w="100%" style={{ position: 'relative' }}>
|
||||
<Flex
|
||||
border="1px solid #e2e8f0"
|
||||
w="100%"
|
||||
borderRadius="var(--chakra-radii-sm)"
|
||||
p="1% 0 0 2.5%"
|
||||
overflowX={variables[inputType].length > 3 ? 'scroll' : 'hidden'}
|
||||
overflowY="hidden"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<Flex justifyContent="start" alignItems="center" w="100%" wrap="wrap">
|
||||
{variables[inputType].map((role: string, index: number) => (
|
||||
<Box key={index} margin="0.5%" role="group">
|
||||
<Tag
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme="gray"
|
||||
minW="fit-content"
|
||||
>
|
||||
<TagLabel cursor="default">{role}</TagLabel>
|
||||
<TagRightIcon
|
||||
boxSize="12px"
|
||||
as={FaTimes}
|
||||
display="none"
|
||||
cursor="pointer"
|
||||
_groupHover={{ display: 'block' }}
|
||||
onClick={() =>
|
||||
updateInputHandler(
|
||||
inputType,
|
||||
ArrayInputOperations.REMOVE,
|
||||
role,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tag>
|
||||
</Box>
|
||||
))}
|
||||
</Flex>
|
||||
<Menu matchWidth={true}>
|
||||
<MenuButton px="10px" py="7.5px">
|
||||
<FaAngleDown />
|
||||
</MenuButton>
|
||||
<MenuList
|
||||
position="absolute"
|
||||
top="0"
|
||||
right="0"
|
||||
zIndex="10"
|
||||
maxH="150"
|
||||
overflowX="scroll"
|
||||
>
|
||||
<MenuOptionGroup
|
||||
title={undefined}
|
||||
value={variables[inputType]}
|
||||
type="checkbox"
|
||||
onChange={(values: string[] | string) => {
|
||||
setVariables({
|
||||
...variables,
|
||||
[inputType]: values,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{availableUserRoles.map((role) => {
|
||||
return (
|
||||
<MenuItemOption
|
||||
key={`multiselect-menu-${role}`}
|
||||
value={role}
|
||||
>
|
||||
{role}
|
||||
</MenuItemOption>
|
||||
);
|
||||
})}
|
||||
</MenuOptionGroup>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
if (Object.values(TextAreaInputType).includes(inputType)) {
|
||||
return (
|
||||
<Textarea
|
||||
{...props}
|
||||
size="lg"
|
||||
fontSize={14}
|
||||
value={variables[inputType] ? variables[inputType] : ''}
|
||||
onChange={(
|
||||
event: Event & {
|
||||
target: HTMLInputElement;
|
||||
},
|
||||
) =>
|
||||
setVariables({
|
||||
...variables,
|
||||
[inputType]: event.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (Object.values(SwitchInputType).includes(inputType)) {
|
||||
return (
|
||||
<Flex w="25%" justifyContent="space-between">
|
||||
<Text h="75%" fontWeight="bold" marginRight="2">
|
||||
Off
|
||||
</Text>
|
||||
<Switch
|
||||
size="md"
|
||||
isChecked={variables[inputType]}
|
||||
onChange={() => {
|
||||
setVariables({
|
||||
...variables,
|
||||
[inputType]: !variables[inputType],
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Text h="75%" fontWeight="bold" marginLeft="2">
|
||||
On
|
||||
</Text>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
if (Object.values(DateInputType).includes(inputType)) {
|
||||
return (
|
||||
<Flex border="1px solid #e2e8f0" w="100%" h="33px" padding="1%">
|
||||
<input
|
||||
type="date"
|
||||
style={{ width: '100%', paddingLeft: '2.5%' }}
|
||||
value={variables[inputType] ? variables[inputType] : ''}
|
||||
onChange={(e) =>
|
||||
setVariables({ ...variables, [inputType]: e.target.value })
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
const props = {
|
||||
size: 'sm',
|
||||
...downshiftProps,
|
||||
};
|
||||
const [availableUserRoles, setAvailableUserRoles] =
|
||||
useState<string[]>(availableRoles);
|
||||
const [inputFieldVisibility, setInputFieldVisibility] = useState<
|
||||
Record<string, boolean>
|
||||
>({
|
||||
ROLES: false,
|
||||
DEFAULT_ROLES: false,
|
||||
PROTECTED_ROLES: false,
|
||||
ALLOWED_ORIGINS: false,
|
||||
roles: false,
|
||||
});
|
||||
const [inputData, setInputData] = useState<Record<string, string>>({
|
||||
ROLES: '',
|
||||
DEFAULT_ROLES: '',
|
||||
PROTECTED_ROLES: '',
|
||||
ALLOWED_ORIGINS: '',
|
||||
roles: '',
|
||||
});
|
||||
const updateInputHandler = (
|
||||
type: string,
|
||||
operation: any,
|
||||
role: string = '',
|
||||
) => {
|
||||
if (operation === ArrayInputOperations.APPEND) {
|
||||
if (inputData[type] !== '') {
|
||||
setVariables({
|
||||
...variables,
|
||||
[type]: [...variables[type], inputData[type]],
|
||||
});
|
||||
setInputData({ ...inputData, [type]: '' });
|
||||
}
|
||||
setInputFieldVisibility({ ...inputFieldVisibility, [type]: false });
|
||||
}
|
||||
if (operation === ArrayInputOperations.REMOVE) {
|
||||
let updatedEnvVars = variables[type].filter(
|
||||
(item: string) => item !== role,
|
||||
);
|
||||
setVariables({
|
||||
...variables,
|
||||
[type]: updatedEnvVars,
|
||||
});
|
||||
}
|
||||
};
|
||||
if (Object.values(TextInputType).includes(inputType)) {
|
||||
return (
|
||||
<InputGroup size="sm">
|
||||
<Input
|
||||
{...props}
|
||||
value={variables[inputType] ? variables[inputType] : ''}
|
||||
onChange={(
|
||||
event: Event & {
|
||||
target: HTMLInputElement;
|
||||
},
|
||||
) =>
|
||||
setVariables({
|
||||
...variables,
|
||||
[inputType]: event.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<InputRightElement
|
||||
children={<FaRegClone color="#bfbfbf" />}
|
||||
cursor="pointer"
|
||||
onClick={() => copyTextToClipboard(variables[inputType])}
|
||||
/>
|
||||
</InputGroup>
|
||||
);
|
||||
}
|
||||
if (Object.values(HiddenInputType).includes(inputType)) {
|
||||
return (
|
||||
<InputGroup size="sm">
|
||||
<Input
|
||||
{...props}
|
||||
value={variables[inputType] || ''}
|
||||
onChange={(
|
||||
event: Event & {
|
||||
target: HTMLInputElement;
|
||||
},
|
||||
) =>
|
||||
setVariables({
|
||||
...variables,
|
||||
[inputType]: event.target.value,
|
||||
})
|
||||
}
|
||||
type={!fieldVisibility[inputType] ? 'password' : 'text'}
|
||||
/>
|
||||
<InputRightElement
|
||||
right="15px"
|
||||
children={
|
||||
<Flex>
|
||||
{fieldVisibility[inputType] ? (
|
||||
<Center
|
||||
w="25px"
|
||||
margin="0 1.5%"
|
||||
cursor="pointer"
|
||||
onClick={() =>
|
||||
setFieldVisibility({
|
||||
...fieldVisibility,
|
||||
[inputType]: false,
|
||||
})
|
||||
}
|
||||
>
|
||||
<FaRegEyeSlash color="#bfbfbf" />
|
||||
</Center>
|
||||
) : (
|
||||
<Center
|
||||
w="25px"
|
||||
margin="0 1.5%"
|
||||
cursor="pointer"
|
||||
onClick={() =>
|
||||
setFieldVisibility({
|
||||
...fieldVisibility,
|
||||
[inputType]: true,
|
||||
})
|
||||
}
|
||||
>
|
||||
<FaRegEye color="#bfbfbf" />
|
||||
</Center>
|
||||
)}
|
||||
<Center
|
||||
w="25px"
|
||||
margin="0 1.5%"
|
||||
cursor="pointer"
|
||||
onClick={() => copyTextToClipboard(variables[inputType])}
|
||||
>
|
||||
<FaRegClone color="#bfbfbf" />
|
||||
</Center>
|
||||
</Flex>
|
||||
}
|
||||
/>
|
||||
</InputGroup>
|
||||
);
|
||||
}
|
||||
if (Object.values(ArrayInputType).includes(inputType)) {
|
||||
return (
|
||||
<Flex
|
||||
border="1px solid #e2e8f0"
|
||||
w="100%"
|
||||
borderRadius={5}
|
||||
paddingTop="0.5%"
|
||||
overflowX={variables[inputType].length > 3 ? 'scroll' : 'hidden'}
|
||||
overflowY="hidden"
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
>
|
||||
{variables[inputType].map((role: string, index: number) => (
|
||||
<Box key={index} margin="0.5%" role="group">
|
||||
<Tag
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme="gray"
|
||||
minW="fit-content"
|
||||
>
|
||||
<TagLabel cursor="default">{role}</TagLabel>
|
||||
<TagRightIcon
|
||||
boxSize="12px"
|
||||
as={FaTimes}
|
||||
display="none"
|
||||
cursor="pointer"
|
||||
_groupHover={{ display: 'block' }}
|
||||
onClick={() =>
|
||||
updateInputHandler(
|
||||
inputType,
|
||||
ArrayInputOperations.REMOVE,
|
||||
role,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tag>
|
||||
</Box>
|
||||
))}
|
||||
{inputFieldVisibility[inputType] ? (
|
||||
<Box ml="1%" mb="0.75%">
|
||||
<Input
|
||||
type="text"
|
||||
size="xs"
|
||||
minW="150px"
|
||||
placeholder="add a new value"
|
||||
value={inputData[inputType] || ''}
|
||||
onChange={(e: any) => {
|
||||
setInputData({ ...inputData, [inputType]: e.target.value });
|
||||
}}
|
||||
onBlur={() =>
|
||||
updateInputHandler(inputType, ArrayInputOperations.APPEND)
|
||||
}
|
||||
onKeyPress={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
updateInputHandler(inputType, ArrayInputOperations.APPEND);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
) : (
|
||||
<Box
|
||||
marginLeft="0.5%"
|
||||
cursor="pointer"
|
||||
onClick={() =>
|
||||
setInputFieldVisibility({
|
||||
...inputFieldVisibility,
|
||||
[inputType]: true,
|
||||
})
|
||||
}
|
||||
>
|
||||
<Tag
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme="gray"
|
||||
minW="fit-content"
|
||||
>
|
||||
<FaPlus />
|
||||
</Tag>
|
||||
</Box>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
if (Object.values(SelectInputType).includes(inputType)) {
|
||||
const { options, ...rest } = props;
|
||||
return (
|
||||
<Select
|
||||
size="sm"
|
||||
{...rest}
|
||||
value={variables[inputType] ? variables[inputType] : ''}
|
||||
onChange={(e) =>
|
||||
setVariables({ ...variables, [inputType]: e.target.value })
|
||||
}
|
||||
>
|
||||
{Object.entries(options).map(([key, value]: any) => (
|
||||
<option value={value} key={key}>
|
||||
{key}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
if (Object.values(MultiSelectInputType).includes(inputType)) {
|
||||
return (
|
||||
<Flex w="100%" style={{ position: 'relative' }}>
|
||||
<Flex
|
||||
border="1px solid #e2e8f0"
|
||||
w="100%"
|
||||
borderRadius="var(--chakra-radii-sm)"
|
||||
p="1% 0 0 2.5%"
|
||||
overflowX={variables[inputType].length > 3 ? 'scroll' : 'hidden'}
|
||||
overflowY="hidden"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<Flex justifyContent="start" alignItems="center" w="100%" wrap="wrap">
|
||||
{variables[inputType].map((role: string, index: number) => (
|
||||
<Box key={index} margin="0.5%" role="group">
|
||||
<Tag
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme="gray"
|
||||
minW="fit-content"
|
||||
>
|
||||
<TagLabel cursor="default">{role}</TagLabel>
|
||||
<TagRightIcon
|
||||
boxSize="12px"
|
||||
as={FaTimes}
|
||||
display="none"
|
||||
cursor="pointer"
|
||||
_groupHover={{ display: 'block' }}
|
||||
onClick={() =>
|
||||
updateInputHandler(
|
||||
inputType,
|
||||
ArrayInputOperations.REMOVE,
|
||||
role,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tag>
|
||||
</Box>
|
||||
))}
|
||||
</Flex>
|
||||
<Menu matchWidth={true}>
|
||||
<MenuButton px="10px" py="7.5px">
|
||||
<FaAngleDown />
|
||||
</MenuButton>
|
||||
<MenuList
|
||||
position="absolute"
|
||||
top="0"
|
||||
right="0"
|
||||
zIndex="10"
|
||||
maxH="150"
|
||||
overflowX="scroll"
|
||||
>
|
||||
<MenuOptionGroup
|
||||
title={undefined}
|
||||
value={variables[inputType]}
|
||||
type="checkbox"
|
||||
onChange={(values: string[] | string) => {
|
||||
setVariables({
|
||||
...variables,
|
||||
[inputType]: values,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{availableUserRoles.map((role) => {
|
||||
return (
|
||||
<MenuItemOption
|
||||
key={`multiselect-menu-${role}`}
|
||||
value={role}
|
||||
>
|
||||
{role}
|
||||
</MenuItemOption>
|
||||
);
|
||||
})}
|
||||
</MenuOptionGroup>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
if (Object.values(TextAreaInputType).includes(inputType)) {
|
||||
return (
|
||||
<Textarea
|
||||
{...props}
|
||||
size="lg"
|
||||
fontSize={14}
|
||||
value={variables[inputType] ? variables[inputType] : ''}
|
||||
onChange={(
|
||||
event: Event & {
|
||||
target: HTMLInputElement;
|
||||
},
|
||||
) =>
|
||||
setVariables({
|
||||
...variables,
|
||||
[inputType]: event.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (Object.values(SwitchInputType).includes(inputType)) {
|
||||
return (
|
||||
<Flex w="25%" justifyContent="space-between">
|
||||
<Text h="75%" fontWeight="bold" marginRight="2">
|
||||
Off
|
||||
</Text>
|
||||
<Switch
|
||||
size="md"
|
||||
isChecked={variables[inputType]}
|
||||
onChange={() => {
|
||||
setVariables({
|
||||
...variables,
|
||||
[inputType]: !variables[inputType],
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Text h="75%" fontWeight="bold" marginLeft="2">
|
||||
On
|
||||
</Text>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
if (Object.values(DateInputType).includes(inputType)) {
|
||||
return (
|
||||
<Flex border="1px solid #e2e8f0" w="100%" h="33px" padding="1%">
|
||||
<input
|
||||
type="date"
|
||||
style={{ width: '100%', paddingLeft: '2.5%' }}
|
||||
value={variables[inputType] ? variables[inputType] : ''}
|
||||
onChange={(e) =>
|
||||
setVariables({ ...variables, [inputType]: e.target.value })
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default InputField;
|
||||
|
@@ -1,312 +1,314 @@
|
||||
export const LOGO_URL =
|
||||
'https://user-images.githubusercontent.com/6964334/147834043-fc384cab-e7ca-40f8-9663-38fc25fd5f3a.png';
|
||||
'https://user-images.githubusercontent.com/6964334/147834043-fc384cab-e7ca-40f8-9663-38fc25fd5f3a.png';
|
||||
|
||||
export const TextInputType = {
|
||||
ACCESS_TOKEN_EXPIRY_TIME: 'ACCESS_TOKEN_EXPIRY_TIME',
|
||||
CLIENT_ID: 'CLIENT_ID',
|
||||
GOOGLE_CLIENT_ID: 'GOOGLE_CLIENT_ID',
|
||||
GITHUB_CLIENT_ID: 'GITHUB_CLIENT_ID',
|
||||
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
|
||||
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
|
||||
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
|
||||
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
|
||||
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
|
||||
REDIS_URL: 'REDIS_URL',
|
||||
SMTP_HOST: 'SMTP_HOST',
|
||||
SMTP_PORT: 'SMTP_PORT',
|
||||
SMTP_USERNAME: 'SMTP_USERNAME',
|
||||
SENDER_EMAIL: 'SENDER_EMAIL',
|
||||
ORGANIZATION_NAME: 'ORGANIZATION_NAME',
|
||||
ORGANIZATION_LOGO: 'ORGANIZATION_LOGO',
|
||||
DATABASE_NAME: 'DATABASE_NAME',
|
||||
DATABASE_TYPE: 'DATABASE_TYPE',
|
||||
DATABASE_URL: 'DATABASE_URL',
|
||||
GIVEN_NAME: 'given_name',
|
||||
MIDDLE_NAME: 'middle_name',
|
||||
FAMILY_NAME: 'family_name',
|
||||
NICKNAME: 'nickname',
|
||||
PHONE_NUMBER: 'phone_number',
|
||||
PICTURE: 'picture',
|
||||
ACCESS_TOKEN_EXPIRY_TIME: 'ACCESS_TOKEN_EXPIRY_TIME',
|
||||
CLIENT_ID: 'CLIENT_ID',
|
||||
GOOGLE_CLIENT_ID: 'GOOGLE_CLIENT_ID',
|
||||
GITHUB_CLIENT_ID: 'GITHUB_CLIENT_ID',
|
||||
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
|
||||
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
|
||||
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
|
||||
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
|
||||
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
|
||||
REDIS_URL: 'REDIS_URL',
|
||||
SMTP_HOST: 'SMTP_HOST',
|
||||
SMTP_PORT: 'SMTP_PORT',
|
||||
SMTP_USERNAME: 'SMTP_USERNAME',
|
||||
SMTP_LOCAL_NAME: 'SMTP_LOCAL_NAME',
|
||||
SENDER_EMAIL: 'SENDER_EMAIL',
|
||||
ORGANIZATION_NAME: 'ORGANIZATION_NAME',
|
||||
ORGANIZATION_LOGO: 'ORGANIZATION_LOGO',
|
||||
DATABASE_NAME: 'DATABASE_NAME',
|
||||
DATABASE_TYPE: 'DATABASE_TYPE',
|
||||
DATABASE_URL: 'DATABASE_URL',
|
||||
GIVEN_NAME: 'given_name',
|
||||
MIDDLE_NAME: 'middle_name',
|
||||
FAMILY_NAME: 'family_name',
|
||||
NICKNAME: 'nickname',
|
||||
PHONE_NUMBER: 'phone_number',
|
||||
PICTURE: 'picture',
|
||||
};
|
||||
|
||||
export const HiddenInputType = {
|
||||
CLIENT_SECRET: 'CLIENT_SECRET',
|
||||
GOOGLE_CLIENT_SECRET: 'GOOGLE_CLIENT_SECRET',
|
||||
GITHUB_CLIENT_SECRET: 'GITHUB_CLIENT_SECRET',
|
||||
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
|
||||
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
|
||||
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
||||
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
||||
JWT_SECRET: 'JWT_SECRET',
|
||||
SMTP_PASSWORD: 'SMTP_PASSWORD',
|
||||
ADMIN_SECRET: 'ADMIN_SECRET',
|
||||
OLD_ADMIN_SECRET: 'OLD_ADMIN_SECRET',
|
||||
CLIENT_SECRET: 'CLIENT_SECRET',
|
||||
GOOGLE_CLIENT_SECRET: 'GOOGLE_CLIENT_SECRET',
|
||||
GITHUB_CLIENT_SECRET: 'GITHUB_CLIENT_SECRET',
|
||||
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
|
||||
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
|
||||
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
||||
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
||||
JWT_SECRET: 'JWT_SECRET',
|
||||
SMTP_PASSWORD: 'SMTP_PASSWORD',
|
||||
ADMIN_SECRET: 'ADMIN_SECRET',
|
||||
OLD_ADMIN_SECRET: 'OLD_ADMIN_SECRET',
|
||||
};
|
||||
|
||||
export const ArrayInputType = {
|
||||
ROLES: 'ROLES',
|
||||
DEFAULT_ROLES: 'DEFAULT_ROLES',
|
||||
PROTECTED_ROLES: 'PROTECTED_ROLES',
|
||||
ALLOWED_ORIGINS: 'ALLOWED_ORIGINS',
|
||||
ROLES: 'ROLES',
|
||||
DEFAULT_ROLES: 'DEFAULT_ROLES',
|
||||
PROTECTED_ROLES: 'PROTECTED_ROLES',
|
||||
ALLOWED_ORIGINS: 'ALLOWED_ORIGINS',
|
||||
};
|
||||
|
||||
export const SelectInputType = {
|
||||
JWT_TYPE: 'JWT_TYPE',
|
||||
GENDER: 'gender',
|
||||
JWT_TYPE: 'JWT_TYPE',
|
||||
GENDER: 'gender',
|
||||
};
|
||||
|
||||
export const MultiSelectInputType = {
|
||||
USER_ROLES: 'roles',
|
||||
USER_ROLES: 'roles',
|
||||
};
|
||||
|
||||
export const TextAreaInputType = {
|
||||
CUSTOM_ACCESS_TOKEN_SCRIPT: 'CUSTOM_ACCESS_TOKEN_SCRIPT',
|
||||
JWT_PRIVATE_KEY: 'JWT_PRIVATE_KEY',
|
||||
JWT_PUBLIC_KEY: 'JWT_PUBLIC_KEY',
|
||||
CUSTOM_ACCESS_TOKEN_SCRIPT: 'CUSTOM_ACCESS_TOKEN_SCRIPT',
|
||||
JWT_PRIVATE_KEY: 'JWT_PRIVATE_KEY',
|
||||
JWT_PUBLIC_KEY: 'JWT_PUBLIC_KEY',
|
||||
};
|
||||
|
||||
export const SwitchInputType = {
|
||||
APP_COOKIE_SECURE: 'APP_COOKIE_SECURE',
|
||||
ADMIN_COOKIE_SECURE: 'ADMIN_COOKIE_SECURE',
|
||||
DISABLE_LOGIN_PAGE: 'DISABLE_LOGIN_PAGE',
|
||||
DISABLE_MAGIC_LINK_LOGIN: 'DISABLE_MAGIC_LINK_LOGIN',
|
||||
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
|
||||
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
|
||||
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
|
||||
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
|
||||
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
|
||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: 'DISABLE_MULTI_FACTOR_AUTHENTICATION',
|
||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: 'ENFORCE_MULTI_FACTOR_AUTHENTICATION',
|
||||
APP_COOKIE_SECURE: 'APP_COOKIE_SECURE',
|
||||
ADMIN_COOKIE_SECURE: 'ADMIN_COOKIE_SECURE',
|
||||
DISABLE_LOGIN_PAGE: 'DISABLE_LOGIN_PAGE',
|
||||
DISABLE_MAGIC_LINK_LOGIN: 'DISABLE_MAGIC_LINK_LOGIN',
|
||||
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
|
||||
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
|
||||
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
|
||||
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
|
||||
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
|
||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: 'DISABLE_MULTI_FACTOR_AUTHENTICATION',
|
||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: 'ENFORCE_MULTI_FACTOR_AUTHENTICATION',
|
||||
};
|
||||
|
||||
export const DateInputType = {
|
||||
BIRTHDATE: 'birthdate',
|
||||
BIRTHDATE: 'birthdate',
|
||||
};
|
||||
|
||||
export const ArrayInputOperations = {
|
||||
APPEND: 'APPEND',
|
||||
REMOVE: 'REMOVE',
|
||||
APPEND: 'APPEND',
|
||||
REMOVE: 'REMOVE',
|
||||
};
|
||||
|
||||
export const HMACEncryptionType = {
|
||||
HS256: 'HS256',
|
||||
HS384: 'HS384',
|
||||
HS512: 'HS512',
|
||||
HS256: 'HS256',
|
||||
HS384: 'HS384',
|
||||
HS512: 'HS512',
|
||||
};
|
||||
|
||||
export const RSAEncryptionType = {
|
||||
RS256: 'RS256',
|
||||
RS384: 'RS384',
|
||||
RS512: 'RS512',
|
||||
RS256: 'RS256',
|
||||
RS384: 'RS384',
|
||||
RS512: 'RS512',
|
||||
};
|
||||
|
||||
export const ECDSAEncryptionType = {
|
||||
ES256: 'ES256',
|
||||
ES384: 'ES384',
|
||||
ES512: 'ES512',
|
||||
ES256: 'ES256',
|
||||
ES384: 'ES384',
|
||||
ES512: 'ES512',
|
||||
};
|
||||
|
||||
export interface envVarTypes {
|
||||
GOOGLE_CLIENT_ID: string;
|
||||
GOOGLE_CLIENT_SECRET: string;
|
||||
GITHUB_CLIENT_ID: string;
|
||||
GITHUB_CLIENT_SECRET: string;
|
||||
FACEBOOK_CLIENT_ID: string;
|
||||
FACEBOOK_CLIENT_SECRET: string;
|
||||
LINKEDIN_CLIENT_ID: string;
|
||||
LINKEDIN_CLIENT_SECRET: string;
|
||||
APPLE_CLIENT_ID: string;
|
||||
APPLE_CLIENT_SECRET: string;
|
||||
TWITTER_CLIENT_ID: string;
|
||||
TWITTER_CLIENT_SECRET: string;
|
||||
ROLES: [string] | [];
|
||||
DEFAULT_ROLES: [string] | [];
|
||||
PROTECTED_ROLES: [string] | [];
|
||||
JWT_TYPE: string;
|
||||
JWT_SECRET: string;
|
||||
JWT_ROLE_CLAIM: string;
|
||||
JWT_PRIVATE_KEY: string;
|
||||
JWT_PUBLIC_KEY: string;
|
||||
REDIS_URL: string;
|
||||
SMTP_HOST: string;
|
||||
SMTP_PORT: string;
|
||||
SMTP_USERNAME: string;
|
||||
SMTP_PASSWORD: string;
|
||||
SENDER_EMAIL: string;
|
||||
ALLOWED_ORIGINS: [string] | [];
|
||||
ORGANIZATION_NAME: string;
|
||||
ORGANIZATION_LOGO: string;
|
||||
CUSTOM_ACCESS_TOKEN_SCRIPT: string;
|
||||
ADMIN_SECRET: string;
|
||||
APP_COOKIE_SECURE: boolean;
|
||||
ADMIN_COOKIE_SECURE: boolean;
|
||||
DISABLE_LOGIN_PAGE: boolean;
|
||||
DISABLE_MAGIC_LINK_LOGIN: boolean;
|
||||
DISABLE_EMAIL_VERIFICATION: boolean;
|
||||
DISABLE_BASIC_AUTHENTICATION: boolean;
|
||||
DISABLE_SIGN_UP: boolean;
|
||||
DISABLE_STRONG_PASSWORD: boolean;
|
||||
OLD_ADMIN_SECRET: string;
|
||||
DATABASE_NAME: string;
|
||||
DATABASE_TYPE: string;
|
||||
DATABASE_URL: string;
|
||||
ACCESS_TOKEN_EXPIRY_TIME: string;
|
||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: boolean;
|
||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: boolean;
|
||||
GOOGLE_CLIENT_ID: string;
|
||||
GOOGLE_CLIENT_SECRET: string;
|
||||
GITHUB_CLIENT_ID: string;
|
||||
GITHUB_CLIENT_SECRET: string;
|
||||
FACEBOOK_CLIENT_ID: string;
|
||||
FACEBOOK_CLIENT_SECRET: string;
|
||||
LINKEDIN_CLIENT_ID: string;
|
||||
LINKEDIN_CLIENT_SECRET: string;
|
||||
APPLE_CLIENT_ID: string;
|
||||
APPLE_CLIENT_SECRET: string;
|
||||
TWITTER_CLIENT_ID: string;
|
||||
TWITTER_CLIENT_SECRET: string;
|
||||
ROLES: [string] | [];
|
||||
DEFAULT_ROLES: [string] | [];
|
||||
PROTECTED_ROLES: [string] | [];
|
||||
JWT_TYPE: string;
|
||||
JWT_SECRET: string;
|
||||
JWT_ROLE_CLAIM: string;
|
||||
JWT_PRIVATE_KEY: string;
|
||||
JWT_PUBLIC_KEY: string;
|
||||
REDIS_URL: string;
|
||||
SMTP_HOST: string;
|
||||
SMTP_PORT: string;
|
||||
SMTP_USERNAME: string;
|
||||
SMTP_PASSWORD: string;
|
||||
SMTP_LOCAL_NAME: string;
|
||||
SENDER_EMAIL: string;
|
||||
ALLOWED_ORIGINS: [string] | [];
|
||||
ORGANIZATION_NAME: string;
|
||||
ORGANIZATION_LOGO: string;
|
||||
CUSTOM_ACCESS_TOKEN_SCRIPT: string;
|
||||
ADMIN_SECRET: string;
|
||||
APP_COOKIE_SECURE: boolean;
|
||||
ADMIN_COOKIE_SECURE: boolean;
|
||||
DISABLE_LOGIN_PAGE: boolean;
|
||||
DISABLE_MAGIC_LINK_LOGIN: boolean;
|
||||
DISABLE_EMAIL_VERIFICATION: boolean;
|
||||
DISABLE_BASIC_AUTHENTICATION: boolean;
|
||||
DISABLE_SIGN_UP: boolean;
|
||||
DISABLE_STRONG_PASSWORD: boolean;
|
||||
OLD_ADMIN_SECRET: string;
|
||||
DATABASE_NAME: string;
|
||||
DATABASE_TYPE: string;
|
||||
DATABASE_URL: string;
|
||||
ACCESS_TOKEN_EXPIRY_TIME: string;
|
||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: boolean;
|
||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: boolean;
|
||||
}
|
||||
|
||||
export const envSubViews = {
|
||||
INSTANCE_INFO: 'instance-info',
|
||||
ROLES: 'roles',
|
||||
JWT_CONFIG: 'jwt-config',
|
||||
SESSION_STORAGE: 'session-storage',
|
||||
EMAIL_CONFIG: 'email-config',
|
||||
WHITELIST_VARIABLES: 'whitelist-variables',
|
||||
ORGANIZATION_INFO: 'organization-info',
|
||||
ACCESS_TOKEN: 'access-token',
|
||||
FEATURES: 'features',
|
||||
ADMIN_SECRET: 'admin-secret',
|
||||
DB_CRED: 'db-cred',
|
||||
INSTANCE_INFO: 'instance-info',
|
||||
ROLES: 'roles',
|
||||
JWT_CONFIG: 'jwt-config',
|
||||
SESSION_STORAGE: 'session-storage',
|
||||
EMAIL_CONFIG: 'email-config',
|
||||
WHITELIST_VARIABLES: 'whitelist-variables',
|
||||
ORGANIZATION_INFO: 'organization-info',
|
||||
ACCESS_TOKEN: 'access-token',
|
||||
FEATURES: 'features',
|
||||
ADMIN_SECRET: 'admin-secret',
|
||||
DB_CRED: 'db-cred',
|
||||
};
|
||||
|
||||
export enum WebhookInputDataFields {
|
||||
ID = 'id',
|
||||
EVENT_NAME = 'event_name',
|
||||
ENDPOINT = 'endpoint',
|
||||
ENABLED = 'enabled',
|
||||
HEADERS = 'headers',
|
||||
ID = 'id',
|
||||
EVENT_NAME = 'event_name',
|
||||
ENDPOINT = 'endpoint',
|
||||
ENABLED = 'enabled',
|
||||
HEADERS = 'headers',
|
||||
}
|
||||
|
||||
export enum EmailTemplateInputDataFields {
|
||||
ID = 'id',
|
||||
EVENT_NAME = 'event_name',
|
||||
SUBJECT = 'subject',
|
||||
CREATED_AT = 'created_at',
|
||||
TEMPLATE = 'template',
|
||||
DESIGN = 'design',
|
||||
ID = 'id',
|
||||
EVENT_NAME = 'event_name',
|
||||
SUBJECT = 'subject',
|
||||
CREATED_AT = 'created_at',
|
||||
TEMPLATE = 'template',
|
||||
DESIGN = 'design',
|
||||
}
|
||||
|
||||
export enum WebhookInputHeaderFields {
|
||||
KEY = 'key',
|
||||
VALUE = 'value',
|
||||
KEY = 'key',
|
||||
VALUE = 'value',
|
||||
}
|
||||
|
||||
export enum UpdateModalViews {
|
||||
ADD = 'add',
|
||||
Edit = 'edit',
|
||||
ADD = 'add',
|
||||
Edit = 'edit',
|
||||
}
|
||||
|
||||
export const pageLimits: number[] = [5, 10, 15];
|
||||
|
||||
export const webhookEventNames = {
|
||||
'User signup': 'user.signup',
|
||||
'User created': 'user.created',
|
||||
'User login': 'user.login',
|
||||
'User deleted': 'user.deleted',
|
||||
'User access enabled': 'user.access_enabled',
|
||||
'User access revoked': 'user.access_revoked',
|
||||
'User signup': 'user.signup',
|
||||
'User created': 'user.created',
|
||||
'User login': 'user.login',
|
||||
'User deleted': 'user.deleted',
|
||||
'User access enabled': 'user.access_enabled',
|
||||
'User access revoked': 'user.access_revoked',
|
||||
};
|
||||
|
||||
export const emailTemplateEventNames = {
|
||||
Signup: 'basic_auth_signup',
|
||||
'Magic Link Login': 'magic_link_login',
|
||||
'Update Email': 'update_email',
|
||||
'Forgot Password': 'forgot_password',
|
||||
'Verify Otp': 'verify_otp',
|
||||
'Invite member': 'invite_member',
|
||||
Signup: 'basic_auth_signup',
|
||||
'Magic Link Login': 'magic_link_login',
|
||||
'Update Email': 'update_email',
|
||||
'Forgot Password': 'forgot_password',
|
||||
'Verify Otp': 'verify_otp',
|
||||
'Invite member': 'invite_member',
|
||||
};
|
||||
|
||||
export enum webhookVerifiedStatus {
|
||||
VERIFIED = 'verified',
|
||||
NOT_VERIFIED = 'not_verified',
|
||||
PENDING = 'verification_pending',
|
||||
VERIFIED = 'verified',
|
||||
NOT_VERIFIED = 'not_verified',
|
||||
PENDING = 'verification_pending',
|
||||
}
|
||||
|
||||
export const emailTemplateVariables = {
|
||||
'user.id': {
|
||||
description: `User identifier`,
|
||||
value: '{.user.id}}',
|
||||
},
|
||||
'user.email': {
|
||||
description: 'User email address',
|
||||
value: '{.user.email}}',
|
||||
},
|
||||
'user.given_name': {
|
||||
description: `User first name`,
|
||||
value: '{.user.given_name}}',
|
||||
},
|
||||
'user.family_name': {
|
||||
description: `User last name`,
|
||||
value: '{.user.family_name}}',
|
||||
},
|
||||
'user.middle_name': {
|
||||
description: `Middle name of user`,
|
||||
value: '{.user.middle_name}}',
|
||||
},
|
||||
'user.nickname': {
|
||||
description: `Nick name of user`,
|
||||
value: '{.user.nickname}}',
|
||||
},
|
||||
'user.preferred_username': {
|
||||
description: `Username, by default it is email`,
|
||||
value: '{.user.preferred_username}}',
|
||||
},
|
||||
'user.signup_methods': {
|
||||
description: `Comma separated list of methods using which user has signed up`,
|
||||
value: '{.user.signup_methods}}',
|
||||
},
|
||||
'user.email_verified': {
|
||||
description: `Whether email is verified or not`,
|
||||
value: '{.user.email_verified}}',
|
||||
},
|
||||
'user.picture': {
|
||||
description: `URL of the user profile picture`,
|
||||
value: '{.user.picture}}',
|
||||
},
|
||||
'user.roles': {
|
||||
description: `Comma separated list of roles assigned to user`,
|
||||
value: '{.user.roles}}',
|
||||
},
|
||||
'user.gender': {
|
||||
description: `Gender of user`,
|
||||
value: '{.user.gender}}',
|
||||
},
|
||||
'user.birthdate': {
|
||||
description: `BirthDate of user`,
|
||||
value: '{.user.birthdate}}',
|
||||
},
|
||||
'user.phone_number': {
|
||||
description: `Phone number of user`,
|
||||
value: '{.user.phone_number}}',
|
||||
},
|
||||
'user.phone_number_verified': {
|
||||
description: `Whether phone number is verified or not`,
|
||||
value: '{.user.phone_number_verified}}',
|
||||
},
|
||||
'user.created_at': {
|
||||
description: `User created at time`,
|
||||
value: '{.user.created_at}}',
|
||||
},
|
||||
'user.updated_at': {
|
||||
description: `Last updated time at user`,
|
||||
value: '{.user.updated_at}}',
|
||||
},
|
||||
'organization.name': {
|
||||
description: `Organization name`,
|
||||
value: '{.organization.name}}',
|
||||
},
|
||||
'organization.logo': {
|
||||
description: `Organization logo`,
|
||||
value: '{.organization.logo}}',
|
||||
},
|
||||
verification_url: {
|
||||
description: `Verification URL in case of events other than verify otp`,
|
||||
value: '{.verification_url}}',
|
||||
},
|
||||
otp: {
|
||||
description: `OTP sent during login with Multi factor authentication`,
|
||||
value: '{.otp}}',
|
||||
},
|
||||
'user.id': {
|
||||
description: `User identifier`,
|
||||
value: '{.user.id}}',
|
||||
},
|
||||
'user.email': {
|
||||
description: 'User email address',
|
||||
value: '{.user.email}}',
|
||||
},
|
||||
'user.given_name': {
|
||||
description: `User first name`,
|
||||
value: '{.user.given_name}}',
|
||||
},
|
||||
'user.family_name': {
|
||||
description: `User last name`,
|
||||
value: '{.user.family_name}}',
|
||||
},
|
||||
'user.middle_name': {
|
||||
description: `Middle name of user`,
|
||||
value: '{.user.middle_name}}',
|
||||
},
|
||||
'user.nickname': {
|
||||
description: `Nick name of user`,
|
||||
value: '{.user.nickname}}',
|
||||
},
|
||||
'user.preferred_username': {
|
||||
description: `Username, by default it is email`,
|
||||
value: '{.user.preferred_username}}',
|
||||
},
|
||||
'user.signup_methods': {
|
||||
description: `Comma separated list of methods using which user has signed up`,
|
||||
value: '{.user.signup_methods}}',
|
||||
},
|
||||
'user.email_verified': {
|
||||
description: `Whether email is verified or not`,
|
||||
value: '{.user.email_verified}}',
|
||||
},
|
||||
'user.picture': {
|
||||
description: `URL of the user profile picture`,
|
||||
value: '{.user.picture}}',
|
||||
},
|
||||
'user.roles': {
|
||||
description: `Comma separated list of roles assigned to user`,
|
||||
value: '{.user.roles}}',
|
||||
},
|
||||
'user.gender': {
|
||||
description: `Gender of user`,
|
||||
value: '{.user.gender}}',
|
||||
},
|
||||
'user.birthdate': {
|
||||
description: `BirthDate of user`,
|
||||
value: '{.user.birthdate}}',
|
||||
},
|
||||
'user.phone_number': {
|
||||
description: `Phone number of user`,
|
||||
value: '{.user.phone_number}}',
|
||||
},
|
||||
'user.phone_number_verified': {
|
||||
description: `Whether phone number is verified or not`,
|
||||
value: '{.user.phone_number_verified}}',
|
||||
},
|
||||
'user.created_at': {
|
||||
description: `User created at time`,
|
||||
value: '{.user.created_at}}',
|
||||
},
|
||||
'user.updated_at': {
|
||||
description: `Last updated time at user`,
|
||||
value: '{.user.updated_at}}',
|
||||
},
|
||||
'organization.name': {
|
||||
description: `Organization name`,
|
||||
value: '{.organization.name}}',
|
||||
},
|
||||
'organization.logo': {
|
||||
description: `Organization logo`,
|
||||
value: '{.organization.logo}}',
|
||||
},
|
||||
verification_url: {
|
||||
description: `Verification URL in case of events other than verify otp`,
|
||||
value: '{.verification_url}}',
|
||||
},
|
||||
otp: {
|
||||
description: `OTP sent during login with Multi factor authentication`,
|
||||
value: '{.otp}}',
|
||||
},
|
||||
};
|
||||
|
||||
export const webhookPayloadExample: string = `{
|
||||
|
@@ -45,6 +45,7 @@ export const EnvVariablesQuery = `
|
||||
SMTP_PORT
|
||||
SMTP_USERNAME
|
||||
SMTP_PASSWORD
|
||||
SMTP_LOCAL_NAME
|
||||
SENDER_EMAIL
|
||||
ALLOWED_ORIGINS
|
||||
ORGANIZATION_NAME
|
||||
|
@@ -65,6 +65,7 @@ const Environment = () => {
|
||||
SMTP_PORT: '',
|
||||
SMTP_USERNAME: '',
|
||||
SMTP_PASSWORD: '',
|
||||
SMTP_LOCAL_NAME: '',
|
||||
SENDER_EMAIL: '',
|
||||
ALLOWED_ORIGINS: [],
|
||||
ORGANIZATION_NAME: '',
|
||||
|
@@ -51,6 +51,8 @@ const (
|
||||
EnvKeySmtpUsername = "SMTP_USERNAME"
|
||||
// EnvKeySmtpPassword key for env variable SMTP_PASSWORD
|
||||
EnvKeySmtpPassword = "SMTP_PASSWORD"
|
||||
// EnvKeySmtpLocalName key for env variable SMTP_LOCAL_NAME
|
||||
EnvKeySmtpLocalName = "SMTP_LOCAL_NAME"
|
||||
// EnvKeySenderEmail key for env variable SENDER_EMAIL
|
||||
EnvKeySenderEmail = "SENDER_EMAIL"
|
||||
// EnvKeyIsEmailServiceEnabled key for env variable IS_EMAIL_SERVICE_ENABLED
|
||||
|
@@ -26,7 +26,6 @@ func NewProvider() (*provider, error) {
|
||||
config := aws.Config{
|
||||
MaxRetries: aws.Int(3),
|
||||
CredentialsChainVerboseErrors: aws.Bool(true), // for full error logs
|
||||
|
||||
}
|
||||
|
||||
if awsRegion != "" {
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -126,6 +127,12 @@ func SendEmail(to []string, event string, data map[string]interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
smtpLocalName, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySmtpLocalName)
|
||||
if err != nil {
|
||||
log.Debugf("Error while getting smtp localname from env variable: %v", err)
|
||||
smtpLocalName = ""
|
||||
}
|
||||
|
||||
isProd, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsProd)
|
||||
if err != nil {
|
||||
log.Errorf("Error while getting env variable: %v", err)
|
||||
@@ -141,6 +148,11 @@ func SendEmail(to []string, event string, data map[string]interface{}) error {
|
||||
if !isProd {
|
||||
d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
}
|
||||
|
||||
if strings.TrimSpace(smtpLocalName) != "" {
|
||||
d.LocalName = smtpLocalName
|
||||
}
|
||||
|
||||
if err := d.DialAndSend(m); err != nil {
|
||||
log.Debug("SMTP Failed: ", err)
|
||||
return err
|
||||
|
8
server/env/env.go
vendored
8
server/env/env.go
vendored
@@ -55,6 +55,7 @@ func InitAllEnv() error {
|
||||
osSmtpPort := os.Getenv(constants.EnvKeySmtpPort)
|
||||
osSmtpUsername := os.Getenv(constants.EnvKeySmtpUsername)
|
||||
osSmtpPassword := os.Getenv(constants.EnvKeySmtpPassword)
|
||||
osSmtpLocalName := os.Getenv(constants.EnvKeySmtpLocalName)
|
||||
osSenderEmail := os.Getenv(constants.EnvKeySenderEmail)
|
||||
osJwtType := os.Getenv(constants.EnvKeyJwtType)
|
||||
osJwtSecret := os.Getenv(constants.EnvKeyJwtSecret)
|
||||
@@ -205,6 +206,13 @@ func InitAllEnv() error {
|
||||
envData[constants.EnvKeySmtpUsername] = osSmtpUsername
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeySmtpLocalName]; !ok || val == "" {
|
||||
envData[constants.EnvKeySmtpLocalName] = osSmtpLocalName
|
||||
}
|
||||
if osSmtpLocalName != "" && envData[constants.EnvKeySmtpLocalName] != osSmtpLocalName {
|
||||
envData[constants.EnvKeySmtpLocalName] = osSmtpLocalName
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeySmtpPassword]; !ok || val == "" {
|
||||
envData[constants.EnvKeySmtpPassword] = osSmtpPassword
|
||||
}
|
||||
|
@@ -123,7 +123,6 @@ github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
|
||||
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gocql/gocql v1.2.0 h1:TZhsCd7fRuye4VyHr3WCvWwIQaZUmjsqnSIXK9FcVCE=
|
||||
github.com/gocql/gocql v1.2.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
||||
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
@@ -258,6 +257,7 @@ github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI=
|
||||
github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
@@ -492,12 +492,11 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b h1:uKO3Js8lXGjpjdc4J3rqs0/Ex5yDKUGfk43tTYWVLas=
|
||||
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -561,14 +560,13 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
@@ -118,6 +118,7 @@ type ComplexityRoot struct {
|
||||
ResetPasswordURL func(childComplexity int) int
|
||||
Roles func(childComplexity int) int
|
||||
SMTPHost func(childComplexity int) int
|
||||
SMTPLocalName func(childComplexity int) int
|
||||
SMTPPassword func(childComplexity int) int
|
||||
SMTPPort func(childComplexity int) int
|
||||
SMTPUsername func(childComplexity int) int
|
||||
@@ -245,6 +246,7 @@ type ComplexityRoot struct {
|
||||
}
|
||||
|
||||
ValidateJWTTokenResponse struct {
|
||||
Claims func(childComplexity int) int
|
||||
IsValid func(childComplexity int) int
|
||||
}
|
||||
|
||||
@@ -805,6 +807,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.Env.SMTPHost(childComplexity), true
|
||||
|
||||
case "Env.SMTP_LOCAL_NAME":
|
||||
if e.complexity.Env.SMTPLocalName == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Env.SMTPLocalName(childComplexity), true
|
||||
|
||||
case "Env.SMTP_PASSWORD":
|
||||
if e.complexity.Env.SMTPPassword == nil {
|
||||
break
|
||||
@@ -1638,6 +1647,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.Users.Users(childComplexity), true
|
||||
|
||||
case "ValidateJWTTokenResponse.claims":
|
||||
if e.complexity.ValidateJWTTokenResponse.Claims == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.ValidateJWTTokenResponse.Claims(childComplexity), true
|
||||
|
||||
case "ValidateJWTTokenResponse.is_valid":
|
||||
if e.complexity.ValidateJWTTokenResponse.IsValid == nil {
|
||||
break
|
||||
@@ -2059,6 +2075,7 @@ type Env {
|
||||
SMTP_PORT: String
|
||||
SMTP_USERNAME: String
|
||||
SMTP_PASSWORD: String
|
||||
SMTP_LOCAL_NAME: String
|
||||
SENDER_EMAIL: String
|
||||
JWT_TYPE: String
|
||||
JWT_SECRET: String
|
||||
@@ -2101,6 +2118,7 @@ type Env {
|
||||
|
||||
type ValidateJWTTokenResponse {
|
||||
is_valid: Boolean!
|
||||
claims: Map
|
||||
}
|
||||
|
||||
type GenerateJWTKeysResponse {
|
||||
@@ -2168,6 +2186,7 @@ input UpdateEnvInput {
|
||||
SMTP_PORT: String
|
||||
SMTP_USERNAME: String
|
||||
SMTP_PASSWORD: String
|
||||
SMTP_LOCAL_NAME: String
|
||||
SENDER_EMAIL: String
|
||||
JWT_TYPE: String
|
||||
JWT_SECRET: String
|
||||
@@ -4442,6 +4461,47 @@ func (ec *executionContext) fieldContext_Env_SMTP_PASSWORD(ctx context.Context,
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Env_SMTP_LOCAL_NAME(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Env_SMTP_LOCAL_NAME(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.SMTPLocalName, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*string)
|
||||
fc.Result = res
|
||||
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Env_SMTP_LOCAL_NAME(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Env",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Env_SENDER_EMAIL(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Env_SENDER_EMAIL(ctx, field)
|
||||
if err != nil {
|
||||
@@ -9085,6 +9145,8 @@ func (ec *executionContext) fieldContext_Query_validate_jwt_token(ctx context.Co
|
||||
switch field.Name {
|
||||
case "is_valid":
|
||||
return ec.fieldContext_ValidateJWTTokenResponse_is_valid(ctx, field)
|
||||
case "claims":
|
||||
return ec.fieldContext_ValidateJWTTokenResponse_claims(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type ValidateJWTTokenResponse", field.Name)
|
||||
},
|
||||
@@ -9344,6 +9406,8 @@ func (ec *executionContext) fieldContext_Query__env(ctx context.Context, field g
|
||||
return ec.fieldContext_Env_SMTP_USERNAME(ctx, field)
|
||||
case "SMTP_PASSWORD":
|
||||
return ec.fieldContext_Env_SMTP_PASSWORD(ctx, field)
|
||||
case "SMTP_LOCAL_NAME":
|
||||
return ec.fieldContext_Env_SMTP_LOCAL_NAME(ctx, field)
|
||||
case "SENDER_EMAIL":
|
||||
return ec.fieldContext_Env_SENDER_EMAIL(ctx, field)
|
||||
case "JWT_TYPE":
|
||||
@@ -10912,6 +10976,47 @@ func (ec *executionContext) fieldContext_ValidateJWTTokenResponse_is_valid(ctx c
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _ValidateJWTTokenResponse_claims(ctx context.Context, field graphql.CollectedField, obj *model.ValidateJWTTokenResponse) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_ValidateJWTTokenResponse_claims(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Claims, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(map[string]interface{})
|
||||
fc.Result = res
|
||||
return ec.marshalOMap2map(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_ValidateJWTTokenResponse_claims(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "ValidateJWTTokenResponse",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type Map does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _VerificationRequest_id(ctx context.Context, field graphql.CollectedField, obj *model.VerificationRequest) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_VerificationRequest_id(ctx, field)
|
||||
if err != nil {
|
||||
@@ -14970,7 +15075,7 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
||||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SENDER_EMAIL", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "ORGANIZATION_NAME", "ORGANIZATION_LOGO"}
|
||||
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_LOCAL_NAME", "SENDER_EMAIL", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "ORGANIZATION_NAME", "ORGANIZATION_LOGO"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
@@ -15041,6 +15146,14 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
case "SMTP_LOCAL_NAME":
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("SMTP_LOCAL_NAME"))
|
||||
it.SMTPLocalName, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
case "SENDER_EMAIL":
|
||||
var err error
|
||||
|
||||
@@ -16026,6 +16139,10 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
|
||||
|
||||
out.Values[i] = ec._Env_SMTP_PASSWORD(ctx, field, obj)
|
||||
|
||||
case "SMTP_LOCAL_NAME":
|
||||
|
||||
out.Values[i] = ec._Env_SMTP_LOCAL_NAME(ctx, field, obj)
|
||||
|
||||
case "SENDER_EMAIL":
|
||||
|
||||
out.Values[i] = ec._Env_SENDER_EMAIL(ctx, field, obj)
|
||||
@@ -17288,6 +17405,10 @@ func (ec *executionContext) _ValidateJWTTokenResponse(ctx context.Context, sel a
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "claims":
|
||||
|
||||
out.Values[i] = ec._ValidateJWTTokenResponse_claims(ctx, field, obj)
|
||||
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
|
@@ -74,6 +74,7 @@ type Env struct {
|
||||
SMTPPort *string `json:"SMTP_PORT"`
|
||||
SMTPUsername *string `json:"SMTP_USERNAME"`
|
||||
SMTPPassword *string `json:"SMTP_PASSWORD"`
|
||||
SMTPLocalName *string `json:"SMTP_LOCAL_NAME"`
|
||||
SenderEmail *string `json:"SENDER_EMAIL"`
|
||||
JwtType *string `json:"JWT_TYPE"`
|
||||
JwtSecret *string `json:"JWT_SECRET"`
|
||||
@@ -271,6 +272,7 @@ type UpdateEnvInput struct {
|
||||
SMTPPort *string `json:"SMTP_PORT"`
|
||||
SMTPUsername *string `json:"SMTP_USERNAME"`
|
||||
SMTPPassword *string `json:"SMTP_PASSWORD"`
|
||||
SMTPLocalName *string `json:"SMTP_LOCAL_NAME"`
|
||||
SenderEmail *string `json:"SENDER_EMAIL"`
|
||||
JwtType *string `json:"JWT_TYPE"`
|
||||
JwtSecret *string `json:"JWT_SECRET"`
|
||||
@@ -384,7 +386,8 @@ type ValidateJWTTokenInput struct {
|
||||
}
|
||||
|
||||
type ValidateJWTTokenResponse struct {
|
||||
IsValid bool `json:"is_valid"`
|
||||
IsValid bool `json:"is_valid"`
|
||||
Claims map[string]interface{} `json:"claims"`
|
||||
}
|
||||
|
||||
type VerificationRequest struct {
|
||||
|
@@ -110,6 +110,7 @@ type Env {
|
||||
SMTP_PORT: String
|
||||
SMTP_USERNAME: String
|
||||
SMTP_PASSWORD: String
|
||||
SMTP_LOCAL_NAME: String
|
||||
SENDER_EMAIL: String
|
||||
JWT_TYPE: String
|
||||
JWT_SECRET: String
|
||||
@@ -152,6 +153,7 @@ type Env {
|
||||
|
||||
type ValidateJWTTokenResponse {
|
||||
is_valid: Boolean!
|
||||
claims: Map
|
||||
}
|
||||
|
||||
type GenerateJWTKeysResponse {
|
||||
@@ -219,6 +221,7 @@ input UpdateEnvInput {
|
||||
SMTP_PORT: String
|
||||
SMTP_USERNAME: String
|
||||
SMTP_PASSWORD: String
|
||||
SMTP_LOCAL_NAME: String
|
||||
SENDER_EMAIL: String
|
||||
JWT_TYPE: String
|
||||
JWT_SECRET: String
|
||||
|
@@ -154,6 +154,7 @@ func TokenHandler() gin.HandlerFunc {
|
||||
"error": "invalid_refresh_token",
|
||||
"error_description": "The refresh token is invalid",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
claims, err := token.ValidateRefreshToken(gc, refreshToken)
|
||||
@@ -163,9 +164,10 @@ func TokenHandler() gin.HandlerFunc {
|
||||
"error": "unauthorized",
|
||||
"error_description": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
userID = claims["sub"].(string)
|
||||
loginMethod := claims["login_method"]
|
||||
claimLoginMethod := claims["login_method"]
|
||||
rolesInterface := claims["roles"].([]interface{})
|
||||
scopeInterface := claims["scope"].([]interface{})
|
||||
for _, v := range rolesInterface {
|
||||
@@ -176,9 +178,11 @@ func TokenHandler() gin.HandlerFunc {
|
||||
}
|
||||
|
||||
sessionKey = userID
|
||||
if loginMethod != nil && loginMethod != "" {
|
||||
sessionKey = loginMethod.(string) + ":" + sessionKey
|
||||
if claimLoginMethod != nil && claimLoginMethod != "" {
|
||||
sessionKey = claimLoginMethod.(string) + ":" + sessionKey
|
||||
loginMethod = claimLoginMethod.(string)
|
||||
}
|
||||
|
||||
// remove older refresh token and rotate it for security
|
||||
go memorystore.Provider.DeleteUserSession(sessionKey, claims["nonce"].(string))
|
||||
}
|
||||
@@ -211,6 +215,7 @@ func TokenHandler() gin.HandlerFunc {
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||
|
@@ -89,6 +89,9 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
|
||||
if val, ok := store[constants.EnvKeySenderEmail]; ok {
|
||||
res.SenderEmail = refs.NewStringRef(val.(string))
|
||||
}
|
||||
if val, ok := store[constants.EnvKeySmtpLocalName]; ok {
|
||||
res.SMTPLocalName = refs.NewStringRef(val.(string))
|
||||
}
|
||||
if val, ok := store[constants.EnvKeyJwtType]; ok {
|
||||
res.JwtType = refs.NewStringRef(val.(string))
|
||||
}
|
||||
|
@@ -62,12 +62,21 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
log.Debug("Failed to generate nonce: ", err)
|
||||
return res, err
|
||||
}
|
||||
redirectURL := parsers.GetAppURL(gc)
|
||||
|
||||
redirectURI := ""
|
||||
// give higher preference to params redirect uri
|
||||
if strings.TrimSpace(refs.StringValue(params.RedirectURI)) != "" {
|
||||
redirectURL = refs.StringValue(params.RedirectURI)
|
||||
redirectURI = refs.StringValue(params.RedirectURI)
|
||||
} else {
|
||||
redirectURI, err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL)
|
||||
if err != nil {
|
||||
log.Debug("ResetPasswordURL not found using default app url: ", err)
|
||||
redirectURI = hostname + "/app/reset-password"
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyResetPasswordURL, redirectURI)
|
||||
}
|
||||
}
|
||||
|
||||
verificationToken, err := token.CreateVerificationToken(params.Email, constants.VerificationTypeForgotPassword, hostname, nonceHash, redirectURL)
|
||||
verificationToken, err := token.CreateVerificationToken(params.Email, constants.VerificationTypeForgotPassword, hostname, nonceHash, redirectURI)
|
||||
if err != nil {
|
||||
log.Debug("Failed to create verification token", err)
|
||||
return res, err
|
||||
@@ -78,7 +87,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||
Email: params.Email,
|
||||
Nonce: nonceHash,
|
||||
RedirectURI: redirectURL,
|
||||
RedirectURI: redirectURI,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Failed to add verification request", err)
|
||||
@@ -89,7 +98,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
go email.SendEmail([]string{params.Email}, constants.VerificationTypeForgotPassword, map[string]interface{}{
|
||||
"user": user.ToMap(),
|
||||
"organization": utils.GetOrganization(),
|
||||
"verification_url": utils.GetForgotPasswordURL(verificationToken, hostname),
|
||||
"verification_url": utils.GetForgotPasswordURL(verificationToken, redirectURI),
|
||||
})
|
||||
|
||||
res = &model.Response{
|
||||
|
@@ -93,5 +93,6 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken
|
||||
}
|
||||
return &model.ValidateJWTTokenResponse{
|
||||
IsValid: true,
|
||||
Claims: claims,
|
||||
}, nil
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -63,24 +62,23 @@ func TestResolvers(t *testing.T) {
|
||||
|
||||
err := db.InitDB()
|
||||
if err != nil {
|
||||
t.Errorf("Error initializing database: %s", err.Error())
|
||||
t.Logf("Error initializing database: %s", err.Error())
|
||||
}
|
||||
|
||||
// clean the persisted config for test to use fresh config
|
||||
envData, err := db.Provider.GetEnv(ctx)
|
||||
fmt.Println("envData", envData.ID, envData.EnvData)
|
||||
if err == nil && envData.ID != "" {
|
||||
envData.EnvData = ""
|
||||
_, err = db.Provider.UpdateEnv(ctx, envData)
|
||||
if err != nil {
|
||||
t.Errorf("Error updating env: %s", err.Error())
|
||||
t.Logf("Error updating env: %s", err.Error())
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Errorf("Error getting env: %s", err.Error())
|
||||
t.Logf("Error getting env: %s", err.Error())
|
||||
}
|
||||
err = env.PersistEnv()
|
||||
if err != nil {
|
||||
t.Errorf("Error persisting env: %s", err.Error())
|
||||
t.Logf("Error persisting env: %s", err.Error())
|
||||
}
|
||||
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEnv, "test")
|
||||
|
@@ -93,5 +93,6 @@ func validateJwtTokenTest(t *testing.T, s TestSetup) {
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, res.IsValid)
|
||||
assert.Equal(t, user.Email, res.Claims["email"])
|
||||
})
|
||||
}
|
||||
|
@@ -114,16 +114,17 @@ func CreateRefreshToken(user models.User, roles, scopes []string, hostname, nonc
|
||||
return "", 0, err
|
||||
}
|
||||
customClaims := jwt.MapClaims{
|
||||
"iss": hostname,
|
||||
"aud": clientID,
|
||||
"sub": user.ID,
|
||||
"exp": expiresAt,
|
||||
"iat": time.Now().Unix(),
|
||||
"token_type": constants.TokenTypeRefreshToken,
|
||||
"roles": roles,
|
||||
"scope": scopes,
|
||||
"nonce": nonce,
|
||||
"login_method": loginMethod,
|
||||
"iss": hostname,
|
||||
"aud": clientID,
|
||||
"sub": user.ID,
|
||||
"exp": expiresAt,
|
||||
"iat": time.Now().Unix(),
|
||||
"token_type": constants.TokenTypeRefreshToken,
|
||||
"roles": roles,
|
||||
"scope": scopes,
|
||||
"nonce": nonce,
|
||||
"login_method": loginMethod,
|
||||
"allowed_roles": strings.Split(user.Roles, ","),
|
||||
}
|
||||
|
||||
token, err := SignJWTToken(customClaims)
|
||||
@@ -153,16 +154,17 @@ func CreateAccessToken(user models.User, roles, scopes []string, hostName, nonce
|
||||
return "", 0, err
|
||||
}
|
||||
customClaims := jwt.MapClaims{
|
||||
"iss": hostName,
|
||||
"aud": clientID,
|
||||
"nonce": nonce,
|
||||
"sub": user.ID,
|
||||
"exp": expiresAt,
|
||||
"iat": time.Now().Unix(),
|
||||
"token_type": constants.TokenTypeAccessToken,
|
||||
"scope": scopes,
|
||||
"roles": roles,
|
||||
"login_method": loginMethod,
|
||||
"iss": hostName,
|
||||
"aud": clientID,
|
||||
"nonce": nonce,
|
||||
"sub": user.ID,
|
||||
"exp": expiresAt,
|
||||
"iat": time.Now().Unix(),
|
||||
"token_type": constants.TokenTypeAccessToken,
|
||||
"scope": scopes,
|
||||
"roles": roles,
|
||||
"login_method": loginMethod,
|
||||
"allowed_roles": strings.Split(user.Roles, ","),
|
||||
}
|
||||
|
||||
token, err := SignJWTToken(customClaims)
|
||||
@@ -256,7 +258,6 @@ func ValidateRefreshToken(gc *gin.Context, refreshToken string) (map[string]inte
|
||||
if loginMethod != nil && loginMethod != "" {
|
||||
sessionKey = loginMethod.(string) + ":" + userID
|
||||
}
|
||||
|
||||
token, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+nonce)
|
||||
if nonce == "" || err != nil {
|
||||
return res, fmt.Errorf(`unauthorized`)
|
||||
|
@@ -81,17 +81,8 @@ func GetOrganization() map[string]interface{} {
|
||||
}
|
||||
|
||||
// GetForgotPasswordURL to get url for given token and hostname
|
||||
func GetForgotPasswordURL(token, hostname string) string {
|
||||
resetPasswordUrl, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if resetPasswordUrl == "" {
|
||||
if err := memorystore.Provider.UpdateEnvVariable(constants.EnvKeyResetPasswordURL, hostname+"/app/reset-password"); err != nil {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
verificationURL := resetPasswordUrl + "?token=" + token
|
||||
func GetForgotPasswordURL(token, redirectURI string) string {
|
||||
verificationURL := redirectURI + "?token=" + token
|
||||
return verificationURL
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user