Change domain to realm_id in bugdown and realm filter dicts and caches.

This commit is contained in:
Rishi Gupta
2016-12-30 18:08:43 -08:00
committed by Tim Abbott
parent be6f54d7bb
commit c6e12e74be
8 changed files with 109 additions and 102 deletions

View File

@@ -34,8 +34,8 @@ from zerver.models import Realm, RealmEmoji, Stream, UserProfile, UserActivity,
email_allowed_for_realm, email_to_username, display_recipient_cache_key, \
get_user_profile_by_email, get_stream_cache_key, \
UserActivityInterval, get_active_user_dicts_in_realm, get_active_streams, \
realm_filters_for_domain, RealmFilter, receives_offline_notifications, \
ScheduledJob, realm_filters_for_domain, get_owned_bot_dicts, \
realm_filters_for_realm, RealmFilter, receives_offline_notifications, \
ScheduledJob, get_owned_bot_dicts, \
get_old_unclaimed_attachments, get_cross_realm_emails, receives_online_notifications, \
Reaction
@@ -2796,7 +2796,7 @@ def do_update_message(user_profile, message, subject, propagate_mode, content, r
message.subject = subject
event["stream_id"] = message.recipient.type_id
event["subject"] = subject
event['subject_links'] = bugdown.subject_links(message.sender.realm.domain.lower(), subject)
event['subject_links'] = bugdown.subject_links(message.sender.realm_id, subject)
edit_history_event["prev_subject"] = orig_subject
if propagate_mode in ["change_later", "change_all"]:
@@ -3095,7 +3095,7 @@ def fetch_initial_state_data(user_profile, event_types, queue_id):
state['realm_emoji'] = user_profile.realm.get_emoji()
if want('realm_filters'):
state['realm_filters'] = realm_filters_for_domain(user_profile.realm.domain)
state['realm_filters'] = realm_filters_for_realm(user_profile.realm_id)
if want('realm_user'):
state['realm_users'] = get_realm_user_dicts(user_profile)
@@ -3626,7 +3626,7 @@ def do_set_muted_topics(user_profile, muted_topics):
def notify_realm_filters(realm):
# type: (Realm) -> None
realm_filters = realm_filters_for_domain(realm.domain)
realm_filters = realm_filters_for_realm(realm.id)
user_ids = [userdict['id'] for userdict in get_active_user_dicts_in_realm(realm)]
event = dict(type="realm_filters", realm_filters=realm_filters)
send_event(event, user_ids)

View File

@@ -1022,12 +1022,17 @@ class AtomicLinkPattern(LinkPattern):
ret.text = markdown.util.AtomicString(ret.text)
return ret
# These are used as keys ("realm_ids") to md_engines and the respective
# realm filter caches
DEFAULT_BUGDOWN_KEY = -1
ZEPHYR_MIRROR_BUGDOWN_KEY = -2
class Bugdown(markdown.Extension):
def __init__(self, *args, **kwargs):
# type: (*Any, **Union[bool, None, Text]) -> None
# define default configs
self.config = {
"realm_filters": [kwargs['realm_filters'], "Realm-specific filters for domain"],
"realm_filters": [kwargs['realm_filters'], "Realm-specific filters for realm"],
"realm": [kwargs['realm'], "Realm name"]
}
@@ -1163,7 +1168,7 @@ class Bugdown(markdown.Extension):
if settings.CAMO_URI:
md.treeprocessors.add("rewrite_to_https", InlineHttpsProcessor(md), "_end")
if self.getConfig("realm") == "zephyr_mirror":
if self.getConfig("realm") == ZEPHYR_MIRROR_BUGDOWN_KEY:
# Disable almost all inline patterns for zephyr mirror
# users' traffic that is mirrored. Note that
# inline_interesting_links is a treeprocessor and thus is
@@ -1181,8 +1186,8 @@ class Bugdown(markdown.Extension):
if k not in ["paragraph"]:
del md.parser.blockprocessors[k]
md_engines = {}
realm_filter_data = {} # type: Dict[Text, List[Tuple[Text, Text, int]]]
md_engines = {} # type: Dict[int, markdown.Markdown]
realm_filter_data = {} # type: Dict[int, List[Tuple[Text, Text, int]]]
class EscapeHtml(markdown.Extension):
def extendMarkdown(self, md, md_globals):
@@ -1191,7 +1196,7 @@ class EscapeHtml(markdown.Extension):
del md.inlinePatterns['html']
def make_md_engine(key, opts):
# type: (Text, Dict[str, Any]) -> None
# type: (int, Dict[str, Any]) -> None
md_engines[key] = markdown.Markdown(
output_format = 'html',
extensions = [
@@ -1206,12 +1211,12 @@ def make_md_engine(key, opts):
Bugdown(realm_filters=opts["realm_filters"][0],
realm=opts["realm"][0])])
def subject_links(domain, subject):
# type: (Text, Text) -> List[Text]
from zerver.models import get_realm, RealmFilter, realm_filters_for_domain
def subject_links(realm_id, subject):
# type: (int, Text) -> List[Text]
from zerver.models import get_realm, RealmFilter, realm_filters_for_realm
matches = [] # type: List[Text]
realm_filters = realm_filters_for_domain(domain)
realm_filters = realm_filters_for_realm(realm_id)
for realm_filter in realm_filters:
pattern = prepare_realm_pattern(realm_filter[0])
@@ -1219,35 +1224,35 @@ def subject_links(domain, subject):
matches += [realm_filter[1] % m.groupdict()]
return matches
def make_realm_filters(domain, filters):
# type: (Text, List[Tuple[Text, Text, int]]) -> None
def make_realm_filters(realm_id, filters):
# type: (int, List[Tuple[Text, Text, int]]) -> None
global md_engines, realm_filter_data
if domain in md_engines:
del md_engines[domain]
realm_filter_data[domain] = filters
if realm_id in md_engines:
del md_engines[realm_id]
realm_filter_data[realm_id] = filters
# Because of how the Markdown config API works, this has confusing
# large number of layers of dicts/arrays :(
make_md_engine(domain, {"realm_filters": [filters, "Realm-specific filters for %s" % (domain,)],
"realm": [domain, "Realm name"]})
make_md_engine(realm_id, {"realm_filters": [filters, "Realm-specific filters for realm_id %s" % (realm_id,)],
"realm": [realm_id, "Realm name"]})
def maybe_update_realm_filters(domain):
# type: (Optional[Text]) -> None
from zerver.models import realm_filters_for_domain, all_realm_filters
def maybe_update_realm_filters(realm_id):
# type: (Optional[int]) -> None
from zerver.models import realm_filters_for_realm, all_realm_filters
# If domain is None, load all filters
if domain is None:
# If realm_id is None, load all filters
if realm_id is None:
all_filters = all_realm_filters()
all_filters['default'] = []
for domain, filters in six.iteritems(all_filters):
make_realm_filters(domain, filters)
all_filters[DEFAULT_BUGDOWN_KEY] = []
for realm_id, filters in six.iteritems(all_filters):
make_realm_filters(realm_id, filters)
# Hack to ensure that getConfig("realm") is right for mirrored Zephyrs
make_realm_filters("zephyr_mirror", [])
make_realm_filters(ZEPHYR_MIRROR_BUGDOWN_KEY, [])
else:
realm_filters = realm_filters_for_domain(domain)
if domain not in realm_filter_data or realm_filter_data[domain] != realm_filters:
realm_filters = realm_filters_for_realm(realm_id)
if realm_id not in realm_filter_data or realm_filter_data[realm_id] != realm_filters:
# Data has changed, re-load filters
make_realm_filters(domain, realm_filters)
make_realm_filters(realm_id, realm_filters)
# We want to log Markdown parser failures, but shouldn't log the actual input
# message for privacy reasons. The compromise is to replace all alphanumeric
@@ -1278,21 +1283,21 @@ def log_bugdown_error(msg):
could cause an infinite exception loop."""
logging.getLogger('').error(msg)
def do_convert(content, realm_domain=None, message=None, possible_words=None):
# type: (Text, Optional[Text], Optional[Message], Optional[Set[Text]]) -> Optional[Text]
def do_convert(content, realm_id=None, message=None, possible_words=None):
# type: (Text, Optional[int], Optional[Message], Optional[Set[Text]]) -> Optional[Text]
"""Convert Markdown to HTML, with Zulip-specific settings and hacks."""
from zerver.models import get_active_user_dicts_in_realm, get_active_streams, UserProfile
if message:
maybe_update_realm_filters(message.get_realm().domain)
maybe_update_realm_filters(message.get_realm().id)
if realm_domain in md_engines:
_md_engine = md_engines[realm_domain]
if realm_id in md_engines:
_md_engine = md_engines[realm_id]
else:
if 'default' not in md_engines:
maybe_update_realm_filters(domain=None)
if DEFAULT_BUGDOWN_KEY not in md_engines:
maybe_update_realm_filters(realm_id=None)
_md_engine = md_engines["default"]
_md_engine = md_engines[DEFAULT_BUGDOWN_KEY]
# Reset the parser; otherwise it will get slower over time.
_md_engine.reset()
@@ -1364,9 +1369,9 @@ def bugdown_stats_finish():
bugdown_total_requests += 1
bugdown_total_time += (time.time() - bugdown_time_start)
def convert(content, realm_domain=None, message=None, possible_words=None):
# type: (Text, Optional[Text], Optional[Message], Optional[Set[Text]]) -> Optional[Text]
def convert(content, realm_id=None, message=None, possible_words=None):
# type: (Text, Optional[int], Optional[Message], Optional[Set[Text]]) -> Optional[Text]
bugdown_stats_start()
ret = do_convert(content, realm_domain, message, possible_words)
ret = do_convert(content, realm_id, message, possible_words)
bugdown_stats_finish()
return ret

View File

@@ -18,6 +18,7 @@ from zerver.lib.str_utils import force_bytes, dict_with_str_keys
from zerver.lib.timestamp import datetime_to_timestamp
from zerver.models import (
get_realm,
get_display_recipient_by_id,
Message,
Recipient,
@@ -189,7 +190,7 @@ class MessageDict(object):
avatar_url = avatar_url,
client = sending_client_name)
obj['subject_links'] = bugdown.subject_links(sender_realm_domain.lower(), subject)
obj['subject_links'] = bugdown.subject_links(sender_realm_id, subject)
if last_edit_time != None:
obj['last_edit_timestamp'] = datetime_to_timestamp(last_edit_time)
@@ -315,12 +316,14 @@ def render_markdown(message, content, domain=None, realm_alert_words=None, messa
message.alert_words = set()
message.links_for_preview = set()
if not domain:
domain = message.sender.realm.domain
if domain:
realm_id = get_realm(domain).id
else:
realm_id = message.sender.realm.id
if message.sending_client.name == "zephyr_mirror" and message.sender.realm.is_zephyr_mirror_realm:
# Use slightly customized Markdown processor for content
# delivered via zephyr_mirror
domain = u"zephyr_mirror"
realm_id = bugdown.ZEPHYR_MIRROR_BUGDOWN_KEY
possible_words = set() # type: Set[Text]
if realm_alert_words is not None:
@@ -329,7 +332,8 @@ def render_markdown(message, content, domain=None, realm_alert_words=None, messa
possible_words.update(set(words))
# DO MAIN WORK HERE -- call bugdown to convert
rendered_content = bugdown.convert(content, domain, message, possible_words)
rendered_content = bugdown.convert(content, realm_id=realm_id, message=message,
possible_words=possible_words)
message.user_ids_with_alert_words = set()
@@ -342,4 +346,3 @@ def render_markdown(message, content, domain=None, realm_alert_words=None, messa
message.is_me_message = Message.is_status_message(content, rendered_content)
return rendered_content

View File

@@ -46,7 +46,7 @@ Example: ./manage.py realm_filters --realm=zulip --op=show
# type: (*Any, **str) -> None
realm = get_realm_by_string_id(options["string_id"])
if options["op"] == "show":
print("%s: %s" % (realm.domain, all_realm_filters().get(realm.domain, [])))
print("%s: %s" % (realm.string_id, all_realm_filters().get(realm.id, [])))
sys.exit(0)
pattern = options['pattern']

View File

@@ -431,47 +431,46 @@ class RealmFilter(models.Model):
# type: () -> Text
return u"<RealmFilter(%s): %s %s>" % (self.realm.domain, self.pattern, self.url_format_string)
def get_realm_filters_cache_key(domain):
# type: (Text) -> Text
return u'all_realm_filters:%s' % (domain,)
def get_realm_filters_cache_key(realm_id):
# type: (int) -> Text
return u'all_realm_filters:%s' % (realm_id,)
# We have a per-process cache to avoid doing 1000 remote cache queries during page load
per_request_realm_filters_cache = {} # type: Dict[Text, List[Tuple[Text, Text, int]]]
per_request_realm_filters_cache = {} # type: Dict[int, List[Tuple[Text, Text, int]]]
def domain_in_local_realm_filters_cache(domain):
# type: (Text) -> bool
return domain in per_request_realm_filters_cache
def realm_in_local_realm_filters_cache(realm_id):
# type: (int) -> bool
return realm_id in per_request_realm_filters_cache
def realm_filters_for_domain(domain):
# type: (Text) -> List[Tuple[Text, Text, int]]
domain = domain.lower()
if not domain_in_local_realm_filters_cache(domain):
per_request_realm_filters_cache[domain] = realm_filters_for_domain_remote_cache(domain)
return per_request_realm_filters_cache[domain]
def realm_filters_for_realm(realm_id):
# type: (int) -> List[Tuple[Text, Text, int]]
if not realm_in_local_realm_filters_cache(realm_id):
per_request_realm_filters_cache[realm_id] = realm_filters_for_realm_remote_cache(realm_id)
return per_request_realm_filters_cache[realm_id]
@cache_with_key(get_realm_filters_cache_key, timeout=3600*24*7)
def realm_filters_for_domain_remote_cache(domain):
# type: (Text) -> List[Tuple[Text, Text, int]]
def realm_filters_for_realm_remote_cache(realm_id):
# type: (int) -> List[Tuple[Text, Text, int]]
filters = []
for realm_filter in RealmFilter.objects.filter(realm=get_realm(domain)):
for realm_filter in RealmFilter.objects.filter(realm_id=realm_id):
filters.append((realm_filter.pattern, realm_filter.url_format_string, realm_filter.id))
return filters
def all_realm_filters():
# type: () -> Dict[Text, List[Tuple[Text, Text, int]]]
filters = defaultdict(list) # type: Dict[Text, List[Tuple[Text, Text, int]]]
# type: () -> Dict[int, List[Tuple[Text, Text, int]]]
filters = defaultdict(list) # type: Dict[int, List[Tuple[Text, Text, int]]]
for realm_filter in RealmFilter.objects.all():
filters[realm_filter.realm.domain].append((realm_filter.pattern, realm_filter.url_format_string, realm_filter.id))
filters[realm_filter.realm_id].append((realm_filter.pattern, realm_filter.url_format_string, realm_filter.id))
return filters
def flush_realm_filter(sender, **kwargs):
# type: (Any, **Any) -> None
realm = kwargs['instance'].realm
cache_delete(get_realm_filters_cache_key(realm.domain))
realm_id = kwargs['instance'].realm.id
cache_delete(get_realm_filters_cache_key(realm_id))
try:
per_request_realm_filters_cache.pop(realm.domain.lower())
per_request_realm_filters_cache.pop(realm_id)
except KeyError:
pass

View File

@@ -22,14 +22,14 @@ from zerver.lib.test_classes import (
)
from zerver.lib.str_utils import force_str
from zerver.models import (
domain_in_local_realm_filters_cache,
realm_in_local_realm_filters_cache,
flush_per_request_caches,
flush_realm_filter,
get_client,
get_realm_by_string_id,
get_user_profile_by_email,
get_stream,
realm_filters_for_domain,
realm_filters_for_realm,
Message,
Stream,
Realm,
@@ -159,7 +159,7 @@ class FencedBlockPreprocessorTest(TestCase):
def bugdown_convert(text):
# type: (Text) -> Text
return bugdown.convert(text, "zulip.com")
return bugdown.convert(text, get_realm_by_string_id('zulip').id)
class BugdownTest(TestCase):
def common_bugdown_test(self, text, expected):
@@ -222,9 +222,9 @@ class BugdownTest(TestCase):
domain='file_links_test.example.com',
string_id='file_links_test')
bugdown.make_md_engine(
realm.domain,
realm.id,
{'realm_filters': [[], u'file_links_test.example.com'], 'realm': [u'file_links_test.example.com', 'Realm name']})
converted = bugdown.convert(msg, realm_domain=realm.domain)
converted = bugdown.convert(msg, realm_id=realm.id)
self.assertEqual(converted, '<p>Check out this file file:///Volumes/myserver/Users/Shared/pi.py</p>')
def test_inline_youtube(self):
@@ -410,17 +410,17 @@ class BugdownTest(TestCase):
# type: (Text, Text) -> Text
return '<img alt="%s" class="emoji" src="%s" title="%s">' % (name, get_camo_url(url), name)
zulip_realm = get_realm_by_string_id('zulip')
realm = get_realm_by_string_id('zulip')
url = "https://zulip.com/test_realm_emoji.png"
check_add_realm_emoji(zulip_realm, "test", url)
check_add_realm_emoji(realm, "test", url)
# Needs to mock an actual message because that's how bugdown obtains the realm
msg = Message(sender=get_user_profile_by_email("hamlet@zulip.com"))
converted = bugdown.convert(":test:", "zulip.com", msg)
converted = bugdown.convert(":test:", realm_id=realm.id, message=msg)
self.assertEqual(converted, '<p>%s</p>' % (emoji_img(':test:', url)))
do_remove_realm_emoji(zulip_realm, 'test')
converted = bugdown.convert(":test:", "zulip.com", msg)
do_remove_realm_emoji(realm, 'test')
converted = bugdown.convert(":test:", realm_id=realm.id, message=msg)
self.assertEqual(converted, '<p>:test:</p>')
def test_unicode_emoji(self):
@@ -452,18 +452,18 @@ class BugdownTest(TestCase):
flush_per_request_caches()
content = "We should fix #224 and #115, but not issue#124 or #1124z or [trac #15](https://trac.zulip.net/ticket/16) today."
converted = bugdown.convert(content, realm_domain='zulip.com', message=msg)
converted_subject = bugdown.subject_links(realm.domain.lower(), msg.subject)
converted = bugdown.convert(content, realm_id=realm.id, message=msg)
converted_subject = bugdown.subject_links(realm.id, msg.subject)
self.assertEqual(converted, '<p>We should fix <a href="https://trac.zulip.net/ticket/224" target="_blank" title="https://trac.zulip.net/ticket/224">#224</a> and <a href="https://trac.zulip.net/ticket/115" target="_blank" title="https://trac.zulip.net/ticket/115">#115</a>, but not issue#124 or #1124z or <a href="https://trac.zulip.net/ticket/16" target="_blank" title="https://trac.zulip.net/ticket/16">trac #15</a> today.</p>')
self.assertEqual(converted_subject, [u'https://trac.zulip.net/ticket/444'])
RealmFilter(realm=get_realm_by_string_id('zulip'), pattern=r'#(?P<id>[a-zA-Z]+-[0-9]+)',
RealmFilter(realm=realm, pattern=r'#(?P<id>[a-zA-Z]+-[0-9]+)',
url_format_string=r'https://trac.zulip.net/ticket/%(id)s').save()
msg = Message(sender=get_user_profile_by_email('hamlet@zulip.com'))
content = '#ZUL-123 was fixed and code was deployed to production, also #zul-321 was deployed to staging'
converted = bugdown.convert(content, realm_domain='zulip.com', message=msg)
converted = bugdown.convert(content, realm_id=realm.id, message=msg)
self.assertEqual(converted, '<p><a href="https://trac.zulip.net/ticket/ZUL-123" target="_blank" title="https://trac.zulip.net/ticket/ZUL-123">#ZUL-123</a> was fixed and code was deployed to production, also <a href="https://trac.zulip.net/ticket/zul-321" target="_blank" title="https://trac.zulip.net/ticket/zul-321">#zul-321</a> was deployed to staging</p>')
@@ -477,9 +477,9 @@ class BugdownTest(TestCase):
realm_filter.save()
bugdown.realm_filter_data = {}
bugdown.maybe_update_realm_filters(domain=None)
bugdown.maybe_update_realm_filters(None)
all_filters = bugdown.realm_filter_data
zulip_filters = all_filters['zulip.com']
zulip_filters = all_filters[realm.id]
self.assertEqual(len(zulip_filters), 1)
self.assertEqual(zulip_filters[0],
(u'#(?P<id>[0-9]{2,8})', u'https://trac.zulip.net/ticket/%(id)s', realm_filter.id))
@@ -509,20 +509,20 @@ class BugdownTest(TestCase):
# start fresh for our domain
flush()
self.assertFalse(domain_in_local_realm_filters_cache(domain=realm.domain))
self.assertFalse(realm_in_local_realm_filters_cache(realm.id))
# call this just for side effects of populating the cache
realm_filters_for_domain(domain=realm.domain)
self.assertTrue(domain_in_local_realm_filters_cache(realm.domain))
realm_filters_for_realm(realm.id)
self.assertTrue(realm_in_local_realm_filters_cache(realm.id))
# Saving a new RealmFilter should have the side effect of
# flushing the cache.
save_new_realm_filter()
self.assertFalse(domain_in_local_realm_filters_cache(realm.domain))
self.assertFalse(realm_in_local_realm_filters_cache(realm.id))
# and flush it one more time, to make sure we don't get a KeyError
flush()
self.assertFalse(domain_in_local_realm_filters_cache(realm.domain))
self.assertFalse(realm_in_local_realm_filters_cache(realm.id))
def test_realm_patterns_negative(self):
# type: () -> None
@@ -531,7 +531,7 @@ class BugdownTest(TestCase):
url_format_string=r"https://trac.zulip.net/ticket/%(id)s").save()
boring_msg = Message(sender=get_user_profile_by_email("othello@zulip.com"),
subject=u"no match here")
converted_boring_subject = bugdown.subject_links(realm.domain.lower(), boring_msg.subject)
converted_boring_subject = bugdown.subject_links(realm.id, boring_msg.subject)
self.assertEqual(converted_boring_subject, [])
def test_is_status_message(self):
@@ -817,19 +817,19 @@ class BugdownTest(TestCase):
verifies almost all inline patterns are disabled, but
inline_interesting_links is still enabled"""
msg = "**test**"
converted = bugdown.convert(msg, "zephyr_mirror")
converted = bugdown.convert(msg, realm_id=bugdown.ZEPHYR_MIRROR_BUGDOWN_KEY)
self.assertEqual(
converted,
"<p>**test**</p>",
)
msg = "* test"
converted = bugdown.convert(msg, "zephyr_mirror")
converted = bugdown.convert(msg, realm_id=bugdown.ZEPHYR_MIRROR_BUGDOWN_KEY)
self.assertEqual(
converted,
"<p>* test</p>",
)
msg = "https://lists.debian.org/debian-ctte/2014/02/msg00173.html"
converted = bugdown.convert(msg, "zephyr_mirror")
converted = bugdown.convert(msg, realm_id=bugdown.ZEPHYR_MIRROR_BUGDOWN_KEY)
self.assertEqual(
converted,
'<p><a href="https://lists.debian.org/debian-ctte/2014/02/msg00173.html" target="_blank" title="https://lists.debian.org/debian-ctte/2014/02/msg00173.html">https://lists.debian.org/debian-ctte/2014/02/msg00173.html</a></p>',
@@ -868,7 +868,7 @@ class BugdownErrorTests(ZulipTestCase):
# type: () -> None
with self.simulated_markdown_failure():
with self.assertRaises(bugdown.BugdownRenderingException):
bugdown.convert('', 'zulip.com')
bugdown_convert('')
def test_send_message_errors(self):
# type: () -> None

View File

@@ -121,7 +121,7 @@ def api_endpoint_docs(request):
extended_response = response.replace(", ", ",\n ")
else:
extended_response = response
call['rendered_response'] = bugdown.convert("~~~ .py\n" + extended_response + "\n~~~\n", "default")
call['rendered_response'] = bugdown.convert("~~~ .py\n" + extended_response + "\n~~~\n", bugdown.DEFAULT_BUGDOWN_KEY)
for example_type in ('request', 'response'):
for lang in call.get('example_' + example_type, []):
langs.add(lang)

View File

@@ -11,13 +11,13 @@ from zerver.lib.actions import do_add_realm_filter, do_remove_realm_filter
from zerver.lib.response import json_success, json_error
from zerver.lib.rest import rest_dispatch as _rest_dispatch
from zerver.lib.validator import check_string
from zerver.models import realm_filters_for_domain, UserProfile, RealmFilter
from zerver.models import realm_filters_for_realm, UserProfile, RealmFilter
# Custom realm filters
def list_filters(request, user_profile):
# type: (HttpRequest, UserProfile) -> HttpResponse
filters = realm_filters_for_domain(user_profile.realm.domain)
filters = realm_filters_for_realm(user_profile.realm_id)
return json_success({'filters': filters})