mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-09 23:49:27 +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 './i18n';
|
||||||
export * from './wrap-middleware';
|
export * from './wrap-middleware';
|
||||||
export * from './object-to-cli-args';
|
export * from './object-to-cli-args';
|
||||||
|
export * from './parsedValue';
|
||||||
export { Schema } from '@formily/json-schema';
|
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 { AuthConfig, BaseAuth } from '@nocobase/auth';
|
||||||
import { PasswordField } from '@nocobase/database';
|
import { PasswordField } from '@nocobase/database';
|
||||||
import crypto from 'crypto';
|
|
||||||
import { namespace } from '../preset';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import { namespace } from '../preset';
|
||||||
|
import { getDateVars, parsedValue } from '@nocobase/utils';
|
||||||
|
|
||||||
export class BasicAuth extends BaseAuth {
|
export class BasicAuth extends BaseAuth {
|
||||||
constructor(config: AuthConfig) {
|
constructor(config: AuthConfig) {
|
||||||
@ -33,8 +33,8 @@ export class BasicAuth extends BaseAuth {
|
|||||||
const filter = email
|
const filter = email
|
||||||
? { email }
|
? { email }
|
||||||
: {
|
: {
|
||||||
$or: [{ username: account }, { email: account }],
|
$or: [{ username: account }, { email: account }],
|
||||||
};
|
};
|
||||||
const user = await this.userRepository.findOne({
|
const user = await this.userRepository.findOne({
|
||||||
filter,
|
filter,
|
||||||
});
|
});
|
||||||
@ -139,19 +139,55 @@ export class BasicAuth extends BaseAuth {
|
|||||||
const {
|
const {
|
||||||
values: { email },
|
values: { email },
|
||||||
} = ctx.action.params;
|
} = ctx.action.params;
|
||||||
|
|
||||||
if (!email) {
|
if (!email) {
|
||||||
ctx.throw(400, ctx.t('Please fill in your email address', { ns: namespace }));
|
ctx.throw(400, ctx.t('Please fill in your email address', { ns: namespace }));
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await this.userRepository.findOne({
|
const user = await this.userRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
email,
|
email,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
ctx.throw(401, ctx.t('The email is incorrect, please re-enter', { ns: namespace }));
|
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;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user