From ce52e2d0b38716987b3bbafdb86dd9a4bc2fbd53 Mon Sep 17 00:00:00 2001 From: Pe5h4 Date: Wed, 14 Dec 2022 15:28:12 +0100 Subject: [PATCH 01/19] Version bump --- asab-webui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asab-webui b/asab-webui index e7c9b7eb..607f76d7 160000 --- a/asab-webui +++ b/asab-webui @@ -1 +1 @@ -Subproject commit e7c9b7eb60eaba9cae39ea18d569301dcc7500c4 +Subproject commit 607f76d7ed2658f15e2f71190023072b864dd34e From 86e7eb7b62b101d21d2904d25b45405a17d00336 Mon Sep 17 00:00:00 2001 From: Pe5h4 Date: Wed, 14 Dec 2022 15:30:08 +0100 Subject: [PATCH 02/19] WIP create invitation for registration --- .../credentials/CredentialsCreateContainer.js | 158 ++++++++++++++---- 1 file changed, 121 insertions(+), 37 deletions(-) diff --git a/src/modules/auth/credentials/CredentialsCreateContainer.js b/src/modules/auth/credentials/CredentialsCreateContainer.js index 358da475..31cbe5b3 100644 --- a/src/modules/auth/credentials/CredentialsCreateContainer.js +++ b/src/modules/auth/credentials/CredentialsCreateContainer.js @@ -3,6 +3,7 @@ import { useSelector } from 'react-redux'; import { useParams, Link } from 'react-router-dom'; import { useForm } from "react-hook-form"; import { useTranslation } from 'react-i18next'; +import classnames from 'classnames'; import { ButtonWithAuthz } from 'asab-webui'; @@ -10,6 +11,8 @@ import { Container, Row, Col, Card, CardHeader, CardFooter, CardBody, Form, FormGroup, Input, Label, + Nav, NavLink, NavItem, ButtonGroup, + TabPane, TabContent } from 'reactstrap'; import { @@ -26,7 +29,7 @@ function CredentialsCreateContainer(props) { let SeaCatAuthAPI = props.app.axiosCreate('seacat_auth'); const { t, i18n } = useTranslation(); - const { handleSubmit, register, formState: { errors }, getValues, setValue, resetField } = useForm({ + const { handleSubmit, register, formState: { errors }, getValues, setValue, reset, resetField } = useForm({ defaultValues: { 'passwordlink': true, } @@ -35,8 +38,11 @@ function CredentialsCreateContainer(props) { const [provider, setProvider] = useState(undefined); const [config, setConfig] = useState(undefined); + const [activeTab, setActiveTab] = useState('create'); + const resourceCreateCredentials = "authz:tenant:admin"; const resources = useSelector(state => state.auth?.resources); + const tenant = useSelector(state => state.tenant?.current); useEffect(() => { retrieveProviders(); @@ -75,8 +81,8 @@ function CredentialsCreateContainer(props) { // Process credentials creation on submit - const onSubmit = async (values) => { - // Provider-specific data retention + const onCreate = async (values) => { + // Provider-specific data retention let providerInfo = providers[provider]; if (values.username === undefined){ values["username"] = values.email @@ -123,6 +129,44 @@ function CredentialsCreateContainer(props) { } } + const onInvite = async (values) => { + // TODO: remove console.log + console.log(values, "VALUES on invite") + + let body = {}; + let credentials = {}; + let expiration = 999999999; // TODO: enable to set expiration by user and use differerent default + + Promise.all(Object.keys(values).map((key, i) => { + if ((values[key] != undefined) && (values[key].length != 0)) { + credentials[key] = values[key]; + } + })) + + body["credentials"] = credentials; + body["expiration"] = expiration; + + // TODO: remove console.log + console.log(body, "BODY") + + let response; + try { + response = await SeaCatAuthAPI.post(`/${tenant}/invite`, + body, + { + headers: { + 'Content-Type': 'application/json' + } + }); + props.app.addAlert("success", t("CredentialsCreateContainer|Invitation have been sent successfully")); + // Navigate to a newly created credentials + props.history.push(`/auth/credentials/${response.data.credentials_id}`); + } catch(e) { + console.error(e); + props.app.addAlert("warning", t("CredentialsCreateContainer|Something went wrong, failed to send invitation")); + } + } + const changeProvider = (value) => { resetField("username"); resetField("phone"); @@ -133,60 +177,100 @@ function CredentialsCreateContainer(props) { setProvider(value); } + // Swith between the tabs + const toggle = (tab) => { + if(activeTab !== tab) { + reset({}); + setActiveTab(tab); + } + } + return ( -
+
{t('CredentialsCreateContainer|Create new credentials')}
+ + +
+ + + - - - {Object.keys(providers).length > 1 && - - - changeProvider(e.target.value)} - > - {Object.keys(providers).map((key, index) => ( - - ))} - - - } - - {config !== undefined && config.creation.map((item, idx) => { - switch(item.type) { - case 'username': return() - case 'email': return() - case 'password': return() - case 'phone': return() - case 'passwordlink': return() - default: return(
Unknown item: "{item.type}"
) - } - })} - -
+ {Object.keys(providers).length > 1 && + + + changeProvider(e.target.value)} + > + {Object.keys(providers).map((key, index) => ( + + ))} + + + } + + {(activeTab == "create") && (config !== undefined) && config.creation.map((item, idx) => { + switch(item.type) { + case 'username': return() + case 'email': return() + case 'password': return() + case 'phone': return() + case 'passwordlink': return() + default: return(
Unknown item: "{item.type}"
) + } + })} +
+
+ + + {(activeTab == "invite") && + <> + + + + } + + +
- {t('CredentialsCreateContainer|Create credentials')} + {activeTab == "create" ? t('CredentialsCreateContainer|Create credentials') : t('CredentialsCreateContainer|Invite')}
From 9e799c5e447f136b1f0affaa160417ed29a773f9 Mon Sep 17 00:00:00 2001 From: Pe5h4 Date: Wed, 14 Dec 2022 15:30:45 +0100 Subject: [PATCH 03/19] Update username formfields --- src/modules/auth/credentials/FormFields.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/auth/credentials/FormFields.js b/src/modules/auth/credentials/FormFields.js index d3b871d4..50a6eb54 100644 --- a/src/modules/auth/credentials/FormFields.js +++ b/src/modules/auth/credentials/FormFields.js @@ -95,9 +95,9 @@ export function UserNameField(props) { "username", { validate: { - emptyInput: value => (value && value.toString().length !== 0) || t("FormFields|Username cannot be empty!"), + emptyInput: value => (value && value.toString().length !== 0) || (props.required == false) || t("FormFields|Username cannot be empty!"), startWithNumber: value => !(/^\d/).test(value) || t("FormFields|Invalid format, username cannot start with a number"), - vlidation: value => (/^[a-z_][a-z0-9_-]{0,31}$/).test(value) || t("FormFields|Invalid format, only lower-case letters, numbers, dash and underscore are allowed"), + validation: value => (/^[a-z_][a-z0-9_-]{0,31}$|^$/).test(value) || t("FormFields|Invalid format, only lower-case letters, numbers, dash and underscore are allowed"), } } ); From 919b144ae9d8aeaf3ec0b5a629e6fd01333c42c1 Mon Sep 17 00:00:00 2001 From: Pe5h4 Date: Wed, 14 Dec 2022 16:10:19 +0100 Subject: [PATCH 04/19] WIP implementation of resend invitation --- .../credentials/CredentialsDetailContainer.js | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/modules/auth/credentials/CredentialsDetailContainer.js b/src/modules/auth/credentials/CredentialsDetailContainer.js index bba0e034..d6549053 100644 --- a/src/modules/auth/credentials/CredentialsDetailContainer.js +++ b/src/modules/auth/credentials/CredentialsDetailContainer.js @@ -137,7 +137,7 @@ function CredentialsDetailContainer(props) { } } - + // Suspend user const suspendUser = async (suspend) => { if (suspended === false || suspended === undefined) { setSuspended(true); @@ -162,10 +162,29 @@ function CredentialsDetailContainer(props) { } } + // Reset password const resetPwd = () => { props.history.push(`/auth/credentials/${credentials_id}/passwordreset`); } + // Resend invitation + const resendInvitation = async () => { + // TODO: what should be in the body?? + try { + let response = await SeaCatAuthAPI.post(`/invite/${credentials_id}`, + {}, + { headers: + { + 'Content-Type': 'application/json' + } + }); + props.app.addAlert("success", t('CredentialsDetailContainer|Invitation has been send successfully')); + } catch(e) { + console.error(e); + props.app.addAlert("warning", t('CredentialsDetailContainer|Something went wrong, failed to resend invitation')); + } + } + return (
@@ -250,6 +269,14 @@ function CredentialsDetailContainer(props) { > {t('CredentialsDetailContainer|Reset password')} + { resendInvitation() }} + > + {t('CredentialsDetailContainer|Resend invitation')} + From cd43727ef285d6d05af9268c71879a1604017044 Mon Sep 17 00:00:00 2001 From: Pe5h4 Date: Tue, 20 Dec 2022 15:41:08 +0100 Subject: [PATCH 05/19] Add option to display translations with colons --- src/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.js b/src/index.js index f1e0c0a8..e8776d78 100644 --- a/src/index.js +++ b/src/index.js @@ -41,6 +41,7 @@ let ConfigDefaults = { fallbackLng: 'en', supportedLngs: ['en', 'cs'], debug: false, + nsSeparator: false } }; From ebc2d255bdc1609f8bd541bc88719b66c1ec1b9e Mon Sep 17 00:00:00 2001 From: Pe5h4 Date: Tue, 20 Dec 2022 15:41:45 +0100 Subject: [PATCH 06/19] Add wider alert message --- src/modules/auth/credentials/CredentialsCreateContainer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/auth/credentials/CredentialsCreateContainer.js b/src/modules/auth/credentials/CredentialsCreateContainer.js index 31cbe5b3..e5bc74be 100644 --- a/src/modules/auth/credentials/CredentialsCreateContainer.js +++ b/src/modules/auth/credentials/CredentialsCreateContainer.js @@ -163,7 +163,7 @@ function CredentialsCreateContainer(props) { props.history.push(`/auth/credentials/${response.data.credentials_id}`); } catch(e) { console.error(e); - props.app.addAlert("warning", t("CredentialsCreateContainer|Something went wrong, failed to send invitation")); + props.app.addAlert("warning", t(`CredentialsCreateContainer|Something went wrong, failed to send invitation: ${e?.response?.data?.message}`)); } } From 0a5d753b25cc46853b96f8cce4d99c73e8cb51ec Mon Sep 17 00:00:00 2001 From: Pe5h4 Date: Tue, 20 Dec 2022 15:42:44 +0100 Subject: [PATCH 07/19] Refactor resend invite --- .../credentials/CredentialsDetailContainer.js | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/modules/auth/credentials/CredentialsDetailContainer.js b/src/modules/auth/credentials/CredentialsDetailContainer.js index d6549053..f9fd99d6 100644 --- a/src/modules/auth/credentials/CredentialsDetailContainer.js +++ b/src/modules/auth/credentials/CredentialsDetailContainer.js @@ -221,6 +221,17 @@ function CredentialsDetailContainer(props) { {t('CredentialsDetailContainer|Suspended')} }
+ {(data?.registered == false) ? + { resendInvitation() }} + color="link" + resource={resourceManageCredentials} + resources={resources} + > + {t('CredentialsDetailContainer|Resend invitation')} + + : { e.preventDefault(); suspendUserForm((suspended === false) || (suspended === undefined)) }} @@ -234,6 +245,7 @@ function CredentialsDetailContainer(props) { t('CredentialsDetailContainer|Activate user') } + } @@ -269,14 +281,6 @@ function CredentialsDetailContainer(props) { > {t('CredentialsDetailContainer|Reset password')} - { resendInvitation() }} - > - {t('CredentialsDetailContainer|Resend invitation')} - From d5f01ce5ccfc873b7ea7cc2ca6d6da1cf8e3e95d Mon Sep 17 00:00:00 2001 From: Pe5h4 Date: Thu, 5 Jan 2023 16:37:50 +0100 Subject: [PATCH 08/19] Remove console.logs, add comments --- .../auth/credentials/CredentialsCreateContainer.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/modules/auth/credentials/CredentialsCreateContainer.js b/src/modules/auth/credentials/CredentialsCreateContainer.js index e5bc74be..9fc210ed 100644 --- a/src/modules/auth/credentials/CredentialsCreateContainer.js +++ b/src/modules/auth/credentials/CredentialsCreateContainer.js @@ -129,14 +129,14 @@ function CredentialsCreateContainer(props) { } } + // Invite user const onInvite = async (values) => { - // TODO: remove console.log - console.log(values, "VALUES on invite") - let body = {}; let credentials = {}; - let expiration = 999999999; // TODO: enable to set expiration by user and use differerent default + // TODO: Allow setting up the expiration by admin and use differerent default + let expiration = 999999999; + // Fill credentials key with filled values Promise.all(Object.keys(values).map((key, i) => { if ((values[key] != undefined) && (values[key].length != 0)) { credentials[key] = values[key]; @@ -146,9 +146,6 @@ function CredentialsCreateContainer(props) { body["credentials"] = credentials; body["expiration"] = expiration; - // TODO: remove console.log - console.log(body, "BODY") - let response; try { response = await SeaCatAuthAPI.post(`/${tenant}/invite`, From be330c350aa4bfee1879573d05c788a176a68b24 Mon Sep 17 00:00:00 2001 From: Pe5h4 Date: Mon, 9 Jan 2023 10:35:52 +0100 Subject: [PATCH 09/19] Update naming and colors for invited user --- src/modules/auth/credentials/CredentialsCreateContainer.js | 2 +- src/modules/auth/credentials/CredentialsDetailContainer.js | 6 ++++-- src/modules/auth/credentials/credentials.scss | 5 +++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/modules/auth/credentials/CredentialsCreateContainer.js b/src/modules/auth/credentials/CredentialsCreateContainer.js index 9fc210ed..7d58bbd8 100644 --- a/src/modules/auth/credentials/CredentialsCreateContainer.js +++ b/src/modules/auth/credentials/CredentialsCreateContainer.js @@ -191,7 +191,7 @@ function CredentialsCreateContainer(props) {
- {t('CredentialsCreateContainer|Create new credentials')} + {activeTab == "create" ? t('CredentialsCreateContainer|Create new credentials') : t('CredentialsCreateContainer|Invite user')}