Compare commits

...

15 Commits

Author SHA1 Message Date
572616d390 fix: fix bug in ProviderItem.CountryCodes 2024-05-07 17:17:45 +08:00
2187310dbc feat: fix bug in initDefinedOrganization() 2024-05-06 13:57:08 +08:00
26345bb21b feat: add sms provider sendcloud (#2927) 2024-05-06 13:38:55 +08:00
e0455df504 feat: improve record content masking (#2923)
* feat: hide password in record

* feat: improve code format

* feat: improve code format
2024-05-05 12:42:09 +08:00
1dfbbf0e90 feat: fix bug that fails to import built-in org via init_data.json (#2922) 2024-05-05 01:06:15 +08:00
d43d58dee2 feat: fix getProviders() owner bug in product edit page 2024-05-01 18:04:50 +08:00
9eb4b12041 fix: rename to countryCodes for UI 2024-05-01 11:44:21 +08:00
3a45a4ee77 fix: rename to countryCodes 2024-05-01 09:47:44 +08:00
43393f034b feat: fix the Email provider fails to match bug in GetProviderByCategoryAndRule() 2024-05-01 09:44:19 +08:00
bafa80513b fix: improve ProviderTable column UI 2024-05-01 00:46:48 +08:00
8d08140421 fix: fix typo in initBuiltInPermission() 2024-05-01 00:41:16 +08:00
3d29e27d54 feat: support multiple SMS providers for different regions (#2914)
* feat: support using different sms provider for different region

* feat: add multiple support for select and remove log

* feat: revert change for countryCode in loginPage

* feat: revert change for countryCode in user_util.go

* feat: revert change for countryCode in auth.go

* Update application_item.go

* Update CountryCodeSelect.js

* Update ProviderTable.js

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-05-01 00:40:47 +08:00
199f1d4d10 feat: fix Auto-login causing AuthCodeWithPKCE Failures (#2911) 2024-04-30 12:14:50 +08:00
227e938db6 feat: fix error behavior of custom oauth/saml provider in login page in big icon mode (#2900) 2024-04-26 23:33:41 +08:00
739cfd84ed feat: cannot empty SigninMethodTable now 2024-04-26 21:23:23 +08:00
20 changed files with 297 additions and 70 deletions

View File

@ -295,7 +295,7 @@ func (c *ApiController) SendVerificationCode() {
vform.CountryCode = mfaProps.CountryCode
}
provider, err = application.GetSmsProvider(vform.Method)
provider, err = application.GetSmsProvider(vform.Method, vform.CountryCode)
if err != nil {
c.ResponseError(err.Error())
return

4
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/beego/beego v1.12.12
github.com/beevik/etree v1.1.0
github.com/casbin/casbin/v2 v2.77.2
github.com/casdoor/go-sms-sender v0.20.0
github.com/casdoor/go-sms-sender v0.22.0
github.com/casdoor/gomail/v2 v2.0.1
github.com/casdoor/notify v0.45.0
github.com/casdoor/oss v1.6.0
@ -45,7 +45,7 @@ require (
github.com/robfig/cron/v3 v3.0.1
github.com/russellhaering/gosaml2 v0.9.0
github.com/russellhaering/goxmldsig v1.2.0
github.com/sendgrid/sendgrid-go v3.14.0+incompatible // indirect
github.com/sendgrid/sendgrid-go v3.14.0+incompatible
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed

4
go.sum
View File

@ -1083,8 +1083,8 @@ github.com/casbin/casbin/v2 v2.77.2 h1:yQinn/w9x8AswiwqwtrXz93VU48R1aYTXdHEx4RI3
github.com/casbin/casbin/v2 v2.77.2/go.mod h1:mzGx0hYW9/ksOSpw3wNjk3NRAroq5VMFYUQ6G43iGPk=
github.com/casdoor/go-reddit/v2 v2.1.0 h1:kIbfdJ7AA7H0uTQ8s0q4GGZqSS5V9wVE74RrXyD9XPs=
github.com/casdoor/go-reddit/v2 v2.1.0/go.mod h1:eagkvwlZ4Hcsuc/uQsLHYEulz5jN65SVSwV/AIE7zsc=
github.com/casdoor/go-sms-sender v0.20.0 h1:yLbCakV04DzzehhgBklOrSeCFjMwpfKBeemz9b+Y8OM=
github.com/casdoor/go-sms-sender v0.20.0/go.mod h1:cQs7qqohMJBgIVZebOCB8ko09naG1vzFJEH59VNIscs=
github.com/casdoor/go-sms-sender v0.22.0 h1:K4vj6IZgSESNvs8HchI5CIowvXHNpm7rXOV9QnCTZL4=
github.com/casdoor/go-sms-sender v0.22.0/go.mod h1:cQs7qqohMJBgIVZebOCB8ko09naG1vzFJEH59VNIscs=
github.com/casdoor/gomail/v2 v2.0.1 h1:J+FG6x80s9e5lBHUn8Sv0Y56mud34KiWih5YdmudR/w=
github.com/casdoor/gomail/v2 v2.0.1/go.mod h1:VnGPslEAtpix5FjHisR/WKB1qvZDBaujbikxDe9d+2Q=
github.com/casdoor/notify v0.45.0 h1:OlaFvcQFjGOgA4mRx07M8AH1gvb5xNo21mcqrVGlLgk=

View File

@ -670,11 +670,7 @@ func AddApplication(application *Application) (bool, error) {
return affected != 0, nil
}
func DeleteApplication(application *Application) (bool, error) {
if application.Name == "app-built-in" {
return false, nil
}
func deleteApplication(application *Application) (bool, error) {
affected, err := ormer.Engine.ID(core.PK{application.Owner, application.Name}).Delete(&Application{})
if err != nil {
return false, err
@ -683,6 +679,14 @@ func DeleteApplication(application *Application) (bool, error) {
return affected != 0, nil
}
func DeleteApplication(application *Application) (bool, error) {
if application.Name == "app-built-in" {
return false, nil
}
return deleteApplication(application)
}
func (application *Application) GetId() string {
return fmt.Sprintf("%s/%s", application.Owner, application.Name)
}

View File

@ -38,7 +38,20 @@ func (application *Application) GetProviderByCategory(category string) (*Provide
return nil, nil
}
func (application *Application) GetProviderByCategoryAndRule(category string, method string) (*Provider, error) {
func isProviderItemCountryCodeMatched(providerItem *ProviderItem, countryCode string) bool {
if len(providerItem.CountryCodes) == 0 {
return true
}
for _, countryCode2 := range providerItem.CountryCodes {
if countryCode2 == "" || countryCode2 == "All" || countryCode2 == "all" || countryCode2 == countryCode {
return true
}
}
return false
}
func (application *Application) GetProviderByCategoryAndRule(category string, method string, countryCode string) (*Provider, error) {
providers, err := GetProviders(application.Organization)
if err != nil {
return nil, err
@ -54,7 +67,13 @@ func (application *Application) GetProviderByCategoryAndRule(category string, me
}
for _, providerItem := range application.Providers {
if providerItem.Rule == method || (providerItem.Rule == "all" || providerItem.Rule == "" || providerItem.Rule == "None") {
if providerItem.Provider != nil && providerItem.Provider.Category == "SMS" {
if !isProviderItemCountryCodeMatched(providerItem, countryCode) {
continue
}
}
if providerItem.Rule == method || providerItem.Rule == "" || providerItem.Rule == "All" || providerItem.Rule == "all" || providerItem.Rule == "None" {
if provider, ok := m[providerItem.Name]; ok {
return provider, nil
}
@ -65,11 +84,11 @@ func (application *Application) GetProviderByCategoryAndRule(category string, me
}
func (application *Application) GetEmailProvider(method string) (*Provider, error) {
return application.GetProviderByCategoryAndRule("Email", method)
return application.GetProviderByCategoryAndRule("Email", method, "All")
}
func (application *Application) GetSmsProvider(method string) (*Provider, error) {
return application.GetProviderByCategoryAndRule("SMS", method)
func (application *Application) GetSmsProvider(method string, countryCode string) (*Provider, error) {
return application.GetProviderByCategoryAndRule("SMS", method, countryCode)
}
func (application *Application) GetStorageProvider() (*Provider, error) {

View File

@ -409,7 +409,7 @@ func initBuiltInPermission() {
Groups: []string{},
Roles: []string{},
Domains: []string{},
Model: "model-built-in",
Model: "user-model-built-in",
Adapter: "",
ResourceType: "Application",
Resources: []string{"app-built-in"},

View File

@ -266,7 +266,13 @@ func initDefinedOrganization(organization *Organization) {
}
if existed != nil {
return
affected, err := deleteOrganization(organization)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete organization")
}
}
organization.CreatedTime = util.GetCurrentTime()
organization.AccountItems = getBuiltInAccountItems()
@ -284,7 +290,13 @@ func initDefinedApplication(application *Application) {
}
if existed != nil {
return
affected, err := deleteApplication(application)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete application")
}
}
application.CreatedTime = util.GetCurrentTime()
_, err = AddApplication(application)
@ -299,7 +311,13 @@ func initDefinedUser(user *User) {
panic(err)
}
if existed != nil {
return
affected, err := DeleteUser(user)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete user")
}
}
user.CreatedTime = util.GetCurrentTime()
user.Id = util.GenerateId()
@ -319,7 +337,13 @@ func initDefinedCert(cert *Cert) {
}
if existed != nil {
return
affected, err := DeleteCert(cert)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete cert")
}
}
cert.CreatedTime = util.GetCurrentTime()
_, err = AddCert(cert)
@ -335,7 +359,13 @@ func initDefinedLdap(ldap *Ldap) {
}
if existed != nil {
return
affected, err := DeleteLdap(ldap)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete ldap")
}
}
_, err = AddLdap(ldap)
if err != nil {
@ -350,7 +380,13 @@ func initDefinedProvider(provider *Provider) {
}
if existed != nil {
return
affected, err := DeleteProvider(provider)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete provider")
}
}
_, err = AddProvider(provider)
if err != nil {
@ -365,7 +401,13 @@ func initDefinedModel(model *Model) {
}
if existed != nil {
return
affected, err := DeleteModel(model)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete provider")
}
}
model.CreatedTime = util.GetCurrentTime()
_, err = AddModel(model)
@ -381,7 +423,13 @@ func initDefinedPermission(permission *Permission) {
}
if existed != nil {
return
affected, err := DeletePermission(permission)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete permission")
}
}
permission.CreatedTime = util.GetCurrentTime()
_, err = AddPermission(permission)
@ -397,7 +445,13 @@ func initDefinedPayment(payment *Payment) {
}
if existed != nil {
return
affected, err := DeletePayment(payment)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete payment")
}
}
payment.CreatedTime = util.GetCurrentTime()
_, err = AddPayment(payment)
@ -413,7 +467,13 @@ func initDefinedProduct(product *Product) {
}
if existed != nil {
return
affected, err := DeleteProduct(product)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete product")
}
}
product.CreatedTime = util.GetCurrentTime()
_, err = AddProduct(product)
@ -429,7 +489,13 @@ func initDefinedResource(resource *Resource) {
}
if existed != nil {
return
affected, err := DeleteResource(resource)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete resource")
}
}
resource.CreatedTime = util.GetCurrentTime()
_, err = AddResource(resource)
@ -445,7 +511,13 @@ func initDefinedRole(role *Role) {
}
if existed != nil {
return
affected, err := DeleteRole(role)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete role")
}
}
role.CreatedTime = util.GetCurrentTime()
_, err = AddRole(role)
@ -461,7 +533,13 @@ func initDefinedSyncer(syncer *Syncer) {
}
if existed != nil {
return
affected, err := DeleteSyncer(syncer)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete role")
}
}
syncer.CreatedTime = util.GetCurrentTime()
_, err = AddSyncer(syncer)
@ -477,7 +555,13 @@ func initDefinedToken(token *Token) {
}
if existed != nil {
return
affected, err := DeleteToken(token)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete token")
}
}
token.CreatedTime = util.GetCurrentTime()
_, err = AddToken(token)
@ -493,7 +577,13 @@ func initDefinedWebhook(webhook *Webhook) {
}
if existed != nil {
return
affected, err := DeleteWebhook(webhook)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete webhook")
}
}
webhook.CreatedTime = util.GetCurrentTime()
_, err = AddWebhook(webhook)
@ -508,7 +598,13 @@ func initDefinedGroup(group *Group) {
panic(err)
}
if existed != nil {
return
affected, err := DeleteGroup(group)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete group")
}
}
group.CreatedTime = util.GetCurrentTime()
_, err = AddGroup(group)
@ -523,7 +619,13 @@ func initDefinedAdapter(adapter *Adapter) {
panic(err)
}
if existed != nil {
return
affected, err := DeleteAdapter(adapter)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete adapter")
}
}
adapter.CreatedTime = util.GetCurrentTime()
_, err = AddAdapter(adapter)
@ -538,7 +640,13 @@ func initDefinedEnforcer(enforcer *Enforcer) {
panic(err)
}
if existed != nil {
return
affected, err := DeleteEnforcer(enforcer)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete enforcer")
}
}
enforcer.CreatedTime = util.GetCurrentTime()
_, err = AddEnforcer(enforcer)
@ -553,7 +661,13 @@ func initDefinedPlan(plan *Plan) {
panic(err)
}
if existed != nil {
return
affected, err := DeletePlan(plan)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete enforcer")
}
}
plan.CreatedTime = util.GetCurrentTime()
_, err = AddPlan(plan)
@ -568,7 +682,13 @@ func initDefinedPricing(pricing *Pricing) {
panic(err)
}
if existed != nil {
return
affected, err := DeletePricing(pricing)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete pricing")
}
}
pricing.CreatedTime = util.GetCurrentTime()
_, err = AddPricing(pricing)
@ -583,7 +703,13 @@ func initDefinedInvitation(invitation *Invitation) {
panic(err)
}
if existed != nil {
return
affected, err := DeleteInvitation(invitation)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete invitation")
}
}
invitation.CreatedTime = util.GetCurrentTime()
_, err = AddInvitation(invitation, "en")
@ -611,7 +737,13 @@ func initDefinedSubscription(subscription *Subscription) {
panic(err)
}
if existed != nil {
return
affected, err := DeleteSubscription(subscription)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete subscription")
}
}
subscription.CreatedTime = util.GetCurrentTime()
_, err = AddSubscription(subscription)
@ -626,7 +758,13 @@ func initDefinedTransaction(transaction *Transaction) {
panic(err)
}
if existed != nil {
return
affected, err := DeleteTransaction(transaction)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete transaction")
}
}
transaction.CreatedTime = util.GetCurrentTime()
_, err = AddTransaction(transaction)

View File

@ -241,11 +241,7 @@ func AddOrganization(organization *Organization) (bool, error) {
return affected != 0, nil
}
func DeleteOrganization(organization *Organization) (bool, error) {
if organization.Name == "built-in" {
return false, nil
}
func deleteOrganization(organization *Organization) (bool, error) {
affected, err := ormer.Engine.ID(core.PK{organization.Owner, organization.Name}).Delete(&Organization{})
if err != nil {
return false, err
@ -254,6 +250,14 @@ func DeleteOrganization(organization *Organization) (bool, error) {
return affected != 0, nil
}
func DeleteOrganization(organization *Organization) (bool, error) {
if organization.Name == "built-in" {
return false, nil
}
return deleteOrganization(organization)
}
func GetOrganizationByUser(user *User) (*Organization, error) {
if user == nil {
return nil, nil

View File

@ -18,13 +18,14 @@ type ProviderItem struct {
Owner string `json:"owner"`
Name string `json:"name"`
CanSignUp bool `json:"canSignUp"`
CanSignIn bool `json:"canSignIn"`
CanUnlink bool `json:"canUnlink"`
Prompted bool `json:"prompted"`
SignupGroup string `json:"signupGroup"`
Rule string `json:"rule"`
Provider *Provider `json:"provider"`
CanSignUp bool `json:"canSignUp"`
CanSignIn bool `json:"canSignIn"`
CanUnlink bool `json:"canUnlink"`
CountryCodes []string `json:"countryCodes"`
Prompted bool `json:"prompted"`
SignupGroup string `json:"signupGroup"`
Rule string `json:"rule"`
Provider *Provider `json:"provider"`
}
func (application *Application) GetProviderItem(providerName string) *ProviderItem {

View File

@ -17,6 +17,7 @@ package object
import (
"encoding/json"
"fmt"
"regexp"
"strings"
"github.com/beego/beego/context"
@ -25,10 +26,14 @@ import (
"github.com/casvisor/casvisor-go-sdk/casvisorsdk"
)
var logPostOnly bool
var (
logPostOnly bool
passwordRegex *regexp.Regexp
)
func init() {
logPostOnly = conf.GetConfigBool("logPostOnly")
passwordRegex = regexp.MustCompile("\"password\":\".+\"")
}
type Record struct {
@ -40,6 +45,10 @@ type Response struct {
Msg string `json:"msg"`
}
func maskPassword(recordString string) string {
return passwordRegex.ReplaceAllString(recordString, "\"password\":\"***\"")
}
func NewRecord(ctx *context.Context) (*casvisorsdk.Record, error) {
ip := strings.Replace(util.GetIPFromRequest(ctx.Request), ": ", "", -1)
action := strings.Replace(ctx.Request.URL.Path, "/api/", "", -1)
@ -51,6 +60,7 @@ func NewRecord(ctx *context.Context) (*casvisorsdk.Record, error) {
object := ""
if ctx.Input.RequestBody != nil && len(ctx.Input.RequestBody) != 0 {
object = string(ctx.Input.RequestBody)
object = maskPassword(object)
}
respBytes, err := json.Marshal(ctx.Input.Data()["json"])
@ -99,6 +109,8 @@ func AddRecord(record *casvisorsdk.Record) bool {
record.Owner = record.Organization
record.Object = maskPassword(record.Object)
errWebhook := SendWebhooks(record)
if errWebhook == nil {
record.IsTriggered = true

View File

@ -48,7 +48,7 @@ func SendSms(provider *Provider, content string, phoneNumbers ...string) error {
if provider.AppId != "" {
phoneNumbers = append([]string{provider.AppId}, phoneNumbers...)
}
} else if provider.Type == sender.Aliyun {
} else if provider.Type == sender.Aliyun || provider.Type == sender.SendCloud {
for i, number := range phoneNumbers {
phoneNumbers[i] = strings.TrimPrefix(number, "+86")
}

View File

@ -59,7 +59,7 @@ func fastAutoSignin(ctx *context.Context) (string, error) {
scope := ctx.Input.Query("scope")
state := ctx.Input.Query("state")
nonce := ""
codeChallenge := ""
codeChallenge := ctx.Input.Query("code_challenge")
if clientId == "" || responseType != "code" || redirectUri == "" {
return "", nil
}

View File

@ -41,7 +41,7 @@ class ProductEditPage extends React.Component {
UNSAFE_componentWillMount() {
this.getProduct();
this.getOrganizations();
this.getPaymentProviders();
this.getPaymentProviders(this.state.organizationName);
}
getProduct() {
@ -67,8 +67,8 @@ class ProductEditPage extends React.Component {
});
}
getPaymentProviders() {
ProviderBackend.getProviders(this.props.account.owner)
getPaymentProviders(organizationName) {
ProviderBackend.getProviders(organizationName)
.then((res) => {
if (res.status === "ok") {
this.setState({

View File

@ -209,6 +209,8 @@ class ProviderEditPage extends React.Component {
return Setting.getLabel(i18next.t("provider:Public key"), i18next.t("provider:Public key - Tooltip"));
} else if (provider.type === "Msg91 SMS" || provider.type === "Infobip SMS" || provider.type === "OSON SMS") {
return Setting.getLabel(i18next.t("provider:Sender Id"), i18next.t("provider:Sender Id - Tooltip"));
} else if (provider.type === "SendCloud SMS") {
return "SMS_USER";
} else {
return Setting.getLabel(i18next.t("provider:Client ID"), i18next.t("provider:Client ID - Tooltip"));
}
@ -260,6 +262,8 @@ class ProviderEditPage extends React.Component {
return Setting.getLabel(i18next.t("provider:Auth Key"), i18next.t("provider:Auth Key - Tooltip"));
} else if (provider.type === "Infobip SMS") {
return Setting.getLabel(i18next.t("provider:Api Key"), i18next.t("provider:Api Key - Tooltip"));
} else if (provider.type === "SendCloud SMS") {
return "SMS_KEY";
} else {
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip"));
}
@ -1089,7 +1093,7 @@ class ProviderEditPage extends React.Component {
</React.Fragment>
) : this.state.provider.category === "SMS" ? (
<React.Fragment>
{["Custom HTTP SMS", "Twilio SMS", "Amazon SNS", "Azure ACS", "Msg91 SMS", "Infobip SMS"].includes(this.state.provider.type) ?
{["Custom HTTP SMS", "Twilio SMS", "Amazon SNS", "Azure ACS", "Msg91 SMS", "Infobip SMS", "SendCloud SMS"].includes(this.state.provider.type) ?
null :
(<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>

View File

@ -139,6 +139,10 @@ export const OtherProviderInfo = {
logo: `${StaticBaseUrl}/img/social_twilio.svg`,
url: "https://www.twilio.com/messaging",
},
"SendCloud SMS": {
logo: `${StaticBaseUrl}/img/sms_sendcloud.png`,
url: "https://www.sendcloud.net/",
},
"SmsBao SMS": {
logo: `${StaticBaseUrl}/img/social_smsbao.png`,
url: "https://www.smsbao.com/",
@ -1039,6 +1043,7 @@ export function getProviderTypeOptions(category) {
{id: "Huawei Cloud SMS", name: "Huawei Cloud SMS"},
{id: "UCloud SMS", name: "UCloud SMS"},
{id: "Twilio SMS", name: "Twilio SMS"},
{id: "SendCloud SMS", name: "SendCloud SMS"},
{id: "SmsBao SMS", name: "SmsBao SMS"},
{id: "SUBMAIL SMS", name: "SUBMAIL SMS"},
{id: "Msg91 SMS", name: "Msg91 SMS"},

View File

@ -840,7 +840,7 @@ class LoginPage extends React.Component {
{application.displayName}
</span>
</a>
:
:
</div>
<br />
{

View File

@ -172,23 +172,23 @@ export function renderProviderLogo(provider, application, width, margin, size, l
const customAStyle = {display: "block", height: "55px", color: "#000"};
const customButtonStyle = {display: "flex", alignItems: "center", width: "calc(100% - 10px)", height: "50px", margin: "5px", padding: "0 10px", backgroundColor: "transparent", boxShadow: "0px 1px 3px rgba(0,0,0,0.5)", border: "0px", borderRadius: "3px", cursor: "pointer"};
const customImgStyle = {justfyContent: "space-between"};
const customSpanStyle = {textAlign: "center", lineHeight: "50px", width: "100%", fontSize: "19px"};
const customSpanStyle = {textAlign: "center", width: "100%", fontSize: "19px"};
if (provider.category === "OAuth") {
return (
<a key={provider.displayName} href={Provider.getAuthUrl(application, provider, "signup")} style={customAStyle}>
<button style={customButtonStyle}>
<div style={customButtonStyle}>
<img width={26} src={getProviderLogoURL(provider)} alt={provider.displayName} className="provider-img" style={customImgStyle} />
<span style={customSpanStyle}>{text}</span>
</button>
</div>
</a>
);
} else if (provider.category === "SAML") {
return (
<a key={provider.displayName} onClick={() => goToSamlUrl(provider, location)} style={customAStyle}>
<button style={customButtonStyle}>
<div style={customButtonStyle}>
<img width={26} src={getProviderLogoURL(provider)} alt={provider.displayName} className="provider-img" style={customImgStyle} />
<span style={customSpanStyle}>{text}</span>
</button>
</div>
</a>
);
}

View File

@ -13,11 +13,14 @@
// limitations under the License.
import {Select} from "antd";
import i18next from "i18next";
import * as Setting from "../../Setting";
import React from "react";
const {Option} = Select;
export const CountryCodeSelect = (props) => {
const {onChange, style, disabled, initValue} = props;
const {onChange, style, disabled, initValue, mode} = props;
const countryCodes = props.countryCodes ?? [];
const [value, setValue] = React.useState("");
@ -42,11 +45,19 @@ export const CountryCodeSelect = (props) => {
style={style}
disabled={disabled}
value={value}
mode={mode}
dropdownMatchSelectWidth={false}
optionLabelProp={"label"}
onChange={handleOnChange}
filterOption={(input, option) => (option?.text ?? "").toLowerCase().includes(input.toLowerCase())}
>
{
props.hasDefault ? (<Option key={"All"} value={"All"} label={i18next.t("organization:All")} text={"organization:All"} >
<div style={{display: "flex", justifyContent: "space-between", marginRight: "10px"}}>
{i18next.t("organization:All")}
</div>
</Option>) : null
}
{
Setting.getCountryCodeData(countryCodes).map((country) => Setting.getCountryCodeOption(country))
}

View File

@ -15,6 +15,7 @@
import React from "react";
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Input, Row, Select, Switch, Table, Tooltip} from "antd";
import {CountryCodeSelect} from "../common/select/CountryCodeSelect";
import * as Setting from "../Setting";
import i18next from "i18next";
import * as Provider from "../auth/Provider";
@ -29,6 +30,10 @@ class ProviderTable extends React.Component {
};
}
getUserOrganization() {
return this.props.application?.organizationObj;
}
updateTable(table) {
this.props.onUpdateTable(table);
}
@ -79,7 +84,7 @@ class ProviderTable extends React.Component {
// If the provider is email or SMS, set the rule to "all" instead of the default "None"
if (provider.category === "Email" || provider.category === "SMS") {
this.updateField(table, index, "rule", "all");
this.updateField(table, index, "rule", "All");
}
}} >
{
@ -109,6 +114,30 @@ class ProviderTable extends React.Component {
return Provider.getProviderLogoWidget(provider);
},
},
{
title: i18next.t("user:Country/Region"),
dataIndex: "countryCodes",
key: "countryCodes",
width: "140px",
render: (text, record, index) => {
if (record.provider?.category !== "SMS") {
return null;
}
return (
<CountryCodeSelect
style={{width: "100%"}}
hasDefault={true}
mode={"multiple"}
initValue={text ? text : ["All"]}
onChange={(value) => {
this.updateField(table, index, "countryCodes", value);
}}
countryCodes={this.getUserOrganization()?.countryCodes}
/>
);
},
},
{
title: i18next.t("provider:Can signup"),
dataIndex: "canSignUp",
@ -198,7 +227,7 @@ class ProviderTable extends React.Component {
title: i18next.t("application:Rule"),
dataIndex: "rule",
key: "rule",
width: "120px",
width: "160px",
render: (text, record, index) => {
if (record.provider?.type === "Google") {
if (text === "None") {
@ -230,12 +259,12 @@ class ProviderTable extends React.Component {
);
} else if (record.provider?.category === "SMS" || record.provider?.category === "Email") {
if (text === "None") {
text = "all";
text = "All";
}
return (
<Select virtual={false} style={{width: "100%"}}
value={text}
defaultValue="all"
defaultValue="All"
onChange={value => {
this.updateField(table, index, "rule", value);
}}>

View File

@ -164,7 +164,7 @@ class SigninMethodTable extends React.Component {
<Button style={{marginRight: "5px"}} disabled={index === table.length - 1} icon={<DownOutlined />} size="small" onClick={() => this.downRow(table, index)} />
</Tooltip>
<Tooltip placement="topLeft" title={i18next.t("general:Delete")}>
<Button icon={<DeleteOutlined />} size="small" onClick={() => this.deleteRow(items, table, index)} />
<Button disabled={table.length <= 1} icon={<DeleteOutlined />} size="small" onClick={() => this.deleteRow(items, table, index)} />
</Tooltip>
</div>
);