diff --git a/cmd/climc/shell/contacts.go b/cmd/climc/shell/contacts.go index 2958627ad9..1f4d6ab522 100644 --- a/cmd/climc/shell/contacts.go +++ b/cmd/climc/shell/contacts.go @@ -29,11 +29,11 @@ func init() { * 操作用户的通信地址(如果用户的通信地址不存在则进行添加;如果已存在则进行修改;如果设置空则进行删除。) */ type ContactsUpdateOptions struct { - UID string `help:"The user you wanna add contact to (Keystone User ID)"` - CONTACTTYPE string `help:"The contact type email|mobile" choices:"email|mobile|dingtalk"` - CONTACT string `help:"The contacts details mobile number or email address or dingtalk's userid, if set it the empty str means delete"` - Status string `help:"Enabled or disabled contact status" choices:"enable|disable"` - UpdateDingtalk bool `help:"if update dingtalk"` + UID string `help:"The user you wanna add contact to (Keystone User ID)"` + CONTACTTYPE string `help:"The contact type email|mobile" choices:"email|mobile|dingtalk"` + CONTACT string `help:"The contacts details mobile number or email address or dingtalk's userid, if set it the empty str means delete"` + Status string `help:"Enabled or disabled contact status" choices:"enable|disable"` + Pull string `help:"pull some subcontacts(e.g., dingtalk, feishu, etc) related to mobile"` } R(&ContactsUpdateOptions{}, "contact-update", "Create, delete or update contact for user", func(s *mcclient.ClientSession, args *ContactsUpdateOptions) error { arr := jsonutils.NewArray() @@ -52,12 +52,8 @@ func init() { params := jsonutils.NewDict() params.Add(arr, "contacts") - if args.UpdateDingtalk { - params.Add(jsonutils.JSONTrue, "update_dingtalk") - } - - contact, err := modules.Contacts.CustomizedPerformAction(s, args.UID, "update-contact", params) + contact, err := modules.Contacts.CustomizedPerformAction(s, args.UID, "update-contact", args.Pull, params) if err != nil { return err } @@ -66,6 +62,21 @@ func init() { return nil }) + type ContactsPullOptions struct { + UID string `help:"The user you wanna pull contact"` + CONTACTTYPE string `help:"The contact type"` + } + R(&ContactsPullOptions{}, "contact-pull", "Pull contact", func(s *mcclient.ClientSession, args *ContactsPullOptions) error { + params := jsonutils.NewDict() + params.Set("contacts", jsonutils.NewArray()) + contact, err := modules.Contacts.CustomizedPerformAction(s, args.UID, "update-contact", args.CONTACTTYPE, params) + if err != nil { + return err + } + printObject(contact) + return nil + }) + type ContactsDeleteOptions struct { UID string `help:"The user you wanna add contact to (Keystone User ID)"` CONTACTTYPE string `help:"The contact type email|mobile|dingtalk" choices:"email|mobile|dingtalk"` @@ -78,7 +89,7 @@ func init() { arr.Add(tmpObj) params := jsonutils.NewDict() params.Add(arr, "contacts") - contact, err := modules.Contacts.CustomizedPerformAction(s, args.UID, "update-contact", params) + contact, err := modules.Contacts.CustomizedPerformAction(s, args.UID, "update-contact", "", params) if err != nil { return err } @@ -169,7 +180,7 @@ func init() { tmpDict := jsonutils.NewDict() tmpDict.Add(jsonutils.NewString(args.CONTACT_TYPE), "contact_type") tmpDict.Add(jsonutils.NewString(args.CONTACT), "contact") - _, err := modules.Contacts.CustomizedPerformAction(s, args.UID, "verify", tmpDict) + _, err := modules.Contacts.CustomizedPerformAction(s, args.UID, "verify", "", tmpDict) if err != nil { return err } diff --git a/cmd/climc/shell/notification.go b/cmd/climc/shell/notification.go index 39285ec0cb..15f375d393 100644 --- a/cmd/climc/shell/notification.go +++ b/cmd/climc/shell/notification.go @@ -29,7 +29,7 @@ func init() { */ type NotificationCreateOptions struct { - CONTACTTYPE string `help:"User's contacts type" choices:"email|mobile|dingtalk|webconsole"` + CONTACTTYPE string `help:"User's contacts type"` TOPIC string `help:"Title or topic of the notification"` PRIORITY string `help:"Priority of the notification" choices:"normal|important|fatal"` MSG string `help:"The content of the notification"` diff --git a/pkg/cloudcommon/db/usercache.go b/pkg/cloudcommon/db/usercache.go index 2a76b4587a..f3f47e0a1c 100644 --- a/pkg/cloudcommon/db/usercache.go +++ b/pkg/cloudcommon/db/usercache.go @@ -115,10 +115,15 @@ func (manager *SUserCacheManager) FetchUserFromKeystone(ctx context.Context, idS user, err := modules.UsersV3.GetById(s, idStr, nil) if err != nil { if je, ok := err.(*httputils.JSONClientError); ok && je.Code == 404 { - return nil, sql.ErrNoRows + user, err = modules.UsersV3.GetByName(s, idStr, nil) + if je, ok := err.(*httputils.JSONClientError); ok && je.Code == 404 { + return nil, sql.ErrNoRows + } + } + if err != nil { + log.Errorf("fetch user %s fail %s", idStr, err) + return nil, errors.Wrap(err, "modules.UsersV3.Get") } - log.Errorf("fetch user %s fail %s", idStr, err) - return nil, errors.Wrap(err, "modules.UsersV3.Get") } id, _ := user.GetString("id") name, _ := user.GetString("name") @@ -133,7 +138,7 @@ func (manager *SUserCacheManager) Save(ctx context.Context, idStr string, name s objo, err := manager.FetchById(idStr) if err != nil && err != sql.ErrNoRows { - log.Errorf("FetchTenantbyId fail %s", err) + log.Errorf("FetchUserbyId fail %s", err) return nil, err } if err == nil { diff --git a/pkg/mcclient/modules/mod_contacts.go b/pkg/mcclient/modules/mod_contacts.go index 8de03d55f8..7cadf9666e 100644 --- a/pkg/mcclient/modules/mod_contacts.go +++ b/pkg/mcclient/modules/mod_contacts.go @@ -45,7 +45,7 @@ func (this *ContactsManager) DoBatchDeleteContacts(s *mcclient.ClientSession, pa return modulebase.Post(this.ResourceManager, s, path, params, this.Keyword) } -func (this *ContactsManager) CustomizedPerformAction(session *mcclient.ClientSession, id string, action string, +func (this *ContactsManager) CustomizedPerformAction(session *mcclient.ClientSession, id, action, pull string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { body := jsonutils.NewDict() @@ -53,7 +53,10 @@ func (this *ContactsManager) CustomizedPerformAction(session *mcclient.ClientSes body.Add(params, this.Keyword) } path := fmt.Sprintf("/%s/%s/%s?uname=true", this.ContextPath(nil), url.PathEscape(id), url.PathEscape(action)) - return modulebase.Post(this.ResourceManager, session, path, params, this.KeywordPlural) + if len(pull) > 0 { + path += fmt.Sprintf("&pull=%s", pull) + } + return modulebase.Post(this.ResourceManager, session, path, body, this.KeywordPlural) } func (this *ContactsManager) CustomizedGet(session *mcclient.ClientSession, id string, diff --git a/pkg/notify/dispatcher.go b/pkg/notify/dispatcher.go index 44d7186d7a..94048db07b 100644 --- a/pkg/notify/dispatcher.go +++ b/pkg/notify/dispatcher.go @@ -379,7 +379,7 @@ func (self *NotifyModelDispatcher) DeleteContacts(ctx context.Context, uids2 []j // UpdateContacts analysis the data and update corresponding contacts if they exist in the database create new ones. func (self *NotifyModelDispatcher) UpdateContacts(ctx context.Context, idstr string, query jsonutils.JSONObject, - datas []jsonutils.JSONObject, ctxIds []dispatcher.SResourceContext) error { + datas []jsonutils.JSONObject, ctxIds []dispatcher.SResourceContext) (jsonutils.JSONObject, error) { type pair struct { contact string @@ -406,7 +406,7 @@ func (self *NotifyModelDispatcher) UpdateContacts(ctx context.Context, idstr str records, err := models.ContactManager.FetchByUIDAndCType(idstr, contactTypes) if err != nil { - return httperrors.NewGeneralError(err) + return nil, httperrors.NewGeneralError(err) } // updateFailed record the information of failed update @@ -482,13 +482,29 @@ func (self *NotifyModelDispatcher) UpdateContacts(ctx context.Context, idstr str errInfoBuffer.WriteString(" create failed. ") } errInfo := errInfoBuffer.String() - return httperrors.NewGeneralError(errors.Error(errInfo)) + return nil, httperrors.NewGeneralError(errors.Error(errInfo)) } - if query.Contains("update_dingtalk") { - models.UpdateDingtalk(idstr) + if query.Contains("pull") { + cType, _ := query.GetString("pull") + models.PullContact(idstr, cType) } - return nil + + // keep the return value same as this of the GET interface + ret := jsonutils.NewDict() + contact, err := models.ContactManager.FetchByUIDs(ctx, []string{idstr}, false) + if err != nil { + log.Errorf(err.Error()) + return ret, nil + } + outDetails, err := contact[0].GetExtraDetails(ctx, userCred, ret, false) + if err != nil { + log.Errorf(err.Error()) + return ret, nil + } + out := jsonutils.Marshal(outDetails) + out.(*jsonutils.JSONDict).Set("created_at", jsonutils.NewString(contact[0].CreatedAt.String())) + return out, nil } func (self *NotifyModelDispatcher) UpdateTemplate(ctx context.Context, ctype string, query jsonutils.JSONObject, diff --git a/pkg/notify/handlers.go b/pkg/notify/handlers.go index 95b4f4d9cc..6025d21026 100644 --- a/pkg/notify/handlers.go +++ b/pkg/notify/handlers.go @@ -306,19 +306,13 @@ func contactUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Re } uid := params[""] - queryDict := mergeQueryParams(params, query) - update, _ := body.Bool(manager.Keyword(), "update_dingtalk") - if update { - dict := queryDict.(*jsonutils.JSONDict) - dict.Add(jsonutils.JSONTrue, "update_dingtalk") - } - err = manager.UpdateContacts(ctx, uid, queryDict, data, nil) + out, err := manager.UpdateContacts(ctx, uid, mergeQueryParams(params, query), data, nil) if err != nil { log.Errorf(err.Error()) httperrors.BadRequestError(w, "") return } - return + appsrv.SendJSON(w, wrap(out, manager.Keyword())) } // delete contact handler diff --git a/pkg/notify/models/mod_contact.go b/pkg/notify/models/mod_contact.go index 9fbab37a8f..94d2345b5c 100644 --- a/pkg/notify/models/mod_contact.go +++ b/pkg/notify/models/mod_contact.go @@ -115,6 +115,8 @@ func (self *SContactManager) InitializeData() error { return nil } +// FetchByUIDs fetch all SContancts whose uid included in uids. +// If some elements of uids are uname of users, setting param 'uname' as true will fetch correct results. func (self *SContactManager) FetchByUIDs(ctx context.Context, uids []string, uname bool) ([]SContact, error) { var err error if uname { diff --git a/pkg/notify/models/worker.go b/pkg/notify/models/worker.go index 5c981f3391..8d2660633f 100644 --- a/pkg/notify/models/worker.go +++ b/pkg/notify/models/worker.go @@ -108,60 +108,60 @@ func SendVerifyMessage(ctx context.Context, userCred mcclient.TokenCredential, v return nil } -func UpdateDingtalk(uid string) { +func PullContact(uid string, contactType string) { workMan.Run(func() { - updateDingtalk(context.Background(), uid) + pullContact(context.Background(), uid, contactType) }, nil, nil) } -func updateDingtalk(ctx context.Context, uid string) { - contacts, err := ContactManager.FetchByUIDAndCType(uid, []string{MOBILE, DINGTALK}) +func pullContact(ctx context.Context, uid string, contactType string) { + contacts, err := ContactManager.FetchByUIDAndCType(uid, []string{MOBILE, contactType}) if err != nil { log.Errorf("fetch contacts error") } if len(contacts) == 0 { return } - var mobileContact, dingtalkContact *SContact + var mobileContact, subContact *SContact for i := range contacts { if contacts[i].ContactType == MOBILE { mobileContact = &contacts[i] } else { - dingtalkContact = &contacts[i] + subContact = &contacts[i] } } if mobileContact == nil { return } - userid, err := NotifyService.ContactByMobile(ctx, mobileContact.Contact, DINGTALK) + userid, err := NotifyService.ContactByMobile(ctx, mobileContact.Contact, contactType) if err != nil { - log.Errorf("fetch dingtalk userid by mobile failed: %s", err.Error()) + log.Errorf("fetch %s contact by mobile failed: %s", contactType, err.Error()) } - if dingtalkContact != nil { - dingtalkContact.SetModelManager(ContactManager, dingtalkContact) - origin := dingtalkContact.Contact - _, err := db.Update(dingtalkContact, func() error { - dingtalkContact.Contact = userid + if subContact != nil { + subContact.SetModelManager(ContactManager, subContact) + origin := subContact.Contact + _, err := db.Update(subContact, func() error { + subContact.Contact = userid return nil }) if err != nil { - log.Errorf("update dingtalk userid %s => %s failed", origin, userid) + log.Errorf("update %s contact userid %s => %s failed", contactType, origin, userid) } return } contact := SContact{ UID: uid, - ContactType: DINGTALK, + ContactType: contactType, Contact: userid, Enabled: "1", VerifiedAt: time.Now(), } contact.Status = CONTACT_VERIFIED - err = ContactManager.TableSpec().InsertOrUpdate(&contact) + err = ContactManager.TableSpec().Insert(&contact) if err != nil { - log.Errorf("create new dingtalk contact failed") + log.Errorf("create new %s contact failed", contactType) } } diff --git a/pkg/notify/rpc/send.go b/pkg/notify/rpc/send.go index c7c4b48c85..23bfea9dca 100644 --- a/pkg/notify/rpc/send.go +++ b/pkg/notify/rpc/send.go @@ -82,7 +82,7 @@ func (self *SRpcService) InitAll() error { } } if self.SendServices.Len() == 0 { - log.Errorf("No available send service.") + log.Infof("No available send service.") } else { log.Infof("Total %d send service init successful", self.SendServices.Len()) } @@ -285,12 +285,14 @@ func (self *SRpcService) startNewService(ctx context.Context, serviceName string _, err = sendService.UpdateConfig(ctx, &args) if err != nil { st := status.Convert(err) - if st.Code() == codes.Unavailable { + if st.Code() == codes.FailedPrecondition { // no such rpc serve - os.Remove(filename) - return nil, fmt.Errorf("no such rpc serve") + err = fmt.Errorf(st.Message()) } - return nil, fmt.Errorf(st.Message()) + if st.Code() == codes.Unavailable { + err = fmt.Errorf("service is unavailable for now: %s", st.Message()) + } + return nil, errors.Wrap(err, "UpdateConfig") } return sendService, nil