mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-09 15:39:24 +08:00
chore: stash
This commit is contained in:
parent
a1748e1da1
commit
69423adafa
42
packages/core/utils/src/__tests__/parsedValue.test.ts
Normal file
42
packages/core/utils/src/__tests__/parsedValue.test.ts
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* This file is part of the NocoBase (R) project.
|
||||
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||
* Authors: NocoBase Team.
|
||||
*
|
||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { parsedValue } from "../parsedValue";
|
||||
|
||||
describe('parsedValue', () => {
|
||||
it('should correctly parse simple templates', () => {
|
||||
const value = '{{name}} is {{age}} years old';
|
||||
const variables = { name: 'Zhang San', age: 18 };
|
||||
expect(parsedValue(value, variables)).toBe('Zhang San is 18 years old');
|
||||
});
|
||||
|
||||
it('should correctly parse that the template has just one variable', () => {
|
||||
const value = '{{name}}';
|
||||
const variables = { name: 'Zhang San' };
|
||||
expect(parsedValue(value, variables)).toBe('Zhang San');
|
||||
});
|
||||
|
||||
it('should handle nested objects', () => {
|
||||
const value = "{{user.name}}'s email is {{user.email}}";
|
||||
const variables = { user: { name: 'Li Si', email: 'lisi@example.com' } };
|
||||
expect(parsedValue(value, variables)).toBe("Li Si's email is lisi@example.com");
|
||||
});
|
||||
|
||||
it('should handle arrays', () => {
|
||||
const value = '{{fruits.0}} and {{fruits.1}}';
|
||||
const variables = { fruits: ['apple', 'banana'] };
|
||||
expect(parsedValue(value, variables)).toBe('apple and banana');
|
||||
});
|
||||
|
||||
it('should handle undefined variables', () => {
|
||||
const value = '{{name}} and {{undefinedVar}}';
|
||||
const variables = { name: 'Wang Wu' };
|
||||
expect(parsedValue(value, variables)).toBe('Wang Wu and ');
|
||||
});
|
||||
});
|
@ -39,4 +39,5 @@ export * from './url';
|
||||
export * from './i18n';
|
||||
export * from './wrap-middleware';
|
||||
export * from './object-to-cli-args';
|
||||
export * from './parsedValue';
|
||||
export { Schema } from '@formily/json-schema';
|
||||
|
22
packages/core/utils/src/parsedValue.ts
Normal file
22
packages/core/utils/src/parsedValue.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { parse } from "./json-templates";
|
||||
|
||||
function appendArrayColumn(scope, key) {
|
||||
const paths = key.split('.');
|
||||
let data = scope;
|
||||
for (let p = 0; p < paths.length && data != null; p++) {
|
||||
const path = paths[p];
|
||||
const isIndex = path.match(/^\d+$/);
|
||||
if (Array.isArray(data) && !isIndex && !data[path]) {
|
||||
data[path] = data.map((item) => item[path]).flat();
|
||||
}
|
||||
data = data?.[path];
|
||||
}
|
||||
}
|
||||
|
||||
export const parsedValue = (value, variables) => {
|
||||
const template = parse(value);
|
||||
template.parameters.forEach(({ key }) => {
|
||||
appendArrayColumn(variables, key);
|
||||
});
|
||||
return template(variables);
|
||||
};
|
@ -9,9 +9,9 @@
|
||||
|
||||
import { AuthConfig, BaseAuth } from '@nocobase/auth';
|
||||
import { PasswordField } from '@nocobase/database';
|
||||
import crypto from 'crypto';
|
||||
import { namespace } from '../preset';
|
||||
import _ from 'lodash';
|
||||
import { namespace } from '../preset';
|
||||
import { getDateVars, parsedValue } from '@nocobase/utils';
|
||||
|
||||
export class BasicAuth extends BaseAuth {
|
||||
constructor(config: AuthConfig) {
|
||||
@ -139,19 +139,55 @@ export class BasicAuth extends BaseAuth {
|
||||
const {
|
||||
values: { email },
|
||||
} = ctx.action.params;
|
||||
|
||||
if (!email) {
|
||||
ctx.throw(400, ctx.t('Please fill in your email address', { ns: namespace }));
|
||||
}
|
||||
|
||||
const user = await this.userRepository.findOne({
|
||||
where: {
|
||||
email,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
ctx.throw(401, ctx.t('The email is incorrect, please re-enter', { ns: namespace }));
|
||||
}
|
||||
user.resetToken = crypto.randomBytes(20).toString('hex');
|
||||
await user.save();
|
||||
|
||||
// 通过用户认证的接口获取邮件渠道、主题、内容等
|
||||
const { emailChannel, subject, contentType, content, expiresIn } = this.getEmailConfig();
|
||||
|
||||
// 生成重置密码的 token
|
||||
const resetToken = await ctx.app.authManager.jwt.sign({
|
||||
resetPasswordUserId: user.id,
|
||||
}, {
|
||||
expiresIn, // 配置的过期时间
|
||||
});
|
||||
|
||||
// 通过通知管理插件发送邮件
|
||||
const notificationManager = ctx.app.getPlugin('notification-manager');
|
||||
if (notificationManager) {
|
||||
const emailer = notificationManager.getChannel(emailChannel);
|
||||
if (emailer) {
|
||||
await emailer.send({
|
||||
to: email,
|
||||
subject,
|
||||
content: parsedValue(content, {
|
||||
$user: user,
|
||||
$resetLink: `${ctx.request.protocol}://${ctx.request.host}/reset-password?token=${resetToken}`,
|
||||
$date: getDateVars(),
|
||||
$env: ctx.app.environment.getVariables(),
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
ctx.throw(400, ctx.t('Email channel not found', { ns: namespace }));
|
||||
}
|
||||
} else {
|
||||
ctx.throw(500, ctx.t('Notification manager plugin not found', { ns: namespace }));
|
||||
}
|
||||
|
||||
ctx.logger.info(`Password reset email sent to ${email}`);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user