baserules.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. # Copyright 2015, 2016 OpenMarket Ltd
  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. from synapse.push.rulekinds import PRIORITY_CLASS_MAP, PRIORITY_CLASS_INVERSE_MAP
  15. import copy
  16. def list_with_base_rules(rawrules):
  17. """Combine the list of rules set by the user with the default push rules
  18. Args:
  19. rawrules(list): The rules the user has modified or set.
  20. Returns:
  21. A new list with the rules set by the user combined with the defaults.
  22. """
  23. ruleslist = []
  24. # Grab the base rules that the user has modified.
  25. # The modified base rules have a priority_class of -1.
  26. modified_base_rules = {
  27. r['rule_id']: r for r in rawrules if r['priority_class'] < 0
  28. }
  29. # Remove the modified base rules from the list, They'll be added back
  30. # in the default postions in the list.
  31. rawrules = [r for r in rawrules if r['priority_class'] >= 0]
  32. # shove the server default rules for each kind onto the end of each
  33. current_prio_class = PRIORITY_CLASS_INVERSE_MAP.keys()[-1]
  34. ruleslist.extend(make_base_prepend_rules(
  35. PRIORITY_CLASS_INVERSE_MAP[current_prio_class], modified_base_rules
  36. ))
  37. for r in rawrules:
  38. if r['priority_class'] < current_prio_class:
  39. while r['priority_class'] < current_prio_class:
  40. ruleslist.extend(make_base_append_rules(
  41. PRIORITY_CLASS_INVERSE_MAP[current_prio_class],
  42. modified_base_rules,
  43. ))
  44. current_prio_class -= 1
  45. if current_prio_class > 0:
  46. ruleslist.extend(make_base_prepend_rules(
  47. PRIORITY_CLASS_INVERSE_MAP[current_prio_class],
  48. modified_base_rules,
  49. ))
  50. ruleslist.append(r)
  51. while current_prio_class > 0:
  52. ruleslist.extend(make_base_append_rules(
  53. PRIORITY_CLASS_INVERSE_MAP[current_prio_class],
  54. modified_base_rules,
  55. ))
  56. current_prio_class -= 1
  57. if current_prio_class > 0:
  58. ruleslist.extend(make_base_prepend_rules(
  59. PRIORITY_CLASS_INVERSE_MAP[current_prio_class],
  60. modified_base_rules,
  61. ))
  62. return ruleslist
  63. def make_base_append_rules(kind, modified_base_rules):
  64. rules = []
  65. if kind == 'override':
  66. rules = BASE_APPEND_OVERRIDE_RULES
  67. elif kind == 'underride':
  68. rules = BASE_APPEND_UNDERRIDE_RULES
  69. elif kind == 'content':
  70. rules = BASE_APPEND_CONTENT_RULES
  71. # Copy the rules before modifying them
  72. rules = copy.deepcopy(rules)
  73. for r in rules:
  74. # Only modify the actions, keep the conditions the same.
  75. modified = modified_base_rules.get(r['rule_id'])
  76. if modified:
  77. r['actions'] = modified['actions']
  78. return rules
  79. def make_base_prepend_rules(kind, modified_base_rules):
  80. rules = []
  81. if kind == 'override':
  82. rules = BASE_PREPEND_OVERRIDE_RULES
  83. # Copy the rules before modifying them
  84. rules = copy.deepcopy(rules)
  85. for r in rules:
  86. # Only modify the actions, keep the conditions the same.
  87. modified = modified_base_rules.get(r['rule_id'])
  88. if modified:
  89. r['actions'] = modified['actions']
  90. return rules
  91. BASE_APPEND_CONTENT_RULES = [
  92. {
  93. 'rule_id': 'global/content/.m.rule.contains_user_name',
  94. 'conditions': [
  95. {
  96. 'kind': 'event_match',
  97. 'key': 'content.body',
  98. 'pattern_type': 'user_localpart'
  99. }
  100. ],
  101. 'actions': [
  102. 'notify',
  103. {
  104. 'set_tweak': 'sound',
  105. 'value': 'default',
  106. }, {
  107. 'set_tweak': 'highlight'
  108. }
  109. ]
  110. },
  111. ]
  112. BASE_PREPEND_OVERRIDE_RULES = [
  113. {
  114. 'rule_id': 'global/override/.m.rule.master',
  115. 'enabled': False,
  116. 'conditions': [],
  117. 'actions': [
  118. "dont_notify"
  119. ]
  120. }
  121. ]
  122. BASE_APPEND_OVERRIDE_RULES = [
  123. {
  124. 'rule_id': 'global/override/.m.rule.suppress_notices',
  125. 'conditions': [
  126. {
  127. 'kind': 'event_match',
  128. 'key': 'content.msgtype',
  129. 'pattern': 'm.notice',
  130. '_id': '_suppress_notices',
  131. }
  132. ],
  133. 'actions': [
  134. 'dont_notify',
  135. ]
  136. },
  137. # NB. .m.rule.invite_for_me must be higher prio than .m.rule.member_event
  138. # otherwise invites will be matched by .m.rule.member_event
  139. {
  140. 'rule_id': 'global/override/.m.rule.invite_for_me',
  141. 'conditions': [
  142. {
  143. 'kind': 'event_match',
  144. 'key': 'type',
  145. 'pattern': 'm.room.member',
  146. '_id': '_member',
  147. },
  148. {
  149. 'kind': 'event_match',
  150. 'key': 'content.membership',
  151. 'pattern': 'invite',
  152. '_id': '_invite_member',
  153. },
  154. {
  155. 'kind': 'event_match',
  156. 'key': 'state_key',
  157. 'pattern_type': 'user_id'
  158. },
  159. ],
  160. 'actions': [
  161. 'notify',
  162. {
  163. 'set_tweak': 'sound',
  164. 'value': 'default'
  165. }, {
  166. 'set_tweak': 'highlight',
  167. 'value': False
  168. }
  169. ]
  170. },
  171. # Will we sometimes want to know about people joining and leaving?
  172. # Perhaps: if so, this could be expanded upon. Seems the most usual case
  173. # is that we don't though. We add this override rule so that even if
  174. # the room rule is set to notify, we don't get notifications about
  175. # join/leave/avatar/displayname events.
  176. # See also: https://matrix.org/jira/browse/SYN-607
  177. {
  178. 'rule_id': 'global/override/.m.rule.member_event',
  179. 'conditions': [
  180. {
  181. 'kind': 'event_match',
  182. 'key': 'type',
  183. 'pattern': 'm.room.member',
  184. '_id': '_member',
  185. }
  186. ],
  187. 'actions': [
  188. 'dont_notify'
  189. ]
  190. },
  191. ]
  192. BASE_APPEND_UNDERRIDE_RULES = [
  193. {
  194. 'rule_id': 'global/underride/.m.rule.call',
  195. 'conditions': [
  196. {
  197. 'kind': 'event_match',
  198. 'key': 'type',
  199. 'pattern': 'm.call.invite',
  200. '_id': '_call',
  201. }
  202. ],
  203. 'actions': [
  204. 'notify',
  205. {
  206. 'set_tweak': 'sound',
  207. 'value': 'ring'
  208. }, {
  209. 'set_tweak': 'highlight',
  210. 'value': False
  211. }
  212. ]
  213. },
  214. {
  215. 'rule_id': 'global/underride/.m.rule.contains_display_name',
  216. 'conditions': [
  217. {
  218. 'kind': 'contains_display_name'
  219. }
  220. ],
  221. 'actions': [
  222. 'notify',
  223. {
  224. 'set_tweak': 'sound',
  225. 'value': 'default'
  226. }, {
  227. 'set_tweak': 'highlight'
  228. }
  229. ]
  230. },
  231. {
  232. 'rule_id': 'global/underride/.m.rule.room_one_to_one',
  233. 'conditions': [
  234. {
  235. 'kind': 'room_member_count',
  236. 'is': '2',
  237. '_id': 'member_count',
  238. },
  239. {
  240. 'kind': 'event_match',
  241. 'key': 'type',
  242. 'pattern': 'm.room.message',
  243. '_id': '_message',
  244. }
  245. ],
  246. 'actions': [
  247. 'notify',
  248. {
  249. 'set_tweak': 'sound',
  250. 'value': 'default'
  251. }, {
  252. 'set_tweak': 'highlight',
  253. 'value': False
  254. }
  255. ]
  256. },
  257. {
  258. 'rule_id': 'global/underride/.m.rule.message',
  259. 'conditions': [
  260. {
  261. 'kind': 'event_match',
  262. 'key': 'type',
  263. 'pattern': 'm.room.message',
  264. '_id': '_message',
  265. }
  266. ],
  267. 'actions': [
  268. 'notify', {
  269. 'set_tweak': 'highlight',
  270. 'value': False
  271. }
  272. ]
  273. }
  274. ]
  275. BASE_RULE_IDS = set()
  276. for r in BASE_APPEND_CONTENT_RULES:
  277. r['priority_class'] = PRIORITY_CLASS_MAP['content']
  278. r['default'] = True
  279. BASE_RULE_IDS.add(r['rule_id'])
  280. for r in BASE_PREPEND_OVERRIDE_RULES:
  281. r['priority_class'] = PRIORITY_CLASS_MAP['override']
  282. r['default'] = True
  283. BASE_RULE_IDS.add(r['rule_id'])
  284. for r in BASE_APPEND_OVERRIDE_RULES:
  285. r['priority_class'] = PRIORITY_CLASS_MAP['override']
  286. r['default'] = True
  287. BASE_RULE_IDS.add(r['rule_id'])
  288. for r in BASE_APPEND_UNDERRIDE_RULES:
  289. r['priority_class'] = PRIORITY_CLASS_MAP['underride']
  290. r['default'] = True
  291. BASE_RULE_IDS.add(r['rule_id'])