2015-12-26 02:19:28 +01:00
|
|
|
from django.db.models import Q
|
2016-03-21 06:02:48 +01:00
|
|
|
from zerver.models import UserProfile, Realm
|
2019-02-11 15:19:38 +01:00
|
|
|
from zerver.lib.cache import cache_with_key, realm_alert_words_cache_key, \
|
|
|
|
realm_alert_words_automaton_cache_key
|
2013-09-03 22:41:17 +02:00
|
|
|
import ujson
|
2019-02-11 15:19:38 +01:00
|
|
|
import ahocorasick
|
2018-05-10 19:13:36 +02:00
|
|
|
from typing import Dict, Iterable, List
|
2013-09-03 22:41:17 +02:00
|
|
|
|
2013-09-06 20:50:25 +02:00
|
|
|
@cache_with_key(realm_alert_words_cache_key, timeout=3600*24)
|
2018-05-10 19:13:36 +02:00
|
|
|
def alert_words_in_realm(realm: Realm) -> Dict[int, List[str]]:
|
2016-03-21 06:02:48 +01:00
|
|
|
users_query = UserProfile.objects.filter(realm=realm, is_active=True)
|
2015-12-26 02:19:28 +01:00
|
|
|
alert_word_data = users_query.filter(~Q(alert_words=ujson.dumps([]))).values('id', 'alert_words')
|
2020-04-09 21:51:58 +02:00
|
|
|
all_user_words = {elt['id']: ujson.loads(elt['alert_words']) for elt in alert_word_data}
|
|
|
|
user_ids_with_words = {user_id: w for (user_id, w) in all_user_words.items() if len(w)}
|
2013-10-09 20:48:05 +02:00
|
|
|
return user_ids_with_words
|
2013-09-03 22:41:17 +02:00
|
|
|
|
2019-02-11 15:19:38 +01:00
|
|
|
@cache_with_key(realm_alert_words_automaton_cache_key, timeout=3600*24)
|
|
|
|
def get_alert_word_automaton(realm: Realm) -> ahocorasick.Automaton:
|
|
|
|
user_id_with_words = alert_words_in_realm(realm)
|
|
|
|
alert_word_automaton = ahocorasick.Automaton()
|
|
|
|
for (user_id, alert_words) in user_id_with_words.items():
|
|
|
|
for alert_word in alert_words:
|
|
|
|
alert_word_lower = alert_word.lower()
|
|
|
|
if alert_word_automaton.exists(alert_word_lower):
|
|
|
|
(key, user_ids_for_alert_word) = alert_word_automaton.get(alert_word_lower)
|
|
|
|
user_ids_for_alert_word.add(user_id)
|
|
|
|
else:
|
2020-04-09 21:51:58 +02:00
|
|
|
alert_word_automaton.add_word(alert_word_lower, (alert_word_lower, {user_id}))
|
2019-02-11 15:19:38 +01:00
|
|
|
alert_word_automaton.make_automaton()
|
|
|
|
# If the kind is not AHOCORASICK after calling make_automaton, it means there is no key present
|
|
|
|
# and hence we cannot call items on the automaton yet. To avoid it we return None for such cases
|
|
|
|
# where there is no alert-words in the realm.
|
|
|
|
# https://pyahocorasick.readthedocs.io/en/latest/index.html?highlight=Automaton.kind#module-constants
|
|
|
|
if alert_word_automaton.kind != ahocorasick.AHOCORASICK:
|
|
|
|
return None
|
|
|
|
return alert_word_automaton
|
|
|
|
|
2018-05-10 19:13:36 +02:00
|
|
|
def user_alert_words(user_profile: UserProfile) -> List[str]:
|
2013-09-03 22:41:17 +02:00
|
|
|
return ujson.loads(user_profile.alert_words)
|
|
|
|
|
2018-05-10 19:13:36 +02:00
|
|
|
def add_user_alert_words(user_profile: UserProfile, alert_words: Iterable[str]) -> List[str]:
|
2013-09-03 22:41:17 +02:00
|
|
|
words = user_alert_words(user_profile)
|
|
|
|
|
2016-05-10 01:55:43 +02:00
|
|
|
new_words = [w for w in alert_words if w not in words]
|
2013-09-03 22:41:17 +02:00
|
|
|
words.extend(new_words)
|
|
|
|
|
|
|
|
set_user_alert_words(user_profile, words)
|
|
|
|
|
2013-09-11 17:24:27 +02:00
|
|
|
return words
|
|
|
|
|
2018-05-10 19:13:36 +02:00
|
|
|
def remove_user_alert_words(user_profile: UserProfile, alert_words: Iterable[str]) -> List[str]:
|
2013-09-03 22:41:17 +02:00
|
|
|
words = user_alert_words(user_profile)
|
2016-05-10 01:55:43 +02:00
|
|
|
words = [w for w in words if w not in alert_words]
|
2013-09-03 22:41:17 +02:00
|
|
|
|
|
|
|
set_user_alert_words(user_profile, words)
|
|
|
|
|
2013-09-11 17:24:27 +02:00
|
|
|
return words
|
|
|
|
|
2018-05-10 19:13:36 +02:00
|
|
|
def set_user_alert_words(user_profile: UserProfile, alert_words: List[str]) -> None:
|
2013-09-03 22:41:17 +02:00
|
|
|
user_profile.alert_words = ujson.dumps(alert_words)
|
|
|
|
user_profile.save(update_fields=['alert_words'])
|