mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-29 03:51:54 +08:00
fix: notify receiver update precedure recode (#24099)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
@@ -16,6 +16,9 @@ package notify
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/cmd/climc/shell"
|
||||
identity_api "yunion.io/x/onecloud/pkg/apis/identity"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
identity_modules "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
|
||||
modules "yunion.io/x/onecloud/pkg/mcclient/modules/notify"
|
||||
options "yunion.io/x/onecloud/pkg/mcclient/options/notify"
|
||||
)
|
||||
@@ -36,4 +39,32 @@ func init() {
|
||||
cmd.PerformClass("get-types", new(options.ReceiverGetTypeOptions))
|
||||
cmd.Perform("get-subscription", new(options.ReceiverGetSubscriptionOptions))
|
||||
cmd.GetProperty(new(options.SReceiverRoleContactType))
|
||||
|
||||
type SyncUserContactOptions struct {
|
||||
USERID string `json:"user_id"`
|
||||
Mobile string `json:"mobile"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
R(&SyncUserContactOptions{}, "sync-user-contacts", "Sync user contact", func(s *mcclient.ClientSession, args *SyncUserContactOptions) error {
|
||||
userObj, err := identity_modules.UsersV3.Get(s, args.USERID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user := identity_api.UserDetails{}
|
||||
err = userObj.Unmarshal(&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(args.Mobile) == 0 {
|
||||
args.Mobile = user.Mobile
|
||||
}
|
||||
if len(args.Email) == 0 {
|
||||
args.Email = user.Email
|
||||
}
|
||||
err = modules.NotifyReceiver.SyncUserContact(s, user.Id, args.Mobile, args.Email)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/pkg/tristate"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
)
|
||||
|
||||
@@ -65,6 +67,9 @@ var (
|
||||
func ParseInternationalMobile(mobile string) SInternationalMobile {
|
||||
matchs := pareser.FindStringSubmatch(mobile)
|
||||
if len(matchs) == 0 {
|
||||
if len(mobile) == 0 {
|
||||
return SInternationalMobile{}
|
||||
}
|
||||
return SInternationalMobile{
|
||||
AreaCode: defaultAreaCode,
|
||||
Mobile: mobile,
|
||||
@@ -85,7 +90,7 @@ func (im *SInternationalMobile) AcceptExtMobile() {
|
||||
// 对传入的手机号去除地区编号
|
||||
func moveAreaCode(mobile string) string {
|
||||
// 所有地区编号
|
||||
allArea := `283|282|281|280|269|268|267|266|265|264|263|262|261|260|259|258|257|256|255|254|253|252|251|250|249|248|247|246|245|244|243|242|241|240|239|238|237|236|235|234|233|232|231|230|229|228|227|226|225|224|223|222|221|220|219|218|217|216|215|214|213|212|211|210|98|95|94|93|92|91|90|86|84|82|81|66|65|64|63|62|61|60|58|57|56|55|54|53|52|51|49|48|47|46|45|44|43|41|40|39|36|34|33|32|31|30|27|20|7|1`
|
||||
allArea := `852|283|282|281|280|269|268|267|266|265|264|263|262|261|260|259|258|257|256|255|254|253|252|251|250|249|248|247|246|245|244|243|242|241|240|239|238|237|236|235|234|233|232|231|230|229|228|227|226|225|224|223|222|221|220|219|218|217|216|215|214|213|212|211|210|98|95|94|93|92|91|90|86|84|82|81|66|65|64|63|62|61|60|58|57|56|55|54|53|52|51|49|48|47|46|45|44|43|41|40|39|36|34|33|32|31|30|27|20|7|1`
|
||||
temp := strings.Split(allArea, "|")
|
||||
for _, area := range temp {
|
||||
if strings.HasPrefix(mobile, "+"+area) {
|
||||
@@ -111,6 +116,9 @@ func moveExtStr(mobile string) string {
|
||||
}
|
||||
|
||||
func (im SInternationalMobile) String() string {
|
||||
if len(im.Mobile) == 0 {
|
||||
return ""
|
||||
}
|
||||
if im.AreaCode == "" {
|
||||
return im.Mobile
|
||||
}
|
||||
@@ -159,6 +167,17 @@ type ReceiverUpdateInput struct {
|
||||
// example: example@gmail.com
|
||||
Email string `json:"email"`
|
||||
|
||||
// swagger:ignore
|
||||
EnabledEmail tristate.TriState `json:"enabled_email"`
|
||||
// swagger:ignore
|
||||
VerifiedEmail tristate.TriState `json:"verified_email"`
|
||||
// swagger:ignore
|
||||
EnabledMobile tristate.TriState `json:"enabled_mobile"`
|
||||
// swagger:ignore
|
||||
VerifiedMobile tristate.TriState `json:"verified_mobile"`
|
||||
// swagger:ignore
|
||||
Mobile string `json:"mobile"`
|
||||
|
||||
InternationalMobile SInternationalMobile `json:"international_mobile"`
|
||||
|
||||
// description: enabled contacts for user
|
||||
|
||||
@@ -23,15 +23,15 @@ func TestMobileExt(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
SInternationalMobile{
|
||||
"+8612345678901",
|
||||
"+86",
|
||||
Mobile: "+8612345678901",
|
||||
AreaCode: "+86",
|
||||
},
|
||||
"12345678901",
|
||||
},
|
||||
{
|
||||
SInternationalMobile{
|
||||
"+8612345678901;ext=2",
|
||||
"+86",
|
||||
Mobile: "+8612345678901;ext=2",
|
||||
AreaCode: "+86",
|
||||
},
|
||||
"12345678901",
|
||||
},
|
||||
@@ -56,6 +56,20 @@ func TestMobileExt(t *testing.T) {
|
||||
},
|
||||
"12345678901",
|
||||
},
|
||||
{
|
||||
SInternationalMobile{
|
||||
"13811111111",
|
||||
"",
|
||||
},
|
||||
"13811111111",
|
||||
},
|
||||
{
|
||||
SInternationalMobile{
|
||||
"+85213811111111",
|
||||
"",
|
||||
},
|
||||
"13811111111",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
|
||||
@@ -15,16 +15,28 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/httputils"
|
||||
|
||||
notify_apis "yunion.io/x/onecloud/pkg/apis/notify"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
)
|
||||
|
||||
type ReceiverManager struct {
|
||||
modulebase.ResourceManager
|
||||
}
|
||||
|
||||
type ConfigsManager struct {
|
||||
modulebase.ResourceManager
|
||||
}
|
||||
|
||||
var (
|
||||
NotifyReceiver modulebase.ResourceManager
|
||||
NotifyReceiver ReceiverManager
|
||||
NotifyConfig modulebase.ResourceManager
|
||||
NotifyRobot modulebase.ResourceManager
|
||||
Notification modulebase.ResourceManager
|
||||
@@ -34,13 +46,72 @@ var (
|
||||
Configs ConfigsManager
|
||||
)
|
||||
|
||||
func (rm *ReceiverManager) SyncUserContact(s *mcclient.ClientSession, userId string, mobile string, email string) error {
|
||||
recv, err := rm.GetById(s, userId, nil)
|
||||
if err != nil {
|
||||
if httputils.ErrorCode(err) == 404 {
|
||||
// not created yet, do create
|
||||
newRecv := notify_apis.ReceiverCreateInput{
|
||||
UID: userId,
|
||||
}
|
||||
if len(mobile) > 0 {
|
||||
newRecv.InternationalMobile.Mobile = mobile
|
||||
newRecv.EnabledContactTypes = append(newRecv.EnabledContactTypes, "mobile")
|
||||
}
|
||||
if len(email) > 0 {
|
||||
newRecv.Email = email
|
||||
newRecv.EnabledContactTypes = append(newRecv.EnabledContactTypes, "email")
|
||||
}
|
||||
_, err := rm.Create(s, jsonutils.Marshal(newRecv))
|
||||
if err != nil {
|
||||
// create failed
|
||||
return errors.Wrap(err, "create receiver")
|
||||
}
|
||||
// success
|
||||
} else {
|
||||
return errors.Wrap(err, "GetById")
|
||||
}
|
||||
} else {
|
||||
// receiver exists
|
||||
fmt.Println("receiver exists", recv.String())
|
||||
recvObj := notify_apis.ReceiverDetails{}
|
||||
err := recv.Unmarshal(&recvObj)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unmarshal ReceiverDetails")
|
||||
}
|
||||
updateRecv := notify_apis.ReceiverUpdateInput{}
|
||||
changeMobile := false
|
||||
changeEmail := false
|
||||
if mobile != "" && recvObj.InternationalMobile.Mobile != mobile {
|
||||
updateRecv.InternationalMobile.Mobile = mobile
|
||||
updateRecv.EnabledContactTypes = append(updateRecv.EnabledContactTypes, "mobile")
|
||||
changeMobile = true
|
||||
}
|
||||
if email != "" && recvObj.Email != email {
|
||||
updateRecv.Email = email
|
||||
updateRecv.EnabledContactTypes = append(updateRecv.EnabledContactTypes, "email")
|
||||
changeEmail = true
|
||||
}
|
||||
if changeMobile || changeEmail {
|
||||
_, err = rm.Update(s, userId, jsonutils.Marshal(updateRecv))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "update receiver")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
NotifyReceiver = modules.NewNotifyv2Manager(
|
||||
"receiver",
|
||||
"receivers",
|
||||
[]string{"ID", "Name", "Domain_Id", "Project_Domain", "Email", "International_Mobile", "Enabled_Contact_Types", "Verified_Infos"},
|
||||
[]string{},
|
||||
)
|
||||
NotifyReceiver = ReceiverManager{
|
||||
ResourceManager: modules.NewNotifyv2Manager(
|
||||
"receiver",
|
||||
"receivers",
|
||||
[]string{"ID", "Name", "Domain_Id", "Project_Domain", "Email", "International_Mobile", "Enabled_Contact_Types", "Verified_Infos"},
|
||||
[]string{},
|
||||
),
|
||||
}
|
||||
modules.Register(&NotifyReceiver)
|
||||
|
||||
NotifyConfig = modules.NewNotifyv2Manager(
|
||||
|
||||
@@ -94,7 +94,7 @@ type SReceiver struct {
|
||||
|
||||
Email string `width:"128" nullable:"false" create:"optional" update:"user" get:"user" list:"user"`
|
||||
// swagger:ignore
|
||||
Mobile string `width:"32" nullable:"false" create:"optional"`
|
||||
Mobile string `width:"32" nullable:"false" create:"optional" update:"user"`
|
||||
Lang string `width:"8" charset:"ascii" nullable:"false" list:"user" update:"user"`
|
||||
|
||||
// swagger:ignore
|
||||
@@ -618,9 +618,34 @@ func (r *SReceiver) ValidateUpdateData(ctx context.Context, userCred mcclient.To
|
||||
return input, httperrors.NewInputParameterError("invalid email")
|
||||
}
|
||||
// validate mobile
|
||||
input.InternationalMobile.AcceptExtMobile()
|
||||
if ok := len(input.InternationalMobile.Mobile) == 0 || LaxMobileRegexp.MatchString(input.InternationalMobile.Mobile); !ok {
|
||||
return input, httperrors.NewInputParameterError("invalid mobile")
|
||||
if len(input.InternationalMobile.Mobile) > 0 {
|
||||
input.InternationalMobile.AcceptExtMobile()
|
||||
if ok := len(input.InternationalMobile.Mobile) == 0 || LaxMobileRegexp.MatchString(input.InternationalMobile.Mobile); !ok {
|
||||
return input, httperrors.NewInputParameterError("invalid mobile")
|
||||
}
|
||||
input.Mobile = input.InternationalMobile.String()
|
||||
} else {
|
||||
input.InternationalMobile.AreaCode = ""
|
||||
}
|
||||
if input.ForceVerified {
|
||||
allowScope, _ := policy.PolicyManager.AllowScope(userCred, api.SERVICE_TYPE, ReceiverManager.KeywordPlural(), policy.PolicyActionCreate)
|
||||
if allowScope != rbacscope.ScopeSystem {
|
||||
return input, httperrors.ErrNotSufficientPrivilege
|
||||
}
|
||||
}
|
||||
if len(input.Email) > 0 && input.Email != r.Email {
|
||||
if input.ForceVerified {
|
||||
r.VerifiedEmail = tristate.True
|
||||
} else {
|
||||
r.VerifiedEmail = tristate.False
|
||||
}
|
||||
}
|
||||
if len(input.Mobile) > 0 && input.Mobile != r.Mobile {
|
||||
if input.ForceVerified {
|
||||
r.VerifiedMobile = tristate.True
|
||||
} else {
|
||||
r.VerifiedMobile = tristate.False
|
||||
}
|
||||
}
|
||||
|
||||
for _, cType := range input.EnabledContactTypes {
|
||||
@@ -633,78 +658,29 @@ func (r *SReceiver) ValidateUpdateData(ctx context.Context, userCred mcclient.To
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (r *SReceiver) PreUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||||
r.SVirtualResourceBase.PreUpdate(ctx, userCred, query, data)
|
||||
originEmailEnable, originMobileEnable := r.EnabledEmail, r.EnabledMobile
|
||||
func (r *SReceiver) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||||
r.SVirtualResourceBase.PostUpdate(ctx, userCred, query, data)
|
||||
|
||||
var input api.ReceiverUpdateInput
|
||||
data.Unmarshal(&input)
|
||||
if len(input.Email) != 0 && input.Email != r.Email {
|
||||
db.Update(r, func() error {
|
||||
r.VerifiedEmail = tristate.False
|
||||
return nil
|
||||
})
|
||||
r.VerifiedEmail = tristate.False
|
||||
subs, _ := r.GetSubContacts()
|
||||
for i := range subs {
|
||||
if subs[i].ParentContactType == api.EMAIL {
|
||||
db.Update(&subs[i], func() error {
|
||||
subs[i].Verified = tristate.False
|
||||
subs[i].VerifiedNote = "email changed, re-verify"
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
mobile := input.InternationalMobile.String()
|
||||
if len(mobile) != 0 && mobile != r.Mobile {
|
||||
db.Update(r, func() error {
|
||||
r.VerifiedMobile = tristate.False
|
||||
return nil
|
||||
})
|
||||
subs, _ := r.GetSubContacts()
|
||||
for i := range subs {
|
||||
if subs[i].ParentContactType == api.MOBILE {
|
||||
db.Update(&subs[i], func() error {
|
||||
subs[i].Verified = tristate.False
|
||||
subs[i].VerifiedNote = "mobile changed, re-verify"
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 管理后台修改联系人,如果修改或者启用手机号和邮箱,无需进行校验
|
||||
if input.ForceVerified {
|
||||
allowScope, _ := policy.PolicyManager.AllowScope(userCred, api.SERVICE_TYPE, ReceiverManager.KeywordPlural(), policy.PolicyActionCreate)
|
||||
if allowScope == rbacscope.ScopeSystem {
|
||||
db.Update(r, func() error {
|
||||
// 修改并启用
|
||||
if len(input.Email) != 0 && input.Email != r.Email && r.EnabledEmail.Bool() {
|
||||
r.VerifiedEmail = tristate.True
|
||||
}
|
||||
if len(mobile) != 0 && mobile != r.Mobile && r.EnabledMobile.Bool() {
|
||||
r.VerifiedMobile = tristate.True
|
||||
}
|
||||
// 从禁用变启用
|
||||
if !originEmailEnable.Bool() && r.EnabledEmail.Bool() {
|
||||
r.VerifiedEmail = tristate.True
|
||||
}
|
||||
if !originMobileEnable.Bool() && r.EnabledMobile.Bool() {
|
||||
r.VerifiedMobile = tristate.True
|
||||
}
|
||||
subs, _ := r.GetSubContacts()
|
||||
for i := range subs {
|
||||
if subs[i].ParentContactType == api.EMAIL && subs[i].Verified.IsTrue() && r.VerifiedEmail.IsFalse() {
|
||||
db.Update(&subs[i], func() error {
|
||||
subs[i].Verified = tristate.False
|
||||
subs[i].VerifiedNote = "email changed, re-verify"
|
||||
return nil
|
||||
})
|
||||
} else if subs[i].ParentContactType == api.MOBILE && subs[i].Verified.IsTrue() && r.VerifiedMobile.IsFalse() {
|
||||
db.Update(&subs[i], func() error {
|
||||
subs[i].Verified = tristate.False
|
||||
subs[i].VerifiedNote = "mobile changed, re-verify"
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
r.Mobile = mobile
|
||||
err := ReceiverManager.TableSpec().InsertOrUpdate(ctx, r)
|
||||
if err != nil {
|
||||
log.Errorf("InsertOrUpdate: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *SReceiver) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||||
r.SVirtualResourceBase.PostUpdate(ctx, userCred, query, data)
|
||||
cTypes := jsonutils.GetQueryStringArray(data, "enabled_contact_types")
|
||||
err := r.StartSubcontactPullTask(ctx, userCred, cTypes, "")
|
||||
if err != nil {
|
||||
@@ -1080,7 +1056,6 @@ func (r *SReceiver) SetContact(cType string, contact string) error {
|
||||
r.Mobile = contact
|
||||
return nil
|
||||
})
|
||||
r.Mobile = contact
|
||||
default:
|
||||
subs, _ := r.GetSubContacts()
|
||||
for i := range subs {
|
||||
|
||||
@@ -80,8 +80,12 @@ func (self *SubcontactPullTask) OnInit(ctx context.Context, obj db.IStandaloneMo
|
||||
// sync email and mobile to keystone
|
||||
s := auth.GetSession(ctx, self.UserCred, "")
|
||||
mobile := receiver.Mobile
|
||||
if strings.HasPrefix(mobile, "+86 ") {
|
||||
mobile = strings.TrimSpace(mobile[4:])
|
||||
if strings.HasPrefix(mobile, "+") {
|
||||
spaceIdx := strings.Index(mobile, " ")
|
||||
if spaceIdx > 0 {
|
||||
mobile = mobile[spaceIdx+1:]
|
||||
}
|
||||
mobile = strings.TrimSpace(mobile)
|
||||
}
|
||||
params := map[string]string{
|
||||
"email": receiver.Email,
|
||||
|
||||
Reference in New Issue
Block a user