mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
feature(notify): Add query and return value for contact UPDATE interface
1. Add same return value with contact GET interface when updating 2. Add pull params for query to pull subcontact by mobile number. For example, pull user_id from dingtalk throught user's mobile number. 3. Add corresponding feature based on above for climc. 4. UserCache will try FetchByName if there is no id matched user when fetching users from KeyStone.
This commit is contained in:
+23
-12
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -306,19 +306,13 @@ func contactUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
|
||||
uid := params["<uid>"]
|
||||
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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+17
-17
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user