diff --git a/analytics/tests/test_views.py b/analytics/tests/test_views.py index e682a44cd9..a85ee45c39 100644 --- a/analytics/tests/test_views.py +++ b/analytics/tests/test_views.py @@ -3,6 +3,7 @@ from zerver.lib.test_classes import ZulipTestCase from analytics.lib.counts import CountStat from analytics.lib.time_utils import time_range +from analytics.views import rewrite_client_arrays from datetime import datetime, timedelta @@ -34,3 +35,28 @@ class TestTimeRange(ZulipTestCase): [floor_hour-2*HOUR, floor_hour-HOUR, floor_hour, floor_hour+HOUR]) self.assertEqual(time_range(floor_day, floor_day+DAY, CountStat.DAY, 4), [floor_day-2*DAY, floor_day-DAY, floor_day, floor_day+DAY]) + +class TestMapArrays(ZulipTestCase): + def test_map_arrays(self): + # type: () -> None + a = {'desktop app 1.0': [1, 2, 3], + 'desktop app 2.0': [10, 12, 13], + 'desktop app 3.0': [21, 22, 23], + 'website': [1, 2, 3], + 'ZulipiOS': [1, 2, 3], + 'ZulipMobile': [1, 5, 7], + 'ZulipPython': [1, 2, 3], + 'API: Python': [1, 2, 3], + 'SomethingRandom': [4, 5, 6], + 'ZulipGitHubWebhook': [7, 7, 9], + 'ZulipAndroid': [64, 63, 65]} + result = rewrite_client_arrays(a) + self.assertEqual(result, + {'Old desktop app': [32, 36, 39], + 'Old iOS app': [1, 2, 3], + 'New iOS app': [1, 5, 7], + 'Website': [1, 2, 3], + 'Python API': [2, 4, 6], + 'SomethingRandom': [4, 5, 6], + 'GitHub webhook': [7, 7, 9], + 'Android app': [64, 63, 65]}) diff --git a/analytics/views.py b/analytics/views.py index 49a3137114..5b977a54f8 100644 --- a/analytics/views.py +++ b/analytics/views.py @@ -108,6 +108,36 @@ def table_filtered_to_id(table, key_id): else: raise ValueError("Unknown table: %s" % (table,)) +def client_label_map(name): + # type: (str) -> str + if name == "website": + return "Website" + if name.startswith("desktop app"): + return "Old desktop app" + if name == "ZulipAndroid": + return "Android app" + if name == "ZulipiOS": + return "Old iOS app" + if name == "ZulipMobile": + return "New iOS app" + if name in ["ZulipPython", "API: Python"]: + return "Python API" + if name.startswith("Zulip") and name.endswith("Webhook"): + return name[len("Zulip"):-len("Webhook")] + " webhook" + return name + +def rewrite_client_arrays(value_arrays): + # type: (Dict[str, List[int]]) -> Dict[str, List[int]] + mapped_arrays = {} # type: Dict[str, List[int]] + for label, array in value_arrays.items(): + mapped_label = client_label_map(label) + if mapped_label in mapped_arrays: + for i in range(0, len(array)): + mapped_arrays[mapped_label][i] += value_arrays[label][i] + else: + mapped_arrays[mapped_label] = [value_arrays[label][i] for i in range(0, len(array))] + return mapped_arrays + def get_time_series_by_subgroup(stat, table, key_id, end_times, subgroups, labels, include_empty_subgroups): # type: (CountStat, Type[BaseCount], Optional[int], List[datetime], List[str], Optional[List[str]], bool) -> Dict[str, List[int]] if labels is None: @@ -124,6 +154,12 @@ def get_time_series_by_subgroup(stat, table, key_id, end_times, subgroups, label for subgroup, label in zip(subgroups, labels): if (subgroup in value_dicts) or include_empty_subgroups: value_arrays[label] = [value_dicts[subgroup][end_time] for end_time in end_times] + + if stat == COUNT_STATS['messages_sent:client:day']: + # HACK: We rewrite these arrays to collapse the Client objects + # with similar names into a single sum, and generally give + # them better names + return rewrite_client_arrays(value_arrays) return value_arrays