mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-02 11:20:18 +08:00
feat: login by code (#344)
Signed-off-by: abingcbc <abingcbc626@gmail.com>
This commit is contained in:
@ -139,53 +139,35 @@ func (c *ApiController) Login() {
|
|||||||
|
|
||||||
if form.Password == "" {
|
if form.Password == "" {
|
||||||
var verificationCodeType string
|
var verificationCodeType string
|
||||||
|
var checkResult string
|
||||||
|
|
||||||
// check result through Email or Phone
|
// check result through Email or Phone
|
||||||
if strings.Contains(form.Email, "@") {
|
if strings.Contains(form.Username, "@") {
|
||||||
verificationCodeType = "email"
|
verificationCodeType = "email"
|
||||||
checkResult := object.CheckVerificationCode(form.Email, form.EmailCode)
|
checkResult = object.CheckVerificationCode(form.Username, form.Code)
|
||||||
if len(checkResult) != 0 {
|
|
||||||
responseText := fmt.Sprintf("Email%s", checkResult)
|
|
||||||
c.ResponseError(responseText)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
verificationCodeType = "phone"
|
verificationCodeType = "phone"
|
||||||
checkPhone := fmt.Sprintf("+%s%s", form.PhonePrefix, form.Email)
|
if len(form.PhonePrefix) == 0 {
|
||||||
checkResult := object.CheckVerificationCode(checkPhone, form.EmailCode)
|
responseText := fmt.Sprintf("%s%s", verificationCodeType, "No phone prefix")
|
||||||
if len(checkResult) != 0 {
|
|
||||||
responseText := fmt.Sprintf("Phone%s", checkResult)
|
|
||||||
c.ResponseError(responseText)
|
c.ResponseError(responseText)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
checkPhone := fmt.Sprintf("+%s%s", form.PhonePrefix, form.Username)
|
||||||
|
checkResult = object.CheckVerificationCode(checkPhone, form.Code)
|
||||||
}
|
}
|
||||||
|
if len(checkResult) != 0 {
|
||||||
// get user
|
responseText := fmt.Sprintf("%s%s", verificationCodeType, checkResult)
|
||||||
var userId string
|
c.ResponseError(responseText)
|
||||||
if form.Username == "" {
|
|
||||||
userId, _ = c.RequireSignedIn()
|
|
||||||
} else {
|
|
||||||
userId = fmt.Sprintf("%s/%s", form.Organization, form.Username)
|
|
||||||
}
|
|
||||||
|
|
||||||
user = object.GetUser(userId)
|
|
||||||
if user == nil {
|
|
||||||
c.ResponseError("No such user.")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable the verification code
|
// disable the verification code
|
||||||
switch verificationCodeType {
|
object.DisableVerificationCode(form.Username)
|
||||||
case "email":
|
|
||||||
if user.Email != form.Email {
|
user = object.GetUserByFields(form.Organization, form.Username)
|
||||||
c.ResponseError("wrong email!")
|
if user == nil {
|
||||||
}
|
c.ResponseError("No such user.")
|
||||||
object.DisableVerificationCode(form.Email)
|
return
|
||||||
case "phone":
|
|
||||||
if user.Phone != form.Email {
|
|
||||||
c.ResponseError("wrong phone!")
|
|
||||||
}
|
|
||||||
object.DisableVerificationCode(form.Email)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
password := form.Password
|
password := form.Password
|
||||||
|
@ -45,6 +45,7 @@ func (c *ApiController) SendVerificationCode() {
|
|||||||
checkType := c.Ctx.Request.Form.Get("checkType")
|
checkType := c.Ctx.Request.Form.Get("checkType")
|
||||||
checkId := c.Ctx.Request.Form.Get("checkId")
|
checkId := c.Ctx.Request.Form.Get("checkId")
|
||||||
checkKey := c.Ctx.Request.Form.Get("checkKey")
|
checkKey := c.Ctx.Request.Form.Get("checkKey")
|
||||||
|
checkUser := c.Ctx.Request.Form.Get("checkUser")
|
||||||
remoteAddr := util.GetIPFromRequest(c.Ctx.Request)
|
remoteAddr := util.GetIPFromRequest(c.Ctx.Request)
|
||||||
|
|
||||||
if len(destType) == 0 || len(dest) == 0 || len(orgId) == 0 || !strings.Contains(orgId, "/") || len(checkType) == 0 || len(checkId) == 0 || len(checkKey) == 0 {
|
if len(destType) == 0 || len(dest) == 0 || len(orgId) == 0 || !strings.Contains(orgId, "/") || len(checkType) == 0 || len(checkId) == 0 || len(checkKey) == 0 {
|
||||||
@ -67,6 +68,12 @@ func (c *ApiController) SendVerificationCode() {
|
|||||||
organization := object.GetOrganization(orgId)
|
organization := object.GetOrganization(orgId)
|
||||||
application := object.GetApplicationByOrganizationName(organization.Name)
|
application := object.GetApplicationByOrganizationName(organization.Name)
|
||||||
|
|
||||||
|
if checkUser == "true" && user == nil &&
|
||||||
|
object.GetUserByFields(organization.Name, dest) == nil {
|
||||||
|
c.ResponseError("No such user.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
sendResp := errors.New("Invalid dest type.")
|
sendResp := errors.New("Invalid dest type.")
|
||||||
switch destType {
|
switch destType {
|
||||||
case "email":
|
case "email":
|
||||||
|
@ -136,10 +136,9 @@ class ForgetPage extends React.Component {
|
|||||||
AuthBackend.login({
|
AuthBackend.login({
|
||||||
application: forms.step2.getFieldValue("application"),
|
application: forms.step2.getFieldValue("application"),
|
||||||
organization: forms.step2.getFieldValue("organization"),
|
organization: forms.step2.getFieldValue("organization"),
|
||||||
email: forms.step2.getFieldValue("email"),
|
username: forms.step2.getFieldValue("email"),
|
||||||
emailCode: forms.step2.getFieldValue("emailCode"),
|
code: forms.step2.getFieldValue("emailCode"),
|
||||||
phonePrefix: this.state.application?.organizationObj.phonePrefix,
|
phonePrefix: this.state.application?.organizationObj.phonePrefix,
|
||||||
username: this.state.username,
|
|
||||||
type: "login"
|
type: "login"
|
||||||
}, oAuthParams).then(res => {
|
}, oAuthParams).then(res => {
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
|
@ -49,6 +49,7 @@ class LoginPage extends React.Component {
|
|||||||
isCodeSignin: false,
|
isCodeSignin: false,
|
||||||
msg: null,
|
msg: null,
|
||||||
username: null,
|
username: null,
|
||||||
|
validEmailOrPhone: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +110,7 @@ class LoginPage extends React.Component {
|
|||||||
const application = this.getApplicationObj();
|
const application = this.getApplicationObj();
|
||||||
const ths = this;
|
const ths = this;
|
||||||
values["type"] = this.state.type;
|
values["type"] = this.state.type;
|
||||||
|
values["phonePrefix"] = this.getApplicationObj()?.organizationObj.phonePrefix;
|
||||||
const oAuthParams = Util.getOAuthGetParameters();
|
const oAuthParams = Util.getOAuthGetParameters();
|
||||||
|
|
||||||
AuthBackend.login(values, oAuthParams)
|
AuthBackend.login(values, oAuthParams)
|
||||||
@ -288,11 +290,28 @@ class LoginPage extends React.Component {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="username"
|
name="username"
|
||||||
rules={[{ required: true, message: i18next.t("login:Please input your username, Email or phone!") }]}
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: i18next.t("login:Please input your username, Email or phone!")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: (_, value) => {
|
||||||
|
if (this.state.isCodeSignin) {
|
||||||
|
if (this.state.email !== "" && !Setting.isValidEmail(this.state.username) && !Setting.isValidPhone(this.state.username)) {
|
||||||
|
this.setState({validEmailOrPhone: false});
|
||||||
|
return Promise.reject(i18next.t("login:The input is not valid Email or Phone!"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({validEmailOrPhone: true});
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
prefix={<UserOutlined className="site-form-item-icon" />}
|
prefix={<UserOutlined className="site-form-item-icon" />}
|
||||||
placeholder={i18next.t("login:username, Email or phone")}
|
placeholder={ this.state.isCodeSignin ? i18next.t("login:Email or phone") : i18next.t("login:username, Email or phone") }
|
||||||
disabled={!application.enablePassword}
|
disabled={!application.enablePassword}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -308,8 +327,8 @@ class LoginPage extends React.Component {
|
|||||||
rules={[{ required: true, message: i18next.t("login:Please input your code!") }]}
|
rules={[{ required: true, message: i18next.t("login:Please input your code!") }]}
|
||||||
>
|
>
|
||||||
<CountDownInput
|
<CountDownInput
|
||||||
disabled={this.state.username?.length === 0}
|
disabled={this.state.username?.length === 0 || !this.state.validEmailOrPhone}
|
||||||
onButtonClickArgs={[this.state.email, "email", Setting.getApplicationOrgName(application)]}
|
onButtonClickArgs={[this.state.username, "", Setting.getApplicationOrgName(application), true]}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
) : (
|
) : (
|
||||||
|
@ -88,7 +88,7 @@ export function setPassword(userOwner, userName, oldPassword, newPassword) {
|
|||||||
}).then(res => res.json());
|
}).then(res => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sendCode(checkType, checkId, checkKey, dest, type, orgId) {
|
export function sendCode(checkType, checkId, checkKey, dest, type, orgId, checkUser) {
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append("checkType", checkType);
|
formData.append("checkType", checkType);
|
||||||
formData.append("checkId", checkId);
|
formData.append("checkId", checkId);
|
||||||
@ -96,6 +96,7 @@ export function sendCode(checkType, checkId, checkKey, dest, type, orgId) {
|
|||||||
formData.append("dest", dest);
|
formData.append("dest", dest);
|
||||||
formData.append("type", type);
|
formData.append("type", type);
|
||||||
formData.append("organizationId", orgId);
|
formData.append("organizationId", orgId);
|
||||||
|
formData.append("checkUser", checkUser);
|
||||||
return fetch(`${Setting.ServerUrl}/api/send-verification-code`, {
|
return fetch(`${Setting.ServerUrl}/api/send-verification-code`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
|
@ -18,6 +18,8 @@ import * as Setting from "../Setting";
|
|||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import * as UserBackend from "../backend/UserBackend";
|
import * as UserBackend from "../backend/UserBackend";
|
||||||
import {SafetyOutlined} from "@ant-design/icons";
|
import {SafetyOutlined} from "@ant-design/icons";
|
||||||
|
import * as Util from "../auth/Util";
|
||||||
|
import {isValidEmail, isValidPhone} from "../Setting";
|
||||||
|
|
||||||
const { Search } = Input;
|
const { Search } = Input;
|
||||||
|
|
||||||
@ -40,6 +42,14 @@ export const CountDownInput = (props) => {
|
|||||||
|
|
||||||
const handleOk = () => {
|
const handleOk = () => {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
|
if (isValidEmail(onButtonClickArgs[0])) {
|
||||||
|
onButtonClickArgs[1] = "email";
|
||||||
|
} else if (isValidPhone(onButtonClickArgs[0])) {
|
||||||
|
onButtonClickArgs[1] = "phone";
|
||||||
|
} else {
|
||||||
|
Util.showMessage("error", i18next.t("login:Invalid Email or phone"))
|
||||||
|
return;
|
||||||
|
}
|
||||||
UserBackend.sendCode(checkType, checkId, key, ...onButtonClickArgs).then(res => {
|
UserBackend.sendCode(checkType, checkId, key, ...onButtonClickArgs).then(res => {
|
||||||
setKey("");
|
setKey("");
|
||||||
if (res) {
|
if (res) {
|
||||||
|
@ -177,6 +177,7 @@
|
|||||||
"Please input your code!": "Please input your code!",
|
"Please input your code!": "Please input your code!",
|
||||||
"Please input your password!": "Please input your password!",
|
"Please input your password!": "Please input your password!",
|
||||||
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
||||||
|
"Please input your Email or phone!": "Please input your Email or phone!",
|
||||||
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
||||||
"Sign In": "Sign In",
|
"Sign In": "Sign In",
|
||||||
"Sign in with code": "Sign in with code",
|
"Sign in with code": "Sign in with code",
|
||||||
@ -185,7 +186,10 @@
|
|||||||
"Signing in...": "Signing in...",
|
"Signing in...": "Signing in...",
|
||||||
"To access": "To access",
|
"To access": "To access",
|
||||||
"sign up now": "sign up now",
|
"sign up now": "sign up now",
|
||||||
"username, Email or phone": "username, Email or phone"
|
"Email or phone": "Email or phone",
|
||||||
|
"username, Email or phone": "username, Email or phone",
|
||||||
|
"Invalid Email or phone": "Invalid Email or phone",
|
||||||
|
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
|
@ -177,6 +177,7 @@
|
|||||||
"Please input your code!": "Please input your code!",
|
"Please input your code!": "Please input your code!",
|
||||||
"Please input your password!": "Please input your password!",
|
"Please input your password!": "Please input your password!",
|
||||||
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
||||||
|
"Please input your Email or phone!": "Please input your Email or phone!",
|
||||||
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
||||||
"Sign In": "Sign In",
|
"Sign In": "Sign In",
|
||||||
"Sign in with code": "Sign in with code",
|
"Sign in with code": "Sign in with code",
|
||||||
@ -185,7 +186,10 @@
|
|||||||
"Signing in...": "Signing in...",
|
"Signing in...": "Signing in...",
|
||||||
"To access": "To access",
|
"To access": "To access",
|
||||||
"sign up now": "sign up now",
|
"sign up now": "sign up now",
|
||||||
"username, Email or phone": "username, Email or phone"
|
"Email or phone": "Email or phone",
|
||||||
|
"username, Email or phone": "username, Email or phone",
|
||||||
|
"Invalid Email or phone": "Invalid Email or phone",
|
||||||
|
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
|
@ -177,6 +177,7 @@
|
|||||||
"Please input your code!": "Please input your code!",
|
"Please input your code!": "Please input your code!",
|
||||||
"Please input your password!": "Please input your password!",
|
"Please input your password!": "Please input your password!",
|
||||||
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
||||||
|
"Please input your Email or phone!": "Please input your Email or phone!",
|
||||||
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
||||||
"Sign In": "Sign In",
|
"Sign In": "Sign In",
|
||||||
"Sign in with code": "Sign in with code",
|
"Sign in with code": "Sign in with code",
|
||||||
@ -185,7 +186,10 @@
|
|||||||
"Signing in...": "Signing in...",
|
"Signing in...": "Signing in...",
|
||||||
"To access": "To access",
|
"To access": "To access",
|
||||||
"sign up now": "sign up now",
|
"sign up now": "sign up now",
|
||||||
"username, Email or phone": "username, Email or phone"
|
"Email or phone": "Email or phone",
|
||||||
|
"username, Email or phone": "username, Email or phone",
|
||||||
|
"Invalid Email or phone": "Invalid Email or phone",
|
||||||
|
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
|
@ -177,6 +177,7 @@
|
|||||||
"Please input your code!": "Please input your code!",
|
"Please input your code!": "Please input your code!",
|
||||||
"Please input your password!": "Please input your password!",
|
"Please input your password!": "Please input your password!",
|
||||||
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
||||||
|
"Please input your Email or phone!": "Please input your Email or phone!",
|
||||||
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
||||||
"Sign In": "Sign In",
|
"Sign In": "Sign In",
|
||||||
"Sign in with code": "Sign in with code",
|
"Sign in with code": "Sign in with code",
|
||||||
@ -185,7 +186,10 @@
|
|||||||
"Signing in...": "Signing in...",
|
"Signing in...": "Signing in...",
|
||||||
"To access": "To access",
|
"To access": "To access",
|
||||||
"sign up now": "sign up now",
|
"sign up now": "sign up now",
|
||||||
"username, Email or phone": "username, Email or phone"
|
"Email or phone": "Email or phone",
|
||||||
|
"username, Email or phone": "username, Email or phone",
|
||||||
|
"Invalid Email or phone": "Invalid Email or phone",
|
||||||
|
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
|
@ -177,6 +177,7 @@
|
|||||||
"Please input your code!": "Please input your code!",
|
"Please input your code!": "Please input your code!",
|
||||||
"Please input your password!": "Please input your password!",
|
"Please input your password!": "Please input your password!",
|
||||||
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
||||||
|
"Please input your Email or phone!": "Please input your Email or phone!",
|
||||||
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
||||||
"Sign In": "Sign In",
|
"Sign In": "Sign In",
|
||||||
"Sign in with code": "Sign in with code",
|
"Sign in with code": "Sign in with code",
|
||||||
@ -185,7 +186,10 @@
|
|||||||
"Signing in...": "Signing in...",
|
"Signing in...": "Signing in...",
|
||||||
"To access": "To access",
|
"To access": "To access",
|
||||||
"sign up now": "sign up now",
|
"sign up now": "sign up now",
|
||||||
"username, Email or phone": "username, Email or phone"
|
"Email or phone": "Email or phone",
|
||||||
|
"username, Email or phone": "username, Email or phone",
|
||||||
|
"Invalid Email or phone": "Invalid Email or phone",
|
||||||
|
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
|
@ -177,6 +177,7 @@
|
|||||||
"Please input your code!": "Please input your code!",
|
"Please input your code!": "Please input your code!",
|
||||||
"Please input your password!": "Please input your password!",
|
"Please input your password!": "Please input your password!",
|
||||||
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
||||||
|
"Please input your Email or phone!": "Please input your Email or phone!",
|
||||||
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
||||||
"Sign In": "Sign In",
|
"Sign In": "Sign In",
|
||||||
"Sign in with code": "Sign in with code",
|
"Sign in with code": "Sign in with code",
|
||||||
@ -185,7 +186,10 @@
|
|||||||
"Signing in...": "Signing in...",
|
"Signing in...": "Signing in...",
|
||||||
"To access": "To access",
|
"To access": "To access",
|
||||||
"sign up now": "sign up now",
|
"sign up now": "sign up now",
|
||||||
"username, Email or phone": "username, Email or phone"
|
"Email or phone": "Email or phone",
|
||||||
|
"username, Email or phone": "username, Email or phone",
|
||||||
|
"Invalid Email or phone": "Invalid Email or phone",
|
||||||
|
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
|
@ -177,6 +177,7 @@
|
|||||||
"Please input your code!": "请输入您的验证码!",
|
"Please input your code!": "请输入您的验证码!",
|
||||||
"Please input your password!": "请输入您的密码!",
|
"Please input your password!": "请输入您的密码!",
|
||||||
"Please input your password, at least 6 characters!": "请输入您的密码,不少于6位",
|
"Please input your password, at least 6 characters!": "请输入您的密码,不少于6位",
|
||||||
|
"Please input your Email or phone!": "请输入您的Email或手机号!",
|
||||||
"Please input your username, Email or phone!": "请输入您的用户名、Email或手机号!",
|
"Please input your username, Email or phone!": "请输入您的用户名、Email或手机号!",
|
||||||
"Sign In": "登录",
|
"Sign In": "登录",
|
||||||
"Sign in with code": "验证码登录",
|
"Sign in with code": "验证码登录",
|
||||||
@ -185,7 +186,10 @@
|
|||||||
"Signing in...": "正在登录...",
|
"Signing in...": "正在登录...",
|
||||||
"To access": "访问",
|
"To access": "访问",
|
||||||
"sign up now": "立即注册",
|
"sign up now": "立即注册",
|
||||||
"username, Email or phone": "用户名、Email或手机号"
|
"Email or phone": "Email或手机号",
|
||||||
|
"username, Email or phone": "用户名、Email或手机号",
|
||||||
|
"Invalid Email or phone": "无效的Email或手机号",
|
||||||
|
"The input is not valid Email or Phone!": "您输入的电子邮箱格式或手机号有误!"
|
||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
"Default avatar": "默认头像",
|
"Default avatar": "默认头像",
|
||||||
|
Reference in New Issue
Block a user