Location widget =============== A widget used when setting the geographic location of a given person. >>> from canonical.launchpad.webapp.servers import LaunchpadTestRequest >>> from lp.app.widgets.location import LocationWidget >>> from lp.registry.interfaces.person import IPersonSet >>> from lp.services.fields import LocationField >>> salgado = getUtility(IPersonSet).getByName('salgado') >>> field = LocationField(__name__='location', title=u'Location') >>> bound_field = field.bind(salgado) >>> request = LaunchpadTestRequest( ... # Let's pretend requests are coming from Brazil. ... environ={'REMOTE_ADDR': '201.13.165.145'}) When rendering salgado's location widget to himself, we'll center the map around the location where he seems to be, based on the IP address of the request. >>> login_person(salgado) >>> widget = LocationWidget(bound_field, request) >>> widget.zoom 7 >>> widget.center_lat -23... >>> widget.center_lng -45... Since salgado's location hasn't been specified yet, there'll be no visual marker indicating where he is in the map. >>> widget.show_marker 0 If someone else sees salgado's location widget, though, we have no way of guessing what coordinates to center the map around (because the request doesn't come from salgado's browser), so we won't try to do so. >>> login(ANONYMOUS) >>> widget = LocationWidget(bound_field, request) >>> widget.zoom 2 >>> widget.center_lat 15.0 >>> widget.center_lng 0.0 >>> widget.show_marker 0 When rendering the location widget of someone who already specified a location, we'll obviously center the map around that, but we'll also put a visual marker in the latitude/longitude specified as that person's location. >>> kamion = getUtility(IPersonSet).getByName('kamion') >>> bound_field = field.bind(kamion) >>> login_person(kamion) >>> widget = LocationWidget(bound_field, request) >>> widget.zoom 9 >>> widget.center_lat 52... >>> widget.center_lng 0.29... >>> widget.show_marker 1 The widget's getInputValue() method will return a LocationValue object, which stored the geographic coordinates and the timezone. >>> request = LaunchpadTestRequest( ... form={'field.location.time_zone': 'Europe/London', ... 'field.location.latitude': '51.3', ... 'field.location.longitude': '0.32'}) >>> widget = LocationWidget(bound_field, request) >>> widget.hasInput() True >>> location = widget.getInputValue() >>> location >> location.latitude # Only the integral part due to rounding errors. 51... >>> location.longitude 0.32... >>> location.time_zone 'Europe/London' If we try to set only the latitude *or* longitude, but not both, we'll get an error. >>> request = LaunchpadTestRequest( ... form={'field.location.time_zone': 'Europe/London', ... 'field.location.longitude': '0.32'}) >>> widget = LocationWidget(bound_field, request) >>> widget.hasInput() True >>> widget.getInputValue() Traceback (most recent call last): ... WidgetInputError:...Please provide both latitude and longitude... We also get errors if we don't specify a time zone or if the latitude/longitude have non-realistic values. >>> request = LaunchpadTestRequest( ... form={'field.location.latitude': '51.3', ... 'field.location.longitude': '0.32'}) >>> widget = LocationWidget(bound_field, request) >>> widget.hasInput() True >>> location = widget.getInputValue() Traceback (most recent call last): ... MissingInputError: ('field.location.time_zone'... >>> request = LaunchpadTestRequest( ... form={'field.location.time_zone': 'Europe/London', ... 'field.location.latitude': '99.3', ... 'field.location.longitude': '0.32'}) >>> widget = LocationWidget(bound_field, request) >>> widget.hasInput() True >>> widget.getInputValue() Traceback (most recent call last): ... WidgetInputError:...Please provide a more realistic latitude and longitude... The widget's HTML ----------------- The widget's HTML will include elements for the latitude, longitude and time zone fields. The values of these elements will be set from within Javascript whenever the user changes the location on the map. >>> bound_field = field.bind(kamion) >>> request = LaunchpadTestRequest( ... environ={'REMOTE_ADDR': '201.13.165.145'}) >>> login_person(kamion) >>> widget = LocationWidget(bound_field, request) >>> print widget() >> from canonical.config import config >>> config.push('geoname_data', """ ... [launchpad] ... geonames_identity: totoro ... """) >>> print widget.map_javascript # Restore the config the the default state. >>> config_data = config.pop('geoname_data') XSS --- The widget must escape and JS encode the person's displayname to prevent XSS attacks and to make sure the generated javascript can be parsed. >>> kamion.displayname = ( ... "") >>> bound_field = field.bind(kamion) >>> widget = LocationWidget(bound_field, request) >>> print widget.map_javascript ... "<script>alert('John "nasty" O'Brien');</script>",...