mirror of
https://github.com/casdoor/casdoor.git
synced 2025-08-13 09:37:46 +08:00
Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
afd3c4ed25 | ||
![]() |
5caceb4ae2 | ||
![]() |
f5672357e6 | ||
![]() |
181e7c8c7d | ||
![]() |
36c5a9d09b | ||
![]() |
9acb3c499e | ||
![]() |
0e9a3b0f30 | ||
![]() |
d104a292e7 | ||
![]() |
8fbd5b1a74 | ||
![]() |
f5a05ac534 | ||
![]() |
05fade1d05 | ||
![]() |
8aefa02036 | ||
![]() |
3b6ec3e7c4 | ||
![]() |
910816c7a3 | ||
![]() |
412a8b5da7 | ||
![]() |
8ebd16a14e | ||
![]() |
44ec854465 |
@@ -106,12 +106,15 @@ func GetConfigDataSourceName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetLanguage(language string) string {
|
func GetLanguage(language string) string {
|
||||||
if language == "" {
|
if language == "" || language == "*" {
|
||||||
|
return "en"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(language) < 2 {
|
||||||
return "en"
|
return "en"
|
||||||
}
|
}
|
||||||
|
|
||||||
language = language[0:2]
|
language = language[0:2]
|
||||||
|
|
||||||
if strings.Contains(GetConfigString("languages"), language) {
|
if strings.Contains(GetConfigString("languages"), language) {
|
||||||
return language
|
return language
|
||||||
} else {
|
} else {
|
||||||
|
@@ -188,7 +188,7 @@ func (c *ApiController) ResetEmailOrPhone() {
|
|||||||
checkDest := dest
|
checkDest := dest
|
||||||
organization := object.GetOrganizationByUser(user)
|
organization := object.GetOrganizationByUser(user)
|
||||||
if destType == "phone" {
|
if destType == "phone" {
|
||||||
if object.HasUserByField(user.Owner, "phone", user.Phone) {
|
if object.HasUserByField(user.Owner, "phone", dest) {
|
||||||
c.ResponseError(c.T("check:Phone already exists"))
|
c.ResponseError(c.T("check:Phone already exists"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -208,7 +208,7 @@ func (c *ApiController) ResetEmailOrPhone() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if destType == "email" {
|
} else if destType == "email" {
|
||||||
if object.HasUserByField(user.Owner, "email", user.Email) {
|
if object.HasUserByField(user.Owner, "email", dest) {
|
||||||
c.ResponseError(c.T("check:Email already exists"))
|
c.ResponseError(c.T("check:Email already exists"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@@ -50,7 +50,7 @@ func getBuiltInAccountItems() []*AccountItem {
|
|||||||
{Name: "Password", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
{Name: "Password", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||||
{Name: "Email", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
{Name: "Email", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
{Name: "Phone", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
{Name: "Phone", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
{Name: "CountryCode", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
{Name: "Country code", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||||
{Name: "Country/Region", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
{Name: "Country/Region", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
{Name: "Location", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
{Name: "Location", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
{Name: "Affiliation", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
{Name: "Affiliation", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||||
|
@@ -43,7 +43,7 @@ type Payment struct {
|
|||||||
PayUrl string `xorm:"varchar(2000)" json:"payUrl"`
|
PayUrl string `xorm:"varchar(2000)" json:"payUrl"`
|
||||||
ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"`
|
ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"`
|
||||||
State string `xorm:"varchar(100)" json:"state"`
|
State string `xorm:"varchar(100)" json:"state"`
|
||||||
Message string `xorm:"varchar(1000)" json:"message"`
|
Message string `xorm:"varchar(2000)" json:"message"`
|
||||||
|
|
||||||
PersonName string `xorm:"varchar(100)" json:"personName"`
|
PersonName string `xorm:"varchar(100)" json:"personName"`
|
||||||
PersonIdCard string `xorm:"varchar(100)" json:"personIdCard"`
|
PersonIdCard string `xorm:"varchar(100)" json:"personIdCard"`
|
||||||
|
@@ -230,16 +230,20 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
|||||||
// base64 decode
|
// base64 decode
|
||||||
defated, err := base64.StdEncoding.DecodeString(samlRequest)
|
defated, err := base64.StdEncoding.DecodeString(samlRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", method, fmt.Errorf("err: %s", err.Error())
|
return "", "", method, fmt.Errorf("err: Failed to decode SAML request , %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// decompress
|
// decompress
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
rdr := flate.NewReader(bytes.NewReader(defated))
|
rdr := flate.NewReader(bytes.NewReader(defated))
|
||||||
io.Copy(&buffer, rdr)
|
_, err = io.Copy(&buffer, rdr)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
var authnRequest saml.AuthnRequest
|
var authnRequest saml.AuthnRequest
|
||||||
err = xml.Unmarshal(buffer.Bytes(), &authnRequest)
|
err = xml.Unmarshal(buffer.Bytes(), &authnRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", method, fmt.Errorf("err: %s", err.Error())
|
return "", "", method, fmt.Errorf("err: Failed to unmarshal AuthnRequest, please check the SAML request. %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify samlRequest
|
// verify samlRequest
|
||||||
@@ -252,14 +256,15 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
|||||||
block, _ := pem.Decode([]byte(cert.Certificate))
|
block, _ := pem.Decode([]byte(cert.Certificate))
|
||||||
certificate := base64.StdEncoding.EncodeToString(block.Bytes)
|
certificate := base64.StdEncoding.EncodeToString(block.Bytes)
|
||||||
|
|
||||||
_, originBackend := getOriginFromHost(host)
|
|
||||||
|
|
||||||
// redirect Url (Assertion Consumer Url)
|
// redirect Url (Assertion Consumer Url)
|
||||||
if application.SamlReplyUrl != "" {
|
if application.SamlReplyUrl != "" {
|
||||||
method = "POST"
|
method = "POST"
|
||||||
authnRequest.AssertionConsumerServiceURL = application.SamlReplyUrl
|
authnRequest.AssertionConsumerServiceURL = application.SamlReplyUrl
|
||||||
|
} else if authnRequest.AssertionConsumerServiceURL == "" {
|
||||||
|
return "", "", "", fmt.Errorf("err: SAML request don't has attribute 'AssertionConsumerServiceURL' in <samlp:AuthnRequest>")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, originBackend := getOriginFromHost(host)
|
||||||
// build signedResponse
|
// build signedResponse
|
||||||
samlResponse, _ := NewSamlResponse(user, originBackend, certificate, authnRequest.AssertionConsumerServiceURL, authnRequest.Issuer.Url, authnRequest.ID, application.RedirectUris)
|
samlResponse, _ := NewSamlResponse(user, originBackend, certificate, authnRequest.AssertionConsumerServiceURL, authnRequest.Issuer.Url, authnRequest.ID, application.RedirectUris)
|
||||||
randomKeyStore := &X509Key{
|
randomKeyStore := &X509Key{
|
||||||
@@ -279,7 +284,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
|||||||
doc.SetRoot(samlResponse)
|
doc.SetRoot(samlResponse)
|
||||||
xmlBytes, err := doc.WriteToBytes()
|
xmlBytes, err := doc.WriteToBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", method, fmt.Errorf("err: %s", err.Error())
|
return "", "", method, fmt.Errorf("err: Failed to serializes the SAML request into bytes, %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// compress
|
// compress
|
||||||
@@ -287,15 +292,21 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
|||||||
flated := bytes.NewBuffer(nil)
|
flated := bytes.NewBuffer(nil)
|
||||||
writer, err := flate.NewWriter(flated, flate.DefaultCompression)
|
writer, err := flate.NewWriter(flated, flate.DefaultCompression)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", method, fmt.Errorf("err: %s", err.Error())
|
return "", "", method, err
|
||||||
|
}
|
||||||
|
_, err = writer.Write(xmlBytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
err = writer.Close()
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
}
|
}
|
||||||
writer.Write(xmlBytes)
|
|
||||||
writer.Close()
|
|
||||||
xmlBytes = flated.Bytes()
|
xmlBytes = flated.Bytes()
|
||||||
}
|
}
|
||||||
// base64 encode
|
// base64 encode
|
||||||
res := base64.StdEncoding.EncodeToString(xmlBytes)
|
res := base64.StdEncoding.EncodeToString(xmlBytes)
|
||||||
return res, authnRequest.AssertionConsumerServiceURL, method, nil
|
return res, authnRequest.AssertionConsumerServiceURL, method, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSamlResponse11 return a saml1.1 response(not 2.0)
|
// NewSamlResponse11 return a saml1.1 response(not 2.0)
|
||||||
@@ -359,7 +370,10 @@ func NewSamlResponse11(user *User, requestID string, host string) *etree.Element
|
|||||||
|
|
||||||
data, _ := json.Marshal(user)
|
data, _ := json.Marshal(user)
|
||||||
tmp := map[string]string{}
|
tmp := map[string]string{}
|
||||||
json.Unmarshal(data, &tmp)
|
err := json.Unmarshal(data, &tmp)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
for k, v := range tmp {
|
for k, v := range tmp {
|
||||||
if v != "" {
|
if v != "" {
|
||||||
|
@@ -449,7 +449,7 @@ func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) boo
|
|||||||
if len(columns) == 0 {
|
if len(columns) == 0 {
|
||||||
columns = []string{
|
columns = []string{
|
||||||
"owner", "display_name", "avatar",
|
"owner", "display_name", "avatar",
|
||||||
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application",
|
"location", "address", "country_code", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application",
|
||||||
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
|
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
|
||||||
"signin_wrong_times", "last_signin_wrong_time",
|
"signin_wrong_times", "last_signin_wrong_time",
|
||||||
}
|
}
|
||||||
|
@@ -41,7 +41,7 @@ func IsPhoneValid(phone string, countryCode string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IsPhoneAllowInRegin(countryCode string, allowRegions []string) bool {
|
func IsPhoneAllowInRegin(countryCode string, allowRegions []string) bool {
|
||||||
return !ContainsString(allowRegions, countryCode)
|
return ContainsString(allowRegions, countryCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetE164Number(phone string, countryCode string) (string, bool) {
|
func GetE164Number(phone string, countryCode string) (string, bool) {
|
||||||
|
@@ -184,20 +184,19 @@ class OrganizationEditPage extends React.Component {
|
|||||||
</Row>
|
</Row>
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("general:Supported country code"), i18next.t("general:Supported country code - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Supported country codes"), i18next.t("general:Supported country codes - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Select virtual={false} mode={"multiple"} style={{width: "100%"}} value={this.state.organization.countryCodes ?? []}
|
<Select virtual={false} mode={"multiple"} style={{width: "100%"}} value={this.state.organization.countryCodes ?? []}
|
||||||
options={Setting.getCountriesData().map(country => {
|
onChange={value => {
|
||||||
return Setting.getOption(
|
|
||||||
<>
|
|
||||||
{Setting.countryFlag(country)}
|
|
||||||
{`${country.name} +${country.phone}`}
|
|
||||||
</>,
|
|
||||||
country.code);
|
|
||||||
})} onChange={value => {
|
|
||||||
this.updateOrganizationField("countryCodes", value);
|
this.updateOrganizationField("countryCodes", value);
|
||||||
}} />
|
}}
|
||||||
|
filterOption={(input, option) => (option?.text ?? "").toLowerCase().includes(input.toLowerCase())}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
Setting.getCountryCodeData().map((country) => Setting.getCountryCodeOption(country))
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
@@ -37,7 +37,7 @@ class OrganizationListPage extends BaseListPage {
|
|||||||
defaultAvatar: `${Setting.StaticBaseUrl}/img/casbin.svg`,
|
defaultAvatar: `${Setting.StaticBaseUrl}/img/casbin.svg`,
|
||||||
defaultApplication: "",
|
defaultApplication: "",
|
||||||
tags: [],
|
tags: [],
|
||||||
languages: ["en", "zh", "es", "fr", "de", "ja", "ko", "ru", "vi"],
|
languages: Setting.Countries.map(item => item.key),
|
||||||
masterPassword: "",
|
masterPassword: "",
|
||||||
enableSoftDeletion: false,
|
enableSoftDeletion: false,
|
||||||
isProfilePublic: true,
|
isProfilePublic: true,
|
||||||
|
@@ -82,20 +82,20 @@ class ProviderEditPage extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getClientIdLabel() {
|
getClientIdLabel(provider) {
|
||||||
switch (this.state.provider.category) {
|
switch (provider.category) {
|
||||||
case "Email":
|
case "Email":
|
||||||
return Setting.getLabel(i18next.t("signup:Username"), i18next.t("signup:Username - Tooltip"));
|
return Setting.getLabel(i18next.t("signup:Username"), i18next.t("signup:Username - Tooltip"));
|
||||||
case "SMS":
|
case "SMS":
|
||||||
if (this.state.provider.type === "Volc Engine SMS") {
|
if (provider.type === "Volc Engine SMS") {
|
||||||
return Setting.getLabel(i18next.t("provider:Access key"), i18next.t("provider:Access key - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:Access key"), i18next.t("provider:Access key - Tooltip"));
|
||||||
} else if (this.state.provider.type === "Huawei Cloud SMS") {
|
} else if (provider.type === "Huawei Cloud SMS") {
|
||||||
return Setting.getLabel(i18next.t("provider:App key"), i18next.t("provider:App key - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:App key"), i18next.t("provider:App key - Tooltip"));
|
||||||
} else {
|
} else {
|
||||||
return Setting.getLabel(i18next.t("provider:Client ID"), i18next.t("provider:Client ID - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:Client ID"), i18next.t("provider:Client ID - Tooltip"));
|
||||||
}
|
}
|
||||||
case "Captcha":
|
case "Captcha":
|
||||||
if (this.state.provider.type === "Aliyun Captcha") {
|
if (provider.type === "Aliyun Captcha") {
|
||||||
return Setting.getLabel(i18next.t("provider:Access key"), i18next.t("provider:Access key - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:Access key"), i18next.t("provider:Access key - Tooltip"));
|
||||||
} else {
|
} else {
|
||||||
return Setting.getLabel(i18next.t("provider:Site key"), i18next.t("provider:Site key - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:Site key"), i18next.t("provider:Site key - Tooltip"));
|
||||||
@@ -105,20 +105,20 @@ class ProviderEditPage extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getClientSecretLabel() {
|
getClientSecretLabel(provider) {
|
||||||
switch (this.state.provider.category) {
|
switch (provider.category) {
|
||||||
case "Email":
|
case "Email":
|
||||||
return Setting.getLabel(i18next.t("login:Password"), i18next.t("login:Password - Tooltip"));
|
return Setting.getLabel(i18next.t("login:Password"), i18next.t("login:Password - Tooltip"));
|
||||||
case "SMS":
|
case "SMS":
|
||||||
if (this.state.provider.type === "Volc Engine SMS") {
|
if (provider.type === "Volc Engine SMS") {
|
||||||
return Setting.getLabel(i18next.t("provider:Secret access key"), i18next.t("provider:SecretAccessKey - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:Secret access key"), i18next.t("provider:SecretAccessKey - Tooltip"));
|
||||||
} else if (this.state.provider.type === "Huawei Cloud SMS") {
|
} else if (provider.type === "Huawei Cloud SMS") {
|
||||||
return Setting.getLabel(i18next.t("provider:App secret"), i18next.t("provider:AppSecret - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:App secret"), i18next.t("provider:AppSecret - Tooltip"));
|
||||||
} else {
|
} else {
|
||||||
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip"));
|
||||||
}
|
}
|
||||||
case "Captcha":
|
case "Captcha":
|
||||||
if (this.state.provider.type === "Aliyun Captcha") {
|
if (provider.type === "Aliyun Captcha") {
|
||||||
return Setting.getLabel(i18next.t("provider:Secret access key"), i18next.t("provider:SecretAccessKey - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:Secret access key"), i18next.t("provider:SecretAccessKey - Tooltip"));
|
||||||
} else {
|
} else {
|
||||||
return Setting.getLabel(i18next.t("provider:Secret key"), i18next.t("provider:Secret key - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:Secret key"), i18next.t("provider:Secret key - Tooltip"));
|
||||||
@@ -416,7 +416,7 @@ class ProviderEditPage extends React.Component {
|
|||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{this.getClientIdLabel()}
|
{this.getClientIdLabel(this.state.provider)}
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Input value={this.state.provider.clientId} onChange={e => {
|
<Input value={this.state.provider.clientId} onChange={e => {
|
||||||
@@ -426,7 +426,7 @@ class ProviderEditPage extends React.Component {
|
|||||||
</Row>
|
</Row>
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{this.getClientSecretLabel()}
|
{this.getClientSecretLabel(this.state.provider)}
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Input value={this.state.provider.clientSecret} onChange={e => {
|
<Input value={this.state.provider.clientSecret} onChange={e => {
|
||||||
|
@@ -25,7 +25,7 @@ export const ResetModal = (props) => {
|
|||||||
const [confirmLoading, setConfirmLoading] = React.useState(false);
|
const [confirmLoading, setConfirmLoading] = React.useState(false);
|
||||||
const [dest, setDest] = React.useState("");
|
const [dest, setDest] = React.useState("");
|
||||||
const [code, setCode] = React.useState("");
|
const [code, setCode] = React.useState("");
|
||||||
const {buttonText, destType, application} = props;
|
const {buttonText, destType, application, account} = props;
|
||||||
|
|
||||||
const showModal = () => {
|
const showModal = () => {
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
@@ -87,7 +87,7 @@ export const ResetModal = (props) => {
|
|||||||
<Row style={{width: "100%", marginBottom: "20px"}}>
|
<Row style={{width: "100%", marginBottom: "20px"}}>
|
||||||
<Input
|
<Input
|
||||||
addonBefore={destType === "email" ? i18next.t("user:New Email") : i18next.t("user:New phone")}
|
addonBefore={destType === "email" ? i18next.t("user:New Email") : i18next.t("user:New phone")}
|
||||||
prefix={destType === "email" ? <MailOutlined /> : <PhoneOutlined />}
|
prefix={destType === "email" ? <React.Fragment><MailOutlined /> </React.Fragment> : (<React.Fragment><PhoneOutlined /> {`+${Setting.getCountryCode(account.countryCode)}`} </React.Fragment>)}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
onChange={e => setDest(e.target.value)}
|
onChange={e => setDest(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
@@ -82,7 +82,7 @@ class RoleListPage extends BaseListPage {
|
|||||||
...this.getColumnSearchProps("name"),
|
...this.getColumnSearchProps("name"),
|
||||||
render: (text, record, index) => {
|
render: (text, record, index) => {
|
||||||
return (
|
return (
|
||||||
<Link to={`/roles/${text}`}>
|
<Link to={`/roles/${record.owner}/${record.name}`}>
|
||||||
{text}
|
{text}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
@@ -41,17 +41,15 @@ class SelectRegionBox extends React.Component {
|
|||||||
defaultValue={this.props.defaultValue || undefined}
|
defaultValue={this.props.defaultValue || undefined}
|
||||||
placeholder="Please select country/region"
|
placeholder="Please select country/region"
|
||||||
onChange={(value => {this.onChange(value);})}
|
onChange={(value => {this.onChange(value);})}
|
||||||
filterOption={(input, option) =>
|
filterOption={(input, option) => (option?.label ?? "").toLowerCase().includes(input.toLowerCase())}
|
||||||
(option?.label ?? "").toLowerCase().includes(input.toLowerCase())
|
|
||||||
}
|
|
||||||
filterSort={(optionA, optionB) =>
|
filterSort={(optionA, optionB) =>
|
||||||
(optionA?.label ?? "").toLowerCase().localeCompare((optionB?.label ?? "").toLowerCase())
|
(optionA?.label ?? "").toLowerCase().localeCompare((optionB?.label ?? "").toLowerCase())
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
Setting.getCountriesData().map((item) => (
|
Setting.getCountryCodeData().map((item) => (
|
||||||
<Option key={item.code} value={item.code} label={`${item.name} (${item.code})`} >
|
<Option key={item.code} value={item.code} label={`${item.name} (${item.code})`} >
|
||||||
{Setting.countryFlag(item)}
|
{Setting.getCountryImage(item)}
|
||||||
{`${item.name} (${item.code})`}
|
{`${item.name} (${item.code})`}
|
||||||
</Option>
|
</Option>
|
||||||
))
|
))
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import {Checkbox, Form, Modal, Tag, Tooltip, message, theme} from "antd";
|
import {Checkbox, Form, Modal, Select, Tag, Tooltip, message, theme} from "antd";
|
||||||
import {QuestionCircleTwoTone} from "@ant-design/icons";
|
import {QuestionCircleTwoTone} from "@ant-design/icons";
|
||||||
import {isMobile as isMobileDevice} from "react-device-detect";
|
import {isMobile as isMobileDevice} from "react-device-detect";
|
||||||
import "./i18n";
|
import "./i18n";
|
||||||
@@ -26,6 +26,8 @@ import * as Conf from "./Conf";
|
|||||||
import * as phoneNumber from "libphonenumber-js";
|
import * as phoneNumber from "libphonenumber-js";
|
||||||
import * as path from "path-browserify";
|
import * as path from "path-browserify";
|
||||||
|
|
||||||
|
const {Option} = Select;
|
||||||
|
|
||||||
export const ServerUrl = "";
|
export const ServerUrl = "";
|
||||||
|
|
||||||
// export const StaticBaseUrl = "https://cdn.jsdelivr.net/gh/casbin/static";
|
// export const StaticBaseUrl = "https://cdn.jsdelivr.net/gh/casbin/static";
|
||||||
@@ -92,7 +94,7 @@ export const OtherProviderInfo = {
|
|||||||
url: "https://www.huaweicloud.com/product/msgsms.html",
|
url: "https://www.huaweicloud.com/product/msgsms.html",
|
||||||
},
|
},
|
||||||
"Twilio SMS": {
|
"Twilio SMS": {
|
||||||
logo: `${StaticBaseUrl}/img/social_twilio.png`,
|
logo: `${StaticBaseUrl}/img/social_twilio.svg`,
|
||||||
url: "https://www.twilio.com/messaging",
|
url: "https://www.twilio.com/messaging",
|
||||||
},
|
},
|
||||||
"SmsBao SMS": {
|
"SmsBao SMS": {
|
||||||
@@ -206,7 +208,11 @@ export function initCountries() {
|
|||||||
return countries;
|
return countries;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCountriesData(countryCodes = phoneNumber.getCountries()) {
|
export function getCountryCode(country) {
|
||||||
|
return phoneNumber.getCountryCallingCode(country);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCountryCodeData(countryCodes = phoneNumber.getCountries()) {
|
||||||
return countryCodes?.map((countryCode) => {
|
return countryCodes?.map((countryCode) => {
|
||||||
if (phoneNumber.isSupportedCountry(countryCode)) {
|
if (phoneNumber.isSupportedCountry(countryCode)) {
|
||||||
const name = initCountries().getName(countryCode, getLanguage());
|
const name = initCountries().getName(countryCode, getLanguage());
|
||||||
@@ -216,17 +222,28 @@ export function getCountriesData(countryCodes = phoneNumber.getCountries()) {
|
|||||||
phone: phoneNumber.getCountryCallingCode(countryCode),
|
phone: phoneNumber.getCountryCallingCode(countryCode),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
}).filter(item => item.name !== "")
|
||||||
|
.sort((a, b) => a.phone - b.phone);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function countryFlag(country) {
|
export function getCountryCodeOption(country) {
|
||||||
|
return (
|
||||||
|
<Option key={country.code} value={country.code} label={`+${country.phone}`} text={`${country.name}, ${country.code}, ${country.phone}`} >
|
||||||
|
<div style={{display: "flex", justifyContent: "space-between", marginRight: "10px"}}>
|
||||||
|
<div>
|
||||||
|
{getCountryImage(country)}
|
||||||
|
{`${country.name}`}
|
||||||
|
</div>
|
||||||
|
{`+${country.phone}`}
|
||||||
|
</div>
|
||||||
|
</Option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCountryImage(country) {
|
||||||
return <img src={`${StaticBaseUrl}/flag-icons/${country.code}.svg`} alt={country.name} height={20} style={{marginRight: 10}} />;
|
return <img src={`${StaticBaseUrl}/flag-icons/${country.code}.svg`} alt={country.name} height={20} style={{marginRight: 10}} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPhoneCodeFromCountryCode(countryCode) {
|
|
||||||
return phoneNumber.isSupportedCountry(countryCode) ? phoneNumber.getCountryCallingCode(countryCode) : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initServerUrl() {
|
export function initServerUrl() {
|
||||||
// const hostname = window.location.hostname;
|
// const hostname = window.location.hostname;
|
||||||
// if (hostname === "localhost") {
|
// if (hostname === "localhost") {
|
||||||
@@ -332,13 +349,15 @@ export function isValidEmail(email) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isValidPhone(phone, countryCode = "") {
|
export function isValidPhone(phone, countryCode = "") {
|
||||||
if (countryCode !== "") {
|
if (countryCode !== "" && countryCode !== "CN") {
|
||||||
return phoneNumber.isValidPhoneNumber(phone, countryCode);
|
return phoneNumber.isValidPhoneNumber(phone, countryCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// // https://learnku.com/articles/31543, `^s*$` filter empty email individually.
|
// https://learnku.com/articles/31543, `^s*$` filter empty email individually.
|
||||||
|
const phoneCnRegex = /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/;
|
||||||
const phoneRegex = /[0-9]{4,15}$/;
|
const phoneRegex = /[0-9]{4,15}$/;
|
||||||
return phoneRegex.test(phone);
|
|
||||||
|
return countryCode === "CN" ? phoneCnRegex.test(phone) : phoneRegex.test(phone);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isValidInvoiceTitle(invoiceTitle) {
|
export function isValidInvoiceTitle(invoiceTitle) {
|
||||||
|
@@ -29,7 +29,7 @@ import SelectRegionBox from "./SelectRegionBox";
|
|||||||
import WebAuthnCredentialTable from "./WebauthnCredentialTable";
|
import WebAuthnCredentialTable from "./WebauthnCredentialTable";
|
||||||
import ManagedAccountTable from "./ManagedAccountTable";
|
import ManagedAccountTable from "./ManagedAccountTable";
|
||||||
import PropertyTable from "./propertyTable";
|
import PropertyTable from "./propertyTable";
|
||||||
import PhoneNumberInput from "./common/PhoneNumberInput";
|
import {PhoneNumberInput} from "./common/PhoneNumberInput";
|
||||||
|
|
||||||
const {Option} = Select;
|
const {Option} = Select;
|
||||||
|
|
||||||
@@ -285,25 +285,18 @@ class UserEditPage extends React.Component {
|
|||||||
{Setting.getLabel(i18next.t("general:Email"), i18next.t("general:Email - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Email"), i18next.t("general:Email - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col style={{paddingRight: "20px"}} span={11} >
|
<Col style={{paddingRight: "20px"}} span={11} >
|
||||||
{Setting.isLocalAdminUser(this.props.account) ?
|
<Input
|
||||||
(<Input value={this.state.user.email}
|
value={this.state.user.email}
|
||||||
style={{width: "280Px"}}
|
style={{width: "280Px"}}
|
||||||
disabled={disabled}
|
disabled={!Setting.isLocalAdminUser(this.props.account) ? true : disabled}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
this.updateUserField("email", e.target.value);
|
this.updateUserField("email", e.target.value);
|
||||||
}} />) :
|
}}
|
||||||
(<Select virtual={false} value={this.state.user.email}
|
/>
|
||||||
style={{width: "280Px"}}
|
|
||||||
options={[Setting.getItem(this.state.user.email, this.state.user.email)]}
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={e => {
|
|
||||||
this.updateUserField("email", e.target.value);
|
|
||||||
}} />)
|
|
||||||
}
|
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={Setting.isMobile() ? 22 : 11} >
|
<Col span={Setting.isMobile() ? 22 : 11} >
|
||||||
{/* backend auto get the current user, so admin can not edit. Just self can reset*/}
|
{/* backend auto get the current user, so admin can not edit. Just self can reset*/}
|
||||||
{this.isSelf() ? <ResetModal application={this.state.application} disabled={disabled} buttonText={i18next.t("user:Reset Email...")} destType={"email"} /> : null}
|
{this.isSelf() ? <ResetModal application={this.state.application} account={this.props.account} disabled={disabled} buttonText={i18next.t("user:Reset Email...")} destType={"email"} /> : null}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
@@ -314,10 +307,10 @@ class UserEditPage extends React.Component {
|
|||||||
{Setting.getLabel(i18next.t("general:Phone"), i18next.t("general:Phone - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Phone"), i18next.t("general:Phone - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col style={{paddingRight: "20px"}} span={11} >
|
<Col style={{paddingRight: "20px"}} span={11} >
|
||||||
{Setting.isLocalAdminUser(this.props.account) ?
|
|
||||||
<Input.Group compact style={{width: "280Px"}}>
|
<Input.Group compact style={{width: "280Px"}}>
|
||||||
<PhoneNumberInput
|
<PhoneNumberInput
|
||||||
style={{width: "30%"}}
|
style={{width: "30%"}}
|
||||||
|
// disabled={!Setting.isLocalAdminUser(this.props.account) ? true : disabled}
|
||||||
value={this.state.user.countryCode}
|
value={this.state.user.countryCode}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
this.updateUserField("countryCode", value);
|
this.updateUserField("countryCode", value);
|
||||||
@@ -326,22 +319,14 @@ class UserEditPage extends React.Component {
|
|||||||
/>
|
/>
|
||||||
<Input value={this.state.user.phone}
|
<Input value={this.state.user.phone}
|
||||||
style={{width: "70%"}}
|
style={{width: "70%"}}
|
||||||
disabled={disabled}
|
disabled={!Setting.isLocalAdminUser(this.props.account) ? true : disabled}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
this.updateUserField("phone", e.target.value);
|
this.updateUserField("phone", e.target.value);
|
||||||
}} />
|
}} />
|
||||||
</Input.Group>
|
</Input.Group>
|
||||||
:
|
|
||||||
(<Select virtual={false} value={this.state.user.phone === "" ? null : `+${Setting.getPhoneCodeFromCountryCode(this.state.user.countryCode)} ${this.state.user.phone}`}
|
|
||||||
options={this.state.user.phone === "" ? null : [Setting.getItem(`+${Setting.getPhoneCodeFromCountryCode(this.state.user.countryCode)} ${this.state.user.phone}`, this.state.user.phone)]}
|
|
||||||
disabled={disabled}
|
|
||||||
style={{width: "280px"}}
|
|
||||||
onChange={e => {
|
|
||||||
this.updateUserField("phone", e.target.value);
|
|
||||||
}} />)}
|
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={Setting.isMobile() ? 24 : 11} >
|
<Col span={Setting.isMobile() ? 24 : 11} >
|
||||||
{this.isSelf() ? (<ResetModal application={this.state.application} disabled={disabled} buttonText={i18next.t("user:Reset Phone...")} destType={"phone"} />) : null}
|
{this.isSelf() ? (<ResetModal application={this.state.application} account={this.props.account} disabled={disabled} buttonText={i18next.t("user:Reset Phone...")} destType={"phone"} />) : null}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
|
@@ -26,7 +26,7 @@ import SelectRegionBox from "../SelectRegionBox";
|
|||||||
import CustomGithubCorner from "../CustomGithubCorner";
|
import CustomGithubCorner from "../CustomGithubCorner";
|
||||||
import SelectLanguageBox from "../SelectLanguageBox";
|
import SelectLanguageBox from "../SelectLanguageBox";
|
||||||
import {withRouter} from "react-router-dom";
|
import {withRouter} from "react-router-dom";
|
||||||
import PhoneNumberInput from "../common/PhoneNumberInput";
|
import {PhoneNumberInput} from "../common/PhoneNumberInput";
|
||||||
|
|
||||||
const formItemLayout = {
|
const formItemLayout = {
|
||||||
labelCol: {
|
labelCol: {
|
||||||
@@ -82,7 +82,7 @@ class SignupPage extends React.Component {
|
|||||||
this.form = React.createRef();
|
this.form = React.createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillMount() {
|
componentDidMount() {
|
||||||
let applicationName = this.state.applicationName;
|
let applicationName = this.state.applicationName;
|
||||||
const oAuthParams = Util.getOAuthGetParameters();
|
const oAuthParams = Util.getOAuthGetParameters();
|
||||||
if (oAuthParams !== null) {
|
if (oAuthParams !== null) {
|
||||||
@@ -390,39 +390,26 @@ class SignupPage extends React.Component {
|
|||||||
required: required,
|
required: required,
|
||||||
message: i18next.t("signup:Please select your country code!"),
|
message: i18next.t("signup:Please select your country code!"),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
validator: (_, value) => {
|
|
||||||
if (this.state.phone !== "" && !Setting.isValidPhone(this.state.phone, this.state.countryCode)) {
|
|
||||||
this.setState({validPhone: false});
|
|
||||||
return Promise.reject(i18next.t("signup:The input is not valid Phone!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({validPhone: true});
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<PhoneNumberInput
|
<PhoneNumberInput
|
||||||
showSearsh={true}
|
|
||||||
style={{width: "35%"}}
|
style={{width: "35%"}}
|
||||||
value={this.state.countryCode}
|
|
||||||
onChange={(value) => {this.setState({countryCode: value});}}
|
|
||||||
countryCodes={this.getApplicationObj().organizationObj.countryCodes}
|
countryCodes={this.getApplicationObj().organizationObj.countryCodes}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="phone"
|
name="phone"
|
||||||
key="phone"
|
key="phone"
|
||||||
|
dependencies={["countryCode"]}
|
||||||
noStyle
|
noStyle
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: required,
|
required: required,
|
||||||
message: i18next.t("signup:Please input your phone number!"),
|
message: i18next.t("signup:Please input your phone number!"),
|
||||||
},
|
},
|
||||||
{
|
({getFieldValue}) => ({
|
||||||
validator: (_, value) => {
|
validator: (_, value) => {
|
||||||
if (this.state.phone !== "" && !Setting.isValidPhone(this.state.phone, this.state.countryCode)) {
|
if (value !== "" && !Setting.isValidPhone(value, getFieldValue("countryCode"))) {
|
||||||
this.setState({validPhone: false});
|
this.setState({validPhone: false});
|
||||||
return Promise.reject(i18next.t("signup:The input is not valid Phone!"));
|
return Promise.reject(i18next.t("signup:The input is not valid Phone!"));
|
||||||
}
|
}
|
||||||
@@ -430,7 +417,7 @@ class SignupPage extends React.Component {
|
|||||||
this.setState({validPhone: true});
|
this.setState({validPhone: true});
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
@@ -456,6 +443,7 @@ class SignupPage extends React.Component {
|
|||||||
method={"signup"}
|
method={"signup"}
|
||||||
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(application)]}
|
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(application)]}
|
||||||
application={application}
|
application={application}
|
||||||
|
countryCode={this.state.countryCode}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
@@ -560,6 +548,7 @@ class SignupPage extends React.Component {
|
|||||||
initialValues={{
|
initialValues={{
|
||||||
application: application.name,
|
application: application.name,
|
||||||
organization: application.organization,
|
organization: application.organization,
|
||||||
|
countryCode: application.organizationObj.countryCodes?.[0],
|
||||||
}}
|
}}
|
||||||
size="large"
|
size="large"
|
||||||
layout={Setting.isMobile() ? "vertical" : "horizontal"}
|
layout={Setting.isMobile() ? "vertical" : "horizontal"}
|
||||||
|
@@ -51,7 +51,9 @@ window.fetch = async(url, option = {}) => {
|
|||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
originalFetch(url, option).then(res => {
|
originalFetch(url, option).then(res => {
|
||||||
|
if (!url.startsWith("/api/get-organizations")) {
|
||||||
responseFilters.forEach(filter => filter(res.clone()));
|
responseFilters.forEach(filter => filter(res.clone()));
|
||||||
|
}
|
||||||
resolve(res);
|
resolve(res);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -109,12 +109,13 @@ export function setPassword(userOwner, userName, oldPassword, newPassword) {
|
|||||||
}).then(res => res.json());
|
}).then(res => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sendCode(checkType, checkId, checkKey, method, 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);
|
||||||
formData.append("checkKey", checkKey);
|
formData.append("checkKey", checkKey);
|
||||||
formData.append("method", method);
|
formData.append("method", method);
|
||||||
|
formData.append("countryCode", countryCode);
|
||||||
formData.append("dest", dest);
|
formData.append("dest", dest);
|
||||||
formData.append("type", type);
|
formData.append("type", type);
|
||||||
formData.append("applicationId", applicationId);
|
formData.append("applicationId", applicationId);
|
||||||
|
@@ -61,8 +61,13 @@ class HomePage extends React.Component {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.state.applications.forEach(application => {
|
this.state.applications.forEach(application => {
|
||||||
|
let homepageUrl = application.homepageUrl;
|
||||||
|
if (homepageUrl === "<custom-url>") {
|
||||||
|
homepageUrl = this.props.account.homepage;
|
||||||
|
}
|
||||||
|
|
||||||
items.push({
|
items.push({
|
||||||
link: application.homepageUrl, name: application.displayName, organizer: application.description, logo: application.logo, createdTime: "",
|
link: homepageUrl, name: application.displayName, organizer: application.description, logo: application.logo, createdTime: "",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -16,12 +16,10 @@ import {Button} from "antd";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import {CaptchaModal} from "./CaptchaModal";
|
import {CaptchaModal} from "./CaptchaModal";
|
||||||
import * as ProviderBackend from "../backend/ProviderBackend";
|
|
||||||
import * as UserBackend from "../backend/UserBackend";
|
import * as UserBackend from "../backend/UserBackend";
|
||||||
|
|
||||||
export const CaptchaPreview = ({
|
export const CaptchaPreview = ({
|
||||||
provider,
|
provider,
|
||||||
providerName,
|
|
||||||
clientSecret,
|
clientSecret,
|
||||||
captchaType,
|
captchaType,
|
||||||
subType,
|
subType,
|
||||||
@@ -41,9 +39,10 @@ export const CaptchaPreview = ({
|
|||||||
provider.providerUrl = providerUrl;
|
provider.providerUrl = providerUrl;
|
||||||
if (clientSecret !== "***") {
|
if (clientSecret !== "***") {
|
||||||
provider.clientSecret = clientSecret;
|
provider.clientSecret = clientSecret;
|
||||||
ProviderBackend.updateProvider(owner, providerName, provider).then(() => {
|
// ProviderBackend.updateProvider(owner, providerName, provider).then(() => {
|
||||||
|
// setOpen(true);
|
||||||
|
// });
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}
|
}
|
||||||
|
@@ -16,43 +16,29 @@ import {Select} from "antd";
|
|||||||
import * as Setting from "../Setting";
|
import * as Setting from "../Setting";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const {Option} = Select;
|
export const PhoneNumberInput = (props) => {
|
||||||
|
const {onChange, style, disabled, value} = props;
|
||||||
export default function PhoneNumberInput(props) {
|
|
||||||
const {onChange, style, showSearch} = props;
|
|
||||||
const value = props.value ?? "CN";
|
|
||||||
const countryCodes = props.countryCodes ?? [];
|
const countryCodes = props.countryCodes ?? [];
|
||||||
|
|
||||||
const handleOnChange = (e) => {
|
const handleOnChange = (value) => {
|
||||||
onChange?.(e);
|
onChange?.(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
virtual={false}
|
virtual={false}
|
||||||
|
showSearch
|
||||||
style={style}
|
style={style}
|
||||||
|
disabled={disabled}
|
||||||
value={value}
|
value={value}
|
||||||
dropdownMatchSelectWidth={false}
|
dropdownMatchSelectWidth={false}
|
||||||
optionLabelProp={"label"}
|
optionLabelProp={"label"}
|
||||||
showSearch={showSearch}
|
|
||||||
onChange={handleOnChange}
|
onChange={handleOnChange}
|
||||||
filterOption={(input, option) =>
|
filterOption={(input, option) => (option?.text ?? "").toLowerCase().includes(input.toLowerCase())}
|
||||||
(option?.label ?? "").toLowerCase().includes(input.toLowerCase())
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
Setting.getCountriesData(countryCodes).map((country) => (
|
Setting.getCountryCodeData(countryCodes).map((country) => Setting.getCountryCodeOption(country))
|
||||||
<Option key={country.code} value={country.code} label={`+${country.phone}`} >
|
|
||||||
<div style={{display: "flex", justifyContent: "space-between"}}>
|
|
||||||
<div>
|
|
||||||
{Setting.countryFlag(country)}
|
|
||||||
{`${country.name}`}
|
|
||||||
</div>
|
|
||||||
{`+${country.phone}`}
|
|
||||||
</div>
|
|
||||||
</Option>
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
</Select>
|
</Select>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@@ -22,7 +22,7 @@ import {CaptchaWidget} from "./CaptchaWidget";
|
|||||||
const {Search} = Input;
|
const {Search} = Input;
|
||||||
|
|
||||||
export const SendCodeInput = (props) => {
|
export const SendCodeInput = (props) => {
|
||||||
const {disabled, textBefore, onChange, onButtonClickArgs, application, method} = props;
|
const {disabled, textBefore, onChange, onButtonClickArgs, application, method, countryCode} = props;
|
||||||
const [visible, setVisible] = React.useState(false);
|
const [visible, setVisible] = React.useState(false);
|
||||||
const [key, setKey] = React.useState("");
|
const [key, setKey] = React.useState("");
|
||||||
const [captchaImg, setCaptchaImg] = React.useState("");
|
const [captchaImg, setCaptchaImg] = React.useState("");
|
||||||
@@ -53,7 +53,7 @@ export const SendCodeInput = (props) => {
|
|||||||
const handleOk = () => {
|
const handleOk = () => {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
setButtonLoading(true);
|
setButtonLoading(true);
|
||||||
UserBackend.sendCode(checkType, checkId, key, method, ...onButtonClickArgs).then(res => {
|
UserBackend.sendCode(checkType, checkId, key, method, countryCode, ...onButtonClickArgs).then(res => {
|
||||||
setKey("");
|
setKey("");
|
||||||
setButtonLoading(false);
|
setButtonLoading(false);
|
||||||
if (res) {
|
if (res) {
|
||||||
@@ -70,7 +70,7 @@ export const SendCodeInput = (props) => {
|
|||||||
const loadCaptcha = () => {
|
const loadCaptcha = () => {
|
||||||
UserBackend.getCaptcha(application.owner, application.name, false).then(res => {
|
UserBackend.getCaptcha(application.owner, application.name, false).then(res => {
|
||||||
if (res.type === "none") {
|
if (res.type === "none") {
|
||||||
UserBackend.sendCode("none", "", "", method, ...onButtonClickArgs).then(res => {
|
UserBackend.sendCode("none", "", "", method, countryCode, ...onButtonClickArgs).then(res => {
|
||||||
if (res) {
|
if (res) {
|
||||||
handleCountDown(60);
|
handleCountDown(60);
|
||||||
}
|
}
|
||||||
|
@@ -251,8 +251,8 @@
|
|||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
"Successfully deleted": "Successfully deleted",
|
"Successfully deleted": "Successfully deleted",
|
||||||
"Successfully saved": "Successfully saved",
|
"Successfully saved": "Successfully saved",
|
||||||
"Supported country code": "Supported country code",
|
"Supported country codes": "Supported country codes",
|
||||||
"Supported country code - Tooltip": "Supported country code - Tooltip",
|
"Supported country codes - Tooltip": "Supported country codes - Tooltip",
|
||||||
"Swagger": "Swagger",
|
"Swagger": "Swagger",
|
||||||
"Sync": "Sync",
|
"Sync": "Sync",
|
||||||
"Syncers": "Syncers",
|
"Syncers": "Syncers",
|
||||||
|
@@ -251,8 +251,8 @@
|
|||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
"Successfully deleted": "Successfully deleted",
|
"Successfully deleted": "Successfully deleted",
|
||||||
"Successfully saved": "Successfully saved",
|
"Successfully saved": "Successfully saved",
|
||||||
"Supported country code": "Supported country code",
|
"Supported country codes": "Supported country codes",
|
||||||
"Supported country code - Tooltip": "Supported country code - Tooltip",
|
"Supported country codes - Tooltip": "Supported country codes - Tooltip",
|
||||||
"Swagger": "Swagger",
|
"Swagger": "Swagger",
|
||||||
"Sync": "Sync",
|
"Sync": "Sync",
|
||||||
"Syncers": "Syncers",
|
"Syncers": "Syncers",
|
||||||
|
@@ -251,8 +251,8 @@
|
|||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
"Successfully deleted": "Successfully deleted",
|
"Successfully deleted": "Successfully deleted",
|
||||||
"Successfully saved": "Successfully saved",
|
"Successfully saved": "Successfully saved",
|
||||||
"Supported country code": "Supported country code",
|
"Supported country codes": "Supported country codes",
|
||||||
"Supported country code - Tooltip": "Supported country code - Tooltip",
|
"Supported country codes - Tooltip": "Supported country codes - Tooltip",
|
||||||
"Swagger": "Swagger",
|
"Swagger": "Swagger",
|
||||||
"Sync": "Sincronizador",
|
"Sync": "Sincronizador",
|
||||||
"Syncers": "Sincronizadores",
|
"Syncers": "Sincronizadores",
|
||||||
|
@@ -251,8 +251,8 @@
|
|||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
"Successfully deleted": "Successfully deleted",
|
"Successfully deleted": "Successfully deleted",
|
||||||
"Successfully saved": "Successfully saved",
|
"Successfully saved": "Successfully saved",
|
||||||
"Supported country code": "Supported country code",
|
"Supported country codes": "Supported country codes",
|
||||||
"Supported country code - Tooltip": "Supported country code - Tooltip",
|
"Supported country codes - Tooltip": "Supported country codes - Tooltip",
|
||||||
"Swagger": "Swagger",
|
"Swagger": "Swagger",
|
||||||
"Sync": "Sync",
|
"Sync": "Sync",
|
||||||
"Syncers": "Synchronisateurs",
|
"Syncers": "Synchronisateurs",
|
||||||
|
@@ -251,8 +251,8 @@
|
|||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
"Successfully deleted": "Successfully deleted",
|
"Successfully deleted": "Successfully deleted",
|
||||||
"Successfully saved": "Successfully saved",
|
"Successfully saved": "Successfully saved",
|
||||||
"Supported country code": "Supported country code",
|
"Supported country codes": "Supported country codes",
|
||||||
"Supported country code - Tooltip": "Supported country code - Tooltip",
|
"Supported country codes - Tooltip": "Supported country codes - Tooltip",
|
||||||
"Swagger": "Swagger",
|
"Swagger": "Swagger",
|
||||||
"Sync": "Sync",
|
"Sync": "Sync",
|
||||||
"Syncers": "Syncers",
|
"Syncers": "Syncers",
|
||||||
|
@@ -251,8 +251,8 @@
|
|||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
"Successfully deleted": "Successfully deleted",
|
"Successfully deleted": "Successfully deleted",
|
||||||
"Successfully saved": "Successfully saved",
|
"Successfully saved": "Successfully saved",
|
||||||
"Supported country code": "Supported country code",
|
"Supported country codes": "Supported country codes",
|
||||||
"Supported country code - Tooltip": "Supported country code - Tooltip",
|
"Supported country codes - Tooltip": "Supported country codes - Tooltip",
|
||||||
"Swagger": "Swagger",
|
"Swagger": "Swagger",
|
||||||
"Sync": "Sync",
|
"Sync": "Sync",
|
||||||
"Syncers": "Syncers",
|
"Syncers": "Syncers",
|
||||||
|
@@ -251,8 +251,8 @@
|
|||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
"Successfully deleted": "Successfully deleted",
|
"Successfully deleted": "Successfully deleted",
|
||||||
"Successfully saved": "Successfully saved",
|
"Successfully saved": "Successfully saved",
|
||||||
"Supported country code": "Supported country code",
|
"Supported country codes": "Supported country codes",
|
||||||
"Supported country code - Tooltip": "Supported country code - Tooltip",
|
"Supported country codes - Tooltip": "Supported country codes - Tooltip",
|
||||||
"Swagger": "Swagger",
|
"Swagger": "Swagger",
|
||||||
"Sync": "Sync",
|
"Sync": "Sync",
|
||||||
"Syncers": "Синхронизаторы",
|
"Syncers": "Синхронизаторы",
|
||||||
|
@@ -251,8 +251,8 @@
|
|||||||
"Successfully added": "Successfully added",
|
"Successfully added": "Successfully added",
|
||||||
"Successfully deleted": "Successfully deleted",
|
"Successfully deleted": "Successfully deleted",
|
||||||
"Successfully saved": "Successfully saved",
|
"Successfully saved": "Successfully saved",
|
||||||
"Supported country code": "Supported country code",
|
"Supported country codes": "Supported country codes",
|
||||||
"Supported country code - Tooltip": "Supported country code - Tooltip",
|
"Supported country codes - Tooltip": "Supported country codes - Tooltip",
|
||||||
"Swagger": "Swagger",
|
"Swagger": "Swagger",
|
||||||
"Sync": "Sync",
|
"Sync": "Sync",
|
||||||
"Syncers": "Syncers",
|
"Syncers": "Syncers",
|
||||||
|
@@ -251,8 +251,8 @@
|
|||||||
"Successfully added": "添加成功",
|
"Successfully added": "添加成功",
|
||||||
"Successfully deleted": "删除成功",
|
"Successfully deleted": "删除成功",
|
||||||
"Successfully saved": "保存成功",
|
"Successfully saved": "保存成功",
|
||||||
"Supported country code": "支持的国家代码",
|
"Supported country codes": "支持的国家代码",
|
||||||
"Supported country code - Tooltip": "支持发送短信的国家 - Tooltip",
|
"Supported country codes - Tooltip": "支持发送短信的国家 - Tooltip",
|
||||||
"Swagger": "API文档",
|
"Swagger": "API文档",
|
||||||
"Sync": "同步",
|
"Sync": "同步",
|
||||||
"Syncers": "同步器",
|
"Syncers": "同步器",
|
||||||
|
Reference in New Issue
Block a user