bindByMobile,bindByEmail 实现

This commit is contained in:
lxy 2024-09-06 11:17:04 +08:00
parent c7305421d0
commit 3acc02b788
16 changed files with 892 additions and 101 deletions

View File

@ -16,6 +16,16 @@ export type AspectDict<ED extends EntityDict> = {
code: string;
env: WechatMpEnv;
}, context: BackendRuntimeContext<ED>) => Promise<string>;
bindByMobile: (params: {
mobile: string;
captcha: string;
env: WebEnv | WechatMpEnv | NativeEnv;
}, context: BackendRuntimeContext<ED>) => Promise<void>;
bindByEmail: (params: {
email: string;
captcha: string;
env: WebEnv | WechatMpEnv | NativeEnv;
}, context: BackendRuntimeContext<ED>) => Promise<void>;
loginByMobile: (params: {
mobile: string;
captcha: string;

View File

@ -1,4 +1,4 @@
import { loginByAccount, loginByEmail, loginByMobile, loginWechat, loginWechatMp, syncUserInfoWechatMp, sendCaptchaByMobile, sendCaptchaByEmail, switchTo, refreshWechatPublicUserInfo, getWechatMpUserPhoneNumber, logout, loginByWechat, wakeupParasite, refreshToken } from './token';
import { bindByEmail, bindByMobile, loginByAccount, loginByEmail, loginByMobile, loginWechat, loginWechatMp, syncUserInfoWechatMp, sendCaptchaByMobile, sendCaptchaByEmail, switchTo, refreshWechatPublicUserInfo, getWechatMpUserPhoneNumber, logout, loginByWechat, wakeupParasite, refreshToken } from './token';
import { getInfoByUrl } from './extraFile';
import { getApplication, signatureJsSDK, uploadWechatMedia, batchGetArticle, getArticle, batchGetMaterialList, getMaterial, deleteMaterial } from './application';
import { updateConfig, updateApplicationConfig, updateStyle } from './config';
@ -15,6 +15,8 @@ import { getTagUsers, batchtagging, batchuntagging, getUserTags, getUsers, taggi
import { wechatMpJump } from './wechatMpJump';
import { getApplicationPassports, removeApplicationPassportsByPIds } from './applicationPassport';
declare const aspectDict: {
bindByEmail: typeof bindByEmail;
bindByMobile: typeof bindByMobile;
loginByAccount: typeof loginByAccount;
loginByEmail: typeof loginByEmail;
mergeUser: typeof mergeUser;

View File

@ -1,4 +1,4 @@
import { loginByAccount, loginByEmail, loginByMobile, loginWechat, loginWechatMp, syncUserInfoWechatMp, sendCaptchaByMobile, sendCaptchaByEmail, switchTo, refreshWechatPublicUserInfo, getWechatMpUserPhoneNumber, logout, loginByWechat, wakeupParasite, refreshToken, } from './token';
import { bindByEmail, bindByMobile, loginByAccount, loginByEmail, loginByMobile, loginWechat, loginWechatMp, syncUserInfoWechatMp, sendCaptchaByMobile, sendCaptchaByEmail, switchTo, refreshWechatPublicUserInfo, getWechatMpUserPhoneNumber, logout, loginByWechat, wakeupParasite, refreshToken, } from './token';
import { getInfoByUrl } from './extraFile';
import { getApplication, signatureJsSDK, uploadWechatMedia, batchGetArticle, getArticle, batchGetMaterialList, getMaterial, deleteMaterial, } from './application';
import { updateConfig, updateApplicationConfig, updateStyle } from './config';
@ -15,6 +15,8 @@ import { getTagUsers, batchtagging, batchuntagging, getUserTags, getUsers, taggi
import { wechatMpJump, } from './wechatMpJump';
import { getApplicationPassports, removeApplicationPassportsByPIds } from './applicationPassport';
const aspectDict = {
bindByEmail,
bindByMobile,
loginByAccount,
loginByEmail,
mergeUser,

10
es/aspects/token.d.ts vendored
View File

@ -18,6 +18,16 @@ export declare function loginByEmail<ED extends EntityDict>(params: {
disableRegister?: boolean;
env: WebEnv | WechatMpEnv | NativeEnv;
}, context: BRC<ED>): Promise<string>;
export declare function bindByMobile<ED extends EntityDict>(params: {
mobile: string;
captcha: string;
env: WebEnv | WechatMpEnv | NativeEnv;
}, context: BRC<ED>): Promise<void>;
export declare function bindByEmail<ED extends EntityDict>(params: {
email: string;
captcha: string;
env: WebEnv | WechatMpEnv | NativeEnv;
}, context: BRC<ED>): Promise<void>;
export declare function refreshWechatPublicUserInfo<ED extends EntityDict>({}: {}, context: BRC<ED>): Promise<void>;
export declare function loginByWechat<ED extends EntityDict>(params: {
wechatLoginId: string;

View File

@ -686,6 +686,208 @@ export async function loginByEmail(params, context) {
closeRootMode();
return tokenValue;
}
export async function bindByMobile(params, context) {
const { mobile, captcha, env, } = params;
const userId = context.getCurrentUserId();
const bindLogic = async () => {
const systemId = context.getSystemId();
const result = await context.select('captcha', {
data: {
id: 1,
expired: 1,
},
filter: {
origin: 'mobile',
content: mobile,
code: captcha,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
}, { dontCollect: true });
if (result.length > 0) {
const [captchaRow] = result;
if (captchaRow.expired) {
throw new OakUserException('验证码已经过期');
}
// 到这里说明验证码已经通过
//检查当前user是否已绑定mobile
const [boundMobile] = await context.select('mobile', {
data: {
id: 1,
mobile: 1,
},
filter: {
ableState: 'enabled',
userId: userId,
},
}, {
dontCollect: true,
forUpdate: true,
});
if (boundMobile) {
//用户已绑定的mobile与当前输入的mobile一致
if (boundMobile.mobile === mobile) {
throw new OakUserException('已绑定该手机号,无需重复绑定');
}
//更新mobile
await context.operate('mobile', {
id: await generateNewIdAsync(),
action: 'update',
data: {
mobile,
},
filter: {
id: boundMobile.id,
},
}, {});
}
else {
//创建mobile
await context.operate('mobile', {
id: await generateNewIdAsync(),
action: 'create',
data: {
id: await generateNewIdAsync(),
mobile,
userId,
},
}, {});
}
}
else {
throw new OakUserException('验证码无效');
}
};
const closeRootMode = context.openRootMode();
const [otherUserMobile] = await context.select('mobile', {
data: {
id: 1,
mobile: 1,
},
filter: {
mobile: mobile,
ableState: 'enabled',
userId: {
$ne: userId,
}
},
}, { dontCollect: true });
if (otherUserMobile) {
closeRootMode();
throw new OakUserException('该手机号已绑定其他用户,请检查');
}
await bindLogic();
closeRootMode();
}
export async function bindByEmail(params, context) {
const { email, captcha, env, } = params;
const userId = context.getCurrentUserId();
const bindLogic = async () => {
const systemId = context.getSystemId();
const result = await context.select('captcha', {
data: {
id: 1,
expired: 1,
},
filter: {
origin: 'email',
content: email,
code: captcha,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
}, { dontCollect: true });
if (result.length > 0) {
const [captchaRow] = result;
if (captchaRow.expired) {
throw new OakUserException('验证码已经过期');
}
// 到这里说明验证码已经通过
//检查当前user是否已绑定email
const [boundEmail] = await context.select('email', {
data: {
id: 1,
email: 1,
},
filter: {
ableState: 'enabled',
userId: userId,
},
}, {
dontCollect: true,
forUpdate: true,
});
if (boundEmail) {
//用户已绑定的email与当前输入的email一致
if (boundEmail.email === email) {
throw new OakUserException('已绑定该邮箱,无需重复绑定');
}
//更新email
await context.operate('email', {
id: await generateNewIdAsync(),
action: 'update',
data: {
email,
},
filter: {
id: boundEmail.id,
},
}, {});
}
else {
//创建email
await context.operate('email', {
id: await generateNewIdAsync(),
action: 'create',
data: {
id: await generateNewIdAsync(),
email,
userId,
},
}, {});
}
}
else {
throw new OakUserException('验证码无效');
}
};
const closeRootMode = context.openRootMode();
const [otherUserEmail] = await context.select('email', {
data: {
id: 1,
email: 1,
},
filter: {
email: email,
ableState: 'enabled',
userId: {
$ne: userId,
}
},
}, { dontCollect: true });
if (otherUserEmail) {
closeRootMode();
throw new OakUserException('该邮箱已绑定其他用户,请检查');
}
await bindLogic();
closeRootMode();
}
async function setupLoginName(name, env, context) {
const result2 = await context.select('loginName', {
data: {
@ -1339,40 +1541,40 @@ export async function sendCaptchaByMobile({ mobile, env, type: type2, }, context
}
const application = context.getApplication();
const { system } = application;
let mockSend = system?.config?.Sms?.mockSend;
let codeTemplateName = system?.config?.Sms?.defaultCodeTemplateName;
let origin = system?.config?.Sms?.defaultOrigin;
let duration = system?.config?.Sms?.defaultCodeDuration || 1; //多少分钟内有效;
let digit = 4; //验证码位数;
if (type2 === 'login') {
const [applicationPassport] = await context.select('applicationPassport', {
data: {
// let mockSend = system?.config?.Sms?.mockSend;
// let codeTemplateName = system?.config?.Sms?.defaultCodeTemplateName;
// let origin = system?.config?.Sms?.defaultOrigin;
// let duration = system?.config?.Sms?.defaultCodeDuration || 1; //多少分钟内有效;
// let digit = 4 //验证码位数;
// if (type2 === 'login') {
const [applicationPassport] = await context.select('applicationPassport', {
data: {
id: 1,
passportId: 1,
passport: {
id: 1,
passportId: 1,
passport: {
id: 1,
config: 1,
type: 1,
},
applicationId: 1,
config: 1,
type: 1,
},
filter: {
applicationId: application?.id,
passport: {
type: 'sms'
},
}
}, {
dontCollect: true,
});
assert(applicationPassport?.passport);
const config = applicationPassport.passport.config;
mockSend = config.mockSend;
codeTemplateName = config.templateName;
origin = config.defaultOrigin;
duration = config.codeDuration || 1;
digit = config.digit || 4;
}
applicationId: 1,
},
filter: {
applicationId: application?.id,
passport: {
type: 'sms'
},
}
}, {
dontCollect: true,
});
assert(applicationPassport?.passport);
const config = applicationPassport.passport.config;
const mockSend = config.mockSend;
const codeTemplateName = config.templateName;
const origin = config.defaultOrigin;
const duration = config.codeDuration || 1;
const digit = config.digit || 4;
// }
const now = Date.now();
const closeRootMode = context.openRootMode();
if (!mockSend) {

View File

@ -16,6 +16,16 @@ export type AspectDict<ED extends EntityDict> = {
code: string;
env: WechatMpEnv;
}, context: BackendRuntimeContext<ED>) => Promise<string>;
bindByMobile: (params: {
mobile: string;
captcha: string;
env: WebEnv | WechatMpEnv | NativeEnv;
}, context: BackendRuntimeContext<ED>) => Promise<void>;
bindByEmail: (params: {
email: string;
captcha: string;
env: WebEnv | WechatMpEnv | NativeEnv;
}, context: BackendRuntimeContext<ED>) => Promise<void>;
loginByMobile: (params: {
mobile: string;
captcha: string;

View File

@ -1,4 +1,4 @@
import { loginByAccount, loginByEmail, loginByMobile, loginWechat, loginWechatMp, syncUserInfoWechatMp, sendCaptchaByMobile, sendCaptchaByEmail, switchTo, refreshWechatPublicUserInfo, getWechatMpUserPhoneNumber, logout, loginByWechat, wakeupParasite, refreshToken } from './token';
import { bindByEmail, bindByMobile, loginByAccount, loginByEmail, loginByMobile, loginWechat, loginWechatMp, syncUserInfoWechatMp, sendCaptchaByMobile, sendCaptchaByEmail, switchTo, refreshWechatPublicUserInfo, getWechatMpUserPhoneNumber, logout, loginByWechat, wakeupParasite, refreshToken } from './token';
import { getInfoByUrl } from './extraFile';
import { getApplication, signatureJsSDK, uploadWechatMedia, batchGetArticle, getArticle, batchGetMaterialList, getMaterial, deleteMaterial } from './application';
import { updateConfig, updateApplicationConfig, updateStyle } from './config';
@ -15,6 +15,8 @@ import { getTagUsers, batchtagging, batchuntagging, getUserTags, getUsers, taggi
import { wechatMpJump } from './wechatMpJump';
import { getApplicationPassports, removeApplicationPassportsByPIds } from './applicationPassport';
declare const aspectDict: {
bindByEmail: typeof bindByEmail;
bindByMobile: typeof bindByMobile;
loginByAccount: typeof loginByAccount;
loginByEmail: typeof loginByEmail;
mergeUser: typeof mergeUser;

View File

@ -17,6 +17,8 @@ const userWechatPublicTag_1 = require("./userWechatPublicTag");
const wechatMpJump_1 = require("./wechatMpJump");
const applicationPassport_1 = require("./applicationPassport");
const aspectDict = {
bindByEmail: token_1.bindByEmail,
bindByMobile: token_1.bindByMobile,
loginByAccount: token_1.loginByAccount,
loginByEmail: token_1.loginByEmail,
mergeUser: user_1.mergeUser,

View File

@ -18,6 +18,16 @@ export declare function loginByEmail<ED extends EntityDict>(params: {
disableRegister?: boolean;
env: WebEnv | WechatMpEnv | NativeEnv;
}, context: BRC<ED>): Promise<string>;
export declare function bindByMobile<ED extends EntityDict>(params: {
mobile: string;
captcha: string;
env: WebEnv | WechatMpEnv | NativeEnv;
}, context: BRC<ED>): Promise<void>;
export declare function bindByEmail<ED extends EntityDict>(params: {
email: string;
captcha: string;
env: WebEnv | WechatMpEnv | NativeEnv;
}, context: BRC<ED>): Promise<void>;
export declare function refreshWechatPublicUserInfo<ED extends EntityDict>({}: {}, context: BRC<ED>): Promise<void>;
export declare function loginByWechat<ED extends EntityDict>(params: {
wechatLoginId: string;

View File

@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.refreshToken = exports.wakeupParasite = exports.logout = exports.getWechatMpUserPhoneNumber = exports.switchTo = exports.sendCaptchaByEmail = exports.sendCaptchaByMobile = exports.syncUserInfoWechatMp = exports.loginWechatMp = exports.loginWechat = exports.loginByWechat = exports.refreshWechatPublicUserInfo = exports.loginByEmail = exports.loginByAccount = exports.loginByMobile = void 0;
exports.refreshToken = exports.wakeupParasite = exports.logout = exports.getWechatMpUserPhoneNumber = exports.switchTo = exports.sendCaptchaByEmail = exports.sendCaptchaByMobile = exports.syncUserInfoWechatMp = exports.loginWechatMp = exports.loginWechat = exports.loginByWechat = exports.refreshWechatPublicUserInfo = exports.bindByEmail = exports.bindByMobile = exports.loginByEmail = exports.loginByAccount = exports.loginByMobile = void 0;
const tslib_1 = require("tslib");
const uuid_1 = require("oak-domain/lib/utils/uuid");
const WechatSDK_1 = tslib_1.__importDefault(require("oak-external-sdk/lib/WechatSDK"));
@ -693,6 +693,210 @@ async function loginByEmail(params, context) {
return tokenValue;
}
exports.loginByEmail = loginByEmail;
async function bindByMobile(params, context) {
const { mobile, captcha, env, } = params;
const userId = context.getCurrentUserId();
const bindLogic = async () => {
const systemId = context.getSystemId();
const result = await context.select('captcha', {
data: {
id: 1,
expired: 1,
},
filter: {
origin: 'mobile',
content: mobile,
code: captcha,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
}, { dontCollect: true });
if (result.length > 0) {
const [captchaRow] = result;
if (captchaRow.expired) {
throw new types_1.OakUserException('验证码已经过期');
}
// 到这里说明验证码已经通过
//检查当前user是否已绑定mobile
const [boundMobile] = await context.select('mobile', {
data: {
id: 1,
mobile: 1,
},
filter: {
ableState: 'enabled',
userId: userId,
},
}, {
dontCollect: true,
forUpdate: true,
});
if (boundMobile) {
//用户已绑定的mobile与当前输入的mobile一致
if (boundMobile.mobile === mobile) {
throw new types_1.OakUserException('已绑定该手机号,无需重复绑定');
}
//更新mobile
await context.operate('mobile', {
id: await (0, uuid_1.generateNewIdAsync)(),
action: 'update',
data: {
mobile,
},
filter: {
id: boundMobile.id,
},
}, {});
}
else {
//创建mobile
await context.operate('mobile', {
id: await (0, uuid_1.generateNewIdAsync)(),
action: 'create',
data: {
id: await (0, uuid_1.generateNewIdAsync)(),
mobile,
userId,
},
}, {});
}
}
else {
throw new types_1.OakUserException('验证码无效');
}
};
const closeRootMode = context.openRootMode();
const [otherUserMobile] = await context.select('mobile', {
data: {
id: 1,
mobile: 1,
},
filter: {
mobile: mobile,
ableState: 'enabled',
userId: {
$ne: userId,
}
},
}, { dontCollect: true });
if (otherUserMobile) {
closeRootMode();
throw new types_1.OakUserException('该手机号已绑定其他用户,请检查');
}
await bindLogic();
closeRootMode();
}
exports.bindByMobile = bindByMobile;
async function bindByEmail(params, context) {
const { email, captcha, env, } = params;
const userId = context.getCurrentUserId();
const bindLogic = async () => {
const systemId = context.getSystemId();
const result = await context.select('captcha', {
data: {
id: 1,
expired: 1,
},
filter: {
origin: 'email',
content: email,
code: captcha,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
}, { dontCollect: true });
if (result.length > 0) {
const [captchaRow] = result;
if (captchaRow.expired) {
throw new types_1.OakUserException('验证码已经过期');
}
// 到这里说明验证码已经通过
//检查当前user是否已绑定email
const [boundEmail] = await context.select('email', {
data: {
id: 1,
email: 1,
},
filter: {
ableState: 'enabled',
userId: userId,
},
}, {
dontCollect: true,
forUpdate: true,
});
if (boundEmail) {
//用户已绑定的email与当前输入的email一致
if (boundEmail.email === email) {
throw new types_1.OakUserException('已绑定该邮箱,无需重复绑定');
}
//更新email
await context.operate('email', {
id: await (0, uuid_1.generateNewIdAsync)(),
action: 'update',
data: {
email,
},
filter: {
id: boundEmail.id,
},
}, {});
}
else {
//创建email
await context.operate('email', {
id: await (0, uuid_1.generateNewIdAsync)(),
action: 'create',
data: {
id: await (0, uuid_1.generateNewIdAsync)(),
email,
userId,
},
}, {});
}
}
else {
throw new types_1.OakUserException('验证码无效');
}
};
const closeRootMode = context.openRootMode();
const [otherUserEmail] = await context.select('email', {
data: {
id: 1,
email: 1,
},
filter: {
email: email,
ableState: 'enabled',
userId: {
$ne: userId,
}
},
}, { dontCollect: true });
if (otherUserEmail) {
closeRootMode();
throw new types_1.OakUserException('该邮箱已绑定其他用户,请检查');
}
await bindLogic();
closeRootMode();
}
exports.bindByEmail = bindByEmail;
async function setupLoginName(name, env, context) {
const result2 = await context.select('loginName', {
data: {
@ -1351,40 +1555,40 @@ async function sendCaptchaByMobile({ mobile, env, type: type2, }, context) {
}
const application = context.getApplication();
const { system } = application;
let mockSend = system?.config?.Sms?.mockSend;
let codeTemplateName = system?.config?.Sms?.defaultCodeTemplateName;
let origin = system?.config?.Sms?.defaultOrigin;
let duration = system?.config?.Sms?.defaultCodeDuration || 1; //多少分钟内有效;
let digit = 4; //验证码位数;
if (type2 === 'login') {
const [applicationPassport] = await context.select('applicationPassport', {
data: {
// let mockSend = system?.config?.Sms?.mockSend;
// let codeTemplateName = system?.config?.Sms?.defaultCodeTemplateName;
// let origin = system?.config?.Sms?.defaultOrigin;
// let duration = system?.config?.Sms?.defaultCodeDuration || 1; //多少分钟内有效;
// let digit = 4 //验证码位数;
// if (type2 === 'login') {
const [applicationPassport] = await context.select('applicationPassport', {
data: {
id: 1,
passportId: 1,
passport: {
id: 1,
passportId: 1,
passport: {
id: 1,
config: 1,
type: 1,
},
applicationId: 1,
config: 1,
type: 1,
},
filter: {
applicationId: application?.id,
passport: {
type: 'sms'
},
}
}, {
dontCollect: true,
});
(0, assert_1.assert)(applicationPassport?.passport);
const config = applicationPassport.passport.config;
mockSend = config.mockSend;
codeTemplateName = config.templateName;
origin = config.defaultOrigin;
duration = config.codeDuration || 1;
digit = config.digit || 4;
}
applicationId: 1,
},
filter: {
applicationId: application?.id,
passport: {
type: 'sms'
},
}
}, {
dontCollect: true,
});
(0, assert_1.assert)(applicationPassport?.passport);
const config = applicationPassport.passport.config;
const mockSend = config.mockSend;
const codeTemplateName = config.templateName;
const origin = config.defaultOrigin;
const duration = config.codeDuration || 1;
const digit = config.digit || 4;
// }
const now = Date.now();
const closeRootMode = context.openRootMode();
if (!mockSend) {

View File

@ -14,6 +14,8 @@ export declare class Token<ED extends EntityDict> extends Feature {
loginByMobile(mobile: string, captcha?: string, disableRegister?: boolean): Promise<void>;
loginByEmail(email: string, captcha: string, disableRegister?: boolean): Promise<void>;
loginByAccount(account: string, password: string): Promise<void>;
bindByMobile(mobile: string, captcha?: string): Promise<void>;
bindByEmail(email: string, captcha?: string): Promise<void>;
loginByWechatInWebEnv(wechatLoginId: string): Promise<void>;
loginWechat(code: string, params?: {
wechatLoginId?: string;

View File

@ -105,6 +105,24 @@ class Token extends Feature_1.Feature {
await this.storage.save(constants_1.LOCAL_STORAGE_KEYS.token, result);
this.publish();
}
async bindByMobile(mobile, captcha) {
const env = await this.environment.getEnv();
await this.cache.exec('bindByMobile', {
mobile,
captcha,
env,
}, undefined, true);
this.publish();
}
async bindByEmail(email, captcha) {
const env = await this.environment.getEnv();
await this.cache.exec('bindByEmail', {
email,
captcha,
env,
}, undefined, true);
this.publish();
}
async loginByWechatInWebEnv(wechatLoginId) {
const env = await this.environment.getEnv();
const { result } = await this.cache.exec('loginByWechat', {

View File

@ -20,6 +20,22 @@ export type AspectDict<ED extends EntityDict> = {
params: { code: string; env: WechatMpEnv },
context: BackendRuntimeContext<ED>
) => Promise<string>;
bindByMobile: (
params: {
mobile: string;
captcha: string;
env: WebEnv | WechatMpEnv | NativeEnv;
},
context: BackendRuntimeContext<ED>
) => Promise<void>;
bindByEmail: (
params: {
email: string;
captcha: string;
env: WebEnv | WechatMpEnv | NativeEnv;
},
context: BackendRuntimeContext<ED>
) => Promise<void>;
loginByMobile: (
params: {
mobile: string;

View File

@ -1,4 +1,6 @@
import {
bindByEmail,
bindByMobile,
loginByAccount,
loginByEmail,
loginByMobile,
@ -66,6 +68,8 @@ import {
import { getApplicationPassports, removeApplicationPassportsByPIds } from './applicationPassport';
const aspectDict = {
bindByEmail,
bindByMobile,
loginByAccount,
loginByEmail,
mergeUser,

View File

@ -913,6 +913,268 @@ export async function loginByEmail<ED extends EntityDict>(
return tokenValue;
}
export async function bindByMobile<ED extends EntityDict>(
params: {
mobile: string;
captcha: string;
env: WebEnv | WechatMpEnv | NativeEnv;
},
context: BRC<ED>
) {
const { mobile, captcha, env, } = params;
const userId = context.getCurrentUserId();
const bindLogic = async () => {
const systemId = context.getSystemId();
const result = await context.select(
'captcha',
{
data: {
id: 1,
expired: 1,
},
filter: {
origin: 'mobile',
content: mobile,
code: captcha,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
},
{ dontCollect: true }
);
if (result.length > 0) {
const [captchaRow] = result;
if (captchaRow.expired) {
throw new OakUserException('验证码已经过期');
}
// 到这里说明验证码已经通过
//检查当前user是否已绑定mobile
const [boundMobile] = await context.select(
'mobile',
{
data: {
id: 1,
mobile: 1,
},
filter: {
ableState: 'enabled',
userId: userId,
},
},
{
dontCollect: true,
forUpdate: true,
}
)
if (boundMobile) {
//用户已绑定的mobile与当前输入的mobile一致
if (boundMobile.mobile === mobile) {
throw new OakUserException('已绑定该手机号,无需重复绑定');
}
//更新mobile
await context.operate(
'mobile',
{
id: await generateNewIdAsync(),
action: 'update',
data: {
mobile,
},
filter: {
id: boundMobile.id!,
},
},
{}
);
} else {
//创建mobile
await context.operate(
'mobile',
{
id: await generateNewIdAsync(),
action: 'create',
data: {
id: await generateNewIdAsync(),
mobile,
userId,
},
},
{}
);
}
} else {
throw new OakUserException('验证码无效');
}
};
const closeRootMode = context.openRootMode();
const [otherUserMobile] = await context.select(
'mobile',
{
data: {
id: 1,
mobile: 1,
},
filter: {
mobile: mobile!,
ableState: 'enabled',
userId: {
$ne: userId,
}
},
},
{ dontCollect: true }
);
if (otherUserMobile) {
closeRootMode();
throw new OakUserException('该手机号已绑定其他用户,请检查');
}
await bindLogic();
closeRootMode();
}
export async function bindByEmail<ED extends EntityDict>(
params: {
email: string;
captcha: string;
env: WebEnv | WechatMpEnv | NativeEnv;
},
context: BRC<ED>
) {
const { email, captcha, env, } = params;
const userId = context.getCurrentUserId();
const bindLogic = async () => {
const systemId = context.getSystemId();
const result = await context.select(
'captcha',
{
data: {
id: 1,
expired: 1,
},
filter: {
origin: 'email',
content: email,
code: captcha,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
},
{ dontCollect: true }
);
if (result.length > 0) {
const [captchaRow] = result;
if (captchaRow.expired) {
throw new OakUserException('验证码已经过期');
}
// 到这里说明验证码已经通过
//检查当前user是否已绑定email
const [boundEmail] = await context.select(
'email',
{
data: {
id: 1,
email: 1,
},
filter: {
ableState: 'enabled',
userId: userId,
},
},
{
dontCollect: true,
forUpdate: true,
}
)
if (boundEmail) {
//用户已绑定的email与当前输入的email一致
if (boundEmail.email === email) {
throw new OakUserException('已绑定该邮箱,无需重复绑定');
}
//更新email
await context.operate(
'email',
{
id: await generateNewIdAsync(),
action: 'update',
data: {
email,
},
filter: {
id: boundEmail.id!,
},
},
{}
);
} else {
//创建email
await context.operate(
'email',
{
id: await generateNewIdAsync(),
action: 'create',
data: {
id: await generateNewIdAsync(),
email,
userId,
},
},
{}
);
}
} else {
throw new OakUserException('验证码无效');
}
};
const closeRootMode = context.openRootMode();
const [otherUserEmail] = await context.select(
'email',
{
data: {
id: 1,
email: 1,
},
filter: {
email: email!,
ableState: 'enabled',
userId: {
$ne: userId,
}
},
},
{ dontCollect: true }
);
if (otherUserEmail) {
closeRootMode();
throw new OakUserException('该邮箱已绑定其他用户,请检查');
}
await bindLogic();
closeRootMode();
}
async function setupLoginName<ED extends EntityDict>(name: string, env: WebEnv | WechatMpEnv | NativeEnv, context: BRC<ED>) {
const result2 = await context.select(
'loginName',
@ -1869,43 +2131,43 @@ export async function sendCaptchaByMobile<ED extends EntityDict>(
}
const application = context.getApplication();
const { system } = application!;
let mockSend = system?.config?.Sms?.mockSend;
let codeTemplateName = system?.config?.Sms?.defaultCodeTemplateName;
let origin = system?.config?.Sms?.defaultOrigin;
let duration = system?.config?.Sms?.defaultCodeDuration || 1; //多少分钟内有效;
let digit = 4 //验证码位数;
if (type2 === 'login') {
const [applicationPassport] = await context.select('applicationPassport',
{
data: {
// let mockSend = system?.config?.Sms?.mockSend;
// let codeTemplateName = system?.config?.Sms?.defaultCodeTemplateName;
// let origin = system?.config?.Sms?.defaultOrigin;
// let duration = system?.config?.Sms?.defaultCodeDuration || 1; //多少分钟内有效;
// let digit = 4 //验证码位数;
// if (type2 === 'login') {
const [applicationPassport] = await context.select('applicationPassport',
{
data: {
id: 1,
passportId: 1,
passport: {
id: 1,
passportId: 1,
passport: {
id: 1,
config: 1,
type: 1,
},
applicationId: 1,
config: 1,
type: 1,
},
filter: {
applicationId: application?.id!,
passport: {
type: 'sms'
},
}
applicationId: 1,
},
{
dontCollect: true,
filter: {
applicationId: application?.id!,
passport: {
type: 'sms'
},
}
);
assert(applicationPassport?.passport);
const config = applicationPassport.passport.config as SmsConfig;
mockSend = config.mockSend;
codeTemplateName = config.templateName;
origin = config.defaultOrigin;
duration = config.codeDuration || 1;
digit = config.digit || 4;
}
},
{
dontCollect: true,
}
);
assert(applicationPassport?.passport);
const config = applicationPassport.passport.config as SmsConfig;
const mockSend = config.mockSend;
const codeTemplateName = config.templateName;
const origin = config.defaultOrigin;
const duration = config.codeDuration || 1;
const digit = config.digit || 4;
// }
const now = Date.now();
const closeRootMode = context.openRootMode();
if (!mockSend) {

View File

@ -160,6 +160,41 @@ export class Token<ED extends EntityDict> extends Feature {
this.publish();
}
async bindByMobile(
mobile: string,
captcha?: string,
) {
const env = await this.environment.getEnv();
await this.cache.exec(
'bindByMobile',
{
mobile,
captcha,
env,
},
undefined,
true
);
this.publish();
}
async bindByEmail(
email: string,
captcha?: string,
) {
const env = await this.environment.getEnv();
await this.cache.exec(
'bindByEmail',
{
email,
captcha,
env,
},
undefined,
true
);
this.publish();
}
async loginByWechatInWebEnv(wechatLoginId: string) {
const env = await this.environment.getEnv();