mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-04 13:20:19 +08:00
feat: support multiple country codes for sending SMS (#1557)
* feat: support multiple country code * feat: improve UI * feat: migrate accountItem * fix: Aliyun compatible * fix: phone validate * fix: typo
This commit is contained in:
@ -42,7 +42,7 @@ func init() {
|
||||
reFieldWhiteList, _ = regexp.Compile(`^[A-Za-z0-9]+$`)
|
||||
}
|
||||
|
||||
func CheckUserSignup(application *Application, organization *Organization, username string, password string, displayName string, firstName string, lastName string, email string, phone string, affiliation string, lang string) string {
|
||||
func CheckUserSignup(application *Application, organization *Organization, username string, password string, displayName string, firstName string, lastName string, email string, phone string, countryCode string, affiliation string, lang string) string {
|
||||
if organization == nil {
|
||||
return i18n.Translate(lang, "check:Organization does not exist")
|
||||
}
|
||||
@ -107,7 +107,9 @@ func CheckUserSignup(application *Application, organization *Organization, usern
|
||||
|
||||
if HasUserByField(organization.Name, "phone", phone) {
|
||||
return i18n.Translate(lang, "check:Phone already exists")
|
||||
} else if organization.PhonePrefix == "86" && !util.IsPhoneCnValid(phone) {
|
||||
} else if !util.IsPhoneAllowInRegin(countryCode, organization.CountryCodes) {
|
||||
return i18n.Translate(lang, "check:Your region is not allow to signup by phone")
|
||||
} else if !util.IsPhoneValid(phone, countryCode) {
|
||||
return i18n.Translate(lang, "check:Phone number is invalid")
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ func initBuiltInOrganization() bool {
|
||||
WebsiteUrl: "https://example.com",
|
||||
Favicon: fmt.Sprintf("%s/img/casbin/favicon.ico", conf.GetConfigString("staticBaseUrl")),
|
||||
PasswordType: "plain",
|
||||
PhonePrefix: "86",
|
||||
CountryCodes: []string{"CN"},
|
||||
DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
|
||||
Tags: []string{},
|
||||
Languages: []string{"en", "zh", "es", "fr", "de", "ja", "ko", "ru"},
|
||||
@ -68,6 +68,7 @@ func initBuiltInOrganization() bool {
|
||||
{Name: "Password", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Email", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Phone", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "CountryCode", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Country/Region", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Location", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Affiliation", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
@ -109,6 +110,7 @@ func initBuiltInUser() {
|
||||
Avatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
|
||||
Email: "admin@example.com",
|
||||
Phone: "12345678910",
|
||||
CountryCode: "CN",
|
||||
Address: []string{},
|
||||
Affiliation: "Example Inc.",
|
||||
Tag: "staff",
|
||||
|
@ -189,6 +189,7 @@ func initDefinedOrganization(organization *Organization) {
|
||||
{Name: "Password", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Email", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Phone", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "CountryCode", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Country/Region", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Location", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Affiliation", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
|
@ -26,6 +26,7 @@ func DoMigration() {
|
||||
&Migrator_1_101_0_PR_1083{},
|
||||
&Migrator_1_235_0_PR_1530{},
|
||||
&Migrator_1_240_0_PR_1539{},
|
||||
&Migrator_1_245_0_PR_1557{},
|
||||
// more migrators add here in chronological order...
|
||||
}
|
||||
|
||||
|
92
object/migrator_1_245_0_PR_1557.go
Normal file
92
object/migrator_1_245_0_PR_1557.go
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/nyaruka/phonenumbers"
|
||||
"github.com/xorm-io/xorm"
|
||||
"github.com/xorm-io/xorm/migrate"
|
||||
)
|
||||
|
||||
type Migrator_1_245_0_PR_1557 struct{}
|
||||
|
||||
func (*Migrator_1_245_0_PR_1557) IsMigrationNeeded() bool {
|
||||
exist, _ := adapter.Engine.IsTableExist("organization")
|
||||
|
||||
if exist {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (*Migrator_1_245_0_PR_1557) DoMigration() *migrate.Migration {
|
||||
migration := migrate.Migration{
|
||||
ID: "20230215organization--transfer phonePrefix to defaultCountryCode, countryCodes",
|
||||
Migrate: func(engine *xorm.Engine) error {
|
||||
organizations := []*Organization{}
|
||||
err := engine.Table("organization").Find(&organizations, &Organization{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, organization := range organizations {
|
||||
organization.AccountItems = []*AccountItem{
|
||||
{Name: "Organization", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "ID", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
|
||||
{Name: "Name", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Display name", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Avatar", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "User type", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Password", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Email", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Phone", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "CountryCode", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Country/Region", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Location", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Affiliation", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Title", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Homepage", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Bio", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Tag", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Signup application", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Roles", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
|
||||
{Name: "Permissions", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
|
||||
{Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Properties", Visible: false, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "Is global admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "WebAuthn credentials", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Managed accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
}
|
||||
|
||||
sql := fmt.Sprintf("select phone_prefix from organization where owner='%s' and name='%s'", organization.Owner, organization.Name)
|
||||
results, _ := engine.Query(sql)
|
||||
|
||||
phonePrefix := util.ParseInt(string(results[0]["phone_prefix"]))
|
||||
organization.CountryCodes = []string{phonenumbers.GetRegionCodeForCountryCode(phonePrefix)}
|
||||
|
||||
UpdateOrganization(util.GetId(organization.Owner, organization.Name), organization)
|
||||
}
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
return &migration
|
||||
}
|
@ -49,7 +49,7 @@ type Organization struct {
|
||||
Favicon string `xorm:"varchar(100)" json:"favicon"`
|
||||
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
|
||||
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
|
||||
PhonePrefix string `xorm:"varchar(10)" json:"phonePrefix"`
|
||||
CountryCodes []string `xorm:"varchar(200)" json:"countryCodes"`
|
||||
DefaultAvatar string `xorm:"varchar(100)" json:"defaultAvatar"`
|
||||
DefaultApplication string `xorm:"varchar(100)" json:"defaultApplication"`
|
||||
Tags []string `xorm:"mediumtext" json:"tags"`
|
||||
|
@ -14,7 +14,11 @@
|
||||
|
||||
package object
|
||||
|
||||
import "github.com/casdoor/go-sms-sender"
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/casdoor/go-sms-sender"
|
||||
)
|
||||
|
||||
func SendSms(provider *Provider, content string, phoneNumbers ...string) error {
|
||||
client, err := go_sms_sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.AppId)
|
||||
@ -25,6 +29,12 @@ func SendSms(provider *Provider, content string, phoneNumbers ...string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if provider.Type == go_sms_sender.Aliyun {
|
||||
for i, number := range phoneNumbers {
|
||||
phoneNumbers[i] = strings.TrimPrefix(number, "+")
|
||||
}
|
||||
}
|
||||
|
||||
params := map[string]string{}
|
||||
if provider.Type == go_sms_sender.TencentCloud {
|
||||
params["0"] = content
|
||||
|
@ -46,7 +46,8 @@ type User struct {
|
||||
PermanentAvatar string `xorm:"varchar(500)" json:"permanentAvatar"`
|
||||
Email string `xorm:"varchar(100) index" json:"email"`
|
||||
EmailVerified bool `json:"emailVerified"`
|
||||
Phone string `xorm:"varchar(100) index" json:"phone"`
|
||||
Phone string `xorm:"varchar(20) index" json:"phone"`
|
||||
CountryCode string `xorm:"varchar(6)" json:"countryCode"`
|
||||
Location string `xorm:"varchar(100)" json:"location"`
|
||||
Address []string `json:"address"`
|
||||
Affiliation string `xorm:"varchar(100)" json:"affiliation"`
|
||||
@ -454,7 +455,7 @@ func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) boo
|
||||
}
|
||||
}
|
||||
if isGlobalAdmin {
|
||||
columns = append(columns, "name", "email", "phone")
|
||||
columns = append(columns, "name", "email", "phone", "country_code")
|
||||
}
|
||||
|
||||
affected, err := adapter.Engine.ID(core.PK{owner, name}).Cols(columns...).Update(user)
|
||||
|
@ -170,3 +170,18 @@ func ClearUserOAuthProperties(user *User, providerType string) bool {
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func (user *User) GetCountryCode(countryCode string) string {
|
||||
if countryCode != "" {
|
||||
return countryCode
|
||||
}
|
||||
|
||||
if user != nil && user.CountryCode != "" {
|
||||
return user.CountryCode
|
||||
}
|
||||
|
||||
if org := GetOrganizationByUser(user); org != nil && len(org.CountryCodes) > 0 {
|
||||
return org.CountryCodes[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
Reference in New Issue
Block a user