receiver.go 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package models
  15. import (
  16. "context"
  17. "database/sql"
  18. "regexp"
  19. "time"
  20. "golang.org/x/text/language"
  21. "yunion.io/x/jsonutils"
  22. "yunion.io/x/log"
  23. "yunion.io/x/pkg/errors"
  24. "yunion.io/x/pkg/tristate"
  25. "yunion.io/x/pkg/util/rbacscope"
  26. "yunion.io/x/pkg/util/regutils"
  27. "yunion.io/x/pkg/util/sets"
  28. "yunion.io/x/pkg/utils"
  29. "yunion.io/x/sqlchemy"
  30. "yunion.io/x/onecloud/pkg/apis"
  31. identity_api "yunion.io/x/onecloud/pkg/apis/identity"
  32. api "yunion.io/x/onecloud/pkg/apis/notify"
  33. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  34. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  35. "yunion.io/x/onecloud/pkg/cloudcommon/policy"
  36. "yunion.io/x/onecloud/pkg/httperrors"
  37. "yunion.io/x/onecloud/pkg/mcclient"
  38. "yunion.io/x/onecloud/pkg/mcclient/auth"
  39. "yunion.io/x/onecloud/pkg/mcclient/informer"
  40. identity_modules "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
  41. "yunion.io/x/onecloud/pkg/notify/options"
  42. "yunion.io/x/onecloud/pkg/util/logclient"
  43. "yunion.io/x/onecloud/pkg/util/stringutils2"
  44. )
  45. var (
  46. PersonalConfigContactTypes = []string{
  47. api.EMAIL,
  48. api.MOBILE,
  49. api.DINGTALK,
  50. api.FEISHU,
  51. api.WORKWX,
  52. }
  53. RobotContactTypes = []string{
  54. api.FEISHU_ROBOT,
  55. api.DINGTALK_ROBOT,
  56. api.WORKWX_ROBOT,
  57. }
  58. SystemConfigContactTypes = append(
  59. RobotContactTypes,
  60. api.WEBCONSOLE,
  61. api.WEBHOOK,
  62. )
  63. )
  64. type SReceiverManager struct {
  65. db.SVirtualResourceBaseManager
  66. db.SEnabledResourceBaseManager
  67. }
  68. var ReceiverManager *SReceiverManager
  69. func init() {
  70. ReceiverManager = &SReceiverManager{
  71. SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
  72. SReceiver{},
  73. "receivers_tbl",
  74. "receiver",
  75. "receivers",
  76. ),
  77. }
  78. ReceiverManager.SetVirtualObject(ReceiverManager)
  79. }
  80. // 接收人
  81. type SReceiver struct {
  82. db.SVirtualResourceBase
  83. db.SEnabledResourceBase
  84. Email string `width:"128" nullable:"false" create:"optional" update:"user" get:"user" list:"user"`
  85. // swagger:ignore
  86. Mobile string `width:"32" nullable:"false" create:"optional" update:"user"`
  87. Lang string `width:"8" charset:"ascii" nullable:"false" list:"user" update:"user"`
  88. // swagger:ignore
  89. EnabledEmail tristate.TriState `default:"false" update:"user"`
  90. // swagger:ignore
  91. VerifiedEmail tristate.TriState `default:"false" update:"user"`
  92. // swagger:ignore
  93. EnabledMobile tristate.TriState `default:"false" update:"user"`
  94. // swagger:ignore
  95. VerifiedMobile tristate.TriState `default:"false" update:"user"`
  96. // swagger:ignore
  97. // subContactCache map[string]*SSubContact `json:"-"`
  98. }
  99. func (rm *SReceiverManager) CreateByInsertOrUpdate() bool {
  100. return true
  101. }
  102. func (rm *SReceiverManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.ReceiverCreateInput) (api.ReceiverCreateInput, error) {
  103. var err error
  104. input.VirtualResourceCreateInput, err = rm.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.VirtualResourceCreateInput)
  105. if err != nil {
  106. return input, err
  107. }
  108. if len(input.UID) == 0 && len(input.UName) == 0 {
  109. return input, httperrors.NewMissingParameterError("uid or uname")
  110. }
  111. uid := input.UID
  112. if len(input.UID) == 0 {
  113. uid = input.UName
  114. }
  115. user, err := db.UserCacheManager.FetchUserByIdOrName(ctx, uid)
  116. if err != nil {
  117. return input, err
  118. }
  119. input.UID = user.Id
  120. input.UName = user.Name
  121. input.ProjectDomainId = user.DomainId
  122. // hack
  123. input.Name = input.UName
  124. // validate email
  125. if ok := regutils.MatchEmail(input.Email); len(input.Email) > 0 && !ok {
  126. return input, httperrors.NewInputParameterError("invalid email")
  127. }
  128. // validate mobile
  129. input.InternationalMobile.AcceptExtMobile()
  130. if ok := LaxMobileRegexp.MatchString(input.InternationalMobile.Mobile); len(input.InternationalMobile.Mobile) > 0 && !ok {
  131. return input, httperrors.NewInputParameterError("invalid mobile")
  132. }
  133. input.Enabled = pTrue
  134. for _, cType := range input.EnabledContactTypes {
  135. driver := GetDriver(cType)
  136. if driver == nil {
  137. return input, httperrors.NewInputParameterError("invalid enabled contact type %s", cType)
  138. }
  139. }
  140. return input, nil
  141. }
  142. func (r *SReceiver) IsEnabled() bool {
  143. return r.Enabled.Bool()
  144. }
  145. var LaxMobileRegexp = regexp.MustCompile(`[0-9]{6,14}`)
  146. func (r *SReceiver) IsEnabledContactType(ct string) (bool, error) {
  147. if utils.IsInStringArray(ct, SystemConfigContactTypes) {
  148. return true, nil
  149. }
  150. cts, err := r.GetEnabledContactTypes()
  151. if err != nil {
  152. return false, errors.Wrap(err, "GetEnabledContactTypes")
  153. }
  154. return utils.IsInStringArray(ct, cts), nil
  155. }
  156. func (r *SReceiver) IsVerifiedContactType(ct string) (bool, error) {
  157. if utils.IsInStringArray(ct, SystemConfigContactTypes) {
  158. return true, nil
  159. }
  160. cts, err := r.GetVerifiedContactTypes()
  161. if err != nil {
  162. return false, errors.Wrap(err, "GetVerifiedContactTypes")
  163. }
  164. return utils.IsInStringArray(ct, cts), nil
  165. }
  166. func (r *SReceiver) GetEnabledContactTypes() ([]string, error) {
  167. ret := make([]string, 0, 1)
  168. // for email and mobile
  169. if r.EnabledEmail.IsTrue() {
  170. ret = append(ret, api.EMAIL)
  171. }
  172. if r.EnabledMobile.IsTrue() {
  173. ret = append(ret, api.MOBILE)
  174. }
  175. subs, _ := r.GetSubContacts()
  176. for _, sub := range subs {
  177. if sub.Enabled.IsTrue() {
  178. ret = append(ret, sub.Type)
  179. }
  180. }
  181. ret = append(ret, api.WEBCONSOLE)
  182. return ret, nil
  183. }
  184. func (r *SReceiver) markContactType(ctx context.Context, contactType string, isVerified bool, note string) error {
  185. if contactType == api.MOBILE {
  186. _, err := db.Update(r, func() error {
  187. r.VerifiedMobile = tristate.NewFromBool(isVerified)
  188. return nil
  189. })
  190. return err
  191. }
  192. if contactType == api.EMAIL {
  193. _, err := db.Update(r, func() error {
  194. r.VerifiedEmail = tristate.NewFromBool(isVerified)
  195. return nil
  196. })
  197. return err
  198. }
  199. subs, err := r.GetSubContacts()
  200. if err != nil {
  201. return err
  202. }
  203. for i := range subs {
  204. if subs[i].Type == contactType {
  205. _, err := db.Update(&subs[i], func() error {
  206. subs[i].Verified = tristate.NewFromBool(isVerified)
  207. subs[i].VerifiedNote = note
  208. return nil
  209. })
  210. return err
  211. }
  212. }
  213. sub := &SSubContact{
  214. Type: contactType,
  215. ReceiverID: r.Id,
  216. Verified: tristate.NewFromBool(isVerified),
  217. VerifiedNote: note,
  218. ParentContactType: api.MOBILE,
  219. }
  220. sub.SetModelManager(SubContactManager, sub)
  221. return SubContactManager.TableSpec().Insert(ctx, sub)
  222. }
  223. func (r *SReceiver) MarkContactTypeVerified(ctx context.Context, contactType string) error {
  224. return r.markContactType(ctx, contactType, true, "")
  225. }
  226. func (r *SReceiver) MarkContactTypeUnVerified(ctx context.Context, contactType string, note string) error {
  227. return r.markContactType(ctx, contactType, false, note)
  228. }
  229. func (r *SReceiver) GetVerifiedContactTypes() ([]string, error) {
  230. ret := make([]string, 0, 1)
  231. // for email and mobile
  232. if r.VerifiedEmail.IsTrue() {
  233. ret = append(ret, api.EMAIL)
  234. }
  235. if r.VerifiedMobile.IsTrue() {
  236. ret = append(ret, api.MOBILE)
  237. }
  238. subs, _ := r.GetSubContacts()
  239. for _, sub := range subs {
  240. if sub.Verified.IsTrue() {
  241. ret = append(ret, sub.Type)
  242. }
  243. }
  244. return ret, nil
  245. }
  246. func (self *SReceiver) GetSubContacts() ([]SSubContact, error) {
  247. ret := []SSubContact{}
  248. q := SubContactManager.Query().Equals("receiver_id", self.Id)
  249. err := db.FetchModelObjects(SubContactManager, q, &ret)
  250. return ret, err
  251. }
  252. func (rm *SReceiverManager) FetchSubContacts(ids []string) (map[string][]SSubContact, error) {
  253. ret := map[string][]SSubContact{}
  254. q := SubContactManager.Query().In("receiver_id", ids)
  255. subContacts := []SSubContact{}
  256. err := db.FetchModelObjects(SubContactManager, q, &subContacts)
  257. if err != nil {
  258. return ret, err
  259. }
  260. for i := range subContacts {
  261. _, ok := ret[subContacts[i].ReceiverID]
  262. if !ok {
  263. ret[subContacts[i].ReceiverID] = []SSubContact{}
  264. }
  265. ret[subContacts[i].ReceiverID] = append(ret[subContacts[i].ReceiverID], subContacts[i])
  266. }
  267. return ret, nil
  268. }
  269. func (rm *SReceiverManager) ResourceScope() rbacscope.TRbacScope {
  270. return rbacscope.ScopeUser
  271. }
  272. func (rm *SReceiverManager) FetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) {
  273. userStr, _ := jsonutils.GetAnyString2(data, []string{"uid"})
  274. if len(userStr) > 0 {
  275. u, err := db.DefaultUserFetcher(ctx, userStr)
  276. if err != nil {
  277. if err == sql.ErrNoRows {
  278. return nil, httperrors.NewResourceNotFoundError2("user", userStr)
  279. }
  280. return nil, errors.Wrap(err, "UserCacheManager.FetchUserByIdOrName")
  281. }
  282. ownerId := db.SOwnerId{
  283. DomainId: u.DomainId,
  284. Domain: u.Domain,
  285. UserDomain: u.Domain,
  286. UserDomainId: u.DomainId,
  287. UserId: u.Id,
  288. User: u.Name,
  289. }
  290. return &ownerId, nil
  291. }
  292. return db.FetchDomainInfo(ctx, data)
  293. }
  294. func (rm *SReceiverManager) filterByOwnerAndProjectDomain(ctx context.Context, userCred mcclient.TokenCredential, q *sqlchemy.SQuery, scope rbacscope.TRbacScope) (*sqlchemy.SQuery, error) {
  295. if userCred == nil {
  296. return q, nil
  297. }
  298. userIds, err := rm.findUserIdsWithProjectDomain(ctx, userCred, userCred.GetProjectDomainId())
  299. if err != nil {
  300. return nil, errors.Wrap(err, "unable to findUserIdsWithProjectDomain")
  301. }
  302. var projectDomainCondition, ownerCondition sqlchemy.ICondition
  303. switch len(userIds) {
  304. case 0:
  305. projectDomainCondition = nil
  306. case 1:
  307. projectDomainCondition = sqlchemy.Equals(q.Field("id"), userIds[0])
  308. default:
  309. projectDomainCondition = sqlchemy.In(q.Field("id"), userIds)
  310. }
  311. switch scope {
  312. case rbacscope.ScopeDomain:
  313. ownerCondition = sqlchemy.Equals(q.Field("domain_id"), userCred.GetProjectDomainId())
  314. case rbacscope.ScopeProject:
  315. ownerCondition = sqlchemy.Equals(q.Field("id"), userCred.GetUserId())
  316. }
  317. if projectDomainCondition != nil && ownerCondition != nil {
  318. return q.Filter(sqlchemy.OR(projectDomainCondition, ownerCondition)), nil
  319. }
  320. if projectDomainCondition != nil {
  321. return q.Filter(projectDomainCondition), nil
  322. }
  323. if ownerCondition != nil {
  324. return q.Filter(ownerCondition), nil
  325. }
  326. return q, nil
  327. }
  328. func (rm *SReceiverManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, man db.FilterByOwnerProvider, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
  329. log.Debugf("SReceiverManager FilterByOwner is called owner %s scope %s", jsonutils.Marshal(owner), scope)
  330. return rm.SDomainizedResourceBaseManager.FilterByOwner(ctx, q, man, userCred, owner, scope)
  331. }
  332. func (rm *SReceiverManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.ReceiverListInput) (*sqlchemy.SQuery, error) {
  333. q, err := rm.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.VirtualResourceListInput)
  334. if err != nil {
  335. return nil, err
  336. }
  337. if len(input.UID) > 0 {
  338. q = q.Equals("id", input.UID)
  339. }
  340. if len(input.UName) > 0 {
  341. q = q.Equals("name", input.UName)
  342. }
  343. if len(input.EnabledContactType) > 0 {
  344. switch input.EnabledContactType {
  345. case api.MOBILE:
  346. q = q.IsTrue("enabled_mobile")
  347. case api.EMAIL:
  348. q = q.IsTrue("enabled_email")
  349. default:
  350. sq := SubContactManager.Query("receiver_id").Equals("type", input.EnabledContactType).IsTrue("enabled").SubQuery()
  351. q = q.Join(sq, sqlchemy.Equals(sq.Field("receiver_id"), q.Field("id")))
  352. }
  353. }
  354. if len(input.VerifiedContactType) > 0 {
  355. switch input.VerifiedContactType {
  356. case api.MOBILE:
  357. q = q.IsTrue("verified_mobile")
  358. case api.EMAIL:
  359. q = q.IsTrue("verified_email")
  360. default:
  361. sq := SubContactManager.Query("receiver_id").Equals("type", input.VerifiedContactType).IsTrue("verified").SubQuery()
  362. q = q.Join(sq, sqlchemy.Equals(sq.Field("receiver_id"), q.Field("id")))
  363. }
  364. }
  365. return q, nil
  366. }
  367. func (rm *SReceiverManager) findUserIdsWithProjectDomain(ctx context.Context, userCred mcclient.TokenCredential, projectDomainId string) ([]string, error) {
  368. session := auth.GetSession(ctx, userCred, "")
  369. query := jsonutils.NewDict()
  370. query.Set("effective", jsonutils.JSONTrue)
  371. query.Set("project_domain_id", jsonutils.NewString(projectDomainId))
  372. listRet, err := identity_modules.RoleAssignments.List(session, query)
  373. if err != nil {
  374. return nil, errors.Wrap(err, "unable to list RoleAssignments")
  375. }
  376. userIds := sets.NewString()
  377. for i := range listRet.Data {
  378. ras := listRet.Data[i]
  379. user, err := ras.Get("user")
  380. if err == nil {
  381. id, err := user.GetString("id")
  382. if err != nil {
  383. return nil, errors.Wrap(err, "unable to get user.id from result of RoleAssignments.List")
  384. }
  385. userIds.Insert(id)
  386. }
  387. }
  388. return userIds.UnsortedList(), nil
  389. }
  390. func (rm *SReceiverManager) domainIdsFromReceivers(ctx context.Context, receivers []string) ([]string, error) {
  391. res, err := rm.FetchByIdOrNames(ctx, receivers...)
  392. if err != nil {
  393. return nil, errors.Wrap(err, "unable to fetch receivres by id or names")
  394. }
  395. domainIds := sets.NewString()
  396. for i := range res {
  397. domainIds.Insert(res[i].DomainId)
  398. }
  399. return domainIds.UnsortedList(), nil
  400. }
  401. func (rm *SReceiverManager) PerformGetTypes(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ConfigManagerGetTypesInput) (api.ConfigManagerGetTypesOutput, error) {
  402. output := api.ConfigManagerGetTypesOutput{}
  403. var reduce func([]*sqlchemy.SQuery) *sqlchemy.SQuery
  404. var err error
  405. switch input.Operation {
  406. case "", "merge":
  407. reduce = func(qs []*sqlchemy.SQuery) *sqlchemy.SQuery {
  408. q := qs[0]
  409. for i := 1; i < len(qs); i++ {
  410. q = q.In("type", qs[i])
  411. }
  412. return q
  413. }
  414. case "union":
  415. reduce = func(qs []*sqlchemy.SQuery) *sqlchemy.SQuery {
  416. if len(qs) == 1 {
  417. return qs[0]
  418. }
  419. iqs := make([]sqlchemy.IQuery, 0, len(qs))
  420. for i := range qs {
  421. iqs = append(iqs, qs[i])
  422. }
  423. union, _ := sqlchemy.UnionWithError(iqs...)
  424. if err != nil {
  425. }
  426. return union.Query()
  427. }
  428. default:
  429. return output, httperrors.NewInputParameterError("unkown operation %q", input.Operation)
  430. }
  431. domainIds, err := rm.domainIdsFromReceivers(ctx, input.Receivers)
  432. if err != nil {
  433. return output, err
  434. }
  435. domainIds = sets.NewString(append(domainIds, input.DomainIds...)...).UnsortedList()
  436. qs := make([]*sqlchemy.SQuery, 0, len(domainIds))
  437. if len(domainIds) == 0 {
  438. qs = append(qs, ConfigManager.contactTypesQuery(""))
  439. } else {
  440. for i := range domainIds {
  441. ctypeQ := ConfigManager.contactTypesQuery(domainIds[i])
  442. qs = append(qs, ctypeQ)
  443. }
  444. }
  445. q := reduce(qs)
  446. allTypes := make([]struct {
  447. Type string
  448. }, 0, 3)
  449. err = q.All(&allTypes)
  450. if err != nil {
  451. return output, err
  452. }
  453. ret := make([]string, len(allTypes))
  454. for i := range ret {
  455. ret[i] = allTypes[i].Type
  456. }
  457. if !utils.IsInStringArray(api.WEBCONSOLE, ret) {
  458. ret = append(ret, api.WEBCONSOLE)
  459. }
  460. output.Types = ret
  461. return output, nil
  462. }
  463. func (rm *SReceiverManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []interface{}, fields stringutils2.SSortedStrings, isList bool) []api.ReceiverDetails {
  464. sRows := rm.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  465. rows := make([]api.ReceiverDetails, len(objs))
  466. recvIds := []string{}
  467. for i := range rows {
  468. rows[i].VirtualResourceDetails = sRows[i]
  469. user := objs[i].(*SReceiver)
  470. recvIds = append(recvIds, user.Id)
  471. rows[i].InternationalMobile = api.ParseInternationalMobile(user.Mobile)
  472. rows[i].EnabledContactTypes = []string{}
  473. if user.EnabledEmail.Bool() {
  474. rows[i].EnabledContactTypes = append(rows[i].EnabledContactTypes, api.EMAIL)
  475. }
  476. if user.EnabledMobile.Bool() {
  477. rows[i].EnabledContactTypes = append(rows[i].EnabledContactTypes, api.MOBILE)
  478. }
  479. rows[i].EnabledContactTypes = append(rows[i].EnabledContactTypes, api.WEBCONSOLE)
  480. rows[i].VerifiedInfos = []api.VerifiedInfo{
  481. {
  482. ContactType: api.EMAIL,
  483. Verified: user.VerifiedEmail.Bool(),
  484. },
  485. {
  486. ContactType: api.MOBILE,
  487. Verified: user.VerifiedMobile.Bool(),
  488. },
  489. {
  490. ContactType: api.WEBCONSOLE,
  491. Verified: true,
  492. },
  493. }
  494. }
  495. subContacts, err := rm.FetchSubContacts(recvIds)
  496. if err != nil {
  497. return rows
  498. }
  499. for i := range rows {
  500. for _, contact := range subContacts[recvIds[i]] {
  501. if contact.Enabled.Bool() {
  502. rows[i].EnabledContactTypes = append(rows[i].EnabledContactTypes, contact.Type)
  503. }
  504. rows[i].VerifiedInfos = append(rows[i].VerifiedInfos, api.VerifiedInfo{
  505. ContactType: contact.Type,
  506. Verified: contact.Verified.Bool(),
  507. Note: contact.VerifiedNote,
  508. })
  509. }
  510. rows[i].EnabledContactTypes = sortContactType(rows[i].EnabledContactTypes)
  511. }
  512. return rows
  513. }
  514. func (rm *SReceiverManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  515. q, err := rm.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
  516. if err == nil {
  517. return q, nil
  518. }
  519. return q, httperrors.ErrNotFound
  520. }
  521. func (rm *SReceiverManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ReceiverListInput) (*sqlchemy.SQuery, error) {
  522. q, err := rm.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput)
  523. if err != nil {
  524. return nil, err
  525. }
  526. return q, nil
  527. }
  528. func (r *SReceiver) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  529. r.SVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  530. cTypes := jsonutils.GetQueryStringArray(data, "enabled_contact_types")
  531. err := r.StartSubcontactPullTask(ctx, userCred, cTypes, "")
  532. if err != nil {
  533. logclient.AddActionLogWithContext(ctx, r, logclient.ACT_CREATE, err, userCred, false)
  534. return
  535. }
  536. logclient.AddActionLogWithContext(ctx, r, logclient.ACT_CREATE, err, userCred, true)
  537. }
  538. func (r *SReceiver) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  539. err := r.SVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
  540. if err != nil {
  541. return nil
  542. }
  543. var input api.ReceiverCreateInput
  544. err = data.Unmarshal(&input)
  545. if err != nil {
  546. return err
  547. }
  548. r.Id = input.UID
  549. r.Mobile = input.InternationalMobile.String()
  550. // 需求:管理后台新建的联系人,手机号和邮箱无需进行校验
  551. // 方案:检查请求者对于创建联系人 是否具有system scope
  552. allowScope, _ := policy.PolicyManager.AllowScope(userCred, api.SERVICE_TYPE, ReceiverManager.KeywordPlural(), policy.PolicyActionCreate)
  553. if allowScope == rbacscope.ScopeSystem {
  554. if utils.IsInStringArray(api.EMAIL, input.EnabledContactTypes) {
  555. r.VerifiedEmail = tristate.True
  556. }
  557. if utils.IsInStringArray(api.MOBILE, input.EnabledContactTypes) {
  558. r.VerifiedMobile = tristate.True
  559. }
  560. }
  561. return nil
  562. }
  563. func (r *SReceiver) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ReceiverUpdateInput) (api.ReceiverUpdateInput, error) {
  564. var err error
  565. input.VirtualResourceBaseUpdateInput, err = r.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.VirtualResourceBaseUpdateInput)
  566. if err != nil {
  567. return input, err
  568. }
  569. // validate email
  570. if ok := len(input.Email) == 0 || regutils.MatchEmail(input.Email); !ok {
  571. return input, httperrors.NewInputParameterError("invalid email")
  572. }
  573. // validate mobile
  574. if len(input.InternationalMobile.Mobile) > 0 {
  575. input.InternationalMobile.AcceptExtMobile()
  576. if ok := len(input.InternationalMobile.Mobile) == 0 || LaxMobileRegexp.MatchString(input.InternationalMobile.Mobile); !ok {
  577. return input, httperrors.NewInputParameterError("invalid mobile")
  578. }
  579. input.Mobile = input.InternationalMobile.String()
  580. } else {
  581. input.InternationalMobile.AreaCode = ""
  582. }
  583. if input.ForceVerified {
  584. allowScope, _ := policy.PolicyManager.AllowScope(userCred, api.SERVICE_TYPE, ReceiverManager.KeywordPlural(), policy.PolicyActionCreate)
  585. if allowScope != rbacscope.ScopeSystem {
  586. return input, httperrors.ErrNotSufficientPrivilege
  587. }
  588. }
  589. if len(input.Email) > 0 && input.Email != r.Email {
  590. if input.ForceVerified {
  591. r.VerifiedEmail = tristate.True
  592. } else {
  593. r.VerifiedEmail = tristate.False
  594. }
  595. }
  596. if len(input.Mobile) > 0 && input.Mobile != r.Mobile {
  597. if input.ForceVerified {
  598. r.VerifiedMobile = tristate.True
  599. } else {
  600. r.VerifiedMobile = tristate.False
  601. }
  602. }
  603. for _, cType := range input.EnabledContactTypes {
  604. driver := GetDriver(cType)
  605. if driver == nil {
  606. return input, httperrors.NewInputParameterError("invalid enabled contact type %s", cType)
  607. }
  608. }
  609. return input, nil
  610. }
  611. func (r *SReceiver) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  612. r.SVirtualResourceBase.PostUpdate(ctx, userCred, query, data)
  613. var input api.ReceiverUpdateInput
  614. data.Unmarshal(&input)
  615. subs, _ := r.GetSubContacts()
  616. for i := range subs {
  617. if subs[i].ParentContactType == api.EMAIL && subs[i].Verified.IsTrue() && r.VerifiedEmail.IsFalse() {
  618. db.Update(&subs[i], func() error {
  619. subs[i].Verified = tristate.False
  620. subs[i].VerifiedNote = "email changed, re-verify"
  621. return nil
  622. })
  623. } else if subs[i].ParentContactType == api.MOBILE && subs[i].Verified.IsTrue() && r.VerifiedMobile.IsFalse() {
  624. db.Update(&subs[i], func() error {
  625. subs[i].Verified = tristate.False
  626. subs[i].VerifiedNote = "mobile changed, re-verify"
  627. return nil
  628. })
  629. }
  630. }
  631. cTypes := jsonutils.GetQueryStringArray(data, "enabled_contact_types")
  632. err := r.StartSubcontactPullTask(ctx, userCred, cTypes, "")
  633. if err != nil {
  634. logclient.AddActionLogWithContext(ctx, r, logclient.ACT_UPDATE, err, userCred, false)
  635. return
  636. }
  637. logclient.AddActionLogWithContext(ctx, r, logclient.ACT_UPDATE, err, userCred, true)
  638. }
  639. func (r *SReceiver) StartSubcontactPullTask(ctx context.Context, userCred mcclient.TokenCredential, contactTypes []string, parentTaskId string) error {
  640. if len(r.Mobile) == 0 {
  641. return nil
  642. }
  643. r.SetStatus(ctx, userCred, api.RECEIVER_STATUS_PULLING, "")
  644. params := jsonutils.NewDict()
  645. if len(contactTypes) > 0 {
  646. params.Set("contact_types", jsonutils.NewStringArray(contactTypes))
  647. }
  648. task, err := taskman.TaskManager.NewTask(ctx, "SubcontactPullTask", r, userCred, params, parentTaskId, "")
  649. if err != nil {
  650. return err
  651. }
  652. return task.ScheduleRun(nil)
  653. }
  654. func (r *SReceiver) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  655. subs, _ := r.GetSubContacts()
  656. for _, sc := range subs {
  657. err := sc.Delete(ctx, userCred)
  658. if err != nil {
  659. return err
  660. }
  661. }
  662. r.deleteReceiverInSubscriber(ctx)
  663. return r.SVirtualResourceBase.Delete(ctx, userCred)
  664. }
  665. func (r *SReceiver) deleteReceiverInSubscriber(ctx context.Context) error {
  666. q := SubscriberReceiverManager.Query().Equals("receiver_id", r.Id)
  667. srs := make([]SSubscriberReceiver, 0, 2)
  668. err := db.FetchModelObjects(SubscriberReceiverManager, q, &srs)
  669. if err != nil {
  670. return errors.Wrapf(err, "db.FetchModelObjects")
  671. }
  672. for i := range srs {
  673. srs[i].Delete(ctx, nil)
  674. }
  675. return nil
  676. }
  677. func (r *SReceiver) IsOwner(userCred mcclient.TokenCredential) bool {
  678. return r.Id == userCred.GetUserId()
  679. }
  680. // 获取用户订阅
  681. func (r *SReceiver) PerformGetSubscription(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ReceiverGetSubscriptionOptions) (jsonutils.JSONObject, error) {
  682. s := auth.GetAdminSession(ctx, options.Options.Region)
  683. subscribers, err := getSubscriberByReceiverId(r.Id, input.ShowDisabled)
  684. if err != nil {
  685. return nil, errors.Wrap(err, "getSubscriberByReceiverId")
  686. }
  687. type retStruct struct {
  688. SSubscriber
  689. IdentityName string
  690. TopicName string
  691. TopicType string
  692. }
  693. res := []retStruct{}
  694. for _, subscriber := range subscribers {
  695. topicModel, err := TopicManager.FetchById(subscriber.TopicId)
  696. if err != nil {
  697. if errors.Cause(err) != errors.ErrNotFound {
  698. continue
  699. }
  700. return nil, errors.Wrap(err, "fetch topic by id")
  701. }
  702. topic := topicModel.(*STopic)
  703. if topic.Enabled == tristate.False {
  704. continue
  705. }
  706. identityName := ""
  707. if subscriber.Type == api.SUBSCRIBER_TYPE_ROLE {
  708. role := identity_api.RoleDetails{}
  709. roleDetail, err := identity_modules.RolesV3.GetById(s, subscriber.Identification, nil)
  710. if err != nil {
  711. log.Warningf("get %s role details err:%s", subscriber.Identification, err)
  712. }
  713. if roleDetail != nil {
  714. roleDetail.Unmarshal(&role)
  715. identityName = role.Name
  716. }
  717. } else {
  718. identityName = r.Name
  719. }
  720. res = append(res, retStruct{SSubscriber: subscriber, IdentityName: identityName, TopicName: topic.GetName(), TopicType: topic.Type})
  721. }
  722. return jsonutils.Marshal(res), nil
  723. }
  724. func (rm *SReceiverManager) PerformIntellijGet(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ReceiverIntellijGetInput) (jsonutils.JSONObject, error) {
  725. ret := &SReceiver{}
  726. ret.SetModelManager(rm, ret)
  727. err := rm.Query().Equals("id", input.UserId).First(ret)
  728. if err != nil && errors.Cause(err) != sql.ErrNoRows {
  729. return nil, err
  730. }
  731. if len(ret.Id) > 0 {
  732. return jsonutils.Marshal(ret), nil
  733. }
  734. // create one
  735. adminSession := auth.GetAdminSession(ctx, "")
  736. resp, err := identity_modules.UsersV3.GetById(adminSession, input.UserId, jsonutils.Marshal(map[string]string{"scope": "system"}))
  737. if err != nil {
  738. return nil, errors.Wrap(err, "unable get user from keystone")
  739. }
  740. err = resp.Unmarshal(ret)
  741. if err != nil {
  742. return nil, errors.Wrapf(err, "Unmarshal")
  743. }
  744. err = rm.TableSpec().InsertOrUpdate(ctx, ret)
  745. if err != nil {
  746. return nil, errors.Wrap(err, "unable to create receiver")
  747. }
  748. return jsonutils.Marshal(ret), nil
  749. }
  750. func (r *SReceiver) PerformTriggerVerify(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ReceiverTriggerVerifyInput) (jsonutils.JSONObject, error) {
  751. if len(input.ContactType) == 0 {
  752. return nil, httperrors.NewMissingParameterError("contact_type")
  753. }
  754. if !utils.IsInStringArray(input.ContactType, []string{api.EMAIL, api.MOBILE, api.DINGTALK, api.FEISHU, api.WORKWX}) {
  755. return nil, httperrors.NewInputParameterError("not support such contact type %q", input.ContactType)
  756. }
  757. driver := GetDriver(input.ContactType)
  758. if driver.IsPullType() {
  759. return nil, r.StartSubcontactPullTask(ctx, userCred, []string{input.ContactType}, "")
  760. }
  761. _, err := VerificationManager.Create(ctx, r.Id, input.ContactType)
  762. /*if err == ErrVerifyFrequently {
  763. return nil, httperrors.NewForbiddenError("Send verify message too frequently, please try again later")
  764. }*/
  765. if err != nil {
  766. return nil, errors.Wrap(err, "VerifyManager.Create")
  767. }
  768. params := jsonutils.Marshal(input).(*jsonutils.JSONDict)
  769. task, err := taskman.TaskManager.NewTask(ctx, "VerificationSendTask", r, userCred, params, "", "")
  770. if err != nil {
  771. return nil, err
  772. }
  773. return nil, task.ScheduleRun(nil)
  774. }
  775. func (r *SReceiver) PerformVerify(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ReceiverVerifyInput) (jsonutils.JSONObject, error) {
  776. if len(input.ContactType) == 0 {
  777. return nil, httperrors.NewMissingParameterError("contact_type")
  778. }
  779. if !utils.IsInStringArray(input.ContactType, []string{api.EMAIL, api.MOBILE}) {
  780. return nil, httperrors.NewInputParameterError("not support such contact type %q", input.ContactType)
  781. }
  782. verification, err := VerificationManager.Get(r.Id, input.ContactType)
  783. if err != nil {
  784. return nil, err
  785. }
  786. if verification.CreatedAt.Add(time.Duration(options.Options.VerifyValidInterval) * time.Minute).Before(time.Now()) {
  787. return nil, httperrors.NewForbiddenError("The validation expires, please retrieve the verification code again")
  788. }
  789. if verification.Token != input.Token {
  790. return nil, httperrors.NewInputParameterError("wrong token")
  791. }
  792. _, err = db.Update(r, func() error {
  793. switch input.ContactType {
  794. case api.EMAIL:
  795. r.VerifiedEmail = tristate.True
  796. case api.MOBILE:
  797. r.VerifiedMobile = tristate.True
  798. default:
  799. // no way
  800. }
  801. return nil
  802. })
  803. return nil, err
  804. }
  805. func (r *SReceiver) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) {
  806. err := db.EnabledPerformEnable(r, ctx, userCred, true)
  807. if err != nil {
  808. return nil, errors.Wrap(err, "EnabledPerformEnable")
  809. }
  810. return nil, nil
  811. }
  812. func (r *SReceiver) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) {
  813. err := db.EnabledPerformEnable(r, ctx, userCred, false)
  814. if err != nil {
  815. return nil, errors.Wrap(err, "EnabledPerformEnable")
  816. }
  817. return nil, nil
  818. }
  819. func (r *SReceiver) Sync(ctx context.Context) error {
  820. user, err := db.UserCacheManager.FetchUserById(ctx, r.Id)
  821. if err != nil {
  822. return err
  823. }
  824. _, err = db.Update(r, func() error {
  825. r.Name = user.Name
  826. r.DomainId = user.DomainId
  827. if len(user.Lang) > 0 {
  828. r.Lang = user.Lang
  829. }
  830. return nil
  831. })
  832. return errors.Wrap(err, "unable to update")
  833. }
  834. func (r *SReceiver) GetTemplateLang(ctx context.Context) (string, error) {
  835. if len(r.Lang) == 0 {
  836. err := r.Sync(ctx)
  837. if err != nil {
  838. return "", err
  839. }
  840. }
  841. log.Infof("lang: %s", r.Lang)
  842. lang, err := language.Parse(r.Lang)
  843. if err != nil {
  844. return "", errors.Wrapf(err, "unable to prase language %q", r.Lang)
  845. }
  846. tLang := notifyclientI18nTable.LookupByLang(lang, tempalteLang)
  847. return tLang, nil
  848. }
  849. // Implemente interface EventHandler
  850. func (rm *SReceiverManager) OnAdd(obj *jsonutils.JSONDict) {
  851. // do nothing
  852. return
  853. }
  854. func (rm *SReceiverManager) OnUpdate(oldObj, newObj *jsonutils.JSONDict) {
  855. userId, _ := newObj.GetString("id")
  856. receivers, err := rm.FetchByIDs(context.Background(), userId)
  857. if err != nil {
  858. log.Errorf("fail to FetchByIDs: %v", err)
  859. return
  860. }
  861. if len(receivers) == 0 {
  862. return
  863. }
  864. receiver := &receivers[0]
  865. uname, _ := newObj.GetString("name")
  866. domainId, _ := newObj.GetString("domain_id")
  867. lang, _ := newObj.GetString("lang")
  868. if receiver.Name == uname && receiver.DomainId == domainId && receiver.Lang == lang {
  869. return
  870. }
  871. _, err = db.Update(receiver, func() error {
  872. receiver.Name = uname
  873. receiver.DomainId = domainId
  874. receiver.Lang = lang
  875. return nil
  876. })
  877. if err != nil {
  878. log.Errorf("fail to update uname of contact %q: %v", receiver.Id, err)
  879. }
  880. }
  881. func (rm *SReceiverManager) OnDelete(obj *jsonutils.JSONDict) {
  882. userId, _ := obj.GetString("id")
  883. log.Infof("receiver delete event for user %q", userId)
  884. receivers, err := rm.FetchByIDs(context.Background(), userId)
  885. if err != nil {
  886. log.Errorf("fail to FetchByIDs: %v", err)
  887. return
  888. }
  889. if len(receivers) == 0 {
  890. return
  891. }
  892. receiver := &receivers[0]
  893. err = receiver.Delete(context.Background(), auth.GetAdminSession(context.Background(), "").GetToken())
  894. if err != nil {
  895. log.Errorf("fail to delete contact %q: %v", receiver.Id, err)
  896. }
  897. }
  898. // 监听User变化
  899. func (rm *SReceiverManager) StartWatchUserInKeystone() error {
  900. adminSession := auth.GetAdminSession(context.Background(), "")
  901. watchMan, err := informer.NewWatchManagerBySession(adminSession)
  902. if err != nil {
  903. return err
  904. }
  905. resMan := &identity_modules.UsersV3
  906. return watchMan.For(resMan).AddEventHandler(context.Background(), rm)
  907. }
  908. func (rm *SReceiverManager) FetchByIDs(ctx context.Context, ids ...string) ([]SReceiver, error) {
  909. if len(ids) == 0 {
  910. return nil, nil
  911. }
  912. var err error
  913. q := rm.Query()
  914. if len(ids) == 1 {
  915. q = q.Equals("id", ids[0])
  916. } else {
  917. q = q.In("id", ids)
  918. }
  919. contacts := make([]SReceiver, 0, len(ids))
  920. err = db.FetchModelObjects(rm, q, &contacts)
  921. if err != nil {
  922. return nil, err
  923. }
  924. return contacts, nil
  925. }
  926. func idOrNameFilter(q *sqlchemy.SQuery, idOrNames ...string) *sqlchemy.SQuery {
  927. if len(idOrNames) == 0 {
  928. return q
  929. }
  930. var conds []sqlchemy.ICondition
  931. for _, idOrName := range idOrNames {
  932. conds = append(conds, sqlchemy.Equals(q.Field("name"), idOrName))
  933. if !stringutils2.IsUtf8(idOrName) {
  934. conds = append(conds, sqlchemy.Equals(q.Field("id"), idOrName))
  935. }
  936. }
  937. if len(conds) == 1 {
  938. q = q.Filter(conds[0])
  939. } else if len(conds) > 1 {
  940. q = q.Filter(sqlchemy.OR(conds...))
  941. }
  942. return q
  943. }
  944. func (rm *SReceiverManager) FetchByIdOrNames(ctx context.Context, idOrNames ...string) ([]SReceiver, error) {
  945. if len(idOrNames) == 0 {
  946. return nil, nil
  947. }
  948. var err error
  949. q := idOrNameFilter(rm.Query(), idOrNames...)
  950. receivers := make([]SReceiver, 0, len(idOrNames))
  951. err = db.FetchModelObjects(rm, q, &receivers)
  952. if err != nil {
  953. return nil, err
  954. }
  955. return receivers, nil
  956. }
  957. func (rm *SReceiverManager) FetchEnableReceiversByIdOrNames(ctx context.Context, idOrNames ...string) ([]SReceiver, error) {
  958. if len(idOrNames) == 0 {
  959. return nil, nil
  960. }
  961. var err error
  962. q := idOrNameFilter(rm.Query(), idOrNames...)
  963. q.Equals("enabled", true)
  964. receivers := make([]SReceiver, 0, len(idOrNames))
  965. err = db.FetchModelObjects(rm, q, &receivers)
  966. if err != nil {
  967. return nil, err
  968. }
  969. return receivers, nil
  970. }
  971. func (r *SReceiver) SetContact(cType string, contact string) error {
  972. var err error
  973. switch cType {
  974. case api.EMAIL:
  975. _, err = db.Update(r, func() error {
  976. r.Email = contact
  977. return nil
  978. })
  979. case api.MOBILE:
  980. _, err = db.Update(r, func() error {
  981. r.Mobile = contact
  982. return nil
  983. })
  984. default:
  985. subs, _ := r.GetSubContacts()
  986. for i := range subs {
  987. if subs[i].Type == cType {
  988. _, err = db.Update(&subs[i], func() error {
  989. subs[i].Contact = contact
  990. return nil
  991. })
  992. }
  993. }
  994. }
  995. return err
  996. }
  997. func (r *SReceiver) GetContact(cType string) (string, error) {
  998. switch cType {
  999. case api.EMAIL:
  1000. return r.Email, nil
  1001. case api.MOBILE:
  1002. return r.Mobile, nil
  1003. case api.WEBCONSOLE:
  1004. return r.Id, nil
  1005. case api.FEISHU_ROBOT, api.DINGTALK_ROBOT, api.WORKWX_ROBOT:
  1006. return r.Mobile, nil
  1007. default:
  1008. subs, _ := r.GetSubContacts()
  1009. for _, sub := range subs {
  1010. if sub.Type == cType {
  1011. return sub.Contact, nil
  1012. }
  1013. }
  1014. }
  1015. return "", nil
  1016. }
  1017. func (r *SReceiver) PerformEnableContactType(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ReceiverEnableContactTypeInput) (jsonutils.JSONObject, error) {
  1018. for _, cType := range input.EnabledContactTypes {
  1019. driver := GetDriver(cType)
  1020. if driver == nil {
  1021. return nil, httperrors.NewInputParameterError("invalid enabled contact type %s", cType)
  1022. }
  1023. }
  1024. return nil, r.StartSubcontactPullTask(ctx, userCred, input.EnabledContactTypes, "")
  1025. }
  1026. func (rm *SReceiverManager) InitializeData() error {
  1027. return nil
  1028. }
  1029. func (self *SReceiver) GetNotifyReceiver() api.SNotifyReceiver {
  1030. ret := api.SNotifyReceiver{
  1031. DomainId: self.DomainId,
  1032. Enabled: self.Enabled.Bool(),
  1033. }
  1034. return ret
  1035. }
  1036. func (manager *SReceiverManager) SyncUserFromKeystone(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  1037. err := manager.syncUserFromKeystone(ctx, userCred, isStart)
  1038. if err != nil {
  1039. log.Errorf("syncUserFromKeystone error %s", err)
  1040. }
  1041. }
  1042. func InitReceiverProject(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  1043. q := ReceiverManager.Query().IsNullOrEmpty("tenant_id")
  1044. receivers := []SReceiver{}
  1045. err := db.FetchModelObjects(ReceiverManager, q, &receivers)
  1046. if err != nil {
  1047. log.Errorln(errors.Wrap(err, "fetch receiver"))
  1048. return
  1049. }
  1050. for _, receiver := range receivers {
  1051. db.Update(&receiver, func() error {
  1052. receiver.ProjectId = auth.AdminCredential().GetTenantId()
  1053. return nil
  1054. })
  1055. }
  1056. }
  1057. func (manager *SReceiverManager) syncUserFromKeystone(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) error {
  1058. params := jsonutils.NewDict()
  1059. params.Add(jsonutils.NewString(string(rbacscope.ScopeSystem)), "scope")
  1060. // params.Add(jsonutils.JSONTrue, "system")
  1061. params.Add(jsonutils.JSONTrue, "enabled")
  1062. params.Add(jsonutils.NewInt(100), "limit")
  1063. offset := 0
  1064. total := -1
  1065. for total < 0 || offset < total {
  1066. params.Set("offset", jsonutils.NewInt(int64(offset)))
  1067. results, err := identity_modules.UsersV3.List(auth.GetAdminSession(ctx, options.Options.Region), params)
  1068. if err != nil {
  1069. return errors.Wrap(err, "List user")
  1070. }
  1071. for i := range results.Data {
  1072. err := manager.syncUser(ctx, userCred, results.Data[i])
  1073. if err != nil {
  1074. return errors.Wrapf(err, "sync user %s", results.Data[i])
  1075. }
  1076. }
  1077. total = results.Total
  1078. offset += len(results.Data)
  1079. }
  1080. return nil
  1081. }
  1082. func (manager *SReceiverManager) syncUser(ctx context.Context, userCred mcclient.TokenCredential, usrData jsonutils.JSONObject) error {
  1083. usr := identity_api.UserDetails{}
  1084. err := usrData.Unmarshal(&usr)
  1085. if err != nil {
  1086. return errors.Wrap(err, "usrData.Unmarshal")
  1087. }
  1088. if len(usr.Id) == 0 {
  1089. log.Fatalf("sync user with empty id?")
  1090. }
  1091. if len(usr.Email) == 0 && len(usr.Mobile) == 0 {
  1092. // no need to sync
  1093. return nil
  1094. }
  1095. if usr.IsSystemAccount != nil && *usr.IsSystemAccount {
  1096. // no need to sync
  1097. return nil
  1098. }
  1099. recvObj, err := manager.FetchById(usr.Id)
  1100. if err != nil {
  1101. if errors.Cause(err) != sql.ErrNoRows {
  1102. return errors.Wrap(err, "FetchById")
  1103. }
  1104. // new receiver
  1105. recver := SReceiver{}
  1106. recver.SetModelManager(manager, &recver)
  1107. recver.Id = usr.Id
  1108. recver.Name = usr.Name
  1109. recver.Status = api.RECEIVER_STATUS_READY
  1110. recver.DomainId = usr.DomainId
  1111. recver.Enabled = tristate.True
  1112. recver.Mobile = usr.Mobile
  1113. recver.Email = usr.Email
  1114. if len(recver.Mobile) > 0 {
  1115. recver.VerifiedMobile = tristate.True
  1116. }
  1117. if len(recver.Email) > 0 {
  1118. recver.VerifiedEmail = tristate.True
  1119. }
  1120. err := manager.TableSpec().InsertOrUpdate(ctx, &recver)
  1121. if err != nil {
  1122. return errors.Wrap(err, "Insert")
  1123. }
  1124. logclient.AddSimpleActionLog(&recver, logclient.ACT_CREATE, &recver, userCred, true)
  1125. } else {
  1126. // update receiver
  1127. recver := recvObj.(*SReceiver)
  1128. if (len(recver.Mobile) == 0 && len(usr.Mobile) > 0) || (len(recver.Email) == 0 && len(usr.Email) > 0) {
  1129. // need update
  1130. diff, err := db.Update(recver, func() error {
  1131. if len(recver.Mobile) == 0 && len(usr.Mobile) > 0 {
  1132. recver.Mobile = usr.Mobile
  1133. recver.VerifiedMobile = tristate.True
  1134. }
  1135. if len(recver.Email) == 0 && len(usr.Email) > 0 {
  1136. recver.Email = usr.Email
  1137. recver.VerifiedEmail = tristate.True
  1138. }
  1139. return nil
  1140. })
  1141. if err != nil {
  1142. return errors.Wrap(err, "Update")
  1143. }
  1144. logclient.AddSimpleActionLog(recver, logclient.ACT_UPDATE, diff, userCred, true)
  1145. }
  1146. }
  1147. return nil
  1148. }
  1149. func (r *SReceiver) GetDomainId() string {
  1150. return r.DomainId
  1151. }
  1152. func (r *SReceiver) IsRobot() bool {
  1153. return false
  1154. }
  1155. func (r *SReceiver) IsReceiver() bool {
  1156. return true
  1157. }
  1158. func (r *SReceiver) GetName() string {
  1159. return r.Name
  1160. }
  1161. func (manager *SReceiverManager) GetPropertyRoleContactType(ctx context.Context, userCred mcclient.TokenCredential, input api.SRoleContactInput) (jsonutils.JSONObject, error) {
  1162. out := api.SRoleContactOutput{
  1163. ContactType: []string{},
  1164. }
  1165. if len(input.RoleIds) == 0 {
  1166. return nil, httperrors.NewMissingParameterError("role_ids")
  1167. }
  1168. receiverIds := []string{}
  1169. params := jsonutils.NewDict()
  1170. params.Set("roles", jsonutils.NewStringArray(input.RoleIds))
  1171. params.Set("effective", jsonutils.JSONTrue)
  1172. switch input.Scope {
  1173. case api.SUBSCRIBER_SCOPE_SYSTEM:
  1174. case api.SUBSCRIBER_SCOPE_DOMAIN:
  1175. if len(input.ProjectDomainId) == 0 {
  1176. return nil, httperrors.NewMissingParameterError("project_domain_id")
  1177. }
  1178. params.Set("project_domain_id", jsonutils.NewString(input.ProjectDomainId))
  1179. case api.SUBSCRIBER_SCOPE_PROJECT:
  1180. if len(input.ProjectId) == 0 {
  1181. return nil, httperrors.NewMissingParameterError("project_id")
  1182. }
  1183. params.Add(jsonutils.NewString(input.ProjectId), "scope", "project", "id")
  1184. }
  1185. s := auth.GetAdminSession(ctx, "")
  1186. listRet, err := identity_modules.RoleAssignments.List(s, params)
  1187. if err != nil {
  1188. return nil, errors.Wrap(err, "unable to list RoleAssignments")
  1189. }
  1190. roleAssignmentOut := []identity_api.SRoleAssignment{}
  1191. jsonutils.Update(&roleAssignmentOut, listRet.Data)
  1192. for i := range roleAssignmentOut {
  1193. receiverIds = append(receiverIds, roleAssignmentOut[i].User.Id)
  1194. }
  1195. subContacts, err := manager.FetchSubContacts(receiverIds)
  1196. if err != nil {
  1197. return nil, errors.Wrap(err, "fetch subcontacts")
  1198. }
  1199. contactMap := map[string]struct{}{}
  1200. for i := range receiverIds {
  1201. for _, contact := range subContacts[receiverIds[i]] {
  1202. if contact.Enabled.Bool() {
  1203. contactMap[contact.Type] = struct{}{}
  1204. }
  1205. }
  1206. }
  1207. for contactType := range contactMap {
  1208. out.ContactType = append(out.ContactType, contactType)
  1209. }
  1210. return jsonutils.Marshal(out), nil
  1211. }