Skip to content

Commit 116c842

Browse files
authored
chore: fix mail verification (#475)
- remove unsed files from dashboard - update dashboard for inviting user - test invite user functionality from ui
1 parent 1b1bf66 commit 116c842

32 files changed

Lines changed: 132 additions & 1972 deletions

cmd/root.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func init() {
101101
f.StringVar(&rootArgs.config.SMTPSenderEmail, "smtp-sender-email", "", "Sender email for the SMTP server")
102102
f.StringVar(&rootArgs.config.SMTPSenderName, "smtp-sender-name", "", "Sender name for the SMTP server")
103103
f.StringVar(&rootArgs.config.SMTPLocalName, "smtp-local-name", "", "Local name for the SMTP server")
104-
f.BoolVar(&rootArgs.config.SkipTLSVerification, "skip-tls-verification", false, "Skip TLS verification for the SMTP server")
104+
f.BoolVar(&rootArgs.config.SMTPSkipTLSVerification, "smtp-skip-tls-verification", false, "Skip TLS verification for the SMTP server")
105105

106106
// Auth flags
107107
f.StringSliceVar(&rootArgs.config.DefaultRoles, "default-roles", []string{"user"}, "Default user roles to assign")
@@ -205,6 +205,17 @@ func runRoot(c *cobra.Command, args []string) {
205205
Level(zeroLogLevel).
206206
With().Timestamp().Logger()
207207

208+
// Derive IsEmailServiceEnabled from SMTP config
209+
rootArgs.config.IsEmailServiceEnabled = strings.TrimSpace(rootArgs.config.SMTPHost) != "" &&
210+
rootArgs.config.SMTPPort > 0 &&
211+
strings.TrimSpace(rootArgs.config.SMTPSenderEmail) != ""
212+
213+
// Derive IsSMSServiceEnabled from Twilio config
214+
rootArgs.config.IsSMSServiceEnabled = strings.TrimSpace(rootArgs.config.TwilioAPIKey) != "" &&
215+
strings.TrimSpace(rootArgs.config.TwilioAPISecret) != "" &&
216+
strings.TrimSpace(rootArgs.config.TwilioAccountSID) != "" &&
217+
strings.TrimSpace(rootArgs.config.TwilioSender) != ""
218+
208219
// Storage provider
209220
storageProvider, err := storage.New(&rootArgs.config, &storage.Dependencies{
210221
Log: &log,

internal/config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ type Config struct {
8383
// SMTPLocalName is the local name for the SMTP server
8484
SMTPLocalName string
8585
// SkipTLSVerification is the flag to skip TLS verification
86-
SkipTLSVerification bool
86+
SMTPSkipTLSVerification bool
8787

8888
// Memory Store Configurations
8989
// RedisURL is the URL of the redis server

internal/email/email.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func New(
4545
if strings.TrimSpace(config.SMTPLocalName) != "" {
4646
mailer.LocalName = config.SMTPLocalName
4747
}
48-
if config.SkipTLSVerification {
48+
if config.SMTPSkipTLSVerification {
4949
mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
5050
}
5151
return &provider{

internal/integration_tests/magic_link_login_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestMagicLinkLogin(t *testing.T) {
1919
cfg.SMTPSenderEmail = "test@authorizer.dev"
2020
cfg.SMTPSenderName = "Test"
2121
cfg.SMTPLocalName = "Test"
22-
cfg.SkipTLSVerification = true
22+
cfg.SMTPSkipTLSVerification = true
2323
cfg.IsEmailServiceEnabled = true
2424
cfg.IsSMSServiceEnabled = true
2525
cfg.EnableEmailVerification = true

internal/integration_tests/resend_otp_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func TestResendOTP(t *testing.T) {
2626
cfg.SMTPSenderEmail = "test@authorizer.dev"
2727
cfg.SMTPSenderName = "Test"
2828
cfg.SMTPLocalName = "Test"
29-
cfg.SkipTLSVerification = true
29+
cfg.SMTPSkipTLSVerification = true
3030
cfg.IsEmailServiceEnabled = true
3131
cfg.IsSMSServiceEnabled = true
3232
cfg.EnableEmailVerification = true

internal/integration_tests/verify_otp_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func TestVerifyOTP(t *testing.T) {
2222
cfg.SMTPSenderEmail = "test@authorizer.dev"
2323
cfg.SMTPSenderName = "Test"
2424
cfg.SMTPLocalName = "Test"
25-
cfg.SkipTLSVerification = true
25+
cfg.SMTPSkipTLSVerification = true
2626
cfg.IsEmailServiceEnabled = true
2727
cfg.IsSMSServiceEnabled = true
2828
cfg.EnableEmailVerification = true

web/dashboard/src/components/DeleteEmailTemplateModal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
import { useClient } from 'urql';
1919
import { FaRegTrashAlt } from 'react-icons/fa';
2020
import { DeleteEmailTemplate } from '../graphql/mutation';
21-
import { capitalizeFirstLetter } from '../utils';
21+
import { capitalizeFirstLetter, getGraphQLErrorMessage } from '../utils';
2222

2323
interface deleteEmailTemplateModalInputPropTypes {
2424
emailTemplateId: string;
@@ -41,7 +41,7 @@ const DeleteEmailTemplateModal = ({
4141
.toPromise();
4242
if (res.error) {
4343
toast({
44-
title: capitalizeFirstLetter(res.error.message),
44+
title: capitalizeFirstLetter(getGraphQLErrorMessage(res.error, 'Failed to delete email template')),
4545
isClosable: true,
4646
status: 'error',
4747
position: 'top-right',

web/dashboard/src/components/DeleteUserModal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
import { useClient } from 'urql';
1919
import { FaRegTrashAlt } from 'react-icons/fa';
2020
import { DeleteUser } from '../graphql/mutation';
21-
import { capitalizeFirstLetter } from '../utils';
21+
import { capitalizeFirstLetter, getGraphQLErrorMessage } from '../utils';
2222

2323
interface userDataTypes {
2424
id: string;
@@ -48,7 +48,7 @@ const DeleteUserModal = ({
4848
.toPromise();
4949
if (res.error) {
5050
toast({
51-
title: capitalizeFirstLetter(res.error.message),
51+
title: capitalizeFirstLetter(getGraphQLErrorMessage(res.error, 'Failed to delete user')),
5252
isClosable: true,
5353
status: 'error',
5454
position: 'top-right',

web/dashboard/src/components/DeleteWebhookModal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
import { useClient } from 'urql';
1919
import { FaRegTrashAlt } from 'react-icons/fa';
2020
import { DeleteWebhook } from '../graphql/mutation';
21-
import { capitalizeFirstLetter } from '../utils';
21+
import { capitalizeFirstLetter, getGraphQLErrorMessage } from '../utils';
2222

2323
interface deleteWebhookModalInputPropTypes {
2424
webhookId: string;
@@ -41,7 +41,7 @@ const DeleteWebhookModal = ({
4141
.toPromise();
4242
if (res.error) {
4343
toast({
44-
title: capitalizeFirstLetter(res.error.message),
44+
title: capitalizeFirstLetter(getGraphQLErrorMessage(res.error, 'Failed to delete webhook')),
4545
isClosable: true,
4646
status: 'error',
4747
position: 'top-right',

web/dashboard/src/components/EditUserModal.tsx

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ import {
1515
useDisclosure,
1616
Text,
1717
useToast,
18+
Input,
1819
} from '@chakra-ui/react';
1920
import { useClient } from 'urql';
20-
import { FaSave } from 'react-icons/fa';
21+
import { FaSave, FaPlus } from 'react-icons/fa';
2122
import InputField from './InputField';
2223
import {
2324
DateInputType,
2425
MultiSelectInputType,
2526
SelectInputType,
2627
TextInputType,
2728
} from '../constants';
28-
import { getObjectDiff } from '../utils';
29+
import { getObjectDiff, getGraphQLErrorMessage } from '../utils';
2930
import { UpdateUser } from '../graphql/mutation';
30-
import { GetAvailableRolesQuery } from '../graphql/queries';
3131

3232
const GenderTypes = {
3333
Undisclosed: null,
@@ -46,7 +46,7 @@ interface userDataTypes {
4646
birthdate: string;
4747
phone_number: string;
4848
picture: string;
49-
roles: [string] | [];
49+
roles: string[];
5050
}
5151

5252
const EditUserModal = ({
@@ -58,7 +58,7 @@ const EditUserModal = ({
5858
}) => {
5959
const client = useClient();
6060
const toast = useToast();
61-
const [availableRoles, setAvailableRoles] = useState<string[]>([]);
61+
const [newRole, setNewRole] = useState('');
6262
const { isOpen, onOpen, onClose } = useDisclosure();
6363
const [userData, setUserData] = useState<userDataTypes>({
6464
id: '',
@@ -73,19 +73,13 @@ const EditUserModal = ({
7373
picture: '',
7474
roles: [],
7575
});
76+
// Available roles for multiselect: current user roles (no env query)
77+
const availableRoles = Array.from(
78+
new Set([...(userData.roles || []), ...(user.roles || [])]),
79+
);
7680
React.useEffect(() => {
7781
setUserData(user);
78-
fetchAvailableRoles();
79-
}, []);
80-
const fetchAvailableRoles = async () => {
81-
const res = await client.query(GetAvailableRolesQuery).toPromise();
82-
if (res.data?._env?.ROLES && res.data?._env?.PROTECTED_ROLES) {
83-
setAvailableRoles([
84-
...res.data._env.ROLES,
85-
...res.data._env.PROTECTED_ROLES,
86-
]);
87-
}
88-
};
82+
}, [user]);
8983
const saveHandler = async () => {
9084
const diff = getObjectDiff(user, userData);
9185
const updatedUserData = diff.reduce(
@@ -101,7 +95,7 @@ const EditUserModal = ({
10195
.toPromise();
10296
if (res.error) {
10397
toast({
104-
title: 'User data update failed',
98+
title: getGraphQLErrorMessage(res.error, 'User data update failed'),
10599
isClosable: true,
106100
status: 'error',
107101
position: 'top-right',
@@ -229,13 +223,45 @@ const EditUserModal = ({
229223
<Flex w="30%" justifyContent="start" alignItems="center">
230224
<Text fontSize="sm">Roles:</Text>
231225
</Flex>
232-
<Center w="70%">
226+
<Center w="70%" flexDirection="column" alignItems="stretch">
233227
<InputField
234228
variables={userData}
235229
setVariables={setUserData}
236230
availableRoles={availableRoles}
237231
inputType={MultiSelectInputType.USER_ROLES}
238232
/>
233+
<Flex mt={2} gap={2}>
234+
<Input
235+
size="sm"
236+
placeholder="Add role"
237+
value={newRole}
238+
onChange={(e) => setNewRole(e.target.value)}
239+
onKeyDown={(e) => {
240+
if (e.key === 'Enter' && newRole.trim()) {
241+
setUserData({
242+
...userData,
243+
roles: [...(userData.roles || []), newRole.trim()],
244+
});
245+
setNewRole('');
246+
}
247+
}}
248+
/>
249+
<Button
250+
size="sm"
251+
leftIcon={<FaPlus />}
252+
onClick={() => {
253+
if (newRole.trim()) {
254+
setUserData({
255+
...userData,
256+
roles: [...(userData.roles || []), newRole.trim()],
257+
});
258+
setNewRole('');
259+
}
260+
}}
261+
>
262+
Add
263+
</Button>
264+
</Flex>
239265
</Center>
240266
</Flex>
241267
</Stack>

0 commit comments

Comments
 (0)