loginByMobile中的部分逻辑
This commit is contained in:
parent
17a2024233
commit
32f3d7d9f8
|
|
@ -1,5 +1,6 @@
|
|||
import { composeFileUrl } from '../../../../src/utils/extraFile';
|
||||
|
||||
const SEND_KEY = 'captcha:sendAt';
|
||||
export default OakPage({
|
||||
path: 'mobile:me',
|
||||
entity: 'mobile',
|
||||
|
|
@ -12,24 +13,52 @@ export default OakPage({
|
|||
mobile: '',
|
||||
password: '',
|
||||
captcha: '',
|
||||
counter: 0,
|
||||
},
|
||||
async formData({ features }) {
|
||||
const lastSendAt = features.localStorage.load(SEND_KEY);
|
||||
const now = Date.now();
|
||||
let counter = 0;
|
||||
if (typeof lastSendAt === 'number') {
|
||||
counter = Math.max(60 - Math.ceil((now - lastSendAt) / 1000), 0);
|
||||
if (counter > 0) {
|
||||
this.counterHandler = setTimeout(() => this.reRender(), 1000);
|
||||
}
|
||||
else if (this.counterHandler) {
|
||||
clearTimeout(this.couuterHandler);
|
||||
this.counterHandler = undefined;
|
||||
}
|
||||
}
|
||||
return {
|
||||
counter,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onInput(e) {
|
||||
onInput(e: any) {
|
||||
const { dataset, value } = this.resolveInput(e);
|
||||
const{ attr } = dataset;
|
||||
this.setState({
|
||||
[attr]: value,
|
||||
});
|
||||
},
|
||||
async sendCaptcha(type: 'web') {
|
||||
async sendCaptcha() {
|
||||
const { mobile } = this.state;
|
||||
const result = await this.features.token.sendCaptcha(mobile, type);
|
||||
const result = await this.features.token.sendCaptcha(mobile);
|
||||
// 显示返回消息
|
||||
this.setState({
|
||||
oakError: {
|
||||
type: 'success',
|
||||
msg: result,
|
||||
}
|
||||
});
|
||||
this.save(SEND_KEY, Date.now());
|
||||
this.reRender();
|
||||
},
|
||||
async loginByMobile() {
|
||||
const { eventLoggedIn } = this.props;
|
||||
const { mobile, password, captcha } = this.state;
|
||||
await this.features.token.loginByMobile(mobile, password, captcha);
|
||||
this.pub(eventLoggedIn);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
@ -7,10 +7,7 @@ import { isMobile, isPassword, isCaptcha } from 'oak-domain/lib/utils/validator'
|
|||
const { TabPane } = Tabs;
|
||||
|
||||
export default function render() {
|
||||
const { mobile, captcha, password } = this.state;
|
||||
const onFinish = (values: any) => {
|
||||
console.log('Received values of form: ', values);
|
||||
};
|
||||
const { mobile, captcha, password, counter} = this.state;
|
||||
const validMobile = isMobile(mobile);
|
||||
const validCaptcha = isCaptcha(captcha);
|
||||
const validPassword = isPassword(password);
|
||||
|
|
@ -28,11 +25,9 @@ export default function render() {
|
|||
name="normal_login"
|
||||
className="login-form"
|
||||
initialValues={{ remember: true }}
|
||||
onFinish={onFinish}
|
||||
>
|
||||
<Form.Item
|
||||
name="mobile"
|
||||
rules={[{ required: true, message: 'Please input your Mobile!' }]}
|
||||
>
|
||||
<Input
|
||||
allowClear
|
||||
|
|
@ -47,7 +42,6 @@ export default function render() {
|
|||
</Form.Item>
|
||||
<Form.Item
|
||||
name="password"
|
||||
rules={[{ required: true, message: 'Please input your Password!' }]}
|
||||
>
|
||||
<Input
|
||||
allowClear
|
||||
|
|
@ -71,6 +65,7 @@ export default function render() {
|
|||
htmlType="submit"
|
||||
className="login-form-button"
|
||||
disabled={!allowSubmit}
|
||||
onClick={() => this.loginByMobile()}
|
||||
>
|
||||
Log in
|
||||
</Button>
|
||||
|
|
@ -82,11 +77,9 @@ export default function render() {
|
|||
name="normal_login"
|
||||
className="login-form"
|
||||
initialValues={{ remember: true }}
|
||||
onFinish={onFinish}
|
||||
>
|
||||
<Form.Item
|
||||
name="mobile"
|
||||
rules={[{ required: true, message: 'Please input your Mobile!' }]}
|
||||
>
|
||||
<Input.Group compact>
|
||||
<Input
|
||||
|
|
@ -102,16 +95,18 @@ export default function render() {
|
|||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
disabled={!validMobile}
|
||||
onClick={() => this.sendCaptcha('web')}
|
||||
style={{
|
||||
width:65,
|
||||
}}
|
||||
disabled={!validMobile || counter > 0}
|
||||
onClick={() => this.sendCaptcha()}
|
||||
>
|
||||
Send
|
||||
{counter > 0 ? counter : 'Send'}
|
||||
</Button>
|
||||
</Input.Group>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="captcha"
|
||||
rules={[{ required: true, message: 'Please input the captcha received!' }]}
|
||||
>
|
||||
<Input
|
||||
allowClear
|
||||
|
|
@ -136,6 +131,7 @@ export default function render() {
|
|||
htmlType="submit"
|
||||
className="login-form-button"
|
||||
disabled={!allowSubmit}
|
||||
onClick={() => this.loginByMobile()}
|
||||
>
|
||||
Log in
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -118,8 +118,13 @@ export default OakPage({
|
|||
break;
|
||||
}
|
||||
case 'web': {
|
||||
const eventLoggedIn = `token:me:login:${Date.now()}`;
|
||||
this.sub(eventLoggedIn, () => {
|
||||
this.navigateBack();
|
||||
})
|
||||
this.navigateTo({
|
||||
url: '/mobile/login'
|
||||
url: '/mobile/login',
|
||||
eventLoggedIn,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export declare abstract class GeneralRuntimeContext<ED extends EntityDict> exten
|
|||
}> | undefined>;
|
||||
getTokenValue(): string | undefined;
|
||||
toString(): Promise<string>;
|
||||
protected static destructString(strCxt: string): {
|
||||
protected static fromString(strCxt: string): {
|
||||
applicationId: any;
|
||||
scene: any;
|
||||
token: any;
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class GeneralRuntimeContext extends UniversalContext_1.UniversalContext {
|
|||
}
|
||||
return JSON.stringify(data);
|
||||
}
|
||||
static destructString(strCxt) {
|
||||
static fromString(strCxt) {
|
||||
const { applicationId, scene, token, } = JSON.parse(strCxt);
|
||||
return {
|
||||
applicationId,
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ import { EntityDict } from "general-app-domain";
|
|||
import { QiniuUploadInfo } from "oak-frontend-base/src/types/Upload";
|
||||
import { GeneralRuntimeContext } from "..";
|
||||
declare type GeneralAspectDict<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>> = {
|
||||
loginByPassword: (params: {
|
||||
password: string;
|
||||
loginByMobile: (params: {
|
||||
captcha?: string;
|
||||
password?: string;
|
||||
mobile: string;
|
||||
env: WebEnv | WechatMpEnv;
|
||||
}, context: Cxt) => Promise<string>;
|
||||
loginMp: (params: {
|
||||
code: string;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { loginByPassword, loginMp, loginWechatMp, syncUserInfoWechatMp, sendCaptcha } from './token';
|
||||
import { loginByMobile, loginMp, loginWechatMp, syncUserInfoWechatMp, sendCaptcha } from './token';
|
||||
import { getUploadInfo } from './extraFile';
|
||||
export declare const aspectDict: {
|
||||
loginByPassword: typeof loginByPassword;
|
||||
loginByMobile: typeof loginByMobile;
|
||||
loginMp: typeof loginMp;
|
||||
loginWechatMp: typeof loginWechatMp;
|
||||
syncUserInfoWechatMp: typeof syncUserInfoWechatMp;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ const extraFile_1 = require("./extraFile");
|
|||
// import commonAspectDict from 'oak-common-aspect';
|
||||
const lodash_1 = require("lodash");
|
||||
exports.aspectDict = (0, lodash_1.assign)({
|
||||
loginByPassword: token_1.loginByPassword,
|
||||
loginByMobile: token_1.loginByMobile,
|
||||
loginMp: token_1.loginMp,
|
||||
loginWechatMp: token_1.loginWechatMp,
|
||||
syncUserInfoWechatMp: token_1.syncUserInfoWechatMp,
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ import { WebEnv, WechatMpEnv } from 'general-app-domain/Token/Schema';
|
|||
export declare function loginMp<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>>(params: {
|
||||
code: string;
|
||||
}, context: Cxt): Promise<string>;
|
||||
export declare function loginByPassword<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>>(params: {
|
||||
password: string;
|
||||
export declare function loginByMobile<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>>(params: {
|
||||
captcha?: string;
|
||||
password?: string;
|
||||
mobile: string;
|
||||
env: WebEnv | WechatMpEnv;
|
||||
}, context: Cxt): Promise<string>;
|
||||
export declare function loginWechatMp<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>>({ code, env }: {
|
||||
code: string;
|
||||
|
|
|
|||
|
|
@ -3,29 +3,188 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.sendCaptcha = exports.syncUserInfoWechatMp = exports.loginWechatMp = exports.loginByPassword = exports.loginMp = void 0;
|
||||
exports.sendCaptcha = exports.syncUserInfoWechatMp = exports.loginWechatMp = exports.loginByMobile = exports.loginMp = void 0;
|
||||
const oak_external_sdk_1 = require("oak-external-sdk");
|
||||
const assert_1 = __importDefault(require("assert"));
|
||||
const lodash_1 = require("lodash");
|
||||
const types_1 = require("oak-domain/lib/types");
|
||||
const extraFile_1 = require("../utils/extraFile");
|
||||
const Exceptions_1 = require("../types/Exceptions");
|
||||
async function loginMp(params, context) {
|
||||
const { rowStore } = context;
|
||||
throw new Error('method not implemented!');
|
||||
}
|
||||
exports.loginMp = loginMp;
|
||||
async function loginByPassword(params, context) {
|
||||
async function setupMobile(mobile, env, context) {
|
||||
const { rowStore } = context;
|
||||
const { result: [mobile] } = await rowStore.select('mobile', {
|
||||
const currentToken = await context.getToken();
|
||||
const applicationId = context.getApplicationId();
|
||||
const { result: result2 } = await rowStore.select('mobile', {
|
||||
data: {
|
||||
id: 1,
|
||||
mobile: 1,
|
||||
userId: 1,
|
||||
ableState: 1,
|
||||
user: {
|
||||
id: 1,
|
||||
userState: 1,
|
||||
wechatUser$user: {
|
||||
$entity: 'wechatUser',
|
||||
data: {
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, context);
|
||||
throw new Error('method not implemented!');
|
||||
filter: {
|
||||
mobile,
|
||||
ableState: 'enabled',
|
||||
}
|
||||
}, context, { notCollect: true });
|
||||
if (result2.length > 0) {
|
||||
// 此手机号已经存在
|
||||
(0, assert_1.default)(result2.length === 1);
|
||||
const [mobileRow] = result2;
|
||||
if (currentToken) {
|
||||
if (currentToken.userId === mobileRow.userId) {
|
||||
return currentToken.id;
|
||||
}
|
||||
else {
|
||||
// 此时可能要合并用户,如果用户有wechatUser信息,则抛出OakDistinguishUserByWechatUser异常,否则抛出
|
||||
const { user } = mobileRow;
|
||||
const { wechatUser$user } = user;
|
||||
if (wechatUser$user.length > 0) {
|
||||
throw new Exceptions_1.OakDistinguishUserByWechatUserException(mobileRow.userId);
|
||||
}
|
||||
else {
|
||||
throw new Exceptions_1.OakDistinguishUserByBusinessException(mobileRow.userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 此时以该手机号登录 todo根据环境来判断,用户也有可能是新获得此手机号,未来再进一步处理
|
||||
const tokenData = {
|
||||
id: await generateNewId(),
|
||||
applicationId,
|
||||
playerId: mobileRow.userId,
|
||||
env,
|
||||
};
|
||||
const { user } = mobileRow;
|
||||
const { userState } = user;
|
||||
switch (userState) {
|
||||
case 'disabled': {
|
||||
throw new Exceptions_1.OakUserDisabledException();
|
||||
}
|
||||
case 'shadow': {
|
||||
(0, lodash_1.assign)(tokenData, {
|
||||
userId: mobileRow.userId,
|
||||
user: {
|
||||
action: 'activate',
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
(0, assert_1.default)(userState === 'normal');
|
||||
(0, lodash_1.assign)(tokenData, {
|
||||
userId: mobileRow.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
await rowStore.operate('token', {
|
||||
data: tokenData,
|
||||
action: 'create',
|
||||
}, context);
|
||||
return tokenData.id;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//此手机号不存在
|
||||
if (currentToken) {
|
||||
// 创建手机号并与之关联即可
|
||||
const mobileData = {
|
||||
id: await generateNewId(),
|
||||
mobile,
|
||||
userId: currentToken.userId,
|
||||
};
|
||||
await rowStore.operate('mobile', {
|
||||
action: 'create',
|
||||
data: mobileData
|
||||
}, context);
|
||||
return currentToken.id;
|
||||
}
|
||||
else {
|
||||
// 创建token, mobile, user
|
||||
const userData = {
|
||||
id: await generateNewId(),
|
||||
userState: 'normal',
|
||||
};
|
||||
await rowStore.operate('user', {
|
||||
action: 'create',
|
||||
data: userData,
|
||||
}, context);
|
||||
const tokenData = {
|
||||
id: await generateNewId(),
|
||||
userId: userData.id,
|
||||
playerId: userData.id,
|
||||
env,
|
||||
mobile: {
|
||||
action: 'create',
|
||||
data: {
|
||||
id: await generateNewId(),
|
||||
mobile,
|
||||
userId: userData.id,
|
||||
}
|
||||
}
|
||||
};
|
||||
await rowStore.operate('token', {
|
||||
action: 'create',
|
||||
data: tokenData,
|
||||
}, context);
|
||||
return tokenData.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.loginByPassword = loginByPassword;
|
||||
async function loginByMobile(params, context) {
|
||||
const { mobile, captcha, password, env } = params;
|
||||
const { rowStore } = context;
|
||||
if (captcha) {
|
||||
const { result } = await rowStore.select('captcha', {
|
||||
data: {
|
||||
id: 1,
|
||||
expired: 1,
|
||||
},
|
||||
filter: {
|
||||
mobile,
|
||||
code: captcha,
|
||||
},
|
||||
sorter: [{
|
||||
$attr: {
|
||||
$$createAt$$: 1,
|
||||
},
|
||||
$direction: 'desc',
|
||||
}],
|
||||
indexFrom: 0,
|
||||
count: 1,
|
||||
}, context, { notCollect: true });
|
||||
if (result.length > 0) {
|
||||
const [captchaRow] = result;
|
||||
if (captchaRow.expired) {
|
||||
throw new types_1.OakUserException('验证码已经过期');
|
||||
}
|
||||
// 到这里说明验证码已经通过
|
||||
return await setupMobile(mobile, env, context);
|
||||
}
|
||||
else {
|
||||
throw new types_1.OakUserException('验证码无效');
|
||||
}
|
||||
}
|
||||
else {
|
||||
(0, assert_1.default)(password);
|
||||
throw new Error('method not implemented!');
|
||||
}
|
||||
}
|
||||
exports.loginByMobile = loginByMobile;
|
||||
async function loginWechatMp({ code, env }, context) {
|
||||
const { rowStore } = context;
|
||||
const application = (await context.getApplication());
|
||||
|
|
@ -246,6 +405,8 @@ async function syncUserInfoWechatMp({ nickname, avatarUrl, encryptedData, iv, si
|
|||
data: {
|
||||
id: 1,
|
||||
sessionKey: 1,
|
||||
nickname: 1,
|
||||
avatar: 1,
|
||||
user: {
|
||||
id: 1,
|
||||
nickname: 1,
|
||||
|
|
@ -322,6 +483,7 @@ async function syncUserInfoWechatMp({ nickname, avatarUrl, encryptedData, iv, si
|
|||
}
|
||||
}, context);
|
||||
}
|
||||
// todo update nickname/avatar in wechatUser
|
||||
}
|
||||
exports.syncUserInfoWechatMp = syncUserInfoWechatMp;
|
||||
async function sendCaptcha({ mobile, env }, context) {
|
||||
|
|
@ -330,26 +492,28 @@ async function sendCaptcha({ mobile, env }, context) {
|
|||
let { visitorId } = env;
|
||||
const { rowStore } = context;
|
||||
const now = Date.now();
|
||||
const [count1, count2] = await Promise.all([
|
||||
rowStore.count('captcha', {
|
||||
filter: {
|
||||
visitorId,
|
||||
$$createAt$$: {
|
||||
$gt: now - 3600 * 1000,
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
const [count1, count2] = await Promise.all([
|
||||
rowStore.count('captcha', {
|
||||
filter: {
|
||||
visitorId,
|
||||
$$createAt$$: {
|
||||
$gt: now - 3600 * 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, context),
|
||||
rowStore.count('captcha', {
|
||||
filter: {
|
||||
mobile,
|
||||
$$createAt$$: {
|
||||
$gt: now - 3600 * 1000,
|
||||
},
|
||||
}
|
||||
}, context)
|
||||
]);
|
||||
if (count1 > 5 || count2 > 5) {
|
||||
throw new types_1.OakUserException('您已发送很多次短信,请休息会再发吧');
|
||||
}, context),
|
||||
rowStore.count('captcha', {
|
||||
filter: {
|
||||
mobile,
|
||||
$$createAt$$: {
|
||||
$gt: now - 3600 * 1000,
|
||||
},
|
||||
}
|
||||
}, context)
|
||||
]);
|
||||
if (count1 > 5 || count2 > 5) {
|
||||
throw new types_1.OakUserException('您已发送很多次短信,请休息会再发吧');
|
||||
}
|
||||
}
|
||||
const { result: [captcha] } = await rowStore.select('captcha', {
|
||||
data: {
|
||||
|
|
@ -360,7 +524,7 @@ async function sendCaptcha({ mobile, env }, context) {
|
|||
filter: {
|
||||
mobile,
|
||||
$$createAt$$: {
|
||||
$gt: now - 600 * 1000,
|
||||
$gt: now - 60 * 1000,
|
||||
},
|
||||
expired: false,
|
||||
}
|
||||
|
|
@ -389,11 +553,12 @@ async function sendCaptcha({ mobile, env }, context) {
|
|||
code += '0';
|
||||
}
|
||||
}
|
||||
const { v1 } = require('uuid');
|
||||
const id = await generateNewId();
|
||||
console.log('captcha created', id);
|
||||
await rowStore.operate('captcha', {
|
||||
action: 'create',
|
||||
data: {
|
||||
id: v1(),
|
||||
id,
|
||||
mobile,
|
||||
code,
|
||||
visitorId,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,25 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const action_1 = require("oak-domain/lib/actions/action");
|
||||
;
|
||||
const AbleActionDef = (0, action_1.makeAbleActionDef)('enabled');
|
||||
const locale = {
|
||||
zh_CN: {
|
||||
attr: {
|
||||
ableState: '是否可用',
|
||||
mobile: '手机号',
|
||||
user: '关联用户',
|
||||
tokens: '相关令牌',
|
||||
},
|
||||
action: {
|
||||
enable: '启用',
|
||||
disable: '禁用',
|
||||
},
|
||||
v: {
|
||||
ableState: {
|
||||
enabled: '可用的',
|
||||
disabled: '禁用的',
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export interface Schema extends EntityShape {
|
|||
name?: String<16>;
|
||||
nickname?: String<64>;
|
||||
password?: Text;
|
||||
passwordOrigin?: Text;
|
||||
birth?: Datetime;
|
||||
gender?: 'male' | 'female';
|
||||
avatar?: Image;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ const locale = {
|
|||
nickname: '昵称',
|
||||
birth: '生日',
|
||||
password: '密码',
|
||||
passwordOrigin: '明文密码',
|
||||
gender: '性别',
|
||||
avatar: '头像',
|
||||
idCardType: '证件类型',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { String, Datetime, Boolean } from 'oak-domain/lib/types/DataType';
|
||||
import { String, Datetime, Image, Boolean } from 'oak-domain/lib/types/DataType';
|
||||
import { Schema as User } from './User';
|
||||
import { Schema as Application } from './Application';
|
||||
import { Schema as Token } from './Token';
|
||||
|
|
@ -15,4 +15,6 @@ export interface Schema extends EntityShape {
|
|||
user?: User;
|
||||
application: Application;
|
||||
tokens: Array<Token>;
|
||||
nickname?: String<128>;
|
||||
avatar?: Image;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ const locale = {
|
|||
user: '用户',
|
||||
tokens: '相关令牌',
|
||||
application: '应用',
|
||||
nickname: '昵称',
|
||||
avatar: '头像',
|
||||
},
|
||||
v: {
|
||||
origin: {
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ export declare class Token<ED extends EntityDict, Cxt extends GeneralRuntimeCont
|
|||
private cache;
|
||||
private context;
|
||||
constructor(aspectWrapper: AspectWrapper<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>, cache: Cache<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>, context: Cxt);
|
||||
loginByPassword(mobile: string, password: string): Promise<void>;
|
||||
loginByMobile(mobile: string, password?: string, captcha?: string): Promise<void>;
|
||||
loginWechatMp(): Promise<void>;
|
||||
syncUserInfoWechatMp(): Promise<void>;
|
||||
logout(): Promise<void>;
|
||||
getToken(): Promise<string | undefined>;
|
||||
getUserId(): Promise<string | undefined>;
|
||||
isRoot(): Promise<boolean>;
|
||||
sendCaptcha(mobile: string, type: 'web'): Promise<string>;
|
||||
sendCaptcha(mobile: string): Promise<string>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@ class Token extends oak_frontend_base_1.Feature {
|
|||
this.cache = cache;
|
||||
this.context = context;
|
||||
}
|
||||
async loginByPassword(mobile, password) {
|
||||
async loginByMobile(mobile, password, captcha) {
|
||||
const env = await (0, env_1.getEnv)();
|
||||
await this.rwLock.acquire('X');
|
||||
try {
|
||||
const { result } = await this.getAspectWrapper().exec('loginByPassword', { password, mobile });
|
||||
const { result } = await this.getAspectWrapper().exec('loginByMobile', { password, mobile, captcha, env });
|
||||
this.token = result;
|
||||
this.rwLock.release();
|
||||
this.context.setToken(result);
|
||||
|
|
@ -125,7 +126,7 @@ class Token extends oak_frontend_base_1.Feature {
|
|||
}));
|
||||
return tokenValue?.player?.userRole$user.length > 0 ? tokenValue?.player?.userRole$user[0]?.roleId === constants_1.ROOT_ROLE_ID : false;
|
||||
}
|
||||
async sendCaptcha(mobile, type) {
|
||||
async sendCaptcha(mobile) {
|
||||
const env = await (0, env_1.getEnv)();
|
||||
const { result } = await this.getAspectWrapper().exec('sendCaptcha', {
|
||||
mobile,
|
||||
|
|
@ -136,7 +137,7 @@ class Token extends oak_frontend_base_1.Feature {
|
|||
}
|
||||
__decorate([
|
||||
oak_frontend_base_1.Action
|
||||
], Token.prototype, "loginByPassword", null);
|
||||
], Token.prototype, "loginByMobile", null);
|
||||
__decorate([
|
||||
oak_frontend_base_1.Action
|
||||
], Token.prototype, "loginWechatMp", null);
|
||||
|
|
@ -146,4 +147,7 @@ __decorate([
|
|||
__decorate([
|
||||
oak_frontend_base_1.Action
|
||||
], Token.prototype, "logout", null);
|
||||
__decorate([
|
||||
oak_frontend_base_1.Action
|
||||
], Token.prototype, "sendCaptcha", null);
|
||||
exports.Token = Token;
|
||||
|
|
|
|||
|
|
@ -5,3 +5,21 @@ export declare class OakUnloggedInException extends OakUserException {
|
|||
export declare class OakNotEnoughMoneyException extends OakUserException {
|
||||
constructor(message?: string);
|
||||
}
|
||||
export declare class OakDistinguishUserByWechatUserException extends OakUserException {
|
||||
userId: string;
|
||||
constructor(userId: string, message?: string);
|
||||
toString(): string;
|
||||
}
|
||||
export declare class OakDistinguishUserByBusinessException extends OakUserException {
|
||||
userId: string;
|
||||
constructor(userId: string, message?: string);
|
||||
toString(): string;
|
||||
}
|
||||
export declare class OakUserDisabledException extends OakUserException {
|
||||
constructor(message?: string);
|
||||
}
|
||||
export declare function makeException(data: {
|
||||
name: string;
|
||||
message?: string;
|
||||
[A: string]: any;
|
||||
}): import("oak-domain/lib/types").OakException | undefined;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.OakNotEnoughMoneyException = exports.OakUnloggedInException = void 0;
|
||||
exports.makeException = exports.OakUserDisabledException = exports.OakDistinguishUserByBusinessException = exports.OakDistinguishUserByWechatUserException = exports.OakNotEnoughMoneyException = exports.OakUnloggedInException = void 0;
|
||||
const types_1 = require("oak-domain/lib/types");
|
||||
class OakUnloggedInException extends types_1.OakUserException {
|
||||
constructor(message) {
|
||||
|
|
@ -16,3 +16,67 @@ class OakNotEnoughMoneyException extends types_1.OakUserException {
|
|||
}
|
||||
exports.OakNotEnoughMoneyException = OakNotEnoughMoneyException;
|
||||
;
|
||||
class OakDistinguishUserByWechatUserException extends types_1.OakUserException {
|
||||
userId;
|
||||
constructor(userId, message) {
|
||||
super(message || '系统中发现可能属于您的另一帐户');
|
||||
this.userId = userId;
|
||||
}
|
||||
toString() {
|
||||
return JSON.stringify({
|
||||
name: this.name,
|
||||
message: this.message,
|
||||
userId: this.userId,
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.OakDistinguishUserByWechatUserException = OakDistinguishUserByWechatUserException;
|
||||
class OakDistinguishUserByBusinessException extends types_1.OakUserException {
|
||||
userId;
|
||||
constructor(userId, message) {
|
||||
super(message || '系统中发现可能属于您的另一帐户');
|
||||
this.userId = userId;
|
||||
}
|
||||
toString() {
|
||||
return JSON.stringify({
|
||||
name: this.name,
|
||||
message: this.message,
|
||||
userId: this.userId,
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.OakDistinguishUserByBusinessException = OakDistinguishUserByBusinessException;
|
||||
class OakUserDisabledException extends types_1.OakUserException {
|
||||
constructor(message) {
|
||||
super(message || '您的帐户已被禁用,请联系系统管理员');
|
||||
}
|
||||
}
|
||||
exports.OakUserDisabledException = OakUserDisabledException;
|
||||
function makeException(data) {
|
||||
const exception = (0, types_1.makeException)(data);
|
||||
if (exception) {
|
||||
return exception;
|
||||
}
|
||||
const { name, message } = data;
|
||||
switch (name) {
|
||||
case OakUnloggedInException.name: {
|
||||
return new OakUnloggedInException(message);
|
||||
}
|
||||
case OakNotEnoughMoneyException.name: {
|
||||
return new OakNotEnoughMoneyException(message);
|
||||
}
|
||||
case OakDistinguishUserByWechatUserException.name: {
|
||||
return new OakDistinguishUserByWechatUserException(data.userId, message);
|
||||
}
|
||||
case OakDistinguishUserByBusinessException.name: {
|
||||
return new OakDistinguishUserByBusinessException(data.userId, message);
|
||||
}
|
||||
case OakUserDisabledException.name: {
|
||||
return new OakUserDisabledException(message);
|
||||
}
|
||||
default: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.makeException = makeException;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@
|
|||
"build": "tsc",
|
||||
"get:area": "ts-node ./scripts/getAmapArea.ts",
|
||||
"clean:dir": "ts-node ./scripts/cleanDtsAndJs",
|
||||
"postinstall": "npm run prebuild"
|
||||
"postinstall": "npm run prebuild",
|
||||
"test": "ts-node ./test/test.ts"
|
||||
},
|
||||
"main": "src/index"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ export abstract class GeneralRuntimeContext<ED extends EntityDict> extends Unive
|
|||
return JSON.stringify(data);
|
||||
}
|
||||
|
||||
protected static destructString(strCxt: string) {
|
||||
protected static fromString(strCxt: string) {
|
||||
const {
|
||||
applicationId,
|
||||
scene,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { QiniuUploadInfo } from "oak-frontend-base/src/types/Upload";
|
|||
import { GeneralRuntimeContext } from "..";
|
||||
|
||||
type GeneralAspectDict<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>> = {
|
||||
loginByPassword: (params: { password: string, mobile: string }, context: Cxt) => Promise<string>,
|
||||
loginByMobile: (params: { captcha?: string, password?: string, mobile: string, env: WebEnv | WechatMpEnv }, context: Cxt) => Promise<string>,
|
||||
loginMp: (params: { code: string }, context: Cxt) => Promise<string>,
|
||||
loginWechatMp: ({ code, env }: {
|
||||
code: string;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { loginByPassword, loginMp, loginWechatMp, syncUserInfoWechatMp, sendCaptcha } from './token';
|
||||
import { loginByMobile, loginMp, loginWechatMp, syncUserInfoWechatMp, sendCaptcha } from './token';
|
||||
import { getUploadInfo } from './extraFile';
|
||||
// import commonAspectDict from 'oak-common-aspect';
|
||||
import { assign } from 'lodash';
|
||||
export const aspectDict = assign({
|
||||
loginByPassword,
|
||||
loginByMobile,
|
||||
loginMp,
|
||||
loginWechatMp,
|
||||
syncUserInfoWechatMp,
|
||||
|
|
|
|||
|
|
@ -10,24 +10,194 @@ import { Operation as ExtraFileOperation } from 'general-app-domain/ExtraFile/Sc
|
|||
import { assign, isEqual, keys } from 'lodash';
|
||||
import { OakUserException, SelectRowShape } from 'oak-domain/lib/types';
|
||||
import { composeFileUrl, decomposeFileUrl } from '../utils/extraFile';
|
||||
import { OakDistinguishUserByBusinessException, OakDistinguishUserByWechatUserException, OakUserDisabledException } from '../types/Exceptions';
|
||||
|
||||
export async function loginMp<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>>(params: { code: string }, context: Cxt): Promise<string> {
|
||||
const { rowStore } = context;
|
||||
throw new Error('method not implemented!');
|
||||
}
|
||||
|
||||
export async function loginByPassword<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>>(params: { password: string, mobile: string }, context: Cxt): Promise<string> {
|
||||
async function setupMobile<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>>(mobile: string, env: WebEnv | WechatMpEnv, context: Cxt) {
|
||||
const { rowStore } = context;
|
||||
const currentToken = await context.getToken();
|
||||
const applicationId = context.getApplicationId();
|
||||
|
||||
const { result: [mobile] } = await rowStore.select('mobile', {
|
||||
const { result: result2 } = await rowStore.select('mobile', {
|
||||
data: {
|
||||
id: 1,
|
||||
mobile: 1,
|
||||
userId: 1,
|
||||
ableState: 1,
|
||||
user: {
|
||||
id: 1,
|
||||
userState: 1,
|
||||
wechatUser$user: {
|
||||
$entity: 'wechatUser',
|
||||
data: {
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, context);
|
||||
filter: {
|
||||
mobile,
|
||||
ableState: 'enabled',
|
||||
}
|
||||
}, context, { notCollect: true });
|
||||
if (result2.length > 0) {
|
||||
// 此手机号已经存在
|
||||
assert(result2.length === 1);
|
||||
const [ mobileRow ] = result2;
|
||||
if (currentToken) {
|
||||
if (currentToken.userId === mobileRow.userId) {
|
||||
return currentToken.id;
|
||||
}
|
||||
else {
|
||||
// 此时可能要合并用户,如果用户有wechatUser信息,则抛出OakDistinguishUserByWechatUser异常,否则抛出
|
||||
const { user } = mobileRow;
|
||||
const { wechatUser$user } = user as {
|
||||
wechatUser$user: any[];
|
||||
};
|
||||
if (wechatUser$user.length > 0) {
|
||||
throw new OakDistinguishUserByWechatUserException(mobileRow.userId as string);
|
||||
}
|
||||
else {
|
||||
throw new OakDistinguishUserByBusinessException(mobileRow.userId as string);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 此时以该手机号登录 todo根据环境来判断,用户也有可能是新获得此手机号,未来再进一步处理
|
||||
const tokenData: EntityDict['token']['CreateSingle']['data'] = {
|
||||
id: await generateNewId(),
|
||||
applicationId,
|
||||
playerId: mobileRow.userId as string,
|
||||
env,
|
||||
};
|
||||
const { user } = mobileRow;
|
||||
const { userState } = user as SelectRowShape<EntityDict['user']['Schema'], {
|
||||
id: 1,
|
||||
userState: 1,
|
||||
}>;
|
||||
switch (userState) {
|
||||
case 'disabled': {
|
||||
throw new OakUserDisabledException();
|
||||
}
|
||||
case 'shadow': {
|
||||
assign(tokenData, {
|
||||
userId: mobileRow.userId,
|
||||
user: {
|
||||
action: 'activate',
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(userState === 'normal');
|
||||
assign(tokenData, {
|
||||
userId: mobileRow.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('method not implemented!');
|
||||
await rowStore.operate('token', {
|
||||
data: tokenData,
|
||||
action: 'create',
|
||||
}, context);
|
||||
|
||||
return tokenData.id;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//此手机号不存在
|
||||
if (currentToken) {
|
||||
// 创建手机号并与之关联即可
|
||||
const mobileData: EntityDict['mobile']['CreateSingle']['data'] = {
|
||||
id: await generateNewId(),
|
||||
mobile,
|
||||
userId: currentToken.userId!,
|
||||
};
|
||||
await rowStore.operate('mobile', {
|
||||
action: 'create',
|
||||
data: mobileData
|
||||
}, context);
|
||||
return currentToken.id;
|
||||
}
|
||||
else {
|
||||
// 创建token, mobile, user
|
||||
const userData: EntityDict['user']['CreateSingle']['data'] = {
|
||||
id: await generateNewId(),
|
||||
userState: 'normal',
|
||||
};
|
||||
await rowStore.operate('user', {
|
||||
action: 'create',
|
||||
data: userData,
|
||||
}, context);
|
||||
const tokenData: EntityDict['token']['CreateSingle']['data'] = {
|
||||
id: await generateNewId(),
|
||||
userId: userData.id,
|
||||
playerId: userData.id,
|
||||
env,
|
||||
mobile: {
|
||||
action: 'create',
|
||||
data: {
|
||||
id: await generateNewId(),
|
||||
mobile,
|
||||
userId: userData.id,
|
||||
}
|
||||
}
|
||||
};
|
||||
await rowStore.operate('token', {
|
||||
action: 'create',
|
||||
data: tokenData,
|
||||
}, context);
|
||||
|
||||
return tokenData.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function loginByMobile<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>>(
|
||||
params: { captcha?: string, password?: string, mobile: string, env: WebEnv | WechatMpEnv },
|
||||
context: Cxt): Promise<string> {
|
||||
const { mobile, captcha, password, env } = params;
|
||||
const { rowStore } = context;
|
||||
if (captcha) {
|
||||
const { result } = await rowStore.select('captcha', {
|
||||
data: {
|
||||
id: 1,
|
||||
expired: 1,
|
||||
},
|
||||
filter: {
|
||||
mobile,
|
||||
code: captcha,
|
||||
},
|
||||
sorter: [{
|
||||
$attr: {
|
||||
$$createAt$$: 1,
|
||||
},
|
||||
$direction: 'desc',
|
||||
}],
|
||||
indexFrom: 0,
|
||||
count: 1,
|
||||
}, context, { notCollect: true });
|
||||
if (result.length > 0) {
|
||||
const [captchaRow] = result;
|
||||
if (captchaRow.expired) {
|
||||
throw new OakUserException('验证码已经过期');
|
||||
}
|
||||
|
||||
// 到这里说明验证码已经通过
|
||||
return await setupMobile<ED, Cxt>(mobile, env, context);
|
||||
}
|
||||
else {
|
||||
throw new OakUserException('验证码无效');
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(password);
|
||||
throw new Error('method not implemented!');
|
||||
}
|
||||
}
|
||||
|
||||
export async function loginWechatMp<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>>({ code, env }: {
|
||||
|
|
@ -180,7 +350,7 @@ export async function loginWechatMp<ED extends EntityDict, Cxt extends GeneralRu
|
|||
},
|
||||
unionId,
|
||||
}
|
||||
}, context);
|
||||
}, context);
|
||||
const wechatUser2 = wechatUser3 as SelectRowShape<EntityDict['wechatUser']['Schema'], {
|
||||
id: 1,
|
||||
userId: 1,
|
||||
|
|
@ -227,7 +397,7 @@ export async function loginWechatMp<ED extends EntityDict, Cxt extends GeneralRu
|
|||
}
|
||||
|
||||
// 到这里都是要同时创建wechatUser和user对象了
|
||||
const userData : CreateUser = {
|
||||
const userData: CreateUser = {
|
||||
id: await generateNewId(),
|
||||
userState: 'normal',
|
||||
};
|
||||
|
|
@ -268,14 +438,16 @@ export async function loginWechatMp<ED extends EntityDict, Cxt extends GeneralRu
|
|||
*/
|
||||
export async function syncUserInfoWechatMp<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>>({
|
||||
nickname, avatarUrl, encryptedData, iv, signature
|
||||
}: {nickname: string, avatarUrl: string, encryptedData: string, iv: string, signature: string}, context: Cxt) {
|
||||
}: { nickname: string, avatarUrl: string, encryptedData: string, iv: string, signature: string }, context: Cxt) {
|
||||
const { rowStore } = context;
|
||||
const { userId } = (await context.getToken())!;
|
||||
const application = (await context.getApplication())!;
|
||||
const { result: [{ sessionKey, user }]} = await rowStore.select('wechatUser', {
|
||||
const { result: [{ sessionKey, user }] } = await rowStore.select('wechatUser', {
|
||||
data: {
|
||||
id: 1,
|
||||
sessionKey: 1,
|
||||
nickname: 1,
|
||||
avatar:1,
|
||||
user: {
|
||||
id: 1,
|
||||
nickname: 1,
|
||||
|
|
@ -358,6 +530,8 @@ export async function syncUserInfoWechatMp<ED extends EntityDict, Cxt extends Ge
|
|||
}
|
||||
}, context);
|
||||
}
|
||||
|
||||
// todo update nickname/avatar in wechatUser
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -372,28 +546,30 @@ export async function sendCaptcha<ED extends EntityDict, Cxt extends GeneralRunt
|
|||
|
||||
const { rowStore } = context;
|
||||
const now = Date.now();
|
||||
const [count1, count2] = await Promise.all(
|
||||
[
|
||||
rowStore.count('captcha', {
|
||||
filter: {
|
||||
visitorId,
|
||||
$$createAt$$: {
|
||||
$gt: now - 3600 * 1000,
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
const [count1, count2] = await Promise.all(
|
||||
[
|
||||
rowStore.count('captcha', {
|
||||
filter: {
|
||||
visitorId,
|
||||
$$createAt$$: {
|
||||
$gt: now - 3600 * 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, context),
|
||||
rowStore.count('captcha', {
|
||||
filter: {
|
||||
mobile,
|
||||
$$createAt$$: {
|
||||
$gt: now - 3600 * 1000,
|
||||
},
|
||||
}
|
||||
}, context)
|
||||
]
|
||||
);
|
||||
if (count1 > 5 || count2 > 5) {
|
||||
throw new OakUserException('您已发送很多次短信,请休息会再发吧');
|
||||
}, context),
|
||||
rowStore.count('captcha', {
|
||||
filter: {
|
||||
mobile,
|
||||
$$createAt$$: {
|
||||
$gt: now - 3600 * 1000,
|
||||
},
|
||||
}
|
||||
}, context)
|
||||
]
|
||||
);
|
||||
if (count1 > 5 || count2 > 5) {
|
||||
throw new OakUserException('您已发送很多次短信,请休息会再发吧');
|
||||
}
|
||||
}
|
||||
const { result: [captcha] } = await rowStore.select('captcha', {
|
||||
data: {
|
||||
|
|
@ -404,7 +580,7 @@ export async function sendCaptcha<ED extends EntityDict, Cxt extends GeneralRunt
|
|||
filter: {
|
||||
mobile,
|
||||
$$createAt$$: {
|
||||
$gt: now - 600 * 1000,
|
||||
$gt: now - 60 * 1000,
|
||||
},
|
||||
expired: false,
|
||||
}
|
||||
|
|
@ -433,12 +609,13 @@ export async function sendCaptcha<ED extends EntityDict, Cxt extends GeneralRunt
|
|||
code += '0';
|
||||
}
|
||||
}
|
||||
|
||||
const { v1 } = require('uuid');
|
||||
|
||||
const id = await generateNewId();
|
||||
console.log('captcha created', id);
|
||||
await rowStore.operate('captcha', {
|
||||
action: 'create',
|
||||
data: {
|
||||
id: v1(),
|
||||
id,
|
||||
mobile,
|
||||
code,
|
||||
visitorId,
|
||||
|
|
@ -447,7 +624,7 @@ export async function sendCaptcha<ED extends EntityDict, Cxt extends GeneralRunt
|
|||
expiresAt: now + 660 * 1000,
|
||||
}
|
||||
}, context);
|
||||
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return `验证码[${code}]已创建`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Schema as User } from './User';
|
|||
import { Schema as Token } from './Token';
|
||||
import { EntityShape } from 'oak-domain/lib/types/Entity';
|
||||
import { LocaleDef } from 'oak-domain/lib/types/Locale';
|
||||
import { AbleAction, AbleState, makeAbleActionDef } from 'oak-domain/lib/actions/action';
|
||||
|
||||
export interface Schema extends EntityShape {
|
||||
mobile: String<16>;
|
||||
|
|
@ -10,12 +11,28 @@ export interface Schema extends EntityShape {
|
|||
tokens: Array<Token>;
|
||||
};
|
||||
|
||||
const locale: LocaleDef<Schema, '', '', {}> = {
|
||||
type Action = AbleAction;
|
||||
const AbleActionDef = makeAbleActionDef('enabled');
|
||||
|
||||
const locale: LocaleDef<Schema, Action, '', {
|
||||
ableState: AbleState;
|
||||
}> = {
|
||||
zh_CN: {
|
||||
attr: {
|
||||
ableState: '是否可用',
|
||||
mobile: '手机号',
|
||||
user: '关联用户',
|
||||
tokens: '相关令牌',
|
||||
},
|
||||
action: {
|
||||
enable: '启用',
|
||||
disable: '禁用',
|
||||
},
|
||||
v: {
|
||||
ableState: {
|
||||
enabled: '可用的',
|
||||
disabled: '禁用的',
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export interface Schema extends EntityShape {
|
|||
name?: String<16>;
|
||||
nickname?: String<64>;
|
||||
password?: Text;
|
||||
passwordOrigin?: Text;
|
||||
birth?: Datetime;
|
||||
gender?: 'male' | 'female';
|
||||
avatar?: Image;
|
||||
|
|
@ -84,6 +85,7 @@ const locale: LocaleDef<Schema, Action, '', {
|
|||
nickname: '昵称',
|
||||
birth: '生日',
|
||||
password: '密码',
|
||||
passwordOrigin: '明文密码',
|
||||
gender: '性别',
|
||||
avatar: '头像',
|
||||
idCardType: '证件类型',
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ export interface Schema extends EntityShape {
|
|||
user?: User;
|
||||
application: Application;
|
||||
tokens: Array<Token>;
|
||||
nickname?: String<128>;
|
||||
avatar?: Image;
|
||||
};
|
||||
|
||||
const locale: LocaleDef<Schema, '', '', {
|
||||
|
|
@ -35,6 +37,8 @@ const locale: LocaleDef<Schema, '', '', {
|
|||
user: '用户',
|
||||
tokens: '相关令牌',
|
||||
application: '应用',
|
||||
nickname: '昵称',
|
||||
avatar: '头像',
|
||||
},
|
||||
v: {
|
||||
origin: {
|
||||
|
|
|
|||
|
|
@ -24,10 +24,11 @@ export class Token<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>,
|
|||
}
|
||||
|
||||
@Action
|
||||
async loginByPassword(mobile: string, password: string) {
|
||||
async loginByMobile(mobile: string, password?: string, captcha?: string) {
|
||||
const env = await getEnv();
|
||||
await this.rwLock.acquire('X');
|
||||
try {
|
||||
const { result } = await this.getAspectWrapper().exec('loginByPassword', { password, mobile });
|
||||
const { result } = await this.getAspectWrapper().exec('loginByMobile', { password, mobile, captcha, env });
|
||||
this.token = result;
|
||||
this.rwLock.release();
|
||||
this.context.setToken(result);
|
||||
|
|
@ -154,7 +155,8 @@ export class Token<ED extends EntityDict, Cxt extends GeneralRuntimeContext<ED>,
|
|||
return (tokenValue?.player?.userRole$user as any).length > 0 ? (tokenValue?.player?.userRole$user as any)[0]?.roleId === ROOT_ROLE_ID : false;
|
||||
}
|
||||
|
||||
async sendCaptcha(mobile: string, type: 'web') {
|
||||
@Action
|
||||
async sendCaptcha(mobile: string) {
|
||||
const env = await getEnv();
|
||||
const { result } = await this.getAspectWrapper().exec('sendCaptcha', {
|
||||
mobile,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { OakUserException } from "oak-domain/lib/types";
|
||||
import { OakUserException, makeException as makeException2 } from "oak-domain/lib/types";
|
||||
|
||||
export class OakUnloggedInException extends OakUserException {
|
||||
constructor(message?: string) {
|
||||
|
|
@ -9,4 +9,75 @@ export class OakNotEnoughMoneyException extends OakUserException {
|
|||
constructor(message?: string) {
|
||||
super(message || '您的余额不足');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export class OakDistinguishUserByWechatUserException extends OakUserException {
|
||||
userId: string;
|
||||
constructor(userId: string, message?: string) {
|
||||
super(message || '系统中发现可能属于您的另一帐户');
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return JSON.stringify({
|
||||
name: this.name,
|
||||
message: this.message,
|
||||
userId: this.userId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class OakDistinguishUserByBusinessException extends OakUserException {
|
||||
userId: string;
|
||||
constructor(userId: string, message?: string) {
|
||||
super(message || '系统中发现可能属于您的另一帐户');
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return JSON.stringify({
|
||||
name: this.name,
|
||||
message: this.message,
|
||||
userId: this.userId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class OakUserDisabledException extends OakUserException {
|
||||
constructor(message?: string) {
|
||||
super(message || '您的帐户已被禁用,请联系系统管理员');
|
||||
}
|
||||
}
|
||||
|
||||
export function makeException(data: {
|
||||
name: string;
|
||||
message?: string;
|
||||
[A: string]: any;
|
||||
}) {
|
||||
const exception = makeException2(data);
|
||||
if (exception) {
|
||||
return exception;
|
||||
}
|
||||
|
||||
const { name, message } = data;
|
||||
switch (name) {
|
||||
case OakUnloggedInException.name: {
|
||||
return new OakUnloggedInException(message);
|
||||
}
|
||||
case OakNotEnoughMoneyException.name: {
|
||||
return new OakNotEnoughMoneyException(message);
|
||||
}
|
||||
case OakDistinguishUserByWechatUserException.name: {
|
||||
return new OakDistinguishUserByWechatUserException(data.userId, message);
|
||||
}
|
||||
case OakDistinguishUserByBusinessException.name: {
|
||||
return new OakDistinguishUserByBusinessException(data.userId, message);
|
||||
}
|
||||
case OakUserDisabledException.name: {
|
||||
return new OakUserDisabledException(message);
|
||||
}
|
||||
default: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
test/test.ts
25
test/test.ts
|
|
@ -1,22 +1,7 @@
|
|||
import { EntityDict } from 'oak-app-domain';
|
||||
import { SelectRowShape } from 'oak-domain/lib/types/Entity';
|
||||
import { v1 } from 'uuid';
|
||||
|
||||
function select<T extends keyof EntityDict, P extends EntityDict[T]['Selection']['data']>(entity: T, proj: P): SelectRowShape<EntityDict[T]['Schema'], P> {
|
||||
throw new Error('method not implemented');
|
||||
}
|
||||
|
||||
const r = select('address', {
|
||||
id: 1,
|
||||
name: 1,
|
||||
detail: 1,
|
||||
area: {
|
||||
id: 1,
|
||||
name: 1,
|
||||
},
|
||||
$expr10: {
|
||||
$abs: 10,
|
||||
},
|
||||
});
|
||||
|
||||
r.area.name
|
||||
let iter = 0;
|
||||
|
||||
while( iter ++ < 20) {
|
||||
console.log(v1());
|
||||
}
|
||||
Loading…
Reference in New Issue