feat: refactor reset password api and forgetPage.js (#1601)

This commit is contained in:
Yaodong Yu
2023-03-01 15:57:42 +08:00
committed by GitHub
parent b38f2218a3
commit e21087aa50
9 changed files with 539 additions and 340 deletions

View File

@ -80,7 +80,7 @@ m = (r.subOwner == p.subOwner || p.subOwner == "*") && \
p, built-in, *, *, *, *, * p, built-in, *, *, *, *, *
p, app, *, *, *, *, * p, app, *, *, *, *, *
p, *, *, POST, /api/signup, *, * p, *, *, POST, /api/signup, *, *
p, *, *, POST, /api/get-email-and-phone, *, * p, *, *, GET, /api/get-email-and-phone, *, *
p, *, *, POST, /api/login, *, * p, *, *, POST, /api/login, *, *
p, *, *, GET, /api/get-app-login, *, * p, *, *, GET, /api/get-app-login, *, *
p, *, *, POST, /api/logout, *, * p, *, *, POST, /api/logout, *, *

View File

@ -231,24 +231,20 @@ func (c *ApiController) DeleteUser() {
// @Param username formData string true "The username of the user" // @Param username formData string true "The username of the user"
// @Param organization formData string true "The organization of the user" // @Param organization formData string true "The organization of the user"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /get-email-and-phone [post] // @router /get-email-and-phone [get]
func (c *ApiController) GetEmailAndPhone() { func (c *ApiController) GetEmailAndPhone() {
var form RequestForm organization := c.Ctx.Request.Form.Get("organization")
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form) username := c.Ctx.Request.Form.Get("username")
if err != nil {
c.ResponseError(err.Error())
return
}
user := object.GetUserByFields(form.Organization, form.Username) user := object.GetUserByFields(organization, username)
if user == nil { if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(form.Organization, form.Username))) c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(organization, username)))
return return
} }
respUser := object.User{Name: user.Name} respUser := object.User{Name: user.Name}
var contentType string var contentType string
switch form.Username { switch username {
case user.Email: case user.Email:
contentType = "email" contentType = "email"
respUser.Email = user.Email respUser.Email = user.Email
@ -281,7 +277,7 @@ func (c *ApiController) SetPassword() {
newPassword := c.Ctx.Request.Form.Get("newPassword") newPassword := c.Ctx.Request.Form.Get("newPassword")
requestUserId := c.GetSessionUsername() requestUserId := c.GetSessionUsername()
userId := fmt.Sprintf("%s/%s", userOwner, userName) userId := util.GetId(userOwner, userName)
hasPermission, err := object.CheckUserPermission(requestUserId, userId, userOwner, true, c.GetAcceptLanguage()) hasPermission, err := object.CheckUserPermission(requestUserId, userId, userOwner, true, c.GetAcceptLanguage())
if !hasPermission { if !hasPermission {
@ -311,8 +307,7 @@ func (c *ApiController) SetPassword() {
targetUser.Password = newPassword targetUser.Password = newPassword
object.SetUserField(targetUser, "password", targetUser.Password) object.SetUserField(targetUser, "password", targetUser.Password)
c.Data["json"] = Response{Status: "ok"} c.ResponseOk()
c.ServeJSON()
} }
// CheckUserPassword // CheckUserPassword

View File

@ -53,9 +53,11 @@ func GetUserByFields(organization string, field string) *User {
} }
// check email // check email
user = GetUserByField(organization, "email", field) if strings.Contains(field, "@") {
if user != nil { user = GetUserByField(organization, "email", field)
return user if user != nil {
return user
}
} }
// check phone // check phone

View File

@ -112,7 +112,7 @@ func initAPI() {
beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword") beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword")
beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword") beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword")
beego.Router("/api/get-email-and-phone", &controllers.ApiController{}, "POST:GetEmailAndPhone") beego.Router("/api/get-email-and-phone", &controllers.ApiController{}, "GET:GetEmailAndPhone")
beego.Router("/api/send-verification-code", &controllers.ApiController{}, "POST:SendVerificationCode") beego.Router("/api/send-verification-code", &controllers.ApiController{}, "POST:SendVerificationCode")
beego.Router("/api/verify-captcha", &controllers.ApiController{}, "POST:VerifyCaptcha") beego.Router("/api/verify-captcha", &controllers.ApiController{}, "POST:VerifyCaptcha")
beego.Router("/api/reset-email-or-phone", &controllers.ApiController{}, "POST:ResetEmailOrPhone") beego.Router("/api/reset-email-or-phone", &controllers.ApiController{}, "POST:ResetEmailOrPhone")

View File

@ -339,6 +339,42 @@
} }
} }
}, },
"/api/add-session": {
"post": {
"tags": [
"Session API"
],
"description": "Add session for one user in one application. If there are other existing sessions, join the session into the list.",
"operationId": "ApiController.AddSession",
"parameters": [
{
"in": "query",
"name": "id",
"description": "The id(organization/application/user) of session",
"required": true,
"type": "string"
},
{
"in": "query",
"name": "sessionId",
"description": "sessionId to be added",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/api/add-syncer": { "/api/add-syncer": {
"post": { "post": {
"tags": [ "tags": [
@ -889,13 +925,13 @@
"tags": [ "tags": [
"Session API" "Session API"
], ],
"description": "Delete session by userId", "description": "Delete session for one user in one application.",
"operationId": "ApiController.DeleteSession", "operationId": "ApiController.DeleteSession",
"parameters": [ "parameters": [
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id ( owner/name )(owner/name) of user.", "description": "The id(organization/application/user) of session",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@ -1233,7 +1269,7 @@
} }
}, },
"/api/get-email-and-phone": { "/api/get-email-and-phone": {
"post": { "get": {
"tags": [ "tags": [
"User API" "User API"
], ],
@ -1306,7 +1342,7 @@
} }
}, },
"/api/get-ldap": { "/api/get-ldap": {
"post": { "get": {
"tags": [ "tags": [
"Account API" "Account API"
], ],
@ -1322,7 +1358,7 @@
} }
}, },
"/api/get-ldaps": { "/api/get-ldaps": {
"post": { "get": {
"tags": [ "tags": [
"Account API" "Account API"
], ],
@ -1884,12 +1920,41 @@
} }
} }
}, },
"/api/get-session": {
"get": {
"tags": [
"Session API"
],
"description": "Get session for one user in one application.",
"operationId": "ApiController.GetSingleSession",
"parameters": [
{
"in": "query",
"name": "id",
"description": "The id(organization/application/user) of session",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/api/get-sessions": { "/api/get-sessions": {
"get": { "get": {
"tags": [ "tags": [
"Session API" "Session API"
], ],
"description": "Get organization user sessions", "description": "Get organization user sessions.",
"operationId": "ApiController.GetSessions", "operationId": "ApiController.GetSessions",
"parameters": [ "parameters": [
{ {
@ -2356,6 +2421,42 @@
} }
} }
}, },
"/api/is-session-duplicated": {
"get": {
"tags": [
"Session API"
],
"description": "Check if there are other different sessions for one user in one application.",
"operationId": "ApiController.IsSessionDuplicated",
"parameters": [
{
"in": "query",
"name": "id",
"description": "The id(organization/application/user) of session",
"required": true,
"type": "string"
},
{
"in": "query",
"name": "sessionId",
"description": "sessionId to be checked",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/api/login": { "/api/login": {
"post": { "post": {
"tags": [ "tags": [
@ -3224,6 +3325,35 @@
} }
} }
}, },
"/api/update-session": {
"post": {
"tags": [
"Session API"
],
"description": "Update session for one user in one application.",
"operationId": "ApiController.UpdateSession",
"parameters": [
{
"in": "query",
"name": "id",
"description": "The id(organization/application/user) of session",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/api/update-syncer": { "/api/update-syncer": {
"post": { "post": {
"tags": [ "tags": [
@ -3505,11 +3635,11 @@
} }
}, },
"definitions": { "definitions": {
"2346.0xc0001ce990.false": { "2346.0xc000278ab0.false": {
"title": "false", "title": "false",
"type": "object" "type": "object"
}, },
"2381.0xc0001ce9c0.false": { "2381.0xc000278ae0.false": {
"title": "false", "title": "false",
"type": "object" "type": "object"
}, },
@ -3566,6 +3696,9 @@
"code": { "code": {
"type": "string" "type": "string"
}, },
"countryCode": {
"type": "string"
},
"email": { "email": {
"type": "string" "type": "string"
}, },
@ -3599,9 +3732,6 @@
"phoneCode": { "phoneCode": {
"type": "string" "type": "string"
}, },
"phonePrefix": {
"type": "string"
},
"provider": { "provider": {
"type": "string" "type": "string"
}, },
@ -3636,10 +3766,10 @@
"type": "object", "type": "object",
"properties": { "properties": {
"data": { "data": {
"$ref": "#/definitions/2346.0xc0001ce990.false" "$ref": "#/definitions/2346.0xc000278ab0.false"
}, },
"data2": { "data2": {
"$ref": "#/definitions/2381.0xc0001ce9c0.false" "$ref": "#/definitions/2381.0xc000278ae0.false"
}, },
"msg": { "msg": {
"type": "string" "type": "string"
@ -4091,6 +4221,12 @@
"$ref": "#/definitions/object.AccountItem" "$ref": "#/definitions/object.AccountItem"
} }
}, },
"countryCodes": {
"type": "array",
"items": {
"type": "string"
}
},
"createdTime": { "createdTime": {
"type": "string" "type": "string"
}, },
@ -4137,9 +4273,6 @@
"passwordType": { "passwordType": {
"type": "string" "type": "string"
}, },
"phonePrefix": {
"type": "string"
},
"tags": { "tags": {
"type": "array", "type": "array",
"items": { "items": {
@ -4906,6 +5039,9 @@
"cloudfoundry": { "cloudfoundry": {
"type": "string" "type": "string"
}, },
"countryCode": {
"type": "string"
},
"createdIp": { "createdIp": {
"type": "string" "type": "string"
}, },

View File

@ -218,6 +218,30 @@ paths:
description: The Response object description: The Response object
schema: schema:
$ref: '#/definitions/controllers.Response' $ref: '#/definitions/controllers.Response'
/api/add-session:
post:
tags:
- Session API
description: Add session for one user in one application. If there are other existing sessions, join the session into the list.
operationId: ApiController.AddSession
parameters:
- in: query
name: id
description: The id(organization/application/user) of session
required: true
type: string
- in: query
name: sessionId
description: sessionId to be added
required: true
type: string
responses:
"200":
description: The Response object
schema:
type: array
items:
type: string
/api/add-syncer: /api/add-syncer:
post: post:
tags: tags:
@ -574,12 +598,12 @@ paths:
post: post:
tags: tags:
- Session API - Session API
description: Delete session by userId description: Delete session for one user in one application.
operationId: ApiController.DeleteSession operationId: ApiController.DeleteSession
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id ( owner/name )(owner/name) of user. description: The id(organization/application/user) of session
required: true required: true
type: string type: string
responses: responses:
@ -799,7 +823,7 @@ paths:
schema: schema:
$ref: '#/definitions/Response' $ref: '#/definitions/Response'
/api/get-email-and-phone: /api/get-email-and-phone:
post: get:
tags: tags:
- User API - User API
description: get email and phone by username description: get email and phone by username
@ -847,7 +871,7 @@ paths:
items: items:
$ref: '#/definitions/object.User' $ref: '#/definitions/object.User'
/api/get-ldap: /api/get-ldap:
post: get:
tags: tags:
- Account API - Account API
operationId: ApiController.GetLdap operationId: ApiController.GetLdap
@ -857,7 +881,7 @@ paths:
- Account API - Account API
operationId: ApiController.GetLdapser operationId: ApiController.GetLdapser
/api/get-ldaps: /api/get-ldaps:
post: get:
tags: tags:
- Account API - Account API
operationId: ApiController.GetLdaps operationId: ApiController.GetLdaps
@ -1224,11 +1248,30 @@ paths:
type: array type: array
items: items:
$ref: '#/definitions/object.Role' $ref: '#/definitions/object.Role'
/api/get-session:
get:
tags:
- Session API
description: Get session for one user in one application.
operationId: ApiController.GetSingleSession
parameters:
- in: query
name: id
description: The id(organization/application/user) of session
required: true
type: string
responses:
"200":
description: The Response object
schema:
type: array
items:
type: string
/api/get-sessions: /api/get-sessions:
get: get:
tags: tags:
- Session API - Session API
description: Get organization user sessions description: Get organization user sessions.
operationId: ApiController.GetSessions operationId: ApiController.GetSessions
parameters: parameters:
- in: query - in: query
@ -1535,6 +1578,30 @@ paths:
description: The Response object description: The Response object
schema: schema:
$ref: '#/definitions/controllers.Response' $ref: '#/definitions/controllers.Response'
/api/is-session-duplicated:
get:
tags:
- Session API
description: Check if there are other different sessions for one user in one application.
operationId: ApiController.IsSessionDuplicated
parameters:
- in: query
name: id
description: The id(organization/application/user) of session
required: true
type: string
- in: query
name: sessionId
description: sessionId to be checked
required: true
type: string
responses:
"200":
description: The Response object
schema:
type: array
items:
type: string
/api/login: /api/login:
post: post:
tags: tags:
@ -2110,6 +2177,25 @@ paths:
description: The Response object description: The Response object
schema: schema:
$ref: '#/definitions/controllers.Response' $ref: '#/definitions/controllers.Response'
/api/update-session:
post:
tags:
- Session API
description: Update session for one user in one application.
operationId: ApiController.UpdateSession
parameters:
- in: query
name: id
description: The id(organization/application/user) of session
required: true
type: string
responses:
"200":
description: The Response object
schema:
type: array
items:
type: string
/api/update-syncer: /api/update-syncer:
post: post:
tags: tags:
@ -2293,10 +2379,10 @@ paths:
schema: schema:
$ref: '#/definitions/Response' $ref: '#/definitions/Response'
definitions: definitions:
2346.0xc0001ce990.false: 2346.0xc000278ab0.false:
title: "false" title: "false"
type: object type: object
2381.0xc0001ce9c0.false: 2381.0xc000278ae0.false:
title: "false" title: "false"
type: object type: object
Response: Response:
@ -2336,6 +2422,8 @@ definitions:
type: string type: string
code: code:
type: string type: string
countryCode:
type: string
email: email:
type: string type: string
emailCode: emailCode:
@ -2358,8 +2446,6 @@ definitions:
type: string type: string
phoneCode: phoneCode:
type: string type: string
phonePrefix:
type: string
provider: provider:
type: string type: string
redirectUri: redirectUri:
@ -2383,9 +2469,9 @@ definitions:
type: object type: object
properties: properties:
data: data:
$ref: '#/definitions/2346.0xc0001ce990.false' $ref: '#/definitions/2346.0xc000278ab0.false'
data2: data2:
$ref: '#/definitions/2381.0xc0001ce9c0.false' $ref: '#/definitions/2381.0xc000278ae0.false'
msg: msg:
type: string type: string
name: name:
@ -2689,6 +2775,10 @@ definitions:
type: array type: array
items: items:
$ref: '#/definitions/object.AccountItem' $ref: '#/definitions/object.AccountItem'
countryCodes:
type: array
items:
type: string
createdTime: createdTime:
type: string type: string
defaultApplication: defaultApplication:
@ -2720,8 +2810,6 @@ definitions:
type: string type: string
passwordType: passwordType:
type: string type: string
phonePrefix:
type: string
tags: tags:
type: array type: array
items: items:
@ -3237,6 +3325,8 @@ definitions:
type: string type: string
cloudfoundry: cloudfoundry:
type: string type: string
countryCode:
type: string
createdIp: createdIp:
type: string type: string
createdTime: createdTime:

View File

@ -36,11 +36,10 @@ export function signup(values) {
}).then(res => res.json()); }).then(res => res.json());
} }
export function getEmailAndPhone(values) { export function getEmailAndPhone(organization, username) {
return fetch(`${authConfig.serverUrl}/api/get-email-and-phone`, { return fetch(`${authConfig.serverUrl}/api/get-email-and-phone?organization=${organization}&username=${username}`, {
method: "POST", method: "GET",
credentials: "include", credentials: "include",
body: JSON.stringify(values),
headers: { headers: {
"Accept-Language": Setting.getAcceptLanguage(), "Accept-Language": Setting.getAcceptLanguage(),
}, },

View File

@ -24,8 +24,6 @@ import * as UserBackend from "../backend/UserBackend";
import {CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons"; import {CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons";
import CustomGithubCorner from "../CustomGithubCorner"; import CustomGithubCorner from "../CustomGithubCorner";
import {withRouter} from "react-router-dom"; import {withRouter} from "react-router-dom";
const {Step} = Steps;
const {Option} = Select; const {Option} = Select;
class ForgetPage extends React.Component { class ForgetPage extends React.Component {
@ -33,23 +31,21 @@ class ForgetPage extends React.Component {
super(props); super(props);
this.state = { this.state = {
classes: props, classes: props,
account: props.account,
applicationName: props.applicationName ?? props.match.params?.applicationName, applicationName: props.applicationName ?? props.match.params?.applicationName,
application: null, application: null,
msg: null, msg: null,
userId: "", userId: "",
username: "", username: "",
name: "", name: "",
email: "",
isFixed: false,
fixedContent: "",
token: "",
phone: "", phone: "",
emailCode: "", email: "",
phoneCode: "", dest: "",
verifyType: null, // "email" or "phone" isVerifyTypeFixed: false,
verifyType: "", // "email", "phone"
current: 0, current: 0,
}; };
this.form = React.createRef();
} }
componentDidMount() { componentDidMount() {
@ -88,72 +84,67 @@ class ForgetPage extends React.Component {
switch (name) { switch (name) {
case "step1": case "step1":
const username = forms.step1.getFieldValue("username"); const username = forms.step1.getFieldValue("username");
AuthBackend.getEmailAndPhone({ AuthBackend.getEmailAndPhone(forms.step1.getFieldValue("organization"), username)
application: forms.step1.getFieldValue("application"), .then((res) => {
organization: forms.step1.getFieldValue("organization"), if (res.status === "ok") {
username: username, const phone = res.data.phone;
}).then((res) => { const email = res.data.email;
if (res.status === "ok") {
const phone = res.data.phone; if (phone === "" && email === "") {
const email = res.data.email; Setting.showMessage("error", "no verification method!");
const saveFields = () => { } else {
if (this.state.isFixed) { this.setState({
forms.step2.setFieldsValue({email: this.state.fixedContent}); name: res.data.name,
this.setState({username: this.state.fixedContent}); phone: phone,
email: email,
});
const saveFields = (type, dest, fixed) => {
this.setState({
verifyType: type,
isVerifyTypeFixed: fixed,
dest: dest,
});
};
switch (res.data2) {
case "email":
saveFields("email", email, true);
break;
case "phone":
saveFields("phone", phone, true);
break;
case "username":
phone !== "" ? saveFields("phone", phone, false) : saveFields("email", email, false);
}
this.setState({
current: 1,
});
} }
this.setState({current: 1}); } else {
}; Setting.showMessage("error", res.msg);
this.setState({phone: phone, email: email, username: res.data.name, name: res.data.name});
if (phone !== "" && email === "") {
this.setState({
verifyType: "phone",
});
} else if (phone === "" && email !== "") {
this.setState({
verifyType: "email",
});
} }
});
switch (res.data2) {
case "email":
this.setState({isFixed: true, fixedContent: email, verifyType: "email"}, () => {saveFields();});
break;
case "phone":
this.setState({isFixed: true, fixedContent: phone, verifyType: "phone"}, () => {saveFields();});
break;
default:
saveFields();
break;
}
} else {
Setting.showMessage("error", i18next.t(`signup:${res.msg}`));
}
});
break; break;
case "step2": case "step2":
const oAuthParams = Util.getOAuthGetParameters(); const oAuthParams = Util.getOAuthGetParameters();
const login = () => {
AuthBackend.login({ AuthBackend.login({
application: forms.step2.getFieldValue("application"), application: forms.step2.getFieldValue("application"),
organization: forms.step2.getFieldValue("organization"), organization: forms.step2.getFieldValue("organization"),
username: this.state.username, username: forms.step2.getFieldValue("dest"),
name: this.state.name, name: this.state.name,
code: forms.step2.getFieldValue("emailCode"), code: forms.step2.getFieldValue("code"),
type: "login", type: "login",
}, oAuthParams).then(res => { }, oAuthParams).then(res => {
if (res.status === "ok") { if (res.status === "ok") {
this.setState({current: 2, userId: res.data, username: res.data.split("/")[1]}); this.setState({current: 2, userId: res.data});
} else { } else {
Setting.showMessage("error", i18next.t(`signup:${res.msg}`)); Setting.showMessage("error", res.msg);
} }
}); });
};
if (this.state.verifyType === "email") {
this.setState({username: this.state.email}, () => {login();});
} else if (this.state.verifyType === "phone") {
this.setState({username: this.state.phone}, () => {login();});
}
break; break;
default: default:
break; break;
@ -161,13 +152,13 @@ class ForgetPage extends React.Component {
} }
onFinish(values) { onFinish(values) {
values.username = this.state.username; values.username = this.state.name;
values.userOwner = this.getApplicationObj()?.organizationObj.name; values.userOwner = this.getApplicationObj()?.organizationObj.name;
UserBackend.setPassword(values.userOwner, values.username, "", values?.newPassword).then(res => { UserBackend.setPassword(values.userOwner, values.username, "", values?.newPassword).then(res => {
if (res.status === "ok") { if (res.status === "ok") {
Setting.redirectToLoginPage(this.getApplicationObj(), this.props.history); Setting.redirectToLoginPage(this.getApplicationObj(), this.props.history);
} else { } else {
Setting.showMessage("error", i18next.t(`signup:${res.msg}`)); Setting.showMessage("error", res.msg);
} }
}); });
} }
@ -179,7 +170,7 @@ class ForgetPage extends React.Component {
if (this.state.phone !== "") { if (this.state.phone !== "") {
options.push( options.push(
<Option key={"phone"} value={"phone"}> <Option key={"phone"} value={this.state.phone} >
&nbsp;&nbsp;{this.state.phone} &nbsp;&nbsp;{this.state.phone}
</Option> </Option>
); );
@ -187,7 +178,7 @@ class ForgetPage extends React.Component {
if (this.state.email !== "") { if (this.state.email !== "") {
options.push( options.push(
<Option key={"email"} value={"email"}> <Option key={"email"} value={this.state.email} >
&nbsp;&nbsp;{this.state.email} &nbsp;&nbsp;{this.state.email}
</Option> </Option>
); );
@ -202,76 +193,70 @@ class ForgetPage extends React.Component {
this.onFormFinish(name, info, forms); this.onFormFinish(name, info, forms);
}}> }}>
{/* STEP 1: input username -> get email & phone */} {/* STEP 1: input username -> get email & phone */}
<Form {this.state.current === 0 ?
hidden={this.state.current !== 0} <Form
ref={this.form} ref={this.form}
name="step1" name="step1"
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
onFinishFailed={(errorInfo) => console.log(errorInfo)} onFinishFailed={(errorInfo) => console.log(errorInfo)}
initialValues={{ initialValues={{
application: application.name, application: application.name,
organization: application.organization, organization: application.organization,
}} }}
style={{width: "300px"}} style={{width: "300px"}}
size="large" size="large"
>
<Form.Item
style={{height: 0, visibility: "hidden"}}
name="application"
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your application!"
),
},
]}
/>
<Form.Item
style={{height: 0, visibility: "hidden"}}
name="organization"
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your organization!"
),
},
]}
/>
<Form.Item
name="username"
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your username!"
),
whitespace: true,
},
]}
> >
<Input <Form.Item
onChange={(e) => { hidden
this.setState({ name="application"
username: e.target.value, rules={[
}); {
}} required: true,
prefix={<UserOutlined />} message: i18next.t(
placeholder={i18next.t("login:username, Email or phone")} "forget:Please input your application!"
),
},
]}
/> />
</Form.Item> <Form.Item
<br /> hidden
<Form.Item> name="organization"
<Button block type="primary" htmlType="submit"> rules={[
{i18next.t("forget:Next Step")} {
</Button> required: true,
</Form.Item> message: i18next.t(
</Form> "forget:Please input your organization!"
),
},
]}
/>
<Form.Item
name="username"
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your username!"
),
whitespace: true,
},
]}
>
<Input
prefix={<UserOutlined />}
placeholder={i18next.t("login:username, Email or phone")}
/>
</Form.Item>
<br />
<Form.Item>
<Button block type="primary" htmlType="submit">
{i18next.t("forget:Next Step")}
</Button>
</Form.Item>
</Form> : null}
{/* STEP 2: verify email or phone */} {/* STEP 2: verify email or phone */}
<Form {this.state.current === 1 ? <Form
hidden={this.state.current !== 1}
ref={this.form} ref={this.form}
name="step2" name="step2"
onFinishFailed={(errorInfo) => onFinishFailed={(errorInfo) =>
@ -281,9 +266,17 @@ class ForgetPage extends React.Component {
errorInfo.outOfDate errorInfo.outOfDate
) )
} }
onValuesChange={(changedValues, allValues) => {
const verifyType = changedValues.dest?.indexOf("@") === -1 ? "phone" : "email";
this.setState({
dest: changedValues.dest,
verifyType: verifyType,
});
}}
initialValues={{ initialValues={{
application: application.name, application: application.name,
organization: application.organization, organization: application.organization,
dest: this.state.dest,
}} }}
style={{width: "300px"}} style={{width: "300px"}}
size="large" size="large"
@ -301,7 +294,7 @@ class ForgetPage extends React.Component {
]} ]}
/> />
<Form.Item <Form.Item
style={{height: 0, visibility: "hidden"}} hidden
name="organization" name="organization"
rules={[ rules={[
{ {
@ -313,32 +306,24 @@ class ForgetPage extends React.Component {
]} ]}
/> />
<Form.Item <Form.Item
name="email" // use email instead of email/phone to adapt to RequestForm in account.go name="dest"
validateFirst validateFirst
hasFeedback hasFeedback
> >
{ {
this.state.isFixed ? <Input disabled /> : <Select virtual={false}
<Select virtual={false} disabled={this.state.isVerifyTypeFixed}
key={this.state.verifyType} style={{textAlign: "left"}}
style={{textAlign: "left"}} placeholder={i18next.t("forget:Choose email or phone")}
defaultValue={this.state.verifyType} >
disabled={this.state.username === ""} {
placeholder={i18next.t("forget:Choose email or phone")} this.renderOptions()
onChange={(value) => { }
this.setState({ </Select>
verifyType: value,
});
}}
>
{
this.renderOptions()
}
</Select>
} }
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="emailCode" // use emailCode instead of email/phoneCode to adapt to RequestForm in account.go name="code"
rules={[ rules={[
{ {
required: true, required: true,
@ -348,21 +333,11 @@ class ForgetPage extends React.Component {
}, },
]} ]}
> >
{this.state.verifyType === "email" ? ( <SendCodeInput disabled={this.state.dest === ""}
<SendCodeInput method={"forget"}
disabled={this.state.username === "" || this.state.verifyType === ""} onButtonClickArgs={[this.state.dest, this.state.verifyType, Setting.getApplicationName(this.getApplicationObj()), this.state.name]}
method={"forget"} application={application}
onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(this.getApplicationObj()), this.state.name]} />
application={application}
/>
) : (
<SendCodeInput
disabled={this.state.username === "" || this.state.verifyType === ""}
method={"forget"}
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(this.getApplicationObj()), this.state.name]}
application={application}
/>
)}
</Form.Item> </Form.Item>
<br /> <br />
<Form.Item> <Form.Item>
@ -374,109 +349,109 @@ class ForgetPage extends React.Component {
{i18next.t("forget:Next Step")} {i18next.t("forget:Next Step")}
</Button> </Button>
</Form.Item> </Form.Item>
</Form> </Form> : null}
{/* STEP 3 */} {/* STEP 3 */}
<Form {this.state.current === 2 ?
hidden={this.state.current !== 2} <Form
ref={this.form} ref={this.form}
name="step3" name="step3"
onFinish={(values) => this.onFinish(values)} onFinish={(values) => this.onFinish(values)}
onFinishFailed={(errorInfo) => onFinishFailed={(errorInfo) =>
this.onFinishFailed( this.onFinishFailed(
errorInfo.values, errorInfo.values,
errorInfo.errorFields, errorInfo.errorFields,
errorInfo.outOfDate errorInfo.outOfDate
) )
} }
initialValues={{ initialValues={{
application: application.name, application: application.name,
organization: application.organization, organization: application.organization,
}} }}
style={{width: "300px"}} style={{width: "300px"}}
size="large" size="large"
>
<Form.Item
style={{height: 0, visibility: "hidden"}}
name="application"
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your application!"
),
},
]}
/>
<Form.Item
style={{height: 0, visibility: "hidden"}}
name="organization"
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your organization!"
),
},
]}
/>
<Form.Item
name="newPassword"
hidden={this.state.current !== 2}
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your password!"
),
},
]}
hasFeedback
> >
<Input.Password <Form.Item
disabled={this.state.userId === ""} hidden
prefix={<LockOutlined />} name="application"
placeholder={i18next.t("forget:Password")} rules={[
/> {
</Form.Item> required: true,
<Form.Item message: i18next.t(
name="confirm" "forget:Please input your application!"
dependencies={["newPassword"]} ),
hasFeedback
rules={[
{
required: true,
message: i18next.t(
"forget:Please confirm your password!"
),
},
({getFieldValue}) => ({
validator(rule, value) {
if (!value || getFieldValue("newPassword") === value) {
return Promise.resolve();
}
return Promise.reject(
i18next.t(
"forget:Your confirmed password is inconsistent with the password!"
)
);
}, },
}), ]}
]}
>
<Input.Password
disabled={this.state.userId === ""}
prefix={<CheckCircleOutlined />}
placeholder={i18next.t("forget:Confirm")}
/> />
</Form.Item> <Form.Item
<br /> hidden
<Form.Item hidden={this.state.current !== 2}> name="organization"
<Button block type="primary" htmlType="submit" disabled={this.state.userId === ""}> rules={[
{i18next.t("forget:Change Password")} {
</Button> required: true,
</Form.Item> message: i18next.t(
</Form> "forget:Please input your organization!"
),
},
]}
/>
<Form.Item
name="newPassword"
hidden={this.state.current !== 2}
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your password!"
),
},
]}
hasFeedback
>
<Input.Password
disabled={this.state.userId === ""}
prefix={<LockOutlined />}
placeholder={i18next.t("forget:Password")}
/>
</Form.Item>
<Form.Item
name="confirm"
dependencies={["newPassword"]}
hasFeedback
rules={[
{
required: true,
message: i18next.t(
"forget:Please confirm your password!"
),
},
({getFieldValue}) => ({
validator(rule, value) {
if (!value || getFieldValue("newPassword") === value) {
return Promise.resolve();
}
return Promise.reject(
i18next.t(
"forget:Your confirmed password is inconsistent with the password!"
)
);
},
}),
]}
>
<Input.Password
disabled={this.state.userId === ""}
prefix={<CheckCircleOutlined />}
placeholder={i18next.t("forget:Confirm")}
/>
</Form.Item>
<br />
<Form.Item hidden={this.state.current !== 2}>
<Button block type="primary" htmlType="submit" disabled={this.state.userId === ""}>
{i18next.t("forget:Change Password")}
</Button>
</Form.Item>
</Form> : null}
</Form.Provider> </Form.Provider>
); );
} }
@ -516,6 +491,20 @@ class ForgetPage extends React.Component {
<Col span={24}> <Col span={24}>
<Steps <Steps
current={this.state.current} current={this.state.current}
items={[
{
title: i18next.t("forget:Account"),
icon: <UserOutlined />,
},
{
title: i18next.t("forget:Account"),
icon: <SolutionOutlined />,
},
{
title: i18next.t("forget:Account"),
icon: <KeyOutlined />,
},
]}
style={{ style={{
width: "90%", width: "90%",
maxWidth: "500px", maxWidth: "500px",
@ -523,24 +512,12 @@ class ForgetPage extends React.Component {
marginTop: "80px", marginTop: "80px",
}} }}
> >
<Step
title={i18next.t("forget:Account")}
icon={<UserOutlined />}
/>
<Step
title={i18next.t("forget:Verify")}
icon={<SolutionOutlined />}
/>
<Step
title={i18next.t("forget:Reset")}
icon={<KeyOutlined />}
/>
</Steps> </Steps>
</Col> </Col>
</Row> </Row>
</Col> </Col>
<Col span={24} style={{display: "flex", justifyContent: "center"}}> <Col span={24} style={{display: "flex", justifyContent: "center"}}>
<div style={{marginTop: "10px", textAlign: "center"}}> <div style={{marginTop: "40px", textAlign: "center"}}>
{this.renderForm(application)} {this.renderForm(application)}
</div> </div>
</Col> </Col>

View File

@ -109,7 +109,7 @@ export function setPassword(userOwner, userName, oldPassword, newPassword) {
}).then(res => res.json()); }).then(res => res.json());
} }
export function sendCode(checkType, checkId, checkKey, method, countryCode, dest, type, applicationId, checkUser = "") { export function sendCode(checkType, checkId, checkKey, method, countryCode = "", dest, type, applicationId, checkUser = "") {
const formData = new FormData(); const formData = new FormData();
formData.append("checkType", checkType); formData.append("checkType", checkType);
formData.append("checkId", checkId); formData.append("checkId", checkId);