@adminforth/open-signup 1.0.5 → 1.0.6
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.
- package/custom/SignupPage.vue +32 -14
- package/dist/custom/SignupPage.vue +32 -14
- package/dist/index.js +48 -37
- package/index.ts +55 -37
- package/package.json +1 -1
package/custom/SignupPage.vue
CHANGED
|
@@ -141,6 +141,9 @@ import { useRoute, useRouter } from 'vue-router';
|
|
|
141
141
|
import { IconEyeSolid, IconEyeSlashSolid } from '@iconify-prerendered/vue-flowbite';
|
|
142
142
|
import Button from '@/afcl/Button.vue';
|
|
143
143
|
import Link from '@/afcl/Link.vue';
|
|
144
|
+
import { useI18n } from 'vue-i18n';
|
|
145
|
+
|
|
146
|
+
const { t } = useI18n();
|
|
144
147
|
|
|
145
148
|
const inProgress = ref(false);
|
|
146
149
|
|
|
@@ -158,7 +161,7 @@ const sentToEmail: Ref<string> = ref('');
|
|
|
158
161
|
|
|
159
162
|
const requestEmailConfirmation = computed(() => route.meta.requestEmailConfirmation);
|
|
160
163
|
const verifyToken = computed(() => route.query.token);
|
|
161
|
-
const toLoginText = computed(() =>
|
|
164
|
+
const toLoginText = computed(() => verifyToken.value ? t('Go to login') : t('Back to login'));
|
|
162
165
|
const isPasswordNeeded = computed(() => !requestEmailConfirmation.value || (requestEmailConfirmation.value && verifyToken.value));
|
|
163
166
|
|
|
164
167
|
const user = useUserStore();
|
|
@@ -169,22 +172,25 @@ const router = useRouter();
|
|
|
169
172
|
function checkPassword() {
|
|
170
173
|
|
|
171
174
|
if (!password.value || !passwordConfirmation.value) {
|
|
172
|
-
return 'Please enter both password and password confirmation';
|
|
175
|
+
return t('Please enter both password and password confirmation');
|
|
173
176
|
}
|
|
174
177
|
if (password.value !== passwordConfirmation.value) {
|
|
175
|
-
return 'Passwords do not match';
|
|
178
|
+
return t('Passwords do not match');
|
|
176
179
|
}
|
|
177
180
|
|
|
178
|
-
if (
|
|
179
|
-
return
|
|
181
|
+
if (!passwordConstraints.value) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
if (password.value.length < passwordConstraints.value.minLength) {
|
|
185
|
+
return t(`Password must be at least {minLength} characters long`, { minLength: passwordConstraints.value.minLength });
|
|
180
186
|
}
|
|
181
187
|
|
|
182
|
-
if (password.value.length >
|
|
183
|
-
return `Password must be at most
|
|
188
|
+
if (password.value.length > passwordConstraints.value.maxLength) {
|
|
189
|
+
return t(`Password must be at most {maxLength} characters long`, { maxLength: passwordConstraints.value.maxLength });
|
|
184
190
|
}
|
|
185
191
|
|
|
186
|
-
if (
|
|
187
|
-
const valError = applyRegexValidation(password.value,
|
|
192
|
+
if (passwordConstraints.value.validation) {
|
|
193
|
+
const valError = applyRegexValidation(password.value, passwordConstraints.value.validation);
|
|
188
194
|
if (valError) {
|
|
189
195
|
return valError;
|
|
190
196
|
}
|
|
@@ -213,19 +219,31 @@ const backgroundPosition = computed(() => {
|
|
|
213
219
|
return coreStore.config?.loginBackgroundPosition || '1/2';
|
|
214
220
|
});
|
|
215
221
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
222
|
+
|
|
223
|
+
const passwordConstraints: Ref<{
|
|
224
|
+
minLength: number;
|
|
225
|
+
maxLength: number;
|
|
226
|
+
validation: string;
|
|
227
|
+
}> = ref({
|
|
228
|
+
minLength: 8,
|
|
229
|
+
maxLength: 100,
|
|
230
|
+
validation: '',
|
|
231
|
+
});
|
|
219
232
|
|
|
220
233
|
onMounted(async () => {
|
|
221
234
|
await coreStore.getPublicConfig();
|
|
235
|
+
// getPasswordConstraints
|
|
236
|
+
passwordConstraints.value = await callAdminForthApi({
|
|
237
|
+
path: `/plugin/${route.meta.pluginInstanceId}/password-constraints`,
|
|
238
|
+
method: 'GET',
|
|
239
|
+
});
|
|
222
240
|
});
|
|
223
241
|
|
|
224
242
|
async function doSignup() {
|
|
225
243
|
error.value = null;
|
|
226
244
|
const email = emailInput.value!.value;
|
|
227
245
|
if (!email) {
|
|
228
|
-
error.value = 'Please enter your email';
|
|
246
|
+
error.value = t('Please enter your email');
|
|
229
247
|
return;
|
|
230
248
|
}
|
|
231
249
|
if (!requestEmailConfirmation.value && checkPassword()) {
|
|
@@ -274,7 +292,7 @@ const signupAfterEmailConfirmation = async () => {
|
|
|
274
292
|
});
|
|
275
293
|
if (resp.error) {
|
|
276
294
|
window.adminforth.alert({
|
|
277
|
-
message: `Error fetching data:
|
|
295
|
+
message: t(`Error fetching data: {error}`, { error: resp.error }),
|
|
278
296
|
variant: 'danger',
|
|
279
297
|
});
|
|
280
298
|
} else if (resp.redirectTo) {
|
|
@@ -141,6 +141,9 @@ import { useRoute, useRouter } from 'vue-router';
|
|
|
141
141
|
import { IconEyeSolid, IconEyeSlashSolid } from '@iconify-prerendered/vue-flowbite';
|
|
142
142
|
import Button from '@/afcl/Button.vue';
|
|
143
143
|
import Link from '@/afcl/Link.vue';
|
|
144
|
+
import { useI18n } from 'vue-i18n';
|
|
145
|
+
|
|
146
|
+
const { t } = useI18n();
|
|
144
147
|
|
|
145
148
|
const inProgress = ref(false);
|
|
146
149
|
|
|
@@ -158,7 +161,7 @@ const sentToEmail: Ref<string> = ref('');
|
|
|
158
161
|
|
|
159
162
|
const requestEmailConfirmation = computed(() => route.meta.requestEmailConfirmation);
|
|
160
163
|
const verifyToken = computed(() => route.query.token);
|
|
161
|
-
const toLoginText = computed(() =>
|
|
164
|
+
const toLoginText = computed(() => verifyToken.value ? t('Go to login') : t('Back to login'));
|
|
162
165
|
const isPasswordNeeded = computed(() => !requestEmailConfirmation.value || (requestEmailConfirmation.value && verifyToken.value));
|
|
163
166
|
|
|
164
167
|
const user = useUserStore();
|
|
@@ -169,22 +172,25 @@ const router = useRouter();
|
|
|
169
172
|
function checkPassword() {
|
|
170
173
|
|
|
171
174
|
if (!password.value || !passwordConfirmation.value) {
|
|
172
|
-
return 'Please enter both password and password confirmation';
|
|
175
|
+
return t('Please enter both password and password confirmation');
|
|
173
176
|
}
|
|
174
177
|
if (password.value !== passwordConfirmation.value) {
|
|
175
|
-
return 'Passwords do not match';
|
|
178
|
+
return t('Passwords do not match');
|
|
176
179
|
}
|
|
177
180
|
|
|
178
|
-
if (
|
|
179
|
-
return
|
|
181
|
+
if (!passwordConstraints.value) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
if (password.value.length < passwordConstraints.value.minLength) {
|
|
185
|
+
return t(`Password must be at least {minLength} characters long`, { minLength: passwordConstraints.value.minLength });
|
|
180
186
|
}
|
|
181
187
|
|
|
182
|
-
if (password.value.length >
|
|
183
|
-
return `Password must be at most
|
|
188
|
+
if (password.value.length > passwordConstraints.value.maxLength) {
|
|
189
|
+
return t(`Password must be at most {maxLength} characters long`, { maxLength: passwordConstraints.value.maxLength });
|
|
184
190
|
}
|
|
185
191
|
|
|
186
|
-
if (
|
|
187
|
-
const valError = applyRegexValidation(password.value,
|
|
192
|
+
if (passwordConstraints.value.validation) {
|
|
193
|
+
const valError = applyRegexValidation(password.value, passwordConstraints.value.validation);
|
|
188
194
|
if (valError) {
|
|
189
195
|
return valError;
|
|
190
196
|
}
|
|
@@ -213,19 +219,31 @@ const backgroundPosition = computed(() => {
|
|
|
213
219
|
return coreStore.config?.loginBackgroundPosition || '1/2';
|
|
214
220
|
});
|
|
215
221
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
222
|
+
|
|
223
|
+
const passwordConstraints: Ref<{
|
|
224
|
+
minLength: number;
|
|
225
|
+
maxLength: number;
|
|
226
|
+
validation: string;
|
|
227
|
+
}> = ref({
|
|
228
|
+
minLength: 8,
|
|
229
|
+
maxLength: 100,
|
|
230
|
+
validation: '',
|
|
231
|
+
});
|
|
219
232
|
|
|
220
233
|
onMounted(async () => {
|
|
221
234
|
await coreStore.getPublicConfig();
|
|
235
|
+
// getPasswordConstraints
|
|
236
|
+
passwordConstraints.value = await callAdminForthApi({
|
|
237
|
+
path: `/plugin/${route.meta.pluginInstanceId}/password-constraints`,
|
|
238
|
+
method: 'GET',
|
|
239
|
+
});
|
|
222
240
|
});
|
|
223
241
|
|
|
224
242
|
async function doSignup() {
|
|
225
243
|
error.value = null;
|
|
226
244
|
const email = emailInput.value!.value;
|
|
227
245
|
if (!email) {
|
|
228
|
-
error.value = 'Please enter your email';
|
|
246
|
+
error.value = t('Please enter your email');
|
|
229
247
|
return;
|
|
230
248
|
}
|
|
231
249
|
if (!requestEmailConfirmation.value && checkPassword()) {
|
|
@@ -274,7 +292,7 @@ const signupAfterEmailConfirmation = async () => {
|
|
|
274
292
|
});
|
|
275
293
|
if (resp.error) {
|
|
276
294
|
window.adminforth.alert({
|
|
277
|
-
message: `Error fetching data:
|
|
295
|
+
message: t(`Error fetching data: {error}`, { error: resp.error }),
|
|
278
296
|
variant: 'danger',
|
|
279
297
|
});
|
|
280
298
|
} else if (resp.redirectTo) {
|
package/dist/index.js
CHANGED
|
@@ -73,11 +73,6 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
73
73
|
meta: {
|
|
74
74
|
customLayout: true,
|
|
75
75
|
pluginInstanceId: this.pluginInstanceId,
|
|
76
|
-
passwordField: {
|
|
77
|
-
minLength: passwordField.minLength,
|
|
78
|
-
maxLength: passwordField.maxLength,
|
|
79
|
-
validation: passwordField.validation
|
|
80
|
-
},
|
|
81
76
|
requestEmailConfirmation: !!this.options.confirmEmails
|
|
82
77
|
}
|
|
83
78
|
}
|
|
@@ -128,25 +123,37 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
128
123
|
});
|
|
129
124
|
}
|
|
130
125
|
setupEndpoints(server) {
|
|
126
|
+
server.endpoint({
|
|
127
|
+
method: 'GET',
|
|
128
|
+
path: `/plugin/${this.pluginInstanceId}/password-constraints`,
|
|
129
|
+
noAuth: true,
|
|
130
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ tr }) {
|
|
131
|
+
return {
|
|
132
|
+
minLength: this.passwordField.minLength,
|
|
133
|
+
maxLength: this.passwordField.maxLength,
|
|
134
|
+
validation: yield Promise.all(this.passwordField.validation.map((_b) => __awaiter(this, [_b], void 0, function* ({ regExp, message }) { return ({ regExp, message: yield tr(message, 'opensignup') }); }))),
|
|
135
|
+
};
|
|
136
|
+
})
|
|
137
|
+
});
|
|
131
138
|
server.endpoint({
|
|
132
139
|
method: 'POST',
|
|
133
140
|
path: `/plugin/${this.pluginInstanceId}/complete-verified-signup`,
|
|
134
141
|
noAuth: true,
|
|
135
|
-
handler: (
|
|
142
|
+
handler: (_c) => __awaiter(this, [_c], void 0, function* ({ body, response, headers, query, cookies, tr }) {
|
|
136
143
|
const { token, password } = body;
|
|
137
144
|
const { email } = yield this.adminforth.auth.verify(token, 'tempVerifyEmailToken', false);
|
|
138
145
|
if (!email) {
|
|
139
146
|
return { error: 'Invalid token', ok: false };
|
|
140
147
|
}
|
|
141
148
|
if (!password) {
|
|
142
|
-
return { error: 'Password is required', ok: false };
|
|
149
|
+
return { error: tr('Password is required', 'opensignup'), ok: false };
|
|
143
150
|
}
|
|
144
151
|
const userRecord = yield this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
|
|
145
152
|
if (!userRecord) {
|
|
146
|
-
return { error: 'User not found', ok: false };
|
|
153
|
+
return { error: tr('User not found'), ok: false };
|
|
147
154
|
}
|
|
148
155
|
if (userRecord[this.options.confirmEmails.emailConfirmedField]) {
|
|
149
|
-
return { error: 'Email already confirmed', ok: false };
|
|
156
|
+
return { error: tr('Email already confirmed'), ok: false };
|
|
150
157
|
}
|
|
151
158
|
yield this.adminforth.resource(this.authResource.resourceId).update(userRecord[this.authResource.columns.find((col) => col.primaryKey).name], {
|
|
152
159
|
[this.options.confirmEmails.emailConfirmedField]: true,
|
|
@@ -159,7 +166,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
159
166
|
method: 'POST',
|
|
160
167
|
path: `/plugin/${this.pluginInstanceId}/signup`,
|
|
161
168
|
noAuth: true,
|
|
162
|
-
handler: (
|
|
169
|
+
handler: (_d) => __awaiter(this, [_d], void 0, function* ({ body, response, headers, query, cookies, tr }) {
|
|
163
170
|
const { email, url, password } = body;
|
|
164
171
|
// validate email
|
|
165
172
|
if (this.emailField.validation) {
|
|
@@ -172,15 +179,21 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
172
179
|
// validate password
|
|
173
180
|
if (!this.options.confirmEmails) {
|
|
174
181
|
if (password.length < this.passwordField.minLength) {
|
|
175
|
-
return {
|
|
182
|
+
return {
|
|
183
|
+
error: tr(`Password must be at least ${this.passwordField.minLength} characters long`, 'opensignup'),
|
|
184
|
+
ok: false
|
|
185
|
+
};
|
|
176
186
|
}
|
|
177
187
|
if (password.length > this.passwordField.maxLength) {
|
|
178
|
-
return {
|
|
188
|
+
return {
|
|
189
|
+
error: tr(`Password must be at most ${this.passwordField.maxLength} characters long`, 'opensignup'),
|
|
190
|
+
ok: false
|
|
191
|
+
};
|
|
179
192
|
}
|
|
180
193
|
if (this.passwordField.validation) {
|
|
181
194
|
for (const { regExp, message } of this.passwordField.validation) {
|
|
182
195
|
if (!new RegExp(regExp).test(password)) {
|
|
183
|
-
return { error: message, ok: false };
|
|
196
|
+
return { error: tr(message, 'opensignup'), ok: false };
|
|
184
197
|
}
|
|
185
198
|
}
|
|
186
199
|
}
|
|
@@ -188,7 +201,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
188
201
|
// first check again if email already exists
|
|
189
202
|
const existingUser = yield this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
|
|
190
203
|
if ((!this.options.confirmEmails && existingUser) || (this.options.confirmEmails && (existingUser === null || existingUser === void 0 ? void 0 : existingUser[this.emailConfirmedField.name]))) {
|
|
191
|
-
return { error: 'Email already exists', ok: false };
|
|
204
|
+
return { error: tr('Email already exists', 'opensignup'), ok: false };
|
|
192
205
|
}
|
|
193
206
|
// create user
|
|
194
207
|
if (!existingUser) {
|
|
@@ -202,39 +215,37 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
202
215
|
const brandName = this.adminforth.config.customization.brandName;
|
|
203
216
|
const verifyToken = this.adminforth.auth.issueJWT({ email, issuer: brandName }, 'tempVerifyEmailToken', '2h');
|
|
204
217
|
process.env.HEAVY_DEBUG && console.log('🐛Sending reset tok to', verifyToken);
|
|
205
|
-
const emailText = `
|
|
218
|
+
const emailText = tr(`
|
|
206
219
|
Dear user,
|
|
207
|
-
Welcome to
|
|
220
|
+
Welcome to {brandName}!
|
|
208
221
|
|
|
209
222
|
To confirm your email, click the link below:\n\n
|
|
210
223
|
|
|
211
|
-
|
|
224
|
+
{url}?verifyToken={verifyToken}\n\n
|
|
212
225
|
|
|
213
226
|
If you didn't request this, please ignore this email.\n\n
|
|
214
227
|
Link is valid for 2 hours.\n\n
|
|
215
228
|
|
|
216
229
|
Thanks,
|
|
217
|
-
The
|
|
230
|
+
The {brandName} Team
|
|
218
231
|
|
|
219
|
-
|
|
220
|
-
const emailHtml = `
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
`;
|
|
237
|
-
const emailSubject = `Signup request at ${brandName}`;
|
|
232
|
+
`, 'opensignup', { brandName, url, verifyToken });
|
|
233
|
+
const emailHtml = tr(`
|
|
234
|
+
<html>
|
|
235
|
+
<head></head>
|
|
236
|
+
<body>
|
|
237
|
+
<p>Dear user,</p>
|
|
238
|
+
<p>Welcome to {brandName}!</p>
|
|
239
|
+
<p>To confirm your email, click the link below:</p>
|
|
240
|
+
<a href="{url}?token={verifyToken}">Confirm email</a>
|
|
241
|
+
<p>If you didn't request this, please ignore this email.</p>
|
|
242
|
+
<p>Link is valid for 2 hours.</p>
|
|
243
|
+
<p>Thanks,</p>
|
|
244
|
+
<p>The {brandName} Team</p>
|
|
245
|
+
</body>
|
|
246
|
+
</html>
|
|
247
|
+
`, 'opensignup', { brandName, url, verifyToken });
|
|
248
|
+
const emailSubject = tr(`Signup request at {brandName}`, 'opensignup', { brandName });
|
|
238
249
|
// send email with AWS SES this.options.providerOptions.AWS_SES
|
|
239
250
|
this.options.confirmEmails.adapter.sendEmail(this.options.confirmEmails.sendFrom, email, emailText, emailHtml, emailSubject);
|
|
240
251
|
return { ok: true };
|
package/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import AdminForth, { AdminForthPlugin, Filters, suggestIfTypo, AdminForthDataTypes } from "adminforth";
|
|
2
2
|
import type { IAdminForth, IHttpServer, AdminForthComponentDeclaration, AdminForthResourceColumn, AdminForthResource, BeforeLoginConfirmationFunction, HttpExtra } from "adminforth";
|
|
3
3
|
import type { PluginOptions } from './types.js';
|
|
4
|
+
import { error } from "console";
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
@@ -81,11 +82,6 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
81
82
|
meta: {
|
|
82
83
|
customLayout: true,
|
|
83
84
|
pluginInstanceId: this.pluginInstanceId,
|
|
84
|
-
passwordField: {
|
|
85
|
-
minLength: passwordField.minLength,
|
|
86
|
-
maxLength: passwordField.maxLength,
|
|
87
|
-
validation: passwordField.validation
|
|
88
|
-
},
|
|
89
85
|
requestEmailConfirmation: !!this.options.confirmEmails
|
|
90
86
|
}
|
|
91
87
|
}
|
|
@@ -146,11 +142,27 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
146
142
|
|
|
147
143
|
|
|
148
144
|
setupEndpoints(server: IHttpServer) {
|
|
145
|
+
|
|
146
|
+
server.endpoint({
|
|
147
|
+
method: 'GET',
|
|
148
|
+
path: `/plugin/${this.pluginInstanceId}/password-constraints`,
|
|
149
|
+
noAuth: true,
|
|
150
|
+
handler: async ({tr}) => {
|
|
151
|
+
return {
|
|
152
|
+
minLength: this.passwordField.minLength,
|
|
153
|
+
maxLength: this.passwordField.maxLength,
|
|
154
|
+
validation: await Promise.all(
|
|
155
|
+
this.passwordField.validation.map(async ({ regExp, message }) => ({ regExp, message: await tr(message, 'opensignup') }))
|
|
156
|
+
),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
149
161
|
server.endpoint({
|
|
150
162
|
method: 'POST',
|
|
151
163
|
path: `/plugin/${this.pluginInstanceId}/complete-verified-signup`,
|
|
152
164
|
noAuth: true,
|
|
153
|
-
handler: async ({ body, response, headers, query, cookies }) => {
|
|
165
|
+
handler: async ({ body, response, headers, query, cookies, tr }) => {
|
|
154
166
|
const { token, password } = body;
|
|
155
167
|
const { email } = await this.adminforth.auth.verify(token, 'tempVerifyEmailToken', false);
|
|
156
168
|
if (!email) {
|
|
@@ -158,15 +170,15 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
158
170
|
}
|
|
159
171
|
|
|
160
172
|
if(!password) {
|
|
161
|
-
return { error: 'Password is required', ok: false };
|
|
173
|
+
return { error: tr('Password is required', 'opensignup'), ok: false };
|
|
162
174
|
}
|
|
163
175
|
const userRecord = await this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
|
|
164
176
|
if (!userRecord) {
|
|
165
|
-
return { error: 'User not found', ok: false };
|
|
177
|
+
return { error: tr('User not found'), ok: false };
|
|
166
178
|
}
|
|
167
179
|
|
|
168
180
|
if (userRecord[this.options.confirmEmails.emailConfirmedField]) {
|
|
169
|
-
return { error: 'Email already confirmed', ok: false };
|
|
181
|
+
return { error: tr('Email already confirmed'), ok: false };
|
|
170
182
|
}
|
|
171
183
|
|
|
172
184
|
await this.adminforth.resource(this.authResource.resourceId).update(userRecord[this.authResource.columns.find((col) => col.primaryKey).name], {
|
|
@@ -181,7 +193,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
181
193
|
method: 'POST',
|
|
182
194
|
path: `/plugin/${this.pluginInstanceId}/signup`,
|
|
183
195
|
noAuth: true,
|
|
184
|
-
handler: async ({ body, response, headers, query, cookies }) => {
|
|
196
|
+
handler: async ({ body, response, headers, query, cookies, tr }) => {
|
|
185
197
|
const { email, url, password } = body;
|
|
186
198
|
|
|
187
199
|
// validate email
|
|
@@ -196,15 +208,21 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
196
208
|
// validate password
|
|
197
209
|
if (!this.options.confirmEmails) {
|
|
198
210
|
if (password.length < this.passwordField.minLength) {
|
|
199
|
-
return {
|
|
211
|
+
return {
|
|
212
|
+
error: tr(`Password must be at least ${this.passwordField.minLength} characters long`, 'opensignup'),
|
|
213
|
+
ok: false
|
|
214
|
+
};
|
|
200
215
|
}
|
|
201
216
|
if (password.length > this.passwordField.maxLength) {
|
|
202
|
-
return {
|
|
217
|
+
return {
|
|
218
|
+
error: tr(`Password must be at most ${this.passwordField.maxLength} characters long`, 'opensignup'),
|
|
219
|
+
ok: false
|
|
220
|
+
};
|
|
203
221
|
}
|
|
204
222
|
if (this.passwordField.validation) {
|
|
205
223
|
for (const { regExp, message } of this.passwordField.validation) {
|
|
206
224
|
if (!new RegExp(regExp).test(password)) {
|
|
207
|
-
return { error: message, ok: false };
|
|
225
|
+
return { error: tr(message, 'opensignup'), ok: false };
|
|
208
226
|
}
|
|
209
227
|
}
|
|
210
228
|
}
|
|
@@ -213,7 +231,7 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
213
231
|
// first check again if email already exists
|
|
214
232
|
const existingUser = await this.adminforth.resource(this.authResource.resourceId).get(Filters.EQ(this.emailField.name, email));
|
|
215
233
|
if ((!this.options.confirmEmails && existingUser) || (this.options.confirmEmails && existingUser?.[this.emailConfirmedField.name])) {
|
|
216
|
-
return { error: 'Email already exists', ok: false };
|
|
234
|
+
return { error: tr('Email already exists', 'opensignup'), ok: false };
|
|
217
235
|
}
|
|
218
236
|
|
|
219
237
|
// create user
|
|
@@ -237,40 +255,40 @@ export default class OpenSignupPlugin extends AdminForthPlugin {
|
|
|
237
255
|
|
|
238
256
|
const verifyToken = this.adminforth.auth.issueJWT({email, issuer: brandName }, 'tempVerifyEmailToken', '2h');
|
|
239
257
|
process.env.HEAVY_DEBUG && console.log('🐛Sending reset tok to', verifyToken);
|
|
240
|
-
const emailText = `
|
|
258
|
+
const emailText = tr(`
|
|
241
259
|
Dear user,
|
|
242
|
-
Welcome to
|
|
260
|
+
Welcome to {brandName}!
|
|
243
261
|
|
|
244
262
|
To confirm your email, click the link below:\n\n
|
|
245
263
|
|
|
246
|
-
|
|
264
|
+
{url}?verifyToken={verifyToken}\n\n
|
|
247
265
|
|
|
248
266
|
If you didn't request this, please ignore this email.\n\n
|
|
249
267
|
Link is valid for 2 hours.\n\n
|
|
250
268
|
|
|
251
269
|
Thanks,
|
|
252
|
-
The
|
|
270
|
+
The {brandName} Team
|
|
253
271
|
|
|
254
|
-
|
|
272
|
+
`, 'opensignup', { brandName, url, verifyToken }
|
|
273
|
+
);
|
|
255
274
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const emailSubject = `Signup request at ${brandName}`;
|
|
275
|
+
const emailHtml = tr(`
|
|
276
|
+
<html>
|
|
277
|
+
<head></head>
|
|
278
|
+
<body>
|
|
279
|
+
<p>Dear user,</p>
|
|
280
|
+
<p>Welcome to {brandName}!</p>
|
|
281
|
+
<p>To confirm your email, click the link below:</p>
|
|
282
|
+
<a href="{url}?token={verifyToken}">Confirm email</a>
|
|
283
|
+
<p>If you didn't request this, please ignore this email.</p>
|
|
284
|
+
<p>Link is valid for 2 hours.</p>
|
|
285
|
+
<p>Thanks,</p>
|
|
286
|
+
<p>The {brandName} Team</p>
|
|
287
|
+
</body>
|
|
288
|
+
</html>
|
|
289
|
+
`, 'opensignup', { brandName, url, verifyToken });
|
|
290
|
+
|
|
291
|
+
const emailSubject = tr(`Signup request at {brandName}`, 'opensignup', { brandName });
|
|
274
292
|
|
|
275
293
|
// send email with AWS SES this.options.providerOptions.AWS_SES
|
|
276
294
|
this.options.confirmEmails.adapter.sendEmail(this.options.confirmEmails.sendFrom, email, emailText, emailHtml, emailSubject);
|