Exemple #1
0
def email_for_subscription(alert, start_date, frequency):
    """
    Returns a (place_name, text, html) tuple for the given EmailAlert
    object and date.
    """
    start_datetime = datetime.datetime(start_date.year, start_date.month, start_date.day)
    yesterday = datetime.date.today() - datetime.timedelta(days=1)
    end_datetime = datetime.datetime.combine(yesterday, datetime.time(23, 59, 59, 9999)) # the end of yesterday
    # Order by schema__id to group schemas together.
    qs = NewsItem.objects.select_related().filter(schema__is_public=True, pub_date__range=(start_datetime, end_datetime)).order_by('-schema__importance', 'schema__id')
    if alert.include_new_schemas:
        if alert.schemas:
            qs = qs.exclude(schema__id__in=alert.schemas.split(','))
    else:
        if alert.schemas:
            qs = qs.filter(schema__id__in=alert.schemas.split(','))
    if alert.block:
        place_name, place_url = alert.block.pretty_name, alert.block.url()
        place = alert.block
        search_buffer = make_search_buffer(alert.block.location.centroid, alert.radius)
        qs = qs.filter(location__bboverlaps=search_buffer)
    elif alert.location:
        place_name, place_url = alert.location.name, alert.location.url()
        place = alert.location
        qs = qs.filter(newsitemlocation__location__id=alert.location.id)
    ni_list = list(qs)
    if not ni_list:
        raise NoNews
    schemas_used = set([ni.schema for ni in ni_list])
    populate_attributes_if_needed(ni_list, list(schemas_used))
    text, html = email_text_for_place(alert, place, place_name, place_url, ni_list, start_date, frequency)
    return place_name, text, html
Exemple #2
0
def email_for_subscription(alert, start_date, frequency):
    """
    Returns a (place_name, text, html) tuple for the given EmailAlert
    object and date.
    """
    start_datetime = datetime.datetime(start_date.year, start_date.month, start_date.day)
    yesterday = datetime.date.today() - datetime.timedelta(days=1)
    end_datetime = datetime.datetime.combine(yesterday, datetime.time(23, 59, 59, 9999)) # the end of yesterday
    # Order by schema__id to group schemas together.
    qs = NewsItem.objects.select_related().filter(schema__is_public=True, pub_date__range=(start_datetime, end_datetime)).order_by('-schema__importance', 'schema__id')
    if alert.include_new_schemas:
        if alert.schemas:
            qs = qs.exclude(schema__id__in=alert.schemas.split(','))
    else:
        if alert.schemas:
            qs = qs.filter(schema__id__in=alert.schemas.split(','))
    if alert.block:
        place_name, place_url = alert.block.pretty_name, alert.block.url()
        place = alert.block
        search_buffer = make_search_buffer(alert.block.location.centroid, alert.radius)
        qs = qs.filter(location__bboverlaps=search_buffer)
    elif alert.location:
        place_name, place_url = alert.location.name, alert.location.url()
        place = alert.location
        qs = qs.filter(newsitemlocation__location__id=alert.location.id)
    ni_list = list(qs)
    if not ni_list:
        raise NoNews
    schemas_used = set([ni.schema for ni in ni_list])
    populate_attributes_if_needed(ni_list, list(schemas_used))
    text, html = email_text_for_place(alert, place, place_name, place_url, ni_list, start_date, frequency)
    return place_name, text, html
Exemple #3
0
    def test_populate_attributes_if_needed(self):

        from ebpub.db.models import NewsItem
        item = NewsItem.objects.get(title='crime title 1')
        ni_list = [item]

        # It's lazy - but just checking length is enough to trigger
        # attribute population.
        self.assert_(len(item.attributes) > 1)

        from ebpub.db.utils import populate_attributes_if_needed
        schema_list = list(set((ni.schema for ni in ni_list)))
        populate_attributes_if_needed(ni_list, schema_list)
        self.assert_(len(item.attributes) > 1)
        self.assertEqual(item.attributes['arrests'], False)
        self.assertEqual(item.attributes['case_number'], 'case number 1')

        # Get another reference to the same NewsItem and verify that
        # prepopulation and laziness give all the same results.
        ni2 = NewsItem.objects.get(title='crime title 1')
        self.failIf(item is ni2)
        ni2.attributes['beat']  # Triggers loading.
        for key, val in item.attributes.items():
            # ... well, mostly the same.
            # populate_attributes_if_needed() dereferences Lookups,
            # which lazy attribute lookup doesn't yet.  This is crazy,
            # but AttributesForTemplate handles both cases.
            from ebpub.db.models import Lookup
            if isinstance(val, Lookup):
                self.assertEqual(val.id, ni2.attributes[key])
            elif isinstance(val, list) and isinstance(val[0], Lookup):
                self.assertEqual(','.join([str(v.id) for v in val]),
                                 ni2.attributes[key])
            else:
                self.assertEqual(val, ni2.attributes[key])
Exemple #4
0
    def render(self, context):
        schema_id = self.schema_id_variable.resolve(context)
        if hasattr(schema_id, 'id'):
            # It could be a Schema.
            schema_kwargs = {'schema__id': schema_id.id}
        elif isinstance(schema_id, basestring):
            # It could be a slug.
            schema_kwargs = {'schema__slug': schema_id}
        else:
            schema_kwargs = {'schema__id': schema_id}

        att_value = self.att_value_variable.resolve(context)
        sf = SchemaField.objects.select_related().get(name=self.att_name,
                                                      **schema_kwargs)
        queryset = NewsItem.objects.select_related().filter(**schema_kwargs)

        if self.newsitem_id_variable is not None:
            newsitem_id = self.newsitem_id_variable.resolve(context)
            if hasattr(newsitem_id, 'id'):
                # It could be a NewsItem.
                newsitem_id = newsitem_id.id
            queryset = queryset.exclude(id=newsitem_id)

        queryset = queryset.by_attribute(sf, att_value).order_by('-item_date')
        populate_attributes_if_needed(queryset, [sf.schema])

        # We're assigning directly to context.dicts[-1] so that the variable
        # gets set in the top-most context in the context stack. If we didn't
        # do this, the variable would only be available within the specific
        # {% block %} from which the template tag was called, because the
        # {% block %} implementation does a context.push() and context.pop().
        context.dicts[-1][self.context_var] = queryset

        return ''
Exemple #5
0
    def render(self, context):
        schema_id = self.schema_id_variable.resolve(context)
        if hasattr(schema_id, "id"):
            # It could be a Schema.
            schema_kwargs = {"schema__id": schema_id.id}
        elif isinstance(schema_id, basestring):
            # It could be a slug.
            schema_kwargs = {"schema__slug": schema_id}
        else:
            schema_kwargs = {"schema__id": schema_id}

        att_value = self.att_value_variable.resolve(context)
        sf = SchemaField.objects.select_related().get(name=self.att_name, **schema_kwargs)
        queryset = NewsItem.objects.select_related().filter(**schema_kwargs)

        if self.newsitem_id_variable is not None:
            newsitem_id = self.newsitem_id_variable.resolve(context)
            if hasattr(newsitem_id, "id"):
                # It could be a NewsItem.
                newsitem_id = newsitem_id.id
            queryset = queryset.exclude(id=newsitem_id)

        queryset = queryset.by_attribute(sf, att_value).order_by("-item_date")
        populate_attributes_if_needed(queryset, [sf.schema])

        # We're assigning directly to context.dicts[-1] so that the variable
        # gets set in the top-most context in the context stack. If we didn't
        # do this, the variable would only be available within the specific
        # {% block %} from which the template tag was called, because the
        # {% block %} implementation does a context.push() and context.pop().
        context.dicts[-1][self.context_var] = queryset

        return ""
Exemple #6
0
    def items(self, obj):
        # Note that items() returns "packed" tuples instead of objects.
        # This is necessary because we return NewsItems and blog entries,
        # plus different types of NewsItems (bunched vs. unbunched).

        # Limit the feed to all NewsItems published in the last four days.
        # We *do* include items from today in this query, but we'll filter
        # those later in this method so that only today's *uncollapsed* items
        # (schema.can_collapse=False) will be included in the feed. We don't
        # want today's *collapsed* items to be included, because more items
        # might be added to the database before the day is finished, and
        # that would result in the RSS item being updated multiple times, which
        # is annoying.
        today_value = today()
        start_date = today_value - datetime.timedelta(days=4)
        end_date = today_value
        # Note: The pub_date__lt=end_date+(1 day) ensures that we don't miss
        # stuff that has a pub_date of the afternoon of end_date. A straight
        # pub_date__range would miss those items.
        qs = NewsItem.objects.select_related().filter(
            schema__is_public=True,
            pub_date__gte=start_date,
            pub_date__lt=end_date + datetime.timedelta(days=1)).extra(
                select={
                    'pub_date_date': 'date(db_newsitem.pub_date)'
                }).order_by('-pub_date_date', 'schema__id', 'id')

        # Filter out ignored schemas -- those whose slugs are specified in
        # the "ignore" query-string parameter.
        if 'ignore' in self.request.GET:
            schema_slugs = self.request.GET['ignore'].split(',')
            qs = qs.exclude(schema__slug__in=schema_slugs)

        # Filter wanted schemas -- those whose slugs are specified in the
        # "only" query-string parameter.
        if 'only' in self.request.GET:
            schema_slugs = self.request.GET['only'].split(',')
            qs = qs.filter(schema__slug__in=schema_slugs)

        block_radius = self.request.GET.get('radius', BLOCK_RADIUS_DEFAULT)
        if block_radius not in BLOCK_RADIUS_CHOICES:
            raise Http404('Invalid radius')
        ni_list = list(self.newsitems_for_obj(obj, qs, block_radius))
        schema_list = list(set([ni.schema for ni in ni_list]))
        populate_attributes_if_needed(ni_list, schema_list)

        is_block = isinstance(obj, Block)

        # Note that this decorates the results by returning tuples instead of
        # NewsItems. This is necessary because we're bunching.
        for schema_group in bunch_by_date_and_schema(ni_list, today_value):
            schema = schema_group[0].schema
            if schema.can_collapse:
                yield ('newsitem', obj, schema, schema_group, is_block,
                       block_radius)
            else:
                for newsitem in schema_group:
                    yield ('newsitem', obj, schema, newsitem, is_block,
                           block_radius)
Exemple #7
0
    def items(self, obj):
        # Note that items() returns "packed" tuples instead of objects.
        # This is necessary because we return NewsItems and blog entries,
        # plus different types of NewsItems (bunched vs. unbunched).

        # Limit the feed to all NewsItems published in the last four days.
        # We *do* include items from today in this query, but we'll filter
        # those later in this method so that only today's *uncollapsed* items
        # (schema.can_collapse=False) will be included in the feed. We don't
        # want today's *collapsed* items to be included, because more items
        # might be added to the database before the day is finished, and
        # that would result in the RSS item being updated multiple times, which
        # is annoying.

        # TODO: re-use ebpub.db.schemafilters for filtering here.

        # TODO: allow user control over date range
        today_value = today()
        start_date = today_value - datetime.timedelta(days=5)
        # Include future stuff, useful for events
        end_date = today_value + datetime.timedelta(days=5)

        qs = (
            NewsItem.objects.select_related()
            .by_request(self.request)
            .filter(item_date__gte=start_date, item_date__lte=end_date)
            .order_by("-item_date", "schema__id", "id")
        )

        # Filter out ignored schemas -- those whose slugs are specified in
        # the "ignore" query-string parameter.
        if "ignore" in self.request.GET:
            schema_slugs = self.request.GET["ignore"].split(",")
            qs = qs.exclude(schema__slug__in=schema_slugs)

        # Filter wanted schemas -- those whose slugs are specified in the
        # "only" query-string parameter.
        if "only" in self.request.GET:
            schema_slugs = self.request.GET["only"].split(",")
            qs = qs.filter(schema__slug__in=schema_slugs)

        block_radius = self.request.GET.get("radius", BLOCK_RADIUS_DEFAULT)
        if block_radius not in BLOCK_RADIUS_CHOICES:
            raise Http404("Invalid radius")
        ni_list = list(self.newsitems_for_obj(obj, qs, block_radius))
        schema_list = list(set([ni.schema for ni in ni_list]))
        populate_attributes_if_needed(ni_list, schema_list)

        is_block = isinstance(obj, Block)

        # Note that this decorates the results by returning tuples instead of
        # NewsItems. This is necessary because we're bunching.
        for schema_group in bunch_by_date_and_schema(ni_list, today_value):
            schema = schema_group[0].schema
            if schema.can_collapse:
                yield ("newsitem", obj, schema, schema_group, is_block, block_radius)
            else:
                for newsitem in schema_group:
                    yield ("newsitem", obj, schema, newsitem, is_block, block_radius)
Exemple #8
0
def email_for_subscription(alert, start_date, frequency):
    """
    Returns a (place_name, text, html) tuple for the given EmailAlert
    object and date.
    """
    start_datetime = datetime.datetime(start_date.year, start_date.month, start_date.day)
    yesterday = datetime.date.today() - datetime.timedelta(days=1)
    end_datetime = datetime.datetime.combine(yesterday, datetime.time(23, 59, 59, 9999)) # the end of yesterday

    from ebpub.utils.view_utils import get_schema_manager_for_user
    manager = get_schema_manager_for_user(alert.user)
    allowed_schemas = manager.allowed_schema_ids()
    qs = NewsItem.objects.select_related().filter(schema__id__in=allowed_schemas)
    if alert.include_new_schemas:
        # We saved an opt-out list.
        if alert.schemas:
            qs = qs.exclude(schema__id__in=alert.schemas.split(','))
    else:
        # We saved an opt-in list.
        if alert.schemas:
            qs = qs.filter(schema__id__in=alert.schemas.split(','))

    if alert.block_center:
        place = alert._get_block()
        place_name, place_url = place.pretty_name, place.url()
        search_buffer = make_search_buffer(place.geom.centroid, alert.radius)
        qs = qs.filter(location__bboverlaps=search_buffer)

    elif alert.location:
        place_name, place_url = alert.location.name, alert.location.url()
        place = alert.location
        qs = qs.filter(newsitemlocation__location__id=alert.location.id)

    # Order by schema__id to group schemas together.
    news_qs = qs.filter(schema__is_event=False,
                        pub_date__range=(start_datetime, end_datetime),
                        ).order_by('-schema__importance', 'schema__id', '-item_date', '-id')
    events_qs = qs.filter(schema__is_event=True,
                         pub_date__range=(start_datetime, end_datetime),
                         ).order_by('-schema__importance', 'schema__id', 'item_date', 'id')

    news_list = list(news_qs)
    events_list = list(events_qs)
    if not (news_list or events_list):
        raise NoNews
    schemas_used = set([ni.schema for ni in news_list + events_list])
    populate_attributes_if_needed(news_list, list(schemas_used))
    populate_attributes_if_needed(events_list, list(schemas_used))
    newsitem_groups = ({'title': 'Recent', 'newsitems': news_list},
                       {'title': 'Upcoming', 'newsitems': events_list})
    text, html = email_text_for_place(alert, place, place_name, place_url, newsitem_groups, start_date, frequency)
    return place_name, text, html
Exemple #9
0
    def items(self, obj):
        # Note that items() returns "packed" tuples instead of objects.
        # This is necessary because we return NewsItems and blog entries,
        # plus different types of NewsItems (bunched vs. unbunched).

        # Limit the feed to all NewsItems published in the last four days.
        # We *do* include items from today in this query, but we'll filter
        # those later in this method so that only today's *uncollapsed* items
        # (schema.can_collapse=False) will be included in the feed. We don't
        # want today's *collapsed* items to be included, because more items
        # might be added to the database before the day is finished, and
        # that would result in the RSS item being updated multiple times, which
        # is annoying.
        today_value = today()
        start_date = today_value - datetime.timedelta(days=4)
        end_date = today_value
        # Note: The pub_date__lt=end_date+(1 day) ensures that we don't miss
        # stuff that has a pub_date of the afternoon of end_date. A straight
        # pub_date__range would miss those items.
        qs = NewsItem.objects.select_related().filter(schema__is_public=True, pub_date__gte=start_date, pub_date__lt=end_date+datetime.timedelta(days=1)).extra(select={'pub_date_date': 'date(db_newsitem.pub_date)'}).order_by('-pub_date_date', 'schema__id', 'id')

        # Filter out ignored schemas -- those whose slugs are specified in
        # the "ignore" query-string parameter.
        if 'ignore' in self.request.GET:
            schema_slugs = self.request.GET['ignore'].split(',')
            qs = qs.exclude(schema__slug__in=schema_slugs)

        # Filter wanted schemas -- those whose slugs are specified in the
        # "only" query-string parameter.
        if 'only' in self.request.GET:
            schema_slugs = self.request.GET['only'].split(',')
            qs = qs.filter(schema__slug__in=schema_slugs)

        block_radius = self.request.GET.get('radius', BLOCK_RADIUS_DEFAULT)
        if block_radius not in BLOCK_RADIUS_CHOICES:
            raise Http404('Invalid radius')
        ni_list = list(self.newsitems_for_obj(obj, qs, block_radius))
        schema_list = list(set([ni.schema for ni in ni_list]))
        populate_attributes_if_needed(ni_list, schema_list)

        is_block = isinstance(obj, Block)

        # Note that this decorates the results by returning tuples instead of
        # NewsItems. This is necessary because we're bunching.
        for schema_group in bunch_by_date_and_schema(ni_list, today_value):
            schema = schema_group[0].schema
            if schema.can_collapse:
                yield ('newsitem', obj, schema, schema_group, is_block, block_radius)
            else:
                for newsitem in schema_group:
                    yield ('newsitem', obj, schema, newsitem, is_block, block_radius)
Exemple #10
0
    def render(self, context):
        schema_id = self.schema_id_variable.resolve(context)
        newsitem_id = self.newsitem_id_variable.resolve(context)
        att_value = self.att_value_variable.resolve(context)
        sf = SchemaField.objects.select_related().get(schema__id=schema_id, name=self.att_name)
        ni_list = NewsItem.objects.select_related().filter(schema__id=schema_id).exclude(id=newsitem_id).by_attribute(sf, att_value).order_by('-item_date')
        populate_attributes_if_needed(ni_list, [sf.schema])

        # We're assigning directly to context.dicts[-1] so that the variable
        # gets set in the top-most context in the context stack. If we didn't
        # do this, the variable would only be available within the specific
        # {% block %} from which the template tag was called, because the
        # {% block %} implementation does a context.push() and context.pop().
        context.dicts[-1][self.context_var] = ni_list

        return ''
Exemple #11
0
def schema_detail_special_report(request, schema):
    """
    For display of schemas where is_special_report=True.
    """
    ni_list = NewsItem.objects.filter(schema__id=schema.id)
    populate_schema(ni_list, schema)
    populate_attributes_if_needed(ni_list, [schema])

    if schema.allow_charting:
        browsable_locationtype_list = LocationType.objects.filter(is_significant=True)
        schemafield_list = list(schema.schemafield_set.filter(is_filter=True).order_by('display_order'))
    else:
        browsable_locationtype_list = []
        schemafield_list = []

    templates_to_try = ('db/schema_detail/%s.html' % schema.slug, 'db/schema_detail_special_report.html')
    return eb_render(request, templates_to_try, {
        'schema': schema,
        'newsitem_list': ni_list,
        'browsable_locationtype_list': browsable_locationtype_list,
        'schemafield_list': schemafield_list,
        'bodyclass': 'schema-detail-special-report',
        'bodyid': schema.slug,
    })
Exemple #12
0
def place_detail_timeline(request, *args, **kwargs):
    """
    Recent news OR upcoming events for the given Location or Block.
    """
    context, response = _place_detail_normalize_url(request, *args, **kwargs)
    if response is not None:
        return response

    show_upcoming = kwargs.get('show_upcoming')
    schema_manager = get_schema_manager(request)

    if show_upcoming:
        context['breadcrumbs'] = breadcrumbs.place_detail_upcoming(context)
    else:
        context['breadcrumbs'] = breadcrumbs.place_detail_timeline(context)

    is_latest_page = True
    # Check the query string for the max date to use. Otherwise, fall
    # back to today.
    end_date = today()
    if 'start' in request.GET:
        try:
            end_date = parse_date(request.GET['start'], '%m/%d/%Y')
            is_latest_page = False
        except ValueError:
            raise Http404('Invalid date %s' % request.GET['start'])

    filterchain = FilterChain(request=request, context=context)
    filterchain.add('location', context['place'])
    # As an optimization, limit the NewsItems to those on the
    # last (or next) few days.
    # And only fetch for relevant schemas - either event-ish or not.
    if show_upcoming:
        s_list = schema_manager.filter(is_event=True)
        start_date = end_date
        end_date = start_date + datetime.timedelta(days=settings.DEFAULT_DAYS)
        order_by = 'item_date_date'
    else:
        s_list = schema_manager.filter(is_event=False)
        start_date = end_date - datetime.timedelta(days=settings.DEFAULT_DAYS)
        order_by = '-item_date_date'

    filterchain.add('schema', list(s_list))
    filterchain.add('date', start_date, end_date)
    newsitem_qs = filterchain.apply().select_related()
    # TODO: can this really only be done via extra()?
    newsitem_qs = newsitem_qs.extra(
        select={'item_date_date': 'date(db_newsitem.item_date)'},
        order_by=(order_by, '-schema__importance', 'schema')
    )[:constants.NUM_NEWS_ITEMS_PLACE_DETAIL]

    # We're done filtering, so go ahead and do the query, to
    # avoid running it multiple times,
    # per http://docs.djangoproject.com/en/dev/topics/db/optimization
    ni_list = list(newsitem_qs)
    schemas_used = list(set([ni.schema for ni in ni_list]))
    s_list = s_list.filter(is_special_report=False, allow_charting=True).order_by('plural_name')
    populate_attributes_if_needed(ni_list, schemas_used)
    if ni_list:
        next_day = ni_list[-1].item_date - datetime.timedelta(days=1)
    else:
        next_day = None

    hidden_schema_list = []
    if not request.user.is_anonymous():
        hidden_schema_list = [o.schema for o in HiddenSchema.objects.filter(user_id=request.user.id)]

    context.update({
        'newsitem_list': ni_list,
        'next_day': next_day,
        'is_latest_page': is_latest_page,
        'hidden_schema_list': hidden_schema_list,
        'bodyclass': 'place-detail-timeline',
        'bodyid': context.get('place_type') or '',
        'filters': filterchain,
        'show_upcoming': show_upcoming,
    })


    context['filtered_schema_list'] = s_list
    context['map_configuration'] = _preconfigured_map(context);
    response = eb_render(request, 'db/place_detail.html', context)
    for k, v in context['cookies_to_set'].items():
        response.set_cookie(k, v)
    return response
Exemple #13
0
def schema_detail(request, slug):
    s = get_object_or_404(get_schema_manager(request), slug=slug)
    if s.is_special_report:
        return schema_detail_special_report(request, s)

    location_type_list = LocationType.objects.filter(is_significant=True).order_by('slug')
    if s.allow_charting:
        # For the date range, the end_date is the last non-future date
        # with at least one NewsItem.
        try:
            end_date = NewsItem.objects.filter(schema__id=s.id, item_date__lte=today()).values_list('item_date', flat=True).order_by('-item_date')[0]
        except IndexError:
            latest_dates = ()
            date_chart = {}
            start_date = end_date = None
        else:
            start_date = end_date - constants.DAYS_AGGREGATE_TIMEDELTA
            date_chart = get_date_chart_agg_model([s], start_date, end_date, AggregateDay)[0]
            latest_dates = [date['date'] for date in date_chart['dates'] if date['count']]

        # Populate schemafield_list and lookup_list.
        schemafield_list = list(s.schemafield_set.filter(is_filter=True).order_by('display_order'))
        # XXX this duplicates part of schema_filter()
        LOOKUP_MIN_DISPLAYED = 7
        LOOKUP_BUFFER = 4
        lookup_list = []
        for sf in schemafield_list:
            if not (sf.is_charted and sf.is_lookup):
                continue
            top_values = list(AggregateFieldLookup.objects.filter(schema_field__id=sf.id).select_related('lookup').order_by('-total')[:LOOKUP_MIN_DISPLAYED + LOOKUP_BUFFER])
            if len(top_values) == LOOKUP_MIN_DISPLAYED + LOOKUP_BUFFER:
                top_values = top_values[:LOOKUP_MIN_DISPLAYED]
                has_more = True
            else:
                has_more = False
            lookup_list.append({'sf': sf, 'top_values': top_values, 'has_more': has_more})

        location_chartfield_list = []

        # Populate location_chartfield_list.
        for lt in location_type_list:
            # Collect the locations in the location_type here so we don't have
            # to query them again in the select_related() below.
            locations = dict([(loc.id, loc) for loc in lt.location_set.iterator()])

            ni_totals = AggregateLocation.objects.filter(
                schema__id=s.id,
                location_type__id=lt.id,
                location__is_public=True).select_related('location').order_by('-total')

            if ni_totals:  # This runs the query.
                known_count = reduce(operator.add, (n.total for n in ni_totals))
                total_count = date_chart.get('total_count', 0)
                unknown_count = max(0, total_count - known_count)
                location_chartfield_list.append({'location_type': lt, 'locations': ni_totals[:9], 'unknown': unknown_count})
        ni_list = ()
    else:
        date_chart = {}
        latest_dates = schemafield_list = lookup_list = location_chartfield_list = ()
        ni_list = list(NewsItem.objects.filter(schema__id=s.id).order_by('-item_date', '-id')[:30])
        populate_schema(ni_list, s)
        populate_attributes_if_needed(ni_list, [s])

    textsearch_sf_list = list(SchemaField.objects.filter(schema__id=s.id, is_searchable=True).order_by('display_order'))
    boolean_lookup_list = [sf for sf in SchemaField.objects.filter(schema__id=s.id, is_filter=True, is_lookup=False).order_by('display_order') if sf.is_type('bool')]

    templates_to_try = ('db/schema_detail/%s.html' % s.slug, 'db/schema_detail.html')

    # The HIDE_SCHEMA_INTRO_COOKIE_NAME cookie is a comma-separated list of
    # schema IDs for schemas whose intro text should *not* be displayed.
    hide_intro = str(s.id) in request.COOKIES.get(HIDE_SCHEMA_INTRO_COOKIE_NAME, '').split(',')

    context = {
        'schema': s,
        'schemafield_list': schemafield_list,
        'location_type_list': location_type_list,
        'date_chart': date_chart,
        'lookup_list': lookup_list,
        'location_chartfield_list': location_chartfield_list,
        'boolean_lookup_list': boolean_lookup_list,
        'search_list': textsearch_sf_list,
        'newsitem_list': ni_list,
        'latest_dates': latest_dates[-3:],
        'hide_intro': hide_intro,
        'hide_intro_cookie_name': HIDE_SCHEMA_INTRO_COOKIE_NAME,
        'start_date': s.min_date,
        'end_date': today(),
        'bodyclass': 'schema-detail',
        'bodyid': slug,
        'filters': FilterChain(schema=s),
    }
    context['breadcrumbs'] = breadcrumbs.schema_detail(context)
    return eb_render(request, templates_to_try, context)
Exemple #14
0
def place_detail_overview(request, *args, **kwargs):
    context, response = _place_detail_normalize_url(request, *args, **kwargs)
    if response is not None:
        return response
    schema_manager = get_schema_manager(request)
    context['breadcrumbs'] = breadcrumbs.place_detail_overview(context)

    schema_list = SortedDict([(s.id, s) for s in schema_manager.filter(is_special_report=False).order_by('plural_name')])
    # needed = set(schema_list.keys())

    # We actually want two lists of schemas, since we care whether
    # they are news-like or future-event-like.
    import copy
    eventish_schema_list = copy.deepcopy(schema_list)
    newsish_schema_list = copy.deepcopy(schema_list)
    for s_id, schema in schema_list.items():
        if schema.is_event:
            del(newsish_schema_list[s_id])
        else:
            del(eventish_schema_list[s_id])

    filterchain = FilterChain(request=request, context=context)
    filterchain.add('location', context['place'])

    # Distinguish between past news and upcoming events.
    # With some preliminary date limiting too.
    filterchain_news = filterchain.copy()
    filterchain_news.add('date',
                         today() - datetime.timedelta(days=90),
                         today())

    filterchain_events = filterchain.copy()
    filterchain_events.add('date',
                           today(),
                           today() + datetime.timedelta(days=60))

    # Ordering by ID ensures consistency across page views.
    newsitem_qs = filterchain_news.apply().order_by('-item_date', '-id')
    events_qs = filterchain_events.apply().order_by('item_date', 'id')

    # Mapping of schema id -> [schemafields], for building Lookup charts.
    sf_dict = {}
    charted_lookups = SchemaField.objects.filter(
        is_lookup=True, is_charted=True, schema__is_public=True,
        schema__is_special_report=False)
    charted_lookups = charted_lookups.values('id', 'schema_id', 'pretty_name')
    for sf in charted_lookups.order_by('schema__id', 'display_order'):
        sf_dict.setdefault(sf['schema_id'], []).append(sf)

    # Now retrieve newsitems per schema.
    schema_groups, all_newsitems = [], []
    for schema in schema_list.values():
        if schema.id in newsish_schema_list:
            newsitems = newsitem_qs.filter(schema__id=schema.id)
        elif schema.id in eventish_schema_list:
            newsitems = events_qs.filter(schema__id=schema.id)
        else:
            raise RuntimeError("should never get here")
        newsitems = list(newsitems[:s.number_in_overview])
        populate_schema(newsitems, schema)
        schema_groups.append({
            'schema': schema,
            'latest_newsitems': newsitems,
            'has_newsitems': bool(newsitems),
            'lookup_charts': sf_dict.get(schema.id),
        })
        all_newsitems.extend(newsitems)
    schema_list = schema_list.values()
    populate_attributes_if_needed(all_newsitems, schema_list)
    schema_list = [s for s in schema_list if s.allow_charting]

    context['schema_groups'] = schema_groups
    context['filtered_schema_list'] = schema_list
    context['bodyclass'] = 'place-detail-overview'
    if context['is_block']:
        context['bodyid'] = '%s-%s-%s' % (context['place'].street_slug,
                                          context['place'].number(),
                                          context['place'].dir_url_bit())
    else:
        context['bodyid'] = context['location'].slug
    response = eb_render(request, 'db/place_overview.html', context)
    for k, v in context['cookies_to_set'].items():
        response.set_cookie(k, v)
    return response
Exemple #15
0
    idx_start = (page - 1) * constants.FILTER_PER_PAGE
    idx_end = page * constants.FILTER_PER_PAGE
    # Get one extra, so we can tell whether there's a next page.
    ni_list = list(qs[idx_start:idx_end+1])
    if page > 1 and not ni_list:
        raise Http404('No objects on page %s' % page)
    if len(ni_list) > constants.FILTER_PER_PAGE:
        has_next = True
        ni_list = ni_list[:-1]
    else:
        has_next = False
        idx_end = idx_start + len(ni_list)
    has_previous = page > 1

    populate_schema(ni_list, s)
    populate_attributes_if_needed(ni_list, [s])

    # Need map parameters based on location/block, if there is one.
    loc_filter = filterchain.get('location')
    if loc_filter:
        context.update(get_place_info_for_request(
                request,
                place=loc_filter.location_object,
                block_radius=getattr(loc_filter, 'block_radius', None)))
    else:
        # Whole city map.
        context.update({
                'default_lon': settings.DEFAULT_MAP_CENTER_LON,
                'default_lat': settings.DEFAULT_MAP_CENTER_LAT,
                'default_zoom': settings.DEFAULT_MAP_ZOOM,
                })