@require_non_guest_user
@has_request_variables
def get_chart_data(request: HttpRequest, user_profile: UserProfile, chart_name: str=REQ(), min_length: Optional[int]=REQ(converter=to_non_negative_int, default=None), start: Optional[datetime]=REQ(converter=to_utc_datetime, default=None), end: Optional[datetime]=REQ(converter=to_utc_datetime, default=None), realm: Optional[Realm]=None, for_installation: bool=False, remote: bool=False, remote_realm_id: Optional[int]=None, server: Optional['RemoteZulipServer']=None) -> HttpResponse:
    if for_installation:
        if remote:
            assert settings.ZILENCER_ENABLED
            aggregate_table = RemoteInstallationCount
            assert (server is not None)
        else:
            aggregate_table = InstallationCount
    elif remote:
        assert settings.ZILENCER_ENABLED
        aggregate_table = RemoteRealmCount
        assert (server is not None)
        assert (remote_realm_id is not None)
    else:
        aggregate_table = RealmCount
    if (chart_name == 'number_of_humans'):
        stats = [COUNT_STATS['1day_actives::day'], COUNT_STATS['realm_active_humans::day'], COUNT_STATS['active_users_audit:is_bot:day']]
        tables = [aggregate_table]
        subgroup_to_label: Dict[(CountStat, Dict[(Optional[str], str)])] = {stats[0]: {None: '_1day'}, stats[1]: {None: '_15day'}, stats[2]: {'false': 'all_time'}}
        labels_sort_function = None
        include_empty_subgroups = True
    elif (chart_name == 'messages_sent_over_time'):
        stats = [COUNT_STATS['messages_sent:is_bot:hour']]
        tables = [aggregate_table, UserCount]
        subgroup_to_label = {stats[0]: {'false': 'human', 'true': 'bot'}}
        labels_sort_function = None
        include_empty_subgroups = True
    elif (chart_name == 'messages_sent_by_message_type'):
        stats = [COUNT_STATS['messages_sent:message_type:day']]
        tables = [aggregate_table, UserCount]
        subgroup_to_label = {stats[0]: {'public_stream': _('Public streams'), 'private_stream': _('Private streams'), 'private_message': _('Private messages'), 'huddle_message': _('Group private messages')}}
        labels_sort_function = (lambda data: sort_by_totals(data['everyone']))
        include_empty_subgroups = True
    elif (chart_name == 'messages_sent_by_client'):
        stats = [COUNT_STATS['messages_sent:client:day']]
        tables = [aggregate_table, UserCount]
        subgroup_to_label = {stats[0]: {str(id): name for (id, name) in Client.objects.values_list('id', 'name')}}
        labels_sort_function = sort_client_labels
        include_empty_subgroups = False
    elif (chart_name == 'messages_read_over_time'):
        stats = [COUNT_STATS['messages_read::hour']]
        tables = [aggregate_table, UserCount]
        subgroup_to_label = {stats[0]: {None: 'read'}}
        labels_sort_function = None
        include_empty_subgroups = True
    else:
        raise JsonableError(_('Unknown chart name: {}').format(chart_name))
    if (start is not None):
        start = convert_to_UTC(start)
    if (end is not None):
        end = convert_to_UTC(end)
    if ((start is not None) and (end is not None) and (start > end)):
        raise JsonableError(_('Start time is later than end time. Start: {start}, End: {end}').format(start=start, end=end))
    if (realm is None):
        realm = user_profile.realm
    if remote:
        assert (server is not None)
        if (not aggregate_table.objects.filter(server=server).exists()):
            raise JsonableError(_('No analytics data available. Please contact your server administrator.'))
        if (start is None):
            start = aggregate_table.objects.filter(server=server).first().end_time
        if (end is None):
            end = aggregate_table.objects.filter(server=server).last().end_time
    else:
        if (start is None):
            if for_installation:
                start = installation_epoch()
            else:
                start = realm.date_created
        if (end is None):
            end = max(((stat.last_successful_fill() or datetime.min.replace(tzinfo=timezone.utc)) for stat in stats))
        if ((start > end) and ((timezone_now() - start) > MAX_TIME_FOR_FULL_ANALYTICS_GENERATION)):
            logging.warning('User from realm %s attempted to access /stats, but the computed start time: %s (creation of realm or installation) is later than the computed end time: %s (last successful analytics update). Is the analytics cron job running?', realm.string_id, start, end)
            raise JsonableError(_('No analytics data available. Please contact your server administrator.'))
    assert (len({stat.frequency for stat in stats}) == 1)
    end_times = time_range(start, end, stats[0].frequency, min_length)
    data: Dict[(str, Any)] = {'end_times': [int(end_time.timestamp()) for end_time in end_times], 'frequency': stats[0].frequency}
    aggregation_level = {InstallationCount: 'everyone', RealmCount: 'everyone', UserCount: 'user'}
    if settings.ZILENCER_ENABLED:
        aggregation_level[RemoteInstallationCount] = 'everyone'
        aggregation_level[RemoteRealmCount] = 'everyone'
    id_value = {InstallationCount: (- 1), RealmCount: realm.id, UserCount: user_profile.id}
    if settings.ZILENCER_ENABLED:
        if (server is not None):
            id_value[RemoteInstallationCount] = server.id
        if (remote_realm_id is not None):
            id_value[RemoteRealmCount] = remote_realm_id
    for table in tables:
        data[aggregation_level[table]] = {}
        for stat in stats:
            data[aggregation_level[table]].update(get_time_series_by_subgroup(stat, table, id_value[table], end_times, subgroup_to_label[stat], include_empty_subgroups))
    if (labels_sort_function is not None):
        data['display_order'] = labels_sort_function(data)
    else:
        data['display_order'] = None
    return json_success(data=data)
@require_non_guest_user
@has_request_variables
def get_chart_data(request: HttpRequest, user_profile: UserProfile, chart_name: str=REQ(), min_length: Optional[int]=REQ(converter=to_non_negative_int, default=None), start: Optional[datetime]=REQ(converter=to_utc_datetime, default=None), end: Optional[datetime]=REQ(converter=to_utc_datetime, default=None), realm: Optional[Realm]=None, for_installation: bool=False, remote: bool=False, remote_realm_id: Optional[int]=None, server: Optional['RemoteZulipServer']=None) -> HttpResponse:
    if for_installation:
        if remote:
            assert settings.ZILENCER_ENABLED
            aggregate_table = RemoteInstallationCount
            assert (server is not None)
        else:
            aggregate_table = InstallationCount
    elif remote:
        assert settings.ZILENCER_ENABLED
        aggregate_table = RemoteRealmCount
        assert (server is not None)
        assert (remote_realm_id is not None)
    else:
        aggregate_table = RealmCount
    if (chart_name == 'number_of_humans'):
        stats = [COUNT_STATS['1day_actives::day'], COUNT_STATS['realm_active_humans::day'], COUNT_STATS['active_users_audit:is_bot:day']]
        tables = [aggregate_table]
        subgroup_to_label: Dict[(CountStat, Dict[(Optional[str], str)])] = {stats[0]: {None: '_1day'}, stats[1]: {None: '_15day'}, stats[2]: {'false': 'all_time'}}
        labels_sort_function = None
        include_empty_subgroups = True
    elif (chart_name == 'messages_sent_over_time'):
        stats = [COUNT_STATS['messages_sent:is_bot:hour']]
        tables = [aggregate_table, UserCount]
        subgroup_to_label = {stats[0]: {'false': 'human', 'true': 'bot'}}
        labels_sort_function = None
        include_empty_subgroups = True
    elif (chart_name == 'messages_sent_by_message_type'):
        stats = [COUNT_STATS['messages_sent:message_type:day']]
        tables = [aggregate_table, UserCount]
        subgroup_to_label = {stats[0]: {'public_stream': _('Public streams'), 'private_stream': _('Private streams'), 'private_message': _('Private messages'), 'huddle_message': _('Group private messages')}}
        labels_sort_function = (lambda data: sort_by_totals(data['everyone']))
        include_empty_subgroups = True
    elif (chart_name == 'messages_sent_by_client'):
        stats = [COUNT_STATS['messages_sent:client:day']]
        tables = [aggregate_table, UserCount]
        subgroup_to_label = {stats[0]: {str(id): name for (id, name) in Client.objects.values_list('id', 'name')}}
        labels_sort_function = sort_client_labels
        include_empty_subgroups = False
    elif (chart_name == 'messages_read_over_time'):
        stats = [COUNT_STATS['messages_read::hour']]
        tables = [aggregate_table, UserCount]
        subgroup_to_label = {stats[0]: {None: 'read'}}
        labels_sort_function = None
        include_empty_subgroups = True
    else:
        raise JsonableError(_('Unknown chart name: {}').format(chart_name))
    if (start is not None):
        start = convert_to_UTC(start)
    if (end is not None):
        end = convert_to_UTC(end)
    if ((start is not None) and (end is not None) and (start > end)):
        raise JsonableError(_('Start time is later than end time. Start: {start}, End: {end}').format(start=start, end=end))
    if (realm is None):
        realm = user_profile.realm
    if remote:
        assert (server is not None)
        if (not aggregate_table.objects.filter(server=server).exists()):
            raise JsonableError(_('No analytics data available. Please contact your server administrator.'))
        if (start is None):
            start = aggregate_table.objects.filter(server=server).first().end_time
        if (end is None):
            end = aggregate_table.objects.filter(server=server).last().end_time
    else:
        if (start is None):
            if for_installation:
                start = installation_epoch()
            else:
                start = realm.date_created
        if (end is None):
            end = max(((stat.last_successful_fill() or datetime.min.replace(tzinfo=timezone.utc)) for stat in stats))
        if ((start > end) and ((timezone_now() - start) > MAX_TIME_FOR_FULL_ANALYTICS_GENERATION)):
            logging.warning('User from realm %s attempted to access /stats, but the computed start time: %s (creation of realm or installation) is later than the computed end time: %s (last successful analytics update). Is the analytics cron job running?', realm.string_id, start, end)
            raise JsonableError(_('No analytics data available. Please contact your server administrator.'))
    assert (len({stat.frequency for stat in stats}) == 1)
    end_times = time_range(start, end, stats[0].frequency, min_length)
    data: Dict[(str, Any)] = {'end_times': [int(end_time.timestamp()) for end_time in end_times], 'frequency': stats[0].frequency}
    aggregation_level = {InstallationCount: 'everyone', RealmCount: 'everyone', UserCount: 'user'}
    if settings.ZILENCER_ENABLED:
        aggregation_level[RemoteInstallationCount] = 'everyone'
        aggregation_level[RemoteRealmCount] = 'everyone'
    id_value = {InstallationCount: (- 1), RealmCount: realm.id, UserCount: user_profile.id}
    if settings.ZILENCER_ENABLED:
        if (server is not None):
            id_value[RemoteInstallationCount] = server.id
        if (remote_realm_id is not None):
            id_value[RemoteRealmCount] = remote_realm_id
    for table in tables:
        data[aggregation_level[table]] = {}
        for stat in stats:
            data[aggregation_level[table]].update(get_time_series_by_subgroup(stat, table, id_value[table], end_times, subgroup_to_label[stat], include_empty_subgroups))
    if (labels_sort_function is not None):
        data['display_order'] = labels_sort_function(data)
    else:
        data['display_order'] = None
    return json_success(data=data)