def test_ordering(self): chain = FilterChain() args = range(10) random.shuffle(args) for i in args: chain[i] = i self.assertEqual(chain.items(), [(i, i) for i in args]) self.assertEqual(chain.keys(), args)
def _decode_map_permalink(request, show_default_layers=True, filters=None): """ Permalinks for the big map, with more compact query parameters. Returns a map_config dictionary. Accepted parameters: c - map center, separated by underscore, eg. c=-92.28283_38.95658 z - map zoom, eg. z=12 l - layers to display on load, comma- or dash-separated, eg. l=p13,t32,p1 or eg. l=p12345-t7-t9, where p => place layer and t => schema ("type") layer i - items to load specificially by id, comma- or dash-separated, eg. i=t1234-t456 p - popup center, with underscore, eg. p=-92.3438_38.9658 f - popup feature, eg. f=t1234 or f=p1234 where p = a place and t = a news item start_date - start date (inclusive) %m/%d/%Y end_date - end date (inclusive) %m/%d/%Y d - duration in days (overridden by end date), eg. d=7 x - show as 'widget', just the map and nothign around it. Takes no value, eg. x w - width of map (widget only), in pixels h - height of map (widget only), in pixels v - limits what map controls are displayed (widget only). By default, widget-stype map shows none of these. Possible values, joined with no separator: l - layer switcher h - list of headlines next to map p - permalink eg. to turn them all on: v=lhp """ params = request.GET schemas = set() place_types = set() lids = params.get("l", None) show_custom_layer = False if lids is not None: no_layers_specified = False try: pat = re.compile('(\w\d+)') for lid in pat.findall(lids): layer_type = lid[0] layer_id = int(lid[1:]) if layer_type == 'p': place_types.add(layer_id) elif layer_type == 't': schemas.add(layer_id) elif layer_type == 'c': show_custom_layer = True except: pass else: no_layers_specified = True # map center center = params.get("c", None) if center: try: center = [float(x) for x in center.split('_')][0:2] except: pass # map zoom level zoom = params.get("z", None) if zoom: try: zoom = float(zoom) except: pass # popup popup_info = None popup_center = params.get("p", None) popup_feature = params.get("f", None) if popup_center and popup_feature: try: popup_center = [float(x) for x in popup_center.split('_')][0:2] feature_type = popup_feature[0] feature_id = int(popup_feature[1:]) if feature_type == 'p': openblock_type = 'place' elif feature_type == 't': openblock_type = 'newsitem' popup_info = { 'id': feature_id, 'openblock_type': openblock_type, 'lonlat': [popup_center[0], popup_center[1]] } except: popup_center = None popup_feature = None # start and end date range default_interval = datetime.timedelta(days=7) duration = params.get('d') if duration is not None: try: duration = datetime.timedelta(days=int(duration)) except (TypeError, ValueError): duration = default_interval else: duration = default_interval default_enddate = datetime.date.today() default_startdate = default_enddate - duration startdate = params.get('start_date') if startdate is not None: for format in ('%m/%d/%Y', '%Y-%m-%d'): try: startdate = datetime.datetime.strptime(startdate, format).date() break except ValueError: pass if isinstance(startdate, basestring): startdate = None enddate = params.get('end_date') if enddate is not None: for format in ('%m/%d/%Y', '%Y-%m-%d'): try: enddate = datetime.datetime.strptime(enddate, format).date() break except ValueError: pass if isinstance(enddate, basestring): enddate = None # The filters argument can override startdate & enddate. if startdate is None and enddate is None and filters: date_filter = filters.get('date') or filters.get('pubdate') if date_filter: startdate = date_filter.start_date enddate = date_filter.end_date if startdate is None and enddate is None: enddate = datetime.date.today() startdate = enddate - duration elif startdate is None: startdate = enddate - duration elif enddate is None: enddate = startdate + duration if enddate < startdate: enddate = startdate + duration # inject date range into filters if none was specified: if filters and filters.get('date') is None: filters.add('date', startdate, enddate) api_startdate = startdate.strftime("%Y-%m-%d") api_enddate = (enddate + datetime.timedelta(days=1)).strftime("%Y-%m-%d") layers = [] if (startdate != default_startdate) or (enddate != default_enddate): show_custom_layer = True # All available place layers. for place_type in PlaceType.objects.filter(is_mappable=True).all(): layers.append({ 'id': 'p%d' % place_type.id, 'title': place_type.plural_name, 'url': reverse('place_detail_json', args=[place_type.slug]), 'params': {'limit': 1000}, 'minZoom': 15, 'bbox': True, 'visible': place_type.id in place_types # off by default }) # All available NewsItem layers. for schema in get_schema_manager(request).all(): # if filters and 'schema' in filters and filters['schema'].schema == schema: # visible = True if no_layers_specified and show_default_layers and not show_custom_layer: # default on if no 't' param given visible = True elif schemas and schema.id in schemas: visible = True else: visible = False layers.append({ 'id': 't%d' % schema.id, 'title': schema.plural_name, 'url': reverse('map_items_json'), 'params': {'type': schema.slug, 'limit': 1000, 'startdate': api_startdate, 'enddate': api_enddate}, 'bbox': False, 'visible': visible }) # Explicit filtering by ID. ids = params.get('i') or u'' ids = [i.strip() for i in re.split(r'[^\d]+', ids) if i.strip()] if ids: show_custom_layer = True if filters is None: filters = FilterChain(request) filters.replace('id', *ids) # 'Custom' layer. This is a catch-all for all filtering # that isn't just enabling a default layer with the default # date range. # Not visible unless there is something like that to show. if filters and sorted(filters.keys()) not in ([], ['date'], ['date', 'schema'], ['schema']): show_custom_layer = True if filters is not None: # Don't inspect filters['schema']; that's already covered by schemas above. base_url = reverse('map_items_json') layer_url = filters.make_url(base_url=base_url) # Quick ugly hacks to make the itemquery api happy. # Hooray proliferation of spellings. layer_url = layer_url.replace('locations=', 'locationid=') layer_url = layer_url.replace('start_date=', 'startdate=') layer_url = layer_url.replace('end_date=', 'enddate=') if 'schema' in filters: # Normally, filters.make_url() captures the schema in the # path part of the URL. But map_items_json doesn't, # so we add a query parameter. params = {'type': [s.slug for s in filters['schema'].schemas]} else: params = {} custom_layer = { 'url': layer_url, 'params': params, 'title': u"Custom Filter", 'visible': show_custom_layer, 'id': 'c1', } layers.append(custom_layer) is_widget = params.get('x', None) is not None controls = {} control_list = params.get("v", None) if control_list is not None: if 'l' in control_list: controls['layers'] = True if 'h' in control_list: controls['headline_list'] = True if 'p' in control_list: controls['permalink'] = True width = params.get("w", None) if width: try: width = int(width) except: width = None height = params.get("h", None) if height: try: height = int(height) except: height = None config = { 'center': center or [settings.DEFAULT_MAP_CENTER_LON, settings.DEFAULT_MAP_CENTER_LAT], 'zoom': zoom or settings.DEFAULT_MAP_ZOOM, 'layers': layers, 'is_widget': is_widget, 'permalink_params': { 'start_date': startdate.strftime('%m/%d/%Y'), 'end_date': enddate.strftime('%m/%d/%Y'), }, } if 'id' in filters: # Put them in the params so the js code can construct, well, # permalinks with these ids, on the client side. ids = '-'.join(map(str, filters['id'].ids)) config['permalink_params']['i'] = ids if popup_info: config['popup'] = popup_info if is_widget: config['controls'] = controls if width is not None: config['width'] = width if height is not None: config['height'] = height return config
def _decode_map_permalink(request, show_default_layers=True, filters=None): """ Permalinks for the big map, with more compact query parameters. Returns a map_config dictionary. Accepted parameters: c - map center, separated by underscore, eg. c=-92.28283_38.95658 z - map zoom, eg. z=12 l - layers to display on load, comma- or dash-separated, eg. l=p13,t32,p1 or eg. l=p12345-t7-t9, where p => place layer and t => schema ("type") layer i - items to load specificially by id, comma- or dash-separated, eg. i=t1234-t456 p - popup center, with underscore, eg. p=-92.3438_38.9658 f - popup feature, eg. f=t1234 or f=p1234 where p = a place and t = a news item start_date - start date (inclusive) %m/%d/%Y end_date - end date (inclusive) %m/%d/%Y d - duration in days (overridden by end date), eg. d=7 x - show as 'widget', just the map and nothign around it. Takes no value, eg. x w - width of map (widget only), in pixels h - height of map (widget only), in pixels v - limits what map controls are displayed (widget only). By default, widget-stype map shows none of these. Possible values, joined with no separator: l - layer switcher h - list of headlines next to map p - permalink eg. to turn them all on: v=lhp """ params = request.GET schemas = set() place_types = set() lids = params.get("l", None) show_custom_layer = False if lids is not None: no_layers_specified = False try: pat = re.compile('(\w\d+)') for lid in pat.findall(lids): layer_type = lid[0] layer_id = int(lid[1:]) if layer_type == 'p': place_types.add(layer_id) elif layer_type == 't': schemas.add(layer_id) elif layer_type == 'c': show_custom_layer = True except: pass else: no_layers_specified = True # map center center = params.get("c", None) if center: try: center = [float(x) for x in center.split('_')][0:2] except: pass # map zoom level zoom = params.get("z", None) if zoom: try: zoom = float(zoom) except: pass # popup popup_info = None popup_center = params.get("p", None) popup_feature = params.get("f", None) if popup_center and popup_feature: try: popup_center = [float(x) for x in popup_center.split('_')][0:2] feature_type = popup_feature[0] feature_id = int(popup_feature[1:]) if feature_type == 'p': openblock_type = 'place' elif feature_type == 't': openblock_type = 'newsitem' popup_info = { 'id': feature_id, 'openblock_type': openblock_type, 'lonlat': [popup_center[0], popup_center[1]] } except: popup_center = None popup_feature = None # start and end date range default_interval = datetime.timedelta(days=7) duration = params.get('d') if duration is not None: try: duration = datetime.timedelta(days=int(duration)) except (TypeError, ValueError): duration = default_interval else: duration = default_interval default_enddate = datetime.date.today() default_startdate = default_enddate - duration startdate = params.get('start_date') if startdate is not None: for format in ('%m/%d/%Y', '%Y-%m-%d'): try: startdate = datetime.datetime.strptime(startdate, format).date() break except ValueError: pass if isinstance(startdate, basestring): startdate = None enddate = params.get('end_date') if enddate is not None: for format in ('%m/%d/%Y', '%Y-%m-%d'): try: enddate = datetime.datetime.strptime(enddate, format).date() break except ValueError: pass if isinstance(enddate, basestring): enddate = None # The filters argument can override startdate & enddate. if startdate is None and enddate is None and filters: date_filter = filters.get('date') or filters.get('pubdate') if date_filter: startdate = date_filter.start_date enddate = date_filter.end_date if startdate is None and enddate is None: enddate = datetime.date.today() startdate = enddate - duration elif startdate is None: startdate = enddate - duration elif enddate is None: enddate = startdate + duration if enddate < startdate: enddate = startdate + duration # inject date range into filters if none was specified: if filters and filters.get('date') is None: filters.add('date', startdate, enddate) api_startdate = startdate.strftime("%Y-%m-%d") api_enddate = (enddate + datetime.timedelta(days=1)).strftime("%Y-%m-%d") layers = [] if (startdate != default_startdate) or (enddate != default_enddate): show_custom_layer = True # All available place layers. for place_type in PlaceType.objects.filter(is_mappable=True).all(): layers.append({ 'id': 'p%d' % place_type.id, 'title': place_type.plural_name, 'url': reverse('place_detail_json', args=[place_type.slug]), 'params': { 'limit': 1000 }, 'minZoom': 15, 'bbox': True, 'visible': place_type.id in place_types # off by default }) # All available NewsItem layers. for schema in get_schema_manager(request).all(): # if filters and 'schema' in filters and filters['schema'].schema == schema: # visible = True if no_layers_specified and show_default_layers and not show_custom_layer: # default on if no 't' param given visible = True elif schemas and schema.id in schemas: visible = True else: visible = False layers.append({ 'id': 't%d' % schema.id, 'title': schema.plural_name, 'url': reverse('map_items_json'), 'params': { 'type': schema.slug, 'limit': 1000, 'startdate': api_startdate, 'enddate': api_enddate }, 'bbox': False, 'visible': visible }) # Explicit filtering by ID. ids = params.get('i') or u'' ids = [i.strip() for i in re.split(r'[^\d]+', ids) if i.strip()] if ids: show_custom_layer = True if filters is None: filters = FilterChain(request) filters.replace('id', *ids) # 'Custom' layer. This is a catch-all for all filtering # that isn't just enabling a default layer with the default # date range. # Not visible unless there is something like that to show. if filters and sorted(filters.keys()) not in ([], ['date'], [ 'date', 'schema' ], ['schema']): show_custom_layer = True if filters is not None: # Don't inspect filters['schema']; that's already covered by schemas above. base_url = reverse('map_items_json') layer_url = filters.make_url(base_url=base_url) # Quick ugly hacks to make the itemquery api happy. # Hooray proliferation of spellings. layer_url = layer_url.replace('locations=', 'locationid=') layer_url = layer_url.replace('start_date=', 'startdate=') layer_url = layer_url.replace('end_date=', 'enddate=') if 'schema' in filters: # Normally, filters.make_url() captures the schema in the # path part of the URL. But map_items_json doesn't, # so we add a query parameter. params = {'type': [s.slug for s in filters['schema'].schemas]} else: params = {} custom_layer = { 'url': layer_url, 'params': params, 'title': u"Custom Filter", 'visible': show_custom_layer, 'id': 'c1', } layers.append(custom_layer) is_widget = params.get('x', None) is not None controls = {} control_list = params.get("v", None) if control_list is not None: if 'l' in control_list: controls['layers'] = True if 'h' in control_list: controls['headline_list'] = True if 'p' in control_list: controls['permalink'] = True width = params.get("w", None) if width: try: width = int(width) except: width = None height = params.get("h", None) if height: try: height = int(height) except: height = None config = { 'center': center or [settings.DEFAULT_MAP_CENTER_LON, settings.DEFAULT_MAP_CENTER_LAT], 'zoom': zoom or settings.DEFAULT_MAP_ZOOM, 'layers': layers, 'is_widget': is_widget, 'permalink_params': { 'start_date': startdate.strftime('%m/%d/%Y'), 'end_date': enddate.strftime('%m/%d/%Y'), }, } if 'id' in filters: # Put them in the params so the js code can construct, well, # permalinks with these ids, on the client side. ids = '-'.join(map(str, filters['id'].ids)) config['permalink_params']['i'] = ids if popup_info: config['popup'] = popup_info if is_widget: config['controls'] = controls if width is not None: config['width'] = width if height is not None: config['height'] = height return config