From d403d6d62fa0311459b6891ad27554dc86965de8 Mon Sep 17 00:00:00 2001 From: Rain Date: Wed, 11 Mar 2020 17:03:57 +0800 Subject: [PATCH] feat(notify): Compatibility and repair --- cmd/climc/shell/contacts.go | 25 ++++--- cmd/climc/shell/notification.go | 2 +- pkg/apis/notify/contact.go | 2 +- pkg/cloudcommon/db/usercache.go | 5 +- pkg/mcclient/modules/mod_contacts.go | 9 +-- pkg/notify/cache/usercache.go | 4 ++ pkg/notify/dispatcher.go | 97 +++++++++++++++++++--------- pkg/notify/handlers.go | 16 +++-- pkg/notify/models/consts.go | 3 + pkg/notify/models/mod_config.go | 2 +- pkg/notify/models/mod_contact.go | 74 ++++++++++++++------- pkg/notify/models/mod_template.go | 18 ++++++ pkg/notify/models/worker.go | 18 ++++-- pkg/notify/utils/keystone.go | 18 +++++- 14 files changed, 209 insertions(+), 84 deletions(-) diff --git a/cmd/climc/shell/contacts.go b/cmd/climc/shell/contacts.go index 1f4d6ab522..5de65200d0 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"` - Pull string `help:"pull some subcontacts(e.g., dingtalk, feishu, etc) related to mobile"` + 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() @@ -53,7 +53,13 @@ func init() { params := jsonutils.NewDict() params.Add(arr, "contacts") - contact, err := modules.Contacts.CustomizedPerformAction(s, args.UID, "update-contact", args.Pull, params) + pulls := jsonutils.NewArray() + for _, pull := range args.Pull { + pulls.Add(jsonutils.NewString(pull)) + } + params.Add(pulls, "pull") + + contact, err := modules.Contacts.CustomizedPerformAction(s, args.UID, "update-contact", params) if err != nil { return err } @@ -69,7 +75,8 @@ func init() { 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) + params.Set("pull", jsonutils.NewArray(jsonutils.NewString(args.CONTACTTYPE))) + contact, err := modules.Contacts.CustomizedPerformAction(s, args.UID, "update-contact", params) if err != nil { return err } @@ -89,7 +96,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 } @@ -180,7 +187,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 15f375d393..db79cd3f7f 100644 --- a/cmd/climc/shell/notification.go +++ b/cmd/climc/shell/notification.go @@ -41,7 +41,7 @@ func init() { NotificationCreateOptions } - R(&NotificationCreateSingleOptions{}, "notify", "Send a notification to someones", func(s *mcclient.ClientSession, + R(&NotificationCreateSingleOptions{}, "notify", "Send a notification to someone", func(s *mcclient.ClientSession, args *NotificationCreateSingleOptions) error { msg := notify.SNotifyMessage{} diff --git a/pkg/apis/notify/contact.go b/pkg/apis/notify/contact.go index b30695d6ca..27e5fada54 100644 --- a/pkg/apis/notify/contact.go +++ b/pkg/apis/notify/contact.go @@ -19,7 +19,7 @@ import "yunion.io/x/onecloud/pkg/apis" type ContactDetails struct { apis.ModelBaseDetails - Id string `json:"id"` + UID string `json:"uid"` Name string `json:"name"` Details string `json:"details"` } diff --git a/pkg/cloudcommon/db/usercache.go b/pkg/cloudcommon/db/usercache.go index 87b627510e..d73b98af0d 100644 --- a/pkg/cloudcommon/db/usercache.go +++ b/pkg/cloudcommon/db/usercache.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" "runtime/debug" + "time" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -155,6 +156,7 @@ func (manager *SUserCacheManager) Save(ctx context.Context, idStr string, name s obj.Name = name obj.Domain = domain obj.DomainId = domainId + obj.LastCheck = time.Now().UTC() return nil }) if err != nil { @@ -169,7 +171,8 @@ func (manager *SUserCacheManager) Save(ctx context.Context, idStr string, name s obj.Name = name obj.Domain = domain obj.DomainId = domainId - err = manager.TableSpec().Insert(obj) + obj.LastCheck = time.Now().UTC() + err = manager.TableSpec().InsertOrUpdate(obj) if err != nil { return nil, err } else { diff --git a/pkg/mcclient/modules/mod_contacts.go b/pkg/mcclient/modules/mod_contacts.go index 7cadf9666e..5c91cd1ee8 100644 --- a/pkg/mcclient/modules/mod_contacts.go +++ b/pkg/mcclient/modules/mod_contacts.go @@ -40,22 +40,17 @@ func (this *ContactsManager) PerformActionWithArrayParams(s *mcclient.ClientSess } func (this *ContactsManager) DoBatchDeleteContacts(s *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - path := "/contacts/delete-contact" + path := "/contacts/delete-contact?uname=true" return modulebase.Post(this.ResourceManager, s, path, params, this.Keyword) } -func (this *ContactsManager) CustomizedPerformAction(session *mcclient.ClientSession, id, action, pull string, - params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - +func (this *ContactsManager) CustomizedPerformAction(session *mcclient.ClientSession, id, action string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { body := jsonutils.NewDict() if params != nil { body.Add(params, this.Keyword) } path := fmt.Sprintf("/%s/%s/%s?uname=true", this.ContextPath(nil), url.PathEscape(id), url.PathEscape(action)) - if len(pull) > 0 { - path += fmt.Sprintf("&pull=%s", pull) - } return modulebase.Post(this.ResourceManager, session, path, body, this.KeywordPlural) } diff --git a/pkg/notify/cache/usercache.go b/pkg/notify/cache/usercache.go index b0175174c4..af9621cb56 100644 --- a/pkg/notify/cache/usercache.go +++ b/pkg/notify/cache/usercache.go @@ -119,3 +119,7 @@ func (ucm *SUserCacheManager) FetchUserFromLoaclCache(ctx context.Context, q *sq } return users, nil } + +func (u *SUser) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { + return u.SUser.Delete(ctx, userCred) +} diff --git a/pkg/notify/dispatcher.go b/pkg/notify/dispatcher.go index 94048db07b..65204629ee 100644 --- a/pkg/notify/dispatcher.go +++ b/pkg/notify/dispatcher.go @@ -114,6 +114,7 @@ func (self *NotifyModelDispatcher) UpdateConfig(ctx context.Context, body jsonut } } } + log.Debugf("update body: %s", data) keys := data.SortedKeys() config := make(map[string]string) createDataList := make([]jsonutils.JSONObject, 0, len(keys)) @@ -131,6 +132,7 @@ func (self *NotifyModelDispatcher) UpdateConfig(ctx context.Context, body jsonut } // validate configs + log.Debugf("config: %#v", config) isValid, message, err := models.NotifyService.ValidateConfig(ctx, contactType, config) if err != nil { if errors.Cause(err) != errors.ErrNotImplemented { @@ -144,7 +146,7 @@ func (self *NotifyModelDispatcher) UpdateConfig(ctx context.Context, body jsonut // create for _, createData := range createDataList { - _, err := self.Create(ctx, jsonutils.JSONNull, createData, nil) + _, err := self.Create(ctx, jsonutils.NewDict(), createData, nil) if err != nil { return errors.Wrapf(err, "Create config %s for contact type %s failed", createData.String(), contactType) } @@ -155,31 +157,31 @@ func (self *NotifyModelDispatcher) UpdateConfig(ctx context.Context, body jsonut return nil } -func (self *NotifyModelDispatcher) ValidateConfig(ctx context.Context, contactType string, body jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func (self *NotifyModelDispatcher) ValidateConfig(ctx context.Context, contactType string, body jsonutils.JSONObject) error { dict, ok := body.(*jsonutils.JSONDict) if !ok { - return nil, httperrors.NewInputParameterError("") + return httperrors.NewInputParameterError("") } dict = models.ConfigManager.Display2Database(contactType, dict) configs := make(map[string]string) for _, key := range dict.SortedKeys() { value, err := dict.GetString(key) if err != nil { - return nil, errors.Wrap(err, "jsonutils.JsonDict.GetString") + return errors.Wrap(err, "jsonutils.JsonDict.GetString") } configs[key] = value } isValid, message, err := models.NotifyService.ValidateConfig(ctx, contactType, configs) if err != nil { if errors.Cause(err) == errors.ErrNotImplemented { - return nil, httperrors.NewNotImplementedError("validating config of %s", contactType) + return httperrors.NewNotImplementedError("validating config of %s", contactType) } - return nil, err + return err } - ret := jsonutils.NewDict() - ret.Add(jsonutils.NewBool(isValid), "is_valid") - ret.Add(jsonutils.NewString(message), "message") - return ret, nil + if isValid == false { + return httperrors.NewInputParameterError(message) + } + return nil } // CreateNotification create new notifications and send them through rpc.RpcService. @@ -229,7 +231,7 @@ func (self *NotifyModelDispatcher) getIds(data jsonutils.JSONObject, key string) } ret = append(ret, id) } - return ret[:len(ret):len(ret)] + return ret } // Verify process: @@ -348,12 +350,14 @@ func (self *NotifyModelDispatcher) VerifyTrigger(ctx context.Context, params map } // DeleteContacts delete a group of contacts -func (self *NotifyModelDispatcher) DeleteContacts(ctx context.Context, uids2 []jsonutils.JSONObject) error { +func (self *NotifyModelDispatcher) DeleteContacts(ctx context.Context, uidArray []jsonutils.JSONObject) error { // Get all id of uid - uids := make([]string, len(uids2)) - for i := range uids2 { - uids[i] = strings.Trim(uids2[i].String(), `"`) + uids := make([]string, len(uidArray)) + log.Debugf("uidArray: %s", uidArray) + for i := range uidArray { + uids[i], _ = uidArray[i].GetString() } + log.Debugf("uids: %#v", uids) uname := false if v := ctx.Value("uname"); v != nil { uname = true @@ -370,6 +374,8 @@ func (self *NotifyModelDispatcher) DeleteContacts(ctx context.Context, uids2 []j deleteFailed = append(deleteFailed, contact.ID) } } + // clean cache + noutils.DeleteUsers(ctx, userCred, uids) if len(deleteFailed) != 0 { errInfo := strings.Join(deleteFailed, ", ") + " ; these contact delete failed." return errors.Error(errInfo) @@ -379,7 +385,8 @@ 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) (jsonutils.JSONObject, error) { + datas []jsonutils.JSONObject, pullCtypes []jsonutils.JSONObject, ctxIds []dispatcher.SResourceContext) (jsonutils.JSONObject, + error) { type pair struct { contact string @@ -445,24 +452,56 @@ func (self *NotifyModelDispatcher) UpdateContacts(ctx context.Context, idstr str // createFailed record the information of failed creation createFailed := make([]string, 0, 1) // Create contact info - newDatas := make([]map[string]interface{}, 0, len(contactInfos)) + type CreateData struct { + UID string + ContactType string + Contact string + Enabled string + } + newDatas := make([]CreateData, 0, len(contactInfos)) for conType, conPair := range contactInfos { - tmpMap := map[string]interface{}{ - "uid": idstr, - "contact_type": conType, - "contact": conPair.contact, + tmp := CreateData{ + UID: idstr, + ContactType: conType, + Contact: conPair.contact, } if conPair.enabled != "-1" { - tmpMap["enabled"] = conPair.enabled + tmp.Enabled = conPair.enabled } - newDatas = append(newDatas, tmpMap) + newDatas = append(newDatas, tmp) } + pulls := make([]string, len(pullCtypes)) + for i := range pullCtypes { + pulls[i], _ = pullCtypes[i].GetString() + } + + if len(pulls) > 0 { + contacts, err := models.ContactManager.FetchByUIDAndCType(idstr, pulls) + if err != nil { + return nil, err + } + set := sets.NewString(pulls...) + for i := range contacts { + set.Delete(contacts[i].ContactType) + } + for _, ct := range set.UnsortedList() { + tmp := CreateData{ + UID: idstr, + ContactType: ct, + Enabled: "1", + Contact: "user_id", + } + newDatas = append(newDatas, tmp) + } + } + log.Debugf("newDatas: %s", newDatas) + for _, newData := range newDatas { - _, err := self.Create(ctx, jsonutils.JSONNull, jsonutils.Marshal(newData), ctxIds) + _, err := self.Create(ctx, jsonutils.NewDict(), jsonutils.Marshal(newData), ctxIds) if err != nil { createFailed = append(createFailed, fmt.Sprintf(`uid:%q, contact_type:%q, contact:%q`, idstr, - newData["contact_type"], newData["contact"])) + newData.ContactType, newData.Contact)) } } @@ -485,10 +524,7 @@ func (self *NotifyModelDispatcher) UpdateContacts(ctx context.Context, idstr str return nil, httperrors.NewGeneralError(errors.Error(errInfo)) } - if query.Contains("pull") { - cType, _ := query.GetString("pull") - models.PullContact(idstr, cType) - } + models.PullContact(idstr, pulls) // keep the return value same as this of the GET interface ret := jsonutils.NewDict() @@ -497,6 +533,9 @@ func (self *NotifyModelDispatcher) UpdateContacts(ctx context.Context, idstr str log.Errorf(err.Error()) return ret, nil } + if len(contact) == 0 { + return nil, nil + } outDetails, err := contact[0].GetExtraDetails(ctx, userCred, ret, false) if err != nil { log.Errorf(err.Error()) diff --git a/pkg/notify/handlers.go b/pkg/notify/handlers.go index 6025d21026..1cfb73d07a 100644 --- a/pkg/notify/handlers.go +++ b/pkg/notify/handlers.go @@ -55,6 +55,7 @@ func middleware(f appsrv.FilterHandler) appsrv.FilterHandler { hander := func(ctx context.Context, w http.ResponseWriter, r *http.Request) { if _, ok := r.URL.Query()["uname"]; ok { // Uname + log.Debugf("url.Query has a uname") params := appctx.AppContextParams(ctx) if uid, ok := params[""]; ok { userDetail, err := utils.GetUserByIDOrName(ctx, uid) @@ -62,6 +63,7 @@ func middleware(f appsrv.FilterHandler) appsrv.FilterHandler { httperrors.NotFoundError(w, "Uid or Uname Not Found") return } + log.Debugf("find userDetail, id: %s, name: %s", userDetail.Id, userDetail.Name) params[""] = userDetail.Id } ctx = context.WithValue(ctx, "uname", true) @@ -256,12 +258,11 @@ func configValidateHandler(ctx context.Context, w http.ResponseWriter, r *http.R httperrors.GeneralServerError(w, httperrors.NewInputParameterError("need config")) } ctype := params[""] - res, err := manager.ValidateConfig(ctx, ctype, body) + err = manager.ValidateConfig(ctx, ctype, body) if err != nil { httperrors.GeneralServerError(w, err) return } - appsrv.SendJSON(w, res) } func notificationHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { @@ -275,12 +276,11 @@ func notificationHandler(ctx context.Context, w http.ResponseWriter, r *http.Req httperrors.MissingParameterError(w, "gid | uid") return } - ret, err := manager.CreateNotification(ctx, data) + _, err = manager.CreateNotification(ctx, data) if err != nil { httperrors.GeneralServerError(w, err) return } - appsrv.SendJSON(w, ret) } // verify handler @@ -304,14 +304,20 @@ func contactUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Re manager.Keyword(), manager.KeywordPlural())) return } + log.Debugf("data: %s", data) + pullCtypes, _ := body.GetArray(manager.Keyword(), "pull") + log.Debugf("pullCtypes: %s", pullCtypes) uid := params[""] - out, err := manager.UpdateContacts(ctx, uid, mergeQueryParams(params, query), data, nil) + out, err := manager.UpdateContacts(ctx, uid, mergeQueryParams(params, query), data, pullCtypes, nil) if err != nil { log.Errorf(err.Error()) httperrors.BadRequestError(w, "") return } + if out == nil { + return + } appsrv.SendJSON(w, wrap(out, manager.Keyword())) } diff --git a/pkg/notify/models/consts.go b/pkg/notify/models/consts.go index a967993c69..39cbe63ab6 100644 --- a/pkg/notify/models/consts.go +++ b/pkg/notify/models/consts.go @@ -18,7 +18,9 @@ const ( EMAIL = "email" MOBILE = "mobile" DINGTALK = "dingtalk" + FEISHU = "feishu" WEBCONSOLE = "webconsole" + ROBOT = "robot" NOTIFY_RECEIVED = "received" // Received a task about sending a notification NOTIFY_SENT = "sent" // Nofity module has sent notification, but result unkown @@ -40,5 +42,6 @@ const ( // In webconsole, uid is the same as contact. var UpdateNotAllow = map[string]struct{}{ DINGTALK: {}, + FEISHU: {}, WEBCONSOLE: {}, } diff --git a/pkg/notify/models/mod_config.go b/pkg/notify/models/mod_config.go index f135fca732..8b88b4d3d2 100644 --- a/pkg/notify/models/mod_config.go +++ b/pkg/notify/models/mod_config.go @@ -56,7 +56,7 @@ type SConfig struct { Type string `width:"15" nullable:"false" create:"required" list:"user"` KeyText string `width:"30" nullable:"false" create:"required" list:"user"` - ValueText string `width:"100" nullable:"false" create:"required" list:"user"` + ValueText string `width:"256" nullable:"false" create:"required" list:"user"` } // ListItemFilter is a hook function belong to IModelManager interface when Listing. diff --git a/pkg/notify/models/mod_contact.go b/pkg/notify/models/mod_contact.go index 94d2345b5c..71cf9a831a 100644 --- a/pkg/notify/models/mod_contact.go +++ b/pkg/notify/models/mod_contact.go @@ -55,7 +55,7 @@ func init() { type SContact struct { SStatusStandaloneResourceBase - UID string `width:"128" nullable:"false" create:"required" update:"user"` + UID string `width:"128" nullable:"false" create:"required" update:"user" list:"user" get:"user"` ContactType string `width:"16" nullable:"false" create:"required" update:"user"` Contact string `width:"64" nullable:"false" create:"required" update:"user"` Enabled string `width:"5" nullable:"false" default:"1" create:"optional" update:"user"` @@ -163,6 +163,7 @@ func (self *SContactManager) _UIDsFromUIDOrName(ctx context.Context, uidStrs []s for _, uid = range uidSet.UnsortedList() { uids = append(uids, uid) } + log.Debugf("uids %s => %s", uidStrs, uids) return uids, nil } @@ -204,7 +205,7 @@ func (self *SContact) getMoreDetail(ctx context.Context, userCred mcclient.Token if err != nil { return out, errors.Wrapf(err, "fetch Contacts of uid %s error", self.UID) } - out.Id = self.UID + out.UID = self.UID out.Name = uname out.Details = jsonutils.Marshal(contacts).String() @@ -260,16 +261,60 @@ func (self *SContactManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu if !scope.HigherEqual(rbacutils.ScopeSystem) { q = q.Equals("uid", userCred.GetUserId()) } - q = q.GroupBy("uid") + q = q.GroupBy("uid").Desc("created_at") return q, nil } +// Contacts query all contacts by uids and contactType +func (self *SContactManager) Contacts(uids []string, contactType string) ([]SContact, error) { + contacts := make([]SContact, 0, len(uids)) + if contactType == WEBCONSOLE { + for _, uid := range uids { + contacts = append(contacts, SContact{ + UID: uid, + ContactType: WEBCONSOLE, + Contact: uid, + }) + } + return contacts, nil + } + + queryCon := contactType + if strings.Contains(contactType, ROBOT) { + queryCon = MOBILE + } + q := self.Query().Equals("contact_type", queryCon).Equals("enabled", "1").In("uid", uids) + err := db.FetchModelObjects(self, q, &contacts) + if err != nil { + return nil, err + } + + // For Robot Sender, only one message of the same content is sent for multiple users, + // so the user's contact information is a collection of all contact information + if strings.Contains(contactType, ROBOT) { + // hack + contactVals := make([]string, len(contacts)) + uidVals := make([]string, len(contacts)) + for i := range contacts { + contactVals[i] = contacts[i].Contact + uidVals[i] = contacts[i].UID + } + contacts = []SContact{ + { + UID: strings.Join(uidVals, ","), + ContactType: contactType, + Contact: strings.Join(contactVals, ","), + }, + } + } + return contacts, nil +} + func (self *SContactManager) GetAllNotify(ctx context.Context, ids []string, contactType string, group bool) ([]SContact, error) { var uids []string var err error - q := self.Query() if !group { if v := ctx.Value("uname"); v != nil { ids, err = self._UIDsFromUIDOrName(ctx, ids) @@ -289,26 +334,7 @@ func (self *SContactManager) GetAllNotify(ctx context.Context, ids []string, con } uids = uid } - q.Filter(sqlchemy.AND(sqlchemy.In(q.Field("uid"), uids), sqlchemy.Equals(q.Field("contact_type"), - contactType), sqlchemy.Equals(q.Field("status"), CONTACT_VERIFIED))) - - if contactType == WEBCONSOLE { - ret := make([]SContact, len(uids)) - for i := range uids { - ret[i] = SContact{ - UID: uids[i], - ContactType: WEBCONSOLE, - Contact: uids[i], - } - } - return ret, nil - } - contacts := make([]SContact, 0, 2) - err = db.FetchModelObjects(self, q, &contacts) - if err != nil { - return nil, err - } - return contacts, nil + return self.Contacts(uids, contactType) } type SContactResponse struct { diff --git a/pkg/notify/models/mod_template.go b/pkg/notify/models/mod_template.go index d765023a97..57f6d93e9f 100644 --- a/pkg/notify/models/mod_template.go +++ b/pkg/notify/models/mod_template.go @@ -27,6 +27,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" + "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" @@ -208,3 +209,20 @@ func (manager *STemplateManager) ValidateCreateData(ctx context.Context, userCre } return data, nil } + +func (self *STemplateManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { + queryDict := query.(*jsonutils.JSONDict) + if queryDict.Contains("topic") { + val, _ := queryDict.GetString("topic") + q = q.Equals("topic", val) + } + if queryDict.Contains("template_type") { + val, _ := queryDict.GetString("template_type") + q = q.Equals("template_type", val) + } + if queryDict.Contains("contact_type") { + val, _ := queryDict.GetString("contact_type") + q = q.Equals("contact_type", val) + } + return q, nil +} diff --git a/pkg/notify/models/worker.go b/pkg/notify/models/worker.go index 8d2660633f..1d19857fec 100644 --- a/pkg/notify/models/worker.go +++ b/pkg/notify/models/worker.go @@ -39,8 +39,9 @@ func init() { func Send(notifications []*SNotification, userCred mcclient.TokenCredential, contacts []string) { for i := range notifications { + notification, contact := notifications[i], contacts[i] workMan.Run(func() { - sendone(context.Background(), userCred, notifications[i], contacts[i]) + sendone(context.Background(), userCred, notification, contact) }, nil, nil) } } @@ -108,10 +109,13 @@ func SendVerifyMessage(ctx context.Context, userCred mcclient.TokenCredential, v return nil } -func PullContact(uid string, contactType string) { - workMan.Run(func() { - pullContact(context.Background(), uid, contactType) - }, nil, nil) +func PullContact(uid string, contactTypes []string) { + for i := range contactTypes { + ct := contactTypes[i] + workMan.Run(func() { + pullContact(context.Background(), uid, ct) + }, nil, nil) + } } func pullContact(ctx context.Context, uid string, contactType string) { @@ -143,6 +147,10 @@ func pullContact(ctx context.Context, uid string, contactType string) { origin := subContact.Contact _, err := db.Update(subContact, func() error { subContact.Contact = userid + subContact.VerifiedAt = time.Now() + if subContact.Status != CONTACT_VERIFIED { + subContact.Status = CONTACT_VERIFIED + } return nil }) if err != nil { diff --git a/pkg/notify/utils/keystone.go b/pkg/notify/utils/keystone.go index 69d6c7b67e..e512b298ec 100644 --- a/pkg/notify/utils/keystone.go +++ b/pkg/notify/utils/keystone.go @@ -17,8 +17,10 @@ package utils import ( "context" + "yunion.io/x/pkg/errors" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/notify/cache" ) @@ -28,10 +30,24 @@ func GetUserByIDOrName(ctx context.Context, idStr string) (*cache.SUser, error) func GetUsersWithoutRemote(ctx context.Context, idStr []string) ([]cache.SUser, error) { q := cache.UserCacheManager.Query() - q = q.Filter(sqlchemy.OR(sqlchemy.In(q.Field("id"), idStr), sqlchemy.In(q.Field("name"), idStr))) + q = q.Filter(sqlchemy.OR(sqlchemy.In(q.Field("id"), idStr), sqlchemy.In(q.Field("name"), idStr))).Desc("updated_at") return cache.UserCacheManager.FetchUserFromLoaclCache(ctx, q) } +func DeleteUsers(ctx context.Context, userCred mcclient.TokenCredential, ids []string) error { + users, err := GetUsersWithoutRemote(ctx, ids) + if err != nil { + return err + } + for i := range users { + err := users[i].Delete(ctx, userCred) + if err != nil { + return errors.Wrapf(err, "delete cache.SUser %s error", users[i].Id) + } + } + return nil +} + func GetUserIdsLikeName(ctx context.Context, name string) ([]string, error) { users, err := cache.UserCacheManager.FetchUserLikeName(ctx, name, true) if err != nil {