@adminforth/open-signup 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,34 +31,36 @@
31
31
  <!-- Modal header -->
32
32
  <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
33
33
  <h3 class="text-xl font-semibold text-gray-900 dark:text-white">
34
- Sign up into {{ coreStore.config?.brandName }}
34
+ {{$t('Sign up into')}} {{ coreStore.config?.brandName }}
35
35
  </h3>
36
36
  </div>
37
37
  <!-- Modal body -->
38
38
  <div class="p-4 md:p-5">
39
39
  <form v-if="!requestSent" class="space-y-4" role="alert" @submit.prevent>
40
- <div class="relative">
41
- <label for="email" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your email</label>
40
+ <div v-if="!verifyToken" class="relative">
41
+ <label for="email" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{$t('Your email')}}</label>
42
42
  <input type="email" name="email" id="email"
43
43
  tabindex="1"
44
- @keydown.enter="passwordInput.focus()"
44
+ autocomplete="username"
45
+ @keydown.enter="passwordInput?.focus()"
45
46
  ref="emailInput"
46
47
  class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
47
48
  placeholder="name@company.com"
48
49
  required
49
50
  />
50
51
  </div>
51
- <div class="relative">
52
- <label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">New password</label>
52
+ <div v-if="isPasswordNeeded" class="relative">
53
+ <label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{$t('New password')}}</label>
53
54
  <input
54
55
  tabindex="2"
56
+ autocomplete="new-password"
55
57
  ref="passwordInput"
56
58
  :type="unmasked ? 'text' : 'password'"
57
59
  name="password" id="password"
58
60
  v-model="password"
59
- @keydown.enter="passwordConfirmationInput.focus()"
61
+ @keydown.enter="passwordConfirmationInput?.focus()"
60
62
  class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
61
- placeholder="New password" required
63
+ :placeholder="$t('New password')" required
62
64
  />
63
65
 
64
66
  <button
@@ -71,16 +73,17 @@
71
73
  </button>
72
74
  </div>
73
75
 
74
- <div class="relative">
75
- <label for="password_confirmation" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Confirm new password</label>
76
+ <div v-if="isPasswordNeeded" class="relative">
77
+ <label for="password_confirmation" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{$t('Confirm new password')}}</label>
76
78
  <input
77
79
  ref="passwordConfirmationInput"
80
+ autocomplete="new-password"
78
81
  :type="unmasked ? 'text' : 'password'"
79
82
  name="password_confirmation" id="password_confirmation"
80
83
  tabindex="3"
81
84
  v-model="passwordConfirmation"
82
85
  class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
83
- placeholder="Confirm new password" required
86
+ :placeholder="$t('Confirm new password')" required
84
87
  />
85
88
 
86
89
  <button
@@ -97,7 +100,7 @@
97
100
  <svg class="flex-shrink-0 inline w-4 h-4 me-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
98
101
  <path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"/>
99
102
  </svg>
100
- <span class="sr-only">Info</span>
103
+ <span class="sr-only">{{$t('Info')}}</span>
101
104
  <div>
102
105
  {{ validationError || error }}
103
106
  </div>
@@ -105,19 +108,21 @@
105
108
 
106
109
  <Button
107
110
  :disabled="inProgress || (validationRunning && validationError)"
108
- @click="doSignup"
111
+ @click="() => verifyToken ? signupAfterEmailConfirmation() : doSignup()"
109
112
  type="submit"
110
113
  class="w-full"
111
114
  :loader="inProgress"
112
115
  >
113
- Sign up
116
+ {{$t('Sign up')}}
114
117
  </Button>
115
118
  </form>
116
119
  <!-- END of set new paasord -->
117
120
  <div v-else class="flex items center justify-center p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-green-800 dark:text-green-400" role="alert">
118
- If user with specified email exists in our db, then request was sent. Please check your email at {{ sentToEmail }} to reset your password.
119
- </div>
120
-
121
+ {{$t('Please check your email at')}} {{ sentToEmail }} {{$t('to confirm your email address.')}}
122
+ </div>
123
+ <p class="text-gray-500 dark:text-gray-400 font-sm text-right mt-3">
124
+ {{$t('or')}} <Link to="/login">{{ toLoginText }}</Link>
125
+ </p>
121
126
  </div>
122
127
  </div>
123
128
  </div>
@@ -128,7 +133,6 @@
128
133
 
129
134
 
130
135
  <script setup lang="ts">
131
-
132
136
  import { onMounted, ref, computed, Ref } from 'vue';
133
137
  import { useCoreStore } from '@/stores/core';
134
138
  import { useUserStore } from '@/stores/user';
@@ -136,27 +140,33 @@ import { callAdminForthApi, loadFile, applyRegexValidation } from '@/utils';
136
140
  import { useRoute, useRouter } from 'vue-router';
137
141
  import { IconEyeSolid, IconEyeSlashSolid } from '@iconify-prerendered/vue-flowbite';
138
142
  import Button from '@/afcl/Button.vue';
143
+ import Link from '@/afcl/Link.vue';
139
144
 
140
145
  const inProgress = ref(false);
141
146
 
142
147
  const coreStore = useCoreStore();
143
148
  const requestSent = ref(false);
144
149
 
145
- const emailInput = ref(null);
146
- const passwordInput = ref(null);
147
- const passwordConfirmationInput = ref(null);
150
+ const emailInput: Ref<HTMLInputElement | null> = ref(null);
151
+ const passwordInput: Ref<HTMLInputElement | null> = ref(null);
152
+ const passwordConfirmationInput: Ref<HTMLInputElement | null> = ref(null);
148
153
 
149
154
  const password = ref("");
150
155
  const passwordConfirmation = ref("");
151
156
  const unmasked = ref(false);
152
157
  const sentToEmail: Ref<string> = ref('');
153
158
 
159
+ const requestEmailConfirmation = computed(() => route.meta.requestEmailConfirmation);
160
+ const verifyToken = computed(() => route.query.token);
161
+ const toLoginText = computed(() => `${verifyToken.value ? 'Go' : 'Back'} to login`);
162
+ const isPasswordNeeded = computed(() => !requestEmailConfirmation.value || (requestEmailConfirmation.value && verifyToken.value));
163
+
154
164
  const user = useUserStore();
155
165
 
156
166
  const route = useRoute();
157
167
  const router = useRouter();
158
168
 
159
- function checkPassowrd() {
169
+ function checkPassword() {
160
170
 
161
171
  if (!password.value || !passwordConfirmation.value) {
162
172
  return 'Please enter both password and password confirmation';
@@ -187,39 +197,15 @@ const validationRunning = ref(false);
187
197
 
188
198
  const validationError = computed(() => {
189
199
  if (validationRunning.value) {
190
- return checkPassowrd();
200
+ return checkPassword();
191
201
  }
192
202
  return null;
193
203
  });
194
204
 
195
- const error: Ref<str | null> = ref(null);
205
+ const error: Ref<string | null> = ref(null);
196
206
 
197
207
  onMounted(async () => {
198
- if (route.query.token) {
199
- // call method completeVerifiedSignup to confirm { token }
200
- // if success, then redirect to login page
201
-
202
- const resp = await callAdminForthApi({
203
- path: `/plugin/${route.meta.pluginInstanceId}/complete-verified-signup`,
204
- method: 'POST',
205
- body: {
206
- token: route.query.token,
207
- }
208
- });
209
- if (resp.error) {
210
- window.adminforth.alert({
211
- message: `Error fetching data: ${error.message}`,
212
- variant: 'danger',
213
- });
214
- } else if (resp.redirectTo) {
215
- router.push(resp.redirectTo);
216
- } else {
217
- await user.finishLogin();
218
- }
219
- return;
220
-
221
- }
222
- emailInput.value.focus();
208
+ emailInput.value?.focus();
223
209
  });
224
210
 
225
211
 
@@ -242,7 +228,7 @@ async function doSignup() {
242
228
  error.value = 'Please enter your email';
243
229
  return;
244
230
  }
245
- if (checkPassowrd()) {
231
+ if (!requestEmailConfirmation.value && checkPassword()) {
246
232
  validationRunning.value = true;
247
233
  return;
248
234
  }
@@ -254,7 +240,7 @@ async function doSignup() {
254
240
  body: {
255
241
  email,
256
242
  url: window.location.origin + window.location.pathname,
257
- password: password.value,
243
+ ...(!requestEmailConfirmation.value ? {password: password.value} : {}),
258
244
  }
259
245
  });
260
246
  inProgress.value = false;
@@ -264,15 +250,37 @@ async function doSignup() {
264
250
  error.value = null;
265
251
  requestSent.value = true;
266
252
  sentToEmail.value = email;
267
- if (resp.redirectTo) {
253
+ if (resp.redirectTo && !requestEmailConfirmation.value) {
268
254
  router.push(resp.redirectTo);
269
- } else {
255
+ } else if (!requestEmailConfirmation.value) {
270
256
  error.value = null;
271
257
  await user.finishLogin();
272
258
  }
273
259
  }
274
260
  }
275
261
 
276
-
277
-
262
+ const signupAfterEmailConfirmation = async () => {
263
+ if (checkPassword()) {
264
+ validationRunning.value = true;
265
+ return;
266
+ }
267
+ const resp = await callAdminForthApi({
268
+ path: `/plugin/${route.meta.pluginInstanceId}/complete-verified-signup`,
269
+ method: 'POST',
270
+ body: {
271
+ token: verifyToken.value,
272
+ password: password.value,
273
+ }
274
+ });
275
+ if (resp.error) {
276
+ window.adminforth.alert({
277
+ message: `Error fetching data: ${resp.error}`,
278
+ variant: 'danger',
279
+ });
280
+ } else if (resp.redirectTo) {
281
+ router.push(resp.redirectTo);
282
+ } else {
283
+ await user.finishLogin();
284
+ }
285
+ }
278
286
  </script>
@@ -1,8 +1,8 @@
1
1
  <template>
2
2
  <p class="text-gray-500 dark:text-gray-400 font-sm text-left mt-3">
3
- Have no account?
3
+ {{$t('Have no account?')}}
4
4
  <Link to="/signup">
5
- sign up now
5
+ {{$t('sign up now')}}
6
6
  </Link>
7
7
  </p>
8
8
  </template>
@@ -31,34 +31,36 @@
31
31
  <!-- Modal header -->
32
32
  <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
33
33
  <h3 class="text-xl font-semibold text-gray-900 dark:text-white">
34
- Sign up into {{ coreStore.config?.brandName }}
34
+ {{$t('Sign up into')}} {{ coreStore.config?.brandName }}
35
35
  </h3>
36
36
  </div>
37
37
  <!-- Modal body -->
38
38
  <div class="p-4 md:p-5">
39
39
  <form v-if="!requestSent" class="space-y-4" role="alert" @submit.prevent>
40
- <div class="relative">
41
- <label for="email" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your email</label>
40
+ <div v-if="!verifyToken" class="relative">
41
+ <label for="email" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{$t('Your email')}}</label>
42
42
  <input type="email" name="email" id="email"
43
43
  tabindex="1"
44
- @keydown.enter="passwordInput.focus()"
44
+ autocomplete="username"
45
+ @keydown.enter="passwordInput?.focus()"
45
46
  ref="emailInput"
46
47
  class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
47
48
  placeholder="name@company.com"
48
49
  required
49
50
  />
50
51
  </div>
51
- <div class="relative">
52
- <label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">New password</label>
52
+ <div v-if="isPasswordNeeded" class="relative">
53
+ <label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{$t('New password')}}</label>
53
54
  <input
54
55
  tabindex="2"
56
+ autocomplete="new-password"
55
57
  ref="passwordInput"
56
58
  :type="unmasked ? 'text' : 'password'"
57
59
  name="password" id="password"
58
60
  v-model="password"
59
- @keydown.enter="passwordConfirmationInput.focus()"
61
+ @keydown.enter="passwordConfirmationInput?.focus()"
60
62
  class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
61
- placeholder="New password" required
63
+ :placeholder="$t('New password')" required
62
64
  />
63
65
 
64
66
  <button
@@ -71,16 +73,17 @@
71
73
  </button>
72
74
  </div>
73
75
 
74
- <div class="relative">
75
- <label for="password_confirmation" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Confirm new password</label>
76
+ <div v-if="isPasswordNeeded" class="relative">
77
+ <label for="password_confirmation" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{$t('Confirm new password')}}</label>
76
78
  <input
77
79
  ref="passwordConfirmationInput"
80
+ autocomplete="new-password"
78
81
  :type="unmasked ? 'text' : 'password'"
79
82
  name="password_confirmation" id="password_confirmation"
80
83
  tabindex="3"
81
84
  v-model="passwordConfirmation"
82
85
  class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
83
- placeholder="Confirm new password" required
86
+ :placeholder="$t('Confirm new password')" required
84
87
  />
85
88
 
86
89
  <button
@@ -97,7 +100,7 @@
97
100
  <svg class="flex-shrink-0 inline w-4 h-4 me-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
98
101
  <path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"/>
99
102
  </svg>
100
- <span class="sr-only">Info</span>
103
+ <span class="sr-only">{{$t('Info')}}</span>
101
104
  <div>
102
105
  {{ validationError || error }}
103
106
  </div>
@@ -105,19 +108,21 @@
105
108
 
106
109
  <Button
107
110
  :disabled="inProgress || (validationRunning && validationError)"
108
- @click="doSignup"
111
+ @click="() => verifyToken ? signupAfterEmailConfirmation() : doSignup()"
109
112
  type="submit"
110
113
  class="w-full"
111
114
  :loader="inProgress"
112
115
  >
113
- Sign up
116
+ {{$t('Sign up')}}
114
117
  </Button>
115
118
  </form>
116
119
  <!-- END of set new paasord -->
117
120
  <div v-else class="flex items center justify-center p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-green-800 dark:text-green-400" role="alert">
118
- If user with specified email exists in our db, then request was sent. Please check your email at {{ sentToEmail }} to reset your password.
119
- </div>
120
-
121
+ {{$t('Please check your email at')}} {{ sentToEmail }} {{$t('to confirm your email address.')}}
122
+ </div>
123
+ <p class="text-gray-500 dark:text-gray-400 font-sm text-right mt-3">
124
+ {{$t('or')}} <Link to="/login">{{ toLoginText }}</Link>
125
+ </p>
121
126
  </div>
122
127
  </div>
123
128
  </div>
@@ -128,7 +133,6 @@
128
133
 
129
134
 
130
135
  <script setup lang="ts">
131
-
132
136
  import { onMounted, ref, computed, Ref } from 'vue';
133
137
  import { useCoreStore } from '@/stores/core';
134
138
  import { useUserStore } from '@/stores/user';
@@ -136,27 +140,33 @@ import { callAdminForthApi, loadFile, applyRegexValidation } from '@/utils';
136
140
  import { useRoute, useRouter } from 'vue-router';
137
141
  import { IconEyeSolid, IconEyeSlashSolid } from '@iconify-prerendered/vue-flowbite';
138
142
  import Button from '@/afcl/Button.vue';
143
+ import Link from '@/afcl/Link.vue';
139
144
 
140
145
  const inProgress = ref(false);
141
146
 
142
147
  const coreStore = useCoreStore();
143
148
  const requestSent = ref(false);
144
149
 
145
- const emailInput = ref(null);
146
- const passwordInput = ref(null);
147
- const passwordConfirmationInput = ref(null);
150
+ const emailInput: Ref<HTMLInputElement | null> = ref(null);
151
+ const passwordInput: Ref<HTMLInputElement | null> = ref(null);
152
+ const passwordConfirmationInput: Ref<HTMLInputElement | null> = ref(null);
148
153
 
149
154
  const password = ref("");
150
155
  const passwordConfirmation = ref("");
151
156
  const unmasked = ref(false);
152
157
  const sentToEmail: Ref<string> = ref('');
153
158
 
159
+ const requestEmailConfirmation = computed(() => route.meta.requestEmailConfirmation);
160
+ const verifyToken = computed(() => route.query.token);
161
+ const toLoginText = computed(() => `${verifyToken.value ? 'Go' : 'Back'} to login`);
162
+ const isPasswordNeeded = computed(() => !requestEmailConfirmation.value || (requestEmailConfirmation.value && verifyToken.value));
163
+
154
164
  const user = useUserStore();
155
165
 
156
166
  const route = useRoute();
157
167
  const router = useRouter();
158
168
 
159
- function checkPassowrd() {
169
+ function checkPassword() {
160
170
 
161
171
  if (!password.value || !passwordConfirmation.value) {
162
172
  return 'Please enter both password and password confirmation';
@@ -187,39 +197,15 @@ const validationRunning = ref(false);
187
197
 
188
198
  const validationError = computed(() => {
189
199
  if (validationRunning.value) {
190
- return checkPassowrd();
200
+ return checkPassword();
191
201
  }
192
202
  return null;
193
203
  });
194
204
 
195
- const error: Ref<str | null> = ref(null);
205
+ const error: Ref<string | null> = ref(null);
196
206
 
197
207
  onMounted(async () => {
198
- if (route.query.token) {
199
- // call method completeVerifiedSignup to confirm { token }
200
- // if success, then redirect to login page
201
-
202
- const resp = await callAdminForthApi({
203
- path: `/plugin/${route.meta.pluginInstanceId}/complete-verified-signup`,
204
- method: 'POST',
205
- body: {
206
- token: route.query.token,
207
- }
208
- });
209
- if (resp.error) {
210
- window.adminforth.alert({
211
- message: `Error fetching data: ${error.message}`,
212
- variant: 'danger',
213
- });
214
- } else if (resp.redirectTo) {
215
- router.push(resp.redirectTo);
216
- } else {
217
- await user.finishLogin();
218
- }
219
- return;
220
-
221
- }
222
- emailInput.value.focus();
208
+ emailInput.value?.focus();
223
209
  });
224
210
 
225
211
 
@@ -242,7 +228,7 @@ async function doSignup() {
242
228
  error.value = 'Please enter your email';
243
229
  return;
244
230
  }
245
- if (checkPassowrd()) {
231
+ if (!requestEmailConfirmation.value && checkPassword()) {
246
232
  validationRunning.value = true;
247
233
  return;
248
234
  }
@@ -254,7 +240,7 @@ async function doSignup() {
254
240
  body: {
255
241
  email,
256
242
  url: window.location.origin + window.location.pathname,
257
- password: password.value,
243
+ ...(!requestEmailConfirmation.value ? {password: password.value} : {}),
258
244
  }
259
245
  });
260
246
  inProgress.value = false;
@@ -264,15 +250,37 @@ async function doSignup() {
264
250
  error.value = null;
265
251
  requestSent.value = true;
266
252
  sentToEmail.value = email;
267
- if (resp.redirectTo) {
253
+ if (resp.redirectTo && !requestEmailConfirmation.value) {
268
254
  router.push(resp.redirectTo);
269
- } else {
255
+ } else if (!requestEmailConfirmation.value) {
270
256
  error.value = null;
271
257
  await user.finishLogin();
272
258
  }
273
259
  }
274
260
  }
275
261
 
276
-
277
-
262
+ const signupAfterEmailConfirmation = async () => {
263
+ if (checkPassword()) {
264
+ validationRunning.value = true;
265
+ return;
266
+ }
267
+ const resp = await callAdminForthApi({
268
+ path: `/plugin/${route.meta.pluginInstanceId}/complete-verified-signup`,
269
+ method: 'POST',
270
+ body: {
271
+ token: verifyToken.value,
272
+ password: password.value,
273
+ }
274
+ });
275
+ if (resp.error) {
276
+ window.adminforth.alert({
277
+ message: `Error fetching data: ${resp.error}`,
278
+ variant: 'danger',
279
+ });
280
+ } else if (resp.redirectTo) {
281
+ router.push(resp.redirectTo);
282
+ } else {
283
+ await user.finishLogin();
284
+ }
285
+ }
278
286
  </script>
@@ -1,8 +1,8 @@
1
1
  <template>
2
2
  <p class="text-gray-500 dark:text-gray-400 font-sm text-left mt-3">
3
- Have no account?
3
+ {{$t('Have no account?')}}
4
4
  <Link to="/signup">
5
- sign up now
5
+ {{$t('sign up now')}}
6
6
  </Link>
7
7
  </p>
8
8
  </template>
package/dist/index.js CHANGED
@@ -8,7 +8,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import AdminForth, { AdminForthPlugin, Filters, suggestIfTypo, AdminForthDataTypes } from "adminforth";
11
- import { SendEmailCommand, SESClient } from '@aws-sdk/client-ses';
12
11
  export default class OpenSignupPlugin extends AdminForthPlugin {
13
12
  constructor(options) {
14
13
  super(options, import.meta.url);
@@ -23,9 +22,15 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
23
22
  if (!this.options.emailField) {
24
23
  throw new Error(`emailField is required and should be a name of field in auth resource`);
25
24
  }
25
+ // find field with name resourceConfig.emailField in adminforth.auth.usersResourceId and show error if it doesn't exist
26
+ const authResource = adminforth.config.resources.find(r => r.resourceId === adminforth.config.auth.usersResourceId);
27
+ if (!authResource) {
28
+ throw new Error(`Resource with id config.auth.usersResourceId=${adminforth.config.auth.usersResourceId} not found`);
29
+ }
30
+ this.authResource = authResource;
26
31
  if (this.options.confirmEmails) {
27
- if (!this.options.confirmEmails.emailProvider) {
28
- throw new Error(`confirmEmails.emailProvider is required and should be a name of field in auth resource`);
32
+ if (!this.options.confirmEmails.adapter) {
33
+ throw new Error(`confirmEmails.adapter is required and should be a name of field in auth resource`);
29
34
  }
30
35
  if (!this.options.confirmEmails.emailConfirmedField) {
31
36
  throw new Error(`confirmEmails.emailConfirmedField is required and should be a name of field in auth resource`);
@@ -38,16 +43,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
38
43
  `);
39
44
  }
40
45
  this.emailConfirmedField = emailConfirmedField;
41
- if (this.emailConfirmedField.type !== AdminForthDataTypes.BOOLEAN) {
42
- throw new Error(`Field ${this.emailConfirmedField.name} must be of type boolean`);
43
- }
44
46
  }
45
- // find field with name resourceConfig.emailField in adminforth.auth.usersResourceId and show error if it doesn't exist
46
- const authResource = adminforth.config.resources.find(r => r.resourceId === adminforth.config.auth.usersResourceId);
47
- if (!authResource) {
48
- throw new Error(`Resource with id config.auth.usersResourceId=${adminforth.config.auth.usersResourceId} not found`);
49
- }
50
- this.authResource = authResource;
51
47
  const emailField = authResource.columns.find(f => f.name === this.options.emailField);
52
48
  if (!emailField) {
53
49
  const similar = suggestIfTypo(authResource.columns.map(f => f.name), this.options.emailField);
@@ -81,7 +77,8 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
81
77
  minLength: passwordField.minLength,
82
78
  maxLength: passwordField.maxLength,
83
79
  validation: passwordField.validation
84
- }
80
+ },
81
+ requestEmailConfirmation: !!this.options.confirmEmails
85
82
  }
86
83
  }
87
84
  });
@@ -90,24 +87,26 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
90
87
  if (!adminforth.config.auth.beforeLoginConfirmation) {
91
88
  adminforth.config.auth.beforeLoginConfirmation = [];
92
89
  }
93
- // unshift because if e.g. 2fa set it's hook, this one should be first
94
- adminforth.config.auth.beforeLoginConfirmation.unshift((_a) => __awaiter(this, [_a], void 0, function* ({ adminUser }) {
95
- if (!adminUser.dbUser[this.emailConfirmedField.name]) {
96
- return { body: { allowedLogin: false }, error: 'You need to confirm your email to be able to login' };
97
- }
98
- }));
99
90
  }
100
91
  });
101
92
  }
102
93
  validateConfigAfterDiscover(adminforth, resourceConfig) {
103
- // optional method where you can safely check field types after database discovery was performed
94
+ if (this.options.confirmEmails) {
95
+ this.options.confirmEmails.adapter.validate();
96
+ }
97
+ if (this.options.confirmEmails) {
98
+ const emailConfirmedColumn = this.resourceConfig.columns.find(f => f.name === this.options.confirmEmails.emailConfirmedField);
99
+ if (emailConfirmedColumn.type !== AdminForthDataTypes.BOOLEAN) {
100
+ throw new Error(`Field ${this.emailConfirmedField.name} must be of type boolean`);
101
+ }
102
+ }
104
103
  }
105
104
  instanceUniqueRepresentation(pluginOptions) {
106
105
  // optional method to return unique string representation of plugin instance.
107
106
  // Needed if plugin can have multiple instances on one resource
108
107
  return `single`;
109
108
  }
110
- doLogin(email, response) {
109
+ doLogin(email, response, extra) {
111
110
  return __awaiter(this, void 0, void 0, function* () {
112
111
  const username = email;
113
112
  const userRecord = yield this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
@@ -117,7 +116,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
117
116
  username,
118
117
  };
119
118
  const toReturn = { allowedLogin: true, error: '' };
120
- yield this.adminforth.restApi.processLoginCallbacks(adminUser, toReturn, response);
119
+ yield this.adminforth.restApi.processLoginCallbacks(adminUser, toReturn, response, extra);
121
120
  if (toReturn.allowedLogin) {
122
121
  this.adminforth.auth.setAuthCookie({
123
122
  response,
@@ -131,29 +130,36 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
131
130
  setupEndpoints(server) {
132
131
  server.endpoint({
133
132
  method: 'POST',
134
- path: `/plugin/${this.pluginInstanceId}/completeVerifiedSignup`,
133
+ path: `/plugin/${this.pluginInstanceId}/complete-verified-signup`,
135
134
  noAuth: true,
136
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, response }) {
137
- const { token } = body;
138
- const { email } = yield this.adminforth.auth.verify(token, 'tempVerifyEmailToken');
135
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, response, headers, query, cookies }) {
136
+ const { token, password } = body;
137
+ const { email } = yield this.adminforth.auth.verify(token, 'tempVerifyEmailToken', false);
139
138
  if (!email) {
140
139
  return { error: 'Invalid token', ok: false };
141
140
  }
141
+ if (!password) {
142
+ return { error: 'Password is required', ok: false };
143
+ }
142
144
  const userRecord = yield this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
143
145
  if (!userRecord) {
144
146
  return { error: 'User not found', ok: false };
145
147
  }
148
+ if (userRecord[this.options.confirmEmails.emailConfirmedField]) {
149
+ return { error: 'Email already confirmed', ok: false };
150
+ }
146
151
  yield this.adminforth.resource(this.authResource.resourceId).update(userRecord[this.authResource.columns.find((col) => col.primaryKey).name], {
147
- [this.options.confirmEmails.emailConfirmedField]: true
152
+ [this.options.confirmEmails.emailConfirmedField]: true,
153
+ [this.options.passwordHashField]: yield AdminForth.Utils.generatePasswordHash(password),
148
154
  });
149
- return yield this.doLogin(email, response);
155
+ return yield this.doLogin(email, response, { body, headers, query, cookies });
150
156
  })
151
157
  });
152
158
  server.endpoint({
153
159
  method: 'POST',
154
160
  path: `/plugin/${this.pluginInstanceId}/signup`,
155
161
  noAuth: true,
156
- handler: (_b) => __awaiter(this, [_b], void 0, function* ({ body, response }) {
162
+ handler: (_b) => __awaiter(this, [_b], void 0, function* ({ body, response, headers, query, cookies }) {
157
163
  const { email, url, password } = body;
158
164
  // validate email
159
165
  if (this.emailField.validation) {
@@ -164,51 +170,39 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
164
170
  }
165
171
  }
166
172
  // validate password
167
- if (password.length < this.passwordField.minLength) {
168
- return { error: `Password must be at least ${this.passwordField.minLength} characters long`, ok: false };
169
- }
170
- if (password.length > this.passwordField.maxLength) {
171
- return { error: `Password must be at most ${this.passwordField.maxLength} characters long`, ok: false };
172
- }
173
- if (this.passwordField.validation) {
174
- for (const { regExp, message } of this.passwordField.validation) {
175
- if (!new RegExp(regExp).test(password)) {
176
- return { error: message, ok: false };
173
+ if (!this.options.confirmEmails) {
174
+ if (password.length < this.passwordField.minLength) {
175
+ return { error: `Password must be at least ${this.passwordField.minLength} characters long`, ok: false };
176
+ }
177
+ if (password.length > this.passwordField.maxLength) {
178
+ return { error: `Password must be at most ${this.passwordField.maxLength} characters long`, ok: false };
179
+ }
180
+ if (this.passwordField.validation) {
181
+ for (const { regExp, message } of this.passwordField.validation) {
182
+ if (!new RegExp(regExp).test(password)) {
183
+ return { error: message, ok: false };
184
+ }
177
185
  }
178
186
  }
179
187
  }
180
188
  // first check again if email already exists
181
- const existing = yield this.adminforth.resource(this.authResource.resourceId).count(Filters.EQ(this.emailField.name, email));
182
- if (existing > 0) {
189
+ const existingUser = yield this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
190
+ if ((!this.options.confirmEmails && existingUser) || (this.options.confirmEmails && (existingUser === null || existingUser === void 0 ? void 0 : existingUser[this.emailConfirmedField.name]))) {
183
191
  return { error: 'Email already exists', ok: false };
184
192
  }
185
193
  // create user
186
- const created = yield this.adminforth.resource(this.authResource.resourceId).create(Object.assign(Object.assign(Object.assign({}, (this.options.defaultFieldValues || {})), (this.options.confirmEmails ? { [this.options.confirmEmails.emailConfirmedField]: false } : {})), { [this.emailField.name]: email, [this.options.passwordHashField]: yield AdminForth.Utils.generatePasswordHash(password) }));
194
+ if (!existingUser) {
195
+ const created = yield this.adminforth.resource(this.authResource.resourceId).create(Object.assign(Object.assign(Object.assign({}, (this.options.defaultFieldValues || {})), (this.options.confirmEmails ? { [this.options.confirmEmails.emailConfirmedField]: false } : {})), { [this.emailField.name]: email, [this.options.passwordHashField]: password ? yield AdminForth.Utils.generatePasswordHash(password) : '' }));
196
+ }
187
197
  if (!this.options.confirmEmails) {
188
- const resp = yield this.doLogin(email, response);
198
+ const resp = yield this.doLogin(email, response, { body, headers, query, cookies });
189
199
  return resp;
190
200
  }
191
201
  // send confirmation email
192
202
  const brandName = this.adminforth.config.customization.brandName;
193
203
  const verifyToken = this.adminforth.auth.issueJWT({ email, issuer: brandName }, 'tempVerifyEmailToken', '2h');
194
- // send email with AWS SES this.options.providerOptions.AWS_SES
195
- const ses = new SESClient({
196
- region: this.options.confirmEmails.providerOptions.AWS_SES.region,
197
- credentials: {
198
- accessKeyId: this.options.confirmEmails.providerOptions.AWS_SES.accessKeyId,
199
- secretAccessKey: this.options.confirmEmails.providerOptions.AWS_SES.secretAccessKey
200
- }
201
- });
202
204
  process.env.HEAVY_DEBUG && console.log('🐛Sending reset tok to', verifyToken);
203
- const emailCommand = new SendEmailCommand({
204
- Destination: {
205
- ToAddresses: [email]
206
- },
207
- Message: {
208
- Body: {
209
- Text: {
210
- Charset: "UTF-8",
211
- Data: `
205
+ const emailText = `
212
206
  Dear user,
213
207
  Welcome to ${brandName}!
214
208
 
@@ -222,11 +216,8 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
222
216
  Thanks,
223
217
  The ${brandName} Team
224
218
 
225
- `
226
- },
227
- Html: {
228
- Charset: "UTF-8",
229
- Data: `
219
+ `;
220
+ const emailHtml = `
230
221
  <html>
231
222
  <head></head>
232
223
  <body>
@@ -242,26 +233,10 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
242
233
  </html>
243
234
 
244
235
 
245
- `
246
- }
247
- },
248
- Subject: {
249
- Charset: "UTF-8",
250
- Data: `Signup request at ${brandName}`
251
- }
252
- },
253
- Source: `${this.options.confirmEmails.sendFrom}`
254
- });
255
- try {
256
- const sRes = yield ses.send(emailCommand);
257
- }
258
- catch (e) {
259
- console.error('Error sending email', e);
260
- if (process.env.NODE_ENV === 'development') {
261
- return { error: 'Some thing went wrong, please check the console', ok: false };
262
- }
263
- return { error: 'Something went wrong, please contact support', ok: false };
264
- }
236
+ `;
237
+ const emailSubject = `Signup request at ${brandName}`;
238
+ // send email with AWS SES this.options.providerOptions.AWS_SES
239
+ this.options.confirmEmails.adapter.sendEmail(this.options.confirmEmails.sendFrom, email, emailText, emailHtml, emailSubject);
265
240
  return { ok: true };
266
241
  })
267
242
  });
package/index.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import AdminForth, { AdminForthPlugin, Filters, suggestIfTypo, AdminForthDataTypes } from "adminforth";
2
- import type { IAdminForth, IHttpServer, AdminForthComponentDeclaration, AdminForthResourceColumn, AdminForthResource, BeforeLoginConfirmationFunction } from "adminforth";
2
+ import type { IAdminForth, IHttpServer, AdminForthComponentDeclaration, AdminForthResourceColumn, AdminForthResource, BeforeLoginConfirmationFunction, HttpExtra } from "adminforth";
3
3
  import type { PluginOptions } from './types.js';
4
- import { SendEmailCommand, SESClient } from '@aws-sdk/client-ses';
5
4
 
6
5
 
7
6
  export default class OpenSignupPlugin extends AdminForthPlugin {
@@ -25,9 +24,16 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
25
24
  throw new Error(`emailField is required and should be a name of field in auth resource`);
26
25
  }
27
26
 
27
+ // find field with name resourceConfig.emailField in adminforth.auth.usersResourceId and show error if it doesn't exist
28
+ const authResource = adminforth.config.resources.find(r => r.resourceId === adminforth.config.auth.usersResourceId);
29
+ if (!authResource) {
30
+ throw new Error(`Resource with id config.auth.usersResourceId=${adminforth.config.auth.usersResourceId} not found`);
31
+ }
32
+ this.authResource = authResource;
33
+
28
34
  if (this.options.confirmEmails) {
29
- if (!this.options.confirmEmails.emailProvider) {
30
- throw new Error(`confirmEmails.emailProvider is required and should be a name of field in auth resource`);
35
+ if (!this.options.confirmEmails.adapter) {
36
+ throw new Error(`confirmEmails.adapter is required and should be a name of field in auth resource`);
31
37
  }
32
38
  if (!this.options.confirmEmails.emailConfirmedField) {
33
39
  throw new Error(`confirmEmails.emailConfirmedField is required and should be a name of field in auth resource`);
@@ -40,18 +46,8 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
40
46
  `);
41
47
  }
42
48
  this.emailConfirmedField = emailConfirmedField;
43
- if (this.emailConfirmedField.type !== AdminForthDataTypes.BOOLEAN) {
44
- throw new Error(`Field ${this.emailConfirmedField.name} must be of type boolean`);
45
- }
46
49
  }
47
50
 
48
- // find field with name resourceConfig.emailField in adminforth.auth.usersResourceId and show error if it doesn't exist
49
- const authResource = adminforth.config.resources.find(r => r.resourceId === adminforth.config.auth.usersResourceId);
50
- if (!authResource) {
51
- throw new Error(`Resource with id config.auth.usersResourceId=${adminforth.config.auth.usersResourceId} not found`);
52
- }
53
- this.authResource = authResource;
54
-
55
51
  const emailField = authResource.columns.find(f => f.name === this.options.emailField);
56
52
  if (!emailField) {
57
53
  const similar = suggestIfTypo(authResource.columns.map(f => f.name), this.options.emailField);
@@ -89,7 +85,8 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
89
85
  minLength: passwordField.minLength,
90
86
  maxLength: passwordField.maxLength,
91
87
  validation: passwordField.validation
92
- }
88
+ },
89
+ requestEmailConfirmation: !!this.options.confirmEmails
93
90
  }
94
91
  }
95
92
  });
@@ -99,19 +96,21 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
99
96
  if (!adminforth.config.auth.beforeLoginConfirmation) {
100
97
  adminforth.config.auth.beforeLoginConfirmation = [];
101
98
  }
102
- // unshift because if e.g. 2fa set it's hook, this one should be first
103
- (adminforth.config.auth.beforeLoginConfirmation as BeforeLoginConfirmationFunction[]).unshift(
104
- async ({ adminUser }) => {
105
- if (!adminUser.dbUser[this.emailConfirmedField.name]) {
106
- return { body: { allowedLogin: false }, error: 'You need to confirm your email to be able to login' };
107
- }
108
- }
109
- );
110
99
  }
111
100
  }
112
101
 
113
102
  validateConfigAfterDiscover(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
114
- // optional method where you can safely check field types after database discovery was performed
103
+ if (this.options.confirmEmails) {
104
+ this.options.confirmEmails.adapter.validate();
105
+ }
106
+
107
+
108
+ if(this.options.confirmEmails){
109
+ const emailConfirmedColumn = this.resourceConfig.columns.find(f => f.name === this.options.confirmEmails.emailConfirmedField);
110
+ if (emailConfirmedColumn.type !== AdminForthDataTypes.BOOLEAN) {
111
+ throw new Error(`Field ${this.emailConfirmedField.name} must be of type boolean`);
112
+ }
113
+ }
115
114
  }
116
115
 
117
116
  instanceUniqueRepresentation(pluginOptions: any) : string {
@@ -120,7 +119,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
120
119
  return `single`;
121
120
  }
122
121
 
123
- async doLogin(email: string, response: any): Promise<{ error?: string; allowedLogin: boolean; redirectTo?: string; }> {
122
+ async doLogin(email: string, response: any, extra: HttpExtra): Promise<{ error?: string; allowedLogin: boolean; redirectTo?: string; }> {
124
123
 
125
124
  const username = email;
126
125
  const userRecord = await this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
@@ -131,7 +130,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
131
130
  };
132
131
  const toReturn = { allowedLogin: true, error: '' };
133
132
 
134
- await this.adminforth.restApi.processLoginCallbacks(adminUser, toReturn, response);
133
+ await this.adminforth.restApi.processLoginCallbacks(adminUser, toReturn, response, extra);
135
134
  if (toReturn.allowedLogin) {
136
135
  this.adminforth.auth.setAuthCookie({
137
136
  response,
@@ -149,22 +148,32 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
149
148
  setupEndpoints(server: IHttpServer) {
150
149
  server.endpoint({
151
150
  method: 'POST',
152
- path: `/plugin/${this.pluginInstanceId}/completeVerifiedSignup`,
151
+ path: `/plugin/${this.pluginInstanceId}/complete-verified-signup`,
153
152
  noAuth: true,
154
- handler: async ({ body, response }) => {
155
- const { token } = body;
156
- const { email } = await this.adminforth.auth.verify(token, 'tempVerifyEmailToken');
153
+ handler: async ({ body, response, headers, query, cookies }) => {
154
+ const { token, password } = body;
155
+ const { email } = await this.adminforth.auth.verify(token, 'tempVerifyEmailToken', false);
157
156
  if (!email) {
158
157
  return { error: 'Invalid token', ok: false };
159
158
  }
159
+
160
+ if(!password) {
161
+ return { error: 'Password is required', ok: false };
162
+ }
160
163
  const userRecord = await this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
161
164
  if (!userRecord) {
162
165
  return { error: 'User not found', ok: false };
163
166
  }
167
+
168
+ if (userRecord[this.options.confirmEmails.emailConfirmedField]) {
169
+ return { error: 'Email already confirmed', ok: false };
170
+ }
171
+
164
172
  await this.adminforth.resource(this.authResource.resourceId).update(userRecord[this.authResource.columns.find((col) => col.primaryKey).name], {
165
- [this.options.confirmEmails.emailConfirmedField]: true
173
+ [this.options.confirmEmails.emailConfirmedField]: true,
174
+ [this.options.passwordHashField]: await AdminForth.Utils.generatePasswordHash(password),
166
175
  });
167
- return await this.doLogin(email, response);
176
+ return await this.doLogin(email, response, { body, headers, query, cookies });
168
177
  }
169
178
  });
170
179
 
@@ -172,7 +181,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
172
181
  method: 'POST',
173
182
  path: `/plugin/${this.pluginInstanceId}/signup`,
174
183
  noAuth: true,
175
- handler: async ({ body, response }) => {
184
+ handler: async ({ body, response, headers, query, cookies }) => {
176
185
  const { email, url, password } = body;
177
186
 
178
187
  // validate email
@@ -185,36 +194,40 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
185
194
  }
186
195
 
187
196
  // validate password
188
- if (password.length < this.passwordField.minLength) {
189
- return { error: `Password must be at least ${this.passwordField.minLength} characters long`, ok: false };
190
- }
191
- if (password.length > this.passwordField.maxLength) {
192
- return { error: `Password must be at most ${this.passwordField.maxLength} characters long`, ok: false };
193
- }
194
- if (this.passwordField.validation) {
195
- for (const { regExp, message } of this.passwordField.validation) {
196
- if (!new RegExp(regExp).test(password)) {
197
- return { error: message, ok: false };
197
+ if (!this.options.confirmEmails) {
198
+ if (password.length < this.passwordField.minLength) {
199
+ return { error: `Password must be at least ${this.passwordField.minLength} characters long`, ok: false };
200
+ }
201
+ if (password.length > this.passwordField.maxLength) {
202
+ return { error: `Password must be at most ${this.passwordField.maxLength} characters long`, ok: false };
203
+ }
204
+ if (this.passwordField.validation) {
205
+ for (const { regExp, message } of this.passwordField.validation) {
206
+ if (!new RegExp(regExp).test(password)) {
207
+ return { error: message, ok: false };
208
+ }
198
209
  }
199
210
  }
200
211
  }
201
212
 
202
213
  // first check again if email already exists
203
- const existing = await this.adminforth.resource(this.authResource.resourceId).count(Filters.EQ(this.emailField.name, email));
204
- if (existing > 0) {
214
+ const existingUser = await this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
215
+ if ((!this.options.confirmEmails && existingUser) || (this.options.confirmEmails && existingUser?.[this.emailConfirmedField.name])) {
205
216
  return { error: 'Email already exists', ok: false };
206
217
  }
207
218
 
208
219
  // create user
209
- const created = await this.adminforth.resource(this.authResource.resourceId).create({
210
- ...(this.options.defaultFieldValues || {}),
211
- ...(this.options.confirmEmails ? { [this.options.confirmEmails.emailConfirmedField]: false } : {}),
212
- [this.emailField.name]: email,
213
- [this.options.passwordHashField]: await AdminForth.Utils.generatePasswordHash(password),
214
- });
220
+ if (!existingUser) {
221
+ const created = await this.adminforth.resource(this.authResource.resourceId).create({
222
+ ...(this.options.defaultFieldValues || {}),
223
+ ...(this.options.confirmEmails ? { [this.options.confirmEmails.emailConfirmedField]: false } : {}),
224
+ [this.emailField.name]: email,
225
+ [this.options.passwordHashField]: password ? await AdminForth.Utils.generatePasswordHash(password) : '',
226
+ });
227
+ }
215
228
 
216
229
  if (!this.options.confirmEmails) {
217
- const resp = await this.doLogin(email, response);
230
+ const resp = await this.doLogin(email, response, { body, headers, query, cookies });
218
231
  return resp;
219
232
  }
220
233
 
@@ -223,27 +236,8 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
223
236
  const brandName = this.adminforth.config.customization.brandName;
224
237
 
225
238
  const verifyToken = this.adminforth.auth.issueJWT({email, issuer: brandName }, 'tempVerifyEmailToken', '2h');
226
-
227
- // send email with AWS SES this.options.providerOptions.AWS_SES
228
- const ses = new SESClient({
229
- region: this.options.confirmEmails.providerOptions.AWS_SES.region,
230
- credentials: {
231
- accessKeyId: this.options.confirmEmails.providerOptions.AWS_SES.accessKeyId,
232
- secretAccessKey: this.options.confirmEmails.providerOptions.AWS_SES.secretAccessKey
233
- }
234
- });
235
-
236
239
  process.env.HEAVY_DEBUG && console.log('🐛Sending reset tok to', verifyToken);
237
-
238
- const emailCommand = new SendEmailCommand({
239
- Destination: {
240
- ToAddresses: [email]
241
- },
242
- Message: {
243
- Body: {
244
- Text: {
245
- Charset: "UTF-8",
246
- Data: `
240
+ const emailText = `
247
241
  Dear user,
248
242
  Welcome to ${brandName}!
249
243
 
@@ -257,11 +251,9 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
257
251
  Thanks,
258
252
  The ${brandName} Team
259
253
 
260
- `
261
- },
262
- Html: {
263
- Charset: "UTF-8",
264
- Data: `
254
+ `;
255
+
256
+ const emailHtml = `
265
257
  <html>
266
258
  <head></head>
267
259
  <body>
@@ -277,26 +269,11 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
277
269
  </html>
278
270
 
279
271
 
280
- `
281
- }
282
- },
283
- Subject: {
284
- Charset: "UTF-8",
285
- Data: `Signup request at ${brandName}`
286
- }
287
- },
288
- Source: `${this.options.confirmEmails.sendFrom}`
289
- });
272
+ `;
273
+ const emailSubject = `Signup request at ${brandName}`;
290
274
 
291
- try {
292
- const sRes = await ses.send(emailCommand);
293
- } catch (e) {
294
- console.error('Error sending email', e);
295
- if (process.env.NODE_ENV === 'development') {
296
- return { error: 'Some thing went wrong, please check the console', ok: false };
297
- }
298
- return { error: 'Something went wrong, please contact support', ok: false };
299
- }
275
+ // send email with AWS SES this.options.providerOptions.AWS_SES
276
+ this.options.confirmEmails.adapter.sendEmail(this.options.confirmEmails.sendFrom, email, emailText, emailHtml, emailSubject);
300
277
 
301
278
  return { ok: true };
302
279
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/open-signup",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
package/types.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { EmailAdapter } from 'adminforth';
2
+
1
3
  export interface PluginOptions {
2
4
 
3
5
  /**
@@ -40,11 +42,6 @@ export interface PluginOptions {
40
42
  */
41
43
  emailConfirmedField: string;
42
44
 
43
- /**
44
- * Required to confirm email
45
- */
46
- emailProvider: 'AWS_SES' ;
47
-
48
45
  /**
49
46
  * From which email to send password reset emails
50
47
  * e.g. no-reply@example.com
@@ -53,15 +50,9 @@ export interface PluginOptions {
53
50
  sendFrom: string;
54
51
 
55
52
  /**
56
- * Options for email provider
53
+ * Adapter to send emails
57
54
  */
58
- providerOptions: {
59
- AWS_SES: {
60
- region: string;
61
- accessKeyId: string;
62
- secretAccessKey: string;
63
- }
64
- }
55
+ adapter: EmailAdapter;
65
56
  }
66
57
 
67
58