Esempio n. 1
0
    def Post(self, domain, user):  # pylint: disable=unused-argument
        """Creates, updates, or removes a catalog entry."""
        label = self.request.get('label').strip()
        publisher_name = self.request.get('publisher_name').strip()
        if self.request.get('remove'):
            model.CatalogEntry.Delete(domain, label)
            self.redirect('.maps')
        else:
            if not re.match(r'^[\w-]+$', label):  # Valid if alphanumeric, -, _
                raise base_handler.Error(
                    400,
                    'Valid labels may only contain letters, digits, "-", and "_".'
                )
            map_object = model.Map.Get(self.request.get('map'))
            if not map_object:
                raise base_handler.Error(400, 'No such map.')

            # Preserve the "is_listed" flag if the CatalogEntry already exists.
            entry = (model.CatalogEntry.Get(domain, label)
                     or model.CatalogEntry.Create(domain, label, map_object))
            entry.SetMapVersion(map_object)
            if publisher_name:
                entry.SetPublisherName(publisher_name)
            entry.Put()
            self.redirect('.maps')
Esempio n. 2
0
 def Get(self, label, user=None, domain=None):
   domain = domain or config.Get('primary_domain') or ''
   entry = model.CatalogEntry.Get(domain, label)
   if not entry:
     raise base_handler.Error(404, 'No such map.')
   topics = entry.map_root.get('topics', [])
   if not topics:
     raise base_handler.Error(404, 'Map has no topics.')
   self.redirect('%s/%s' % (label, str(topics[0]['id'])))
Esempio n. 3
0
 def Get(self, map_id, topic_id, user=None, domain=None):
     m = model.Map.Get(map_id)
     if not m:
         logging.severe('No map with id %s' % map_id)
         raise base_handler.Error(404, 'No such map.')
     self.GetForMap(m.map_root, m.current_version_id, topic_id, None,
                    domain)
Esempio n. 4
0
  def Get(self, map_id, domain=None):  # pylint: disable=g-bad-name
    """Displays a map in draft mode by its map ID."""
    map_object = model.Map.Get(map_id)
    if not map_object:
      raise base_handler.Error(404, 'Map %r not found.' % map_id)

    if not domain or domain != map_object.domain:
      # The canonical URL for a map contains both the domain and the map ID.
      url = '../%s/.maps/%s' % (map_object.domain, map_id)
      if self.request.GET:  # preserve query params on redirect
        url += '?' + urllib.urlencode(self.request.GET.items())
      return self.redirect(url)

    cm_config = GetConfig(self.request, map_object=map_object,
                          xsrf_token=self.xsrf_token)
    # SECURITY NOTE: cm_config_json is assumed to be safe JSON, and head_html
    # is assumed to be safe HTML; all other template variables are autoescaped.
    # TODO(kpy): Factor out the bits common to MapByLabel.Get and MapById.Get.
    self.response.out.write(self.RenderTemplate('map.html', {
        'maps_api_url': cm_config.pop('maps_api_url', ''),
        'head_html': cm_config.pop('custom_head_html', ''),
        'lang': cm_config['lang'],
        'lang_lower': cm_config['lang'].lower().replace('-', '_'),
        'cm_config_json': base_handler.ToHtmlSafeJson(cm_config)
    }))
Esempio n. 5
0
def GetPlacesApiResults(base_url, request_params, result_key_name=None):
    """Fetches results from Places API given base_url and request params.

  Args:
    base_url: URL prefix to use before the request params
    request_params: An array of key and value pairs for the request
    result_key_name: Name of the results field in the Places API response
        or None if the whole response should be returned
  Returns:
    Value for the result_key_name in the Places API response or all of the
    response if result_key_name is None
  """
    google_api_server_key = config.Get('google_api_server_key')
    if not google_api_server_key:
        raise base_handler.Error(
            500, 'google_api_server_key is not set in the config')
    request_params += [('key', google_api_server_key)]
    url = base_url + urllib.urlencode([(k, v) for k, v in request_params if v])

    # Call Places API if cache doesn't have a corresponding entry for the url
    def GetPlacesJson():
        response = urlfetch.fetch(url=url, deadline=DEADLINE)
        return json.loads(response.content)

    response_content = JSON_PLACES_API_CACHE.Get(url, GetPlacesJson)

    # Parse results
    status = response_content.get('status')
    if status != 'OK' and status != 'ZERO_RESULTS':
        # Something went wrong with the request, log the error
        logging.error('Places API request [%s] failed with error %s', url,
                      status)
        return []
    return (response_content.get(result_key_name)
            if result_key_name else response_content)
Esempio n. 6
0
 def GetDomainAdmin(self, user, domain):  # pylint:disable=unused-argument
     """Displays the administration page for the given domain."""
     domain_name = domain
     perms.AssertAccess(perms.Role.DOMAIN_ADMIN, domain_name)
     domain = domains.Domain.Get(domain_name)
     if not domain:
         raise base_handler.Error(404, 'Unknown domain %r.' % domain_name)
     subject_roles = perms.GetSubjectsForTarget(domain_name)
     user_roles = [(users.Get(subj), _MaxRole(r))
                   for (subj, r) in subject_roles.items()
                   if perms.IsUserId(subj)]
     user_roles.sort(key=lambda (u, r): u.email)
     labels = sorted(e.label
                     for e in model.CatalogEntry.GetAll(domain_name))
     self.response.out.write(
         self.RenderTemplate(
             'admin_domain.html', {
                 'domain': domain,
                 'user_roles': user_roles,
                 'labels': labels,
                 'domain_role': _MaxRole(
                     subject_roles.get(domain_name, set())),
                 'user_permission_choices': DOMAIN_PERMISSION_CHOICES,
                 'initial_domain_role_choices': INITIAL_DOMAIN_ROLE_CHOICES,
                 'show_welcome': self.request.get('welcome', '')
             }))
Esempio n. 7
0
  def Get(self, label, domain=None):  # pylint: disable=g-bad-name
    """Displays a published map by its domain and publication label."""
    domain = domain or config.Get('primary_domain') or ''
    entry = model.CatalogEntry.Get(domain, label)
    if not entry:
      # Fall back to the map list for users that go to /crisismap/maps.
      # TODO(kpy): Remove this when the UI has a way to get to the map list.
      if label == 'maps':
        return self.redirect('.maps')
      raise base_handler.Error(404, 'Label %s/%s not found.' % (domain, label))

    cm_config = GetConfig(self.request, catalog_entry=entry,
                          xsrf_token=self.xsrf_token)
    map_root = cm_config.get('map_root', {})
    # SECURITY NOTE: cm_config_json is assumed to be safe JSON, and head_html
    # is assumed to be safe HTML; all other template variables are autoescaped.
    # Below, we use cm_config.pop() for template variables that aren't part of
    # the API understood by google.cm.Map() and don't need to stay in cm_config.
    self.response.out.write(self.RenderTemplate('map.html', {
        'maps_api_url': cm_config.pop('maps_api_url', ''),
        'head_html': cm_config.pop('custom_head_html', ''),
        'lang': cm_config['lang'],
        'lang_lower': cm_config['lang'].lower().replace('-', '_'),
        'json_proxy_url': cm_config['json_proxy_url'],
        'maproot_url': cm_config.pop('maproot_url', ''),
        'map_title': map_root.get('title', '') + ' | Google Crisis Map',
        'map_description': ToPlainText(map_root.get('description')),
        'map_url': self.request.path_url,
        'map_image': map_root.get('thumbnail_url', ''),
        'cm_config_json': base_handler.ToHtmlSafeJson(cm_config)
    }))
Esempio n. 8
0
 def Post(self, user, domain=''):  # pylint: disable=unused-argument
   map_id = self.request.get('map')
   map_object = model.Map.Get(map_id)
   if not map_object:
     raise base_handler.Error(404, 'Map %r not found.' % map_id)
   map_object.Delete()
   self.redirect('.maps')
Esempio n. 9
0
 def Get(self, map_id):
     """Renders the admin page."""
     perms.AssertAccess(perms.Role.ADMIN)
     map_object = model.Map.Get(map_id) or model.Map.GetDeleted(map_id)
     if not map_object:
         raise base_handler.Error(404, 'Map %r not found.' % map_id)
     self.response.out.write(
         self.RenderTemplate('admin_map.html', {'map': map_object}))
Esempio n. 10
0
 def Get(self, label, topic_id, user=None, domain=None):
     domain = domain or config.Get('primary_domain') or ''
     entry = model.CatalogEntry.Get(domain, label)
     if not entry:
         logging.severe('No map with label %s under domain %s' %
                        (label, domain))
         raise base_handler.Error(404, 'No such map.')
     self.GetForMap(entry.map_root, entry.map_version_id, topic_id, label,
                    domain)
Esempio n. 11
0
 def Post(self):
   _CheckIsDevServer()
   service_name = self.request.get('service', '')
   if service_name == 'urlshortener':
     self.response.out.write('{"id": "http://goo.gl/fakeShortUrl"}')
     return
   else:
     raise base_handler.Error(400,
                              'Unsupported test backend [%s]' % service_name)
Esempio n. 12
0
 def CreateDomain(self, domain_name, user):
     if domains.Domain.Get(domain_name):
         raise base_handler.Error(403,
                                  'Domain %r already exists.' % domain_name)
     domains.Domain.Put(domain_name)
     utils.SetAndTest(
         lambda: perms.Grant(user.id, perms.Role.DOMAIN_ADMIN, domain_name),
         lambda: perms.CheckAccess(perms.Role.DOMAIN_ADMIN, domain_name,
                                   user))
Esempio n. 13
0
def ParseJson(json_string):
    """Parses a JSON or JSONP string and returns the parsed object."""
    match = JSON_CALLBACK_RE.match(json_string)
    if match:
        json_string = match.group(
            1)  # remove the function call around the JSON
    try:
        return json.loads(json_string)
    except (TypeError, ValueError):
        raise base_handler.Error(httplib.FORBIDDEN, 'Invalid JSON.')
Esempio n. 14
0
 def Get(self):
   _CheckIsDevServer()
   service_name = self.request.get('service', '')
   if service_name == 'file':
     # Fetch a static file and return it as an attachment in the response
     file_name = self.request.get('filename', '')
     if file_name[-4:] == '.kml':
       file_content = utils.ReadStaticFile(file_name)
       self.response.headers['Content-Type'] = KML_MIME_TYPE
       self.response.headers.add_header(
           'content-disposition', 'attachment', filename=str(file_name))
       self.response.out.write(file_content)
       return
     else:
       raise base_handler.Error(
           400, 'Unsupported file type %s' % file_name[-4:])
   else:
     raise base_handler.Error(
         400, 'Unsupported test backend [%s]' % service_name)
Esempio n. 15
0
 def AddNewUserIfPresent(self, inputs, domain):
     """Grants domain roles to a new user."""
     new_email = inputs.pop('new_user').strip()
     new_role = inputs.pop('new_user.permission')
     if not new_email or not new_role:
         return
     if not utils.IsValidEmail(new_email):
         raise base_handler.Error(400,
                                  'Invalid e-mail address: %r.' % new_email)
     user = users.GetForEmail(new_email)
     perms.Grant(user.id, new_role, domain)
Esempio n. 16
0
def AssertRateLimitNotExceeded(client_ip):
    """Raises an error if the given IP exceeds its allowed request rate."""
    # We use memcache directly, as our cache abstraction does not support incr(),
    # but avoid key collision by using a Cache object to produce the cache keys.
    cache_key = QPM_CACHE.KeyToJson(client_ip)
    if memcache.get(cache_key) >= MAX_OUTBOUND_QPM_PER_IP:
        raise base_handler.Error(
            HTTP_TOO_MANY_REQUESTS,
            'Rate limit exceeded; please try again later.')
    memcache.add(cache_key, 0, 60)
    memcache.incr(cache_key)
Esempio n. 17
0
  def _GetMap(self, label, domain):
    """Loads the model.Map instance being reviewed by label and domain.

    Args:
      label: A string, the published label for the map.
      domain: A string, the domain in which the map was created, eg gmail.com.

    Returns:
      The model.Map instance being reviewed

    Raises:
      base_handler.Error: If the map csnnot be found.
    """
    domain = domain or config.Get('primary_domain') or ''
    entry = model.CatalogEntry.Get(domain, label)
    if not entry:
      raise base_handler.Error(404, 'Map %r not found.' % label)
    map_object = model.Map.Get(entry.map_id)
    if not map_object:
      raise base_handler.Error(404, 'Map %r not found.' % label)
    return map_object
Esempio n. 18
0
    def Post(self, map_id, domain=None):  # pylint: disable=unused-argument
        """Adds the recipient to the appropriate permission areas."""
        map_object = model.Map.Get(map_id)
        if map_object is None:
            raise base_handler.Error(404, 'Map %r not found.' % map_id)
        role = self.request.get('role')
        recipient_email = self.request.get('recipient')
        message = self.request.get('message', '')

        # If these are empty or invalid, we shouldn't try to do anything.
        if role not in SHARING_ROLES:
            raise base_handler.Error(400, 'Invalid role parameter: %r.' % role)
        if not utils.IsValidEmail(recipient_email):
            raise base_handler.Error(
                400, 'Invalid e-mail address: %r.' % recipient_email)

        # Change the recipient's permission level as specified.
        recipient = users.GetForEmail(recipient_email)
        map_object.ChangePermissionLevel(role, recipient.id)
        # Send the recipient an email.
        self.SendPermissionChangeEmail(recipient_email, map_object, role,
                                       message)
        self.response.set_status(201)
Esempio n. 19
0
 def Fetch():
     """Fetch the URL and return the parsed JSON."""
     AssertRateLimitNotExceeded(client_ip)
     method = post_json and 'POST' or 'GET'
     headers = post_json and {'Content-Type': 'application/json'} or {}
     if referrer:
         headers['Referer'] = referrer
     result = urlfetch.fetch(url, post_json, method, headers)
     if result.status_code != httplib.OK:
         logging.warn(
             'Request for url=%r post_json=%r returned status %r: %r', url,
             post_json, result.status_code, result.content)
         raise base_handler.Error(result.status_code, 'Request failed.')
     return ParseJson(result.content)
Esempio n. 20
0
  def Get(self):
    """Returns legend items extracted from kml at given URL."""
    url = jsonp.SanitizeUrl(self.request.get('url'))
    kml = self.GetKmlFromUrl(url)
    if kml is None:
      raise base_handler.Error(400, 'Failed to get KML from ' + url)

    (icon_styles, line_styles, polygon_styles,
     static_icon_urls, colors) = Extract(kml)

    self.WriteJson({
        'icon_styles': icon_styles, 'line_styles': line_styles,
        'polygon_styles': polygon_styles,
        'static_icon_urls': list(static_icon_urls), 'colors': list(colors)
    })
Esempio n. 21
0
  def _GetMap(self, map_id):
    """Loads the model.Map instance being reviewed by ID.

    Args:
      map_id: A string, the id of the map being reviewed.

    Returns:
      The model.Map instance being reviewed

    Raises:
      base_handler.Error: If the map csnnot be found.
    """
    map_object = model.Map.Get(map_id)
    if not map_object:
      raise base_handler.Error(404, 'Map %r not found.' % map_id)
    return map_object
Esempio n. 22
0
def SanitizeUrl(url):
    """Checks and returns a URL that is safe to fetch, or raises an error.

  Args:
    url: A URL.

  Returns:
    The URL, only if it is considered safe to fetch.

  Raises:
    base_handler.Error: The URL was missing or not safe to fetch.
  """
    scheme, netloc, path, query, _ = urlparse.urlsplit(url)
    if scheme in ['http', 'https']:
        return urlparse.urlunsplit((scheme, netloc, path, query, ''))
    raise base_handler.Error(httplib.BAD_REQUEST, 'Missing or invalid URL.')
Esempio n. 23
0
 def Post(self, map_id):
     """Handles a POST (block/unblock, delete/undelete, or wipe)."""
     perms.AssertAccess(perms.Role.ADMIN)
     map_object = model.Map.Get(map_id) or model.Map.GetDeleted(map_id)
     if not map_object:
         raise base_handler.Error(404, 'Map %r not found.' % map_id)
     if self.request.get('block'):
         map_object.SetBlocked(True)
     if self.request.get('unblock'):
         map_object.SetBlocked(False)
     if self.request.get('delete'):
         map_object.Delete()
     if self.request.get('undelete'):
         map_object.Undelete()
     if self.request.get('wipe'):
         map_object.Wipe()
     self.redirect(map_id)
Esempio n. 24
0
 def Post(self, user, domain):
     """Landing for posts from the domain administration page."""
     which = self.request.POST.pop('form')
     target = self.request.path
     if which != 'create-domain':
         perms.AssertAccess(perms.Role.DOMAIN_ADMIN, domain, user)
         if not domains.Domain.Get(domain):
             raise base_handler.Error(404, 'Unknown domain %r.' % domain)
     if which == 'domain-settings':
         self.UpdateDomainSettings(self.request.POST, domain)
     elif which == 'create-domain':
         self.CreateDomain(domain, user)
         target += '?welcome=1'
     else:  # user or domain permissions
         inputs = dict(self.request.POST)
         self.AddNewUserIfPresent(inputs, domain)
         # Set access to this domain for all users with this e-mail domain.
         self.UpdateDomainRole(inputs, domain)
         # Set access to this domain for individually specified users.
         SetRolesForDomain(self.FindNewPerms(inputs), domain)
     self.redirect(target)
Esempio n. 25
0
def _CheckIsDevServer():
  if not utils.IsDevelopmentServer():
    raise base_handler.Error(500, 'testbackend is only accessible in DEV')
Esempio n. 26
0
  def GetForMap(self, map_root, map_version_id, topic_id, map_label=None):
    """Renders the card for a particular map and topic.

    Args:
      map_root: The MapRoot dictionary for the map.
      map_version_id: The version ID of the MapVersionModel (for a cache key).
      topic_id: The topic ID.
      map_label: The label of the published map (for analytics).
    """
    topic = GetTopic(map_root, topic_id)
    if not topic:
      raise base_handler.Error(404, 'No such topic.')
    output = str(self.request.get('output', ''))
    lat_lon = str(self.request.get('ll', ''))
    max_count = int(self.request.get('n', 5))  # number of results to show
    radius = float(self.request.get('r', 100000))  # radius, metres
    unit = str(self.request.get('unit', self.GetDistanceUnitForCountry()))
    qids = self.request.get('qids').replace(',', ' ').split()
    places_json = self.request.get('places') or '[]'
    place_id = str(self.request.get('place', ''))
    footer_json = self.request.get('footer') or '[]'
    location_unavailable = self.request.get('location_unavailable')
    lang = base_handler.SelectLanguageForRequest(self.request, map_root)
    include_descriptions = self.request.get('show_desc')

    try:
      places = json.loads(places_json)
    except ValueError:
      logging.error('Could not parse ?places= parameter')
    try:
      footer = json.loads(footer_json)
    except ValueError:
      logging.error('Could not parse ?footer= parameter')

    # If '?ll' parameter is supplied, find nearby results.
    center = None
    if lat_lon:
      try:
        lat, lon = lat_lon.split(',')
        center = ndb.GeoPt(float(lat), float(lon))
      except ValueError:
        logging.error('Could not extract center for ?ll parameter')

    # If neither '?ll' nor '?place' parameters are given, or if ?place
    # value is invalid, use a default place.
    place = None
    if not center:
      place = {p['id']: p for p in places}.get(place_id, places and places[0])

    # If '?place' parameter is supplied, use it as the center of the
    # point-radius query.
    if not center and place:
      try:
        lat, lon = place['ll']
        center = ndb.GeoPt(lat, lon)
      except (KeyError, TypeError, ValueError):
        logging.error('Could not extract center for ?place=%s', place_id)

    try:
      # Find POIs associated with the topic layers
      features = GetFilteredFeatures(
          map_root, map_version_id, topic_id, self.request,
          center, radius, max_count)
      html_attrs = GetFeatureAttributions(features)
      SetAnswersAndReportsOnFeatures(features, map_root, topic_id, qids)
      geojson = GetGeoJson(features, include_descriptions)
      geojson['properties'] = {
          'map_id': map_root.get('id'),
          'topic': topic,
          'html_attrs': html_attrs,
          'unit': unit
      }
      if output == 'json':
        self.WriteJson(geojson)
      else:
        self.response.out.write(self.RenderTemplate('card.html', {
            'features': geojson['features'],
            'title': topic.get('title', ''),
            'unit': unit,
            'lang': lang,
            'url_no_unit': RemoveParamsFromUrl(self.request.url, 'unit'),
            'place': place,
            'config_json': json.dumps({
                'url_no_loc': RemoveParamsFromUrl(
                    self.request.url, 'll', 'place'),
                'place': place,
                'location_unavailable': bool(location_unavailable),
                'map_id': map_root.get('id', ''),
                'topic_id': topic_id,
                'map_label': map_label or '',
                'topic_title': topic.get('title', '')
            }),
            'places_json': json.dumps(places),
            'footer_html': RenderFooter(footer or [], html_attrs)
        }))

    except Exception, e:  # pylint:disable=broad-except
      logging.exception(e)
Esempio n. 27
0
 def Get(self, map_id, topic_id, user=None, domain=None):
   m = model.Map.Get(map_id)
   if not m:
     raise base_handler.Error(404, 'No such map.')
   self.GetForMap(m.map_root, m.current_version_id, topic_id)
Esempio n. 28
0
 def CheckAccess(self):
     """Ensures this page is only accessible to developers."""
     if not users.IsDeveloper():
         raise base_handler.Error(404, 'Not found.')
Esempio n. 29
0
    def GetForMap(self,
                  map_root,
                  map_version_id,
                  topic_id,
                  map_label=None,
                  domain=None):
        """Renders the card for a particular map and topic.

    Args:
      map_root: The MapRoot dictionary for the map.
      map_version_id: The version ID of the MapVersionModel (for a cache key).
      topic_id: The topic ID.
      map_label: The label of the published map (for analytics).
      domain: Owner domain of the map
    """
        topic = GetTopic(map_root, topic_id)
        if not topic:
            raise base_handler.Error(404, 'No such topic.')
        lat_lon = str(self.request.get('ll', ''))
        max_count = int(self.request.get('n', 5))  # number of results to show
        radius = float(self.request.get('r', 100000))  # radius, metres
        unit = str(self.request.get('unit', self.GetDistanceUnitForCountry()))
        qids = self.request.get('qids').replace(',', ' ').split()
        places_json = self.request.get('places') or '[]'
        place_id = str(self.request.get('place', ''))
        include_descriptions = int(self.request.get('show_desc', 0))
        include_crowd_reports = int(self.request.get('show_reports', 0))

        try:
            places = json.loads(places_json)
        except ValueError:
            logging.error('Could not parse ?places= parameter')

        # If '?ll' parameter is supplied, find nearby results.
        center = None
        if lat_lon:
            try:
                lat, lon = lat_lon.split(',')
                center = ndb.GeoPt(float(lat), float(lon))
            except ValueError:
                logging.error('Could not extract center for ?ll parameter')

        # If neither '?ll' nor '?place' parameters are given, or if ?place
        # value is invalid, use a default place.
        place = None
        if not center:
            place = {p['id']: p
                     for p in places}.get(place_id, places and places[0])

        # If '?place' parameter is supplied, use it as the center of the
        # point-radius query.
        if not center and place:
            try:
                lat, lon = place['ll']
                center = ndb.GeoPt(lat, lon)
            except (KeyError, TypeError, ValueError):
                logging.error('Could not extract center for ?place=%s',
                              place_id)

        try:
            # Find POIs associated with the topic layers
            features = GetFilteredFeatures(map_root, map_version_id, topic_id,
                                           self.request, center, radius,
                                           max_count)
            html_attrs = GetCardLevelAttributions(features)

            if include_crowd_reports:
                SetAnswersAndReportsOnFeatures(features, map_root, topic_id,
                                               qids)

            geojson = GetGeoJson(features, include_descriptions)
            geojson['properties'] = {
                'map_id': map_root.get('id'),
                'topic': topic,
                'html_attrs': html_attrs,
                'map_url': self.GetMapUrl(topic, map_label, domain, features),
                'unit': unit
            }
            self.WriteJson(geojson)

        except Exception, e:  # pylint:disable=broad-except
            logging.exception(e)