Пример #1
0
    def key_of_coord(self, lon, lat, only_one=True):
        """ For a given coordinate, return the corresponding Navitia key

        Raise RegionNotFound if nothing found

        if only_one param is true return only one key, else return the list of possible keys
        """
        p = geometry.Point(lon, lat)
        valid_instances = []
        # a valid instance is an instance containing the coord and accessible by the user
        found_one = False
        for key, instance in self.instances.iteritems():
            if instance.geom and instance.geom.contains(p):
                found_one = True
                jormun_instance = models.Instance.get_by_name(key)
                if not jormun_instance:
                    raise RegionNotFound(custom_msg="technical problem, impossible "
                                                    "to find region {r} in jormungandr database"
                                         .format(r=key))
                if authentification.has_access(jormun_instance, abort=False):  #TODO, pb how to check the api ?
                    valid_instances.append(key)

        if valid_instances:
            if only_one:
                #If we have only one instance we return the 'best one'
                return choose_best_instance(valid_instances)
            else:
                return valid_instances
        elif found_one:
            raise RegionNotFound(custom_msg="coord {lon};{lat} are covered, "
                                            "but not in regions available for user"
                                 .format(lon=lon, lat=lat))

        raise RegionNotFound(lon=lon, lat=lat)
Пример #2
0
 def mock_key_by_id(object_id, only_one=True):
     if object_id == 'paris':
         if not paris_region:
             raise RegionNotFound('paris')
         return [self.regions[r] for r in paris_region]
     if object_id == 'lima':
         if not lima_region:
             raise RegionNotFound('lima')
         return [self.regions[r] for r in lima_region]
Пример #3
0
 def mock_get_instances(region_str=None, lon=None, lat=None, object_id=None, api='ALL', only_one=True):
     if object_id == 'paris':
         if not paris_region:
             raise RegionNotFound('paris')
         return [self.regions[r] for r in paris_region]
     if object_id == 'lima':
         if not lima_region:
             raise RegionNotFound('lima')
         return [self.regions[r] for r in lima_region]
Пример #4
0
 def _all_keys_of_coord(self, lon, lat):
     p = geometry.Point(lon, lat)
     instances = [i.name for i in self.instances.values() if i.has_point(p)]
     logging.getLogger(__name__).debug("all_keys_of_coord(self, {}, {}) returns {}".format(lon, lat, instances))
     if not instances:
         raise RegionNotFound(lon=lon, lat=lat)
     return instances
Пример #5
0
def instances_comparator(instance1, instance2):
    """
    compare the instances for journey computation

    we want first the non free instances then the free ones
    """
    jormun_bdd_instance1 = models.Instance.get_by_name(instance1)
    jormun_bdd_instance2 = models.Instance.get_by_name(instance2)
    #TODO the is_free should be in the instances, no need to fetch the bdd for this
    if not jormun_bdd_instance1 and not jormun_bdd_instance2:
        raise RegionNotFound(
            custom_msg="technical problem, impossible "
            "to find region {i} and region{j} in jormungandr database".format(
                i=jormun_bdd_instance1, j=jormun_bdd_instance2))
    if not jormun_bdd_instance1:
        return -1
    if not jormun_bdd_instance2:
        return 1

    if jormun_bdd_instance1.is_free != jormun_bdd_instance2.is_free:
        return jormun_bdd_instance1.is_free - jormun_bdd_instance2.is_free

    # TODO choose the smallest region ?
    # take the origin/destination coords into account and choose the region with the center nearest to those coords ?
    return 1
Пример #6
0
def set_request_timezone(region):
    from jormungandr import i_manager

    instance = i_manager.instances.get(region, None)
    if not instance:
        raise RegionNotFound(region)
    set_request_instance_timezone(instance)
Пример #7
0
def has_access(region, api, abort, user):
    """
    Check the Authorization of the current user for this region and this API.
    If abort is True, the request is aborted with the appropriate HTTP code.
    Warning: Please this function is cached therefore it should not be
    dependent of the request context, so keep it as a pure function.
    """
    if current_app.config.get('PUBLIC', False):
        #if jormungandr is on public mode we skip the authentification process
        return True

    if not user:
        #no user --> no need to continue, we can abort, a user is mandatory even for free region
        abort_request(user=user)

    model_instance = Instance.get_by_name(region)

    if not model_instance:
        if abort:
            raise RegionNotFound(region)
        return False

    if (model_instance.is_free
            and user.have_access_to_free_instances) or user.has_access(
                model_instance.id, api):
        return True
    else:
        if abort:
            abort_request(user=user)
        else:
            return False
Пример #8
0
def set_request_instance_timezone(instance):
    logger = logging.getLogger(__name__)

    if not instance:
        raise RegionNotFound()

    if not instance.timezone:
        logger.warning("region {} has no timezone".format(instance.name))
        try:
            g.timezone = None
        except RuntimeError:
            pass  # working outside application context...
        return

    tz = pytz.timezone(instance.timezone)

    if not tz:
        logger.warning(
            "impossible to find timezone: '{}' for region {}".format(
                instance.timezone, instance.name))

    try:
        g.timezone = tz
    except RuntimeError:
        pass  # working outside of an application context...
Пример #9
0
    def get_regions(self,
                    region_str=None,
                    lon=None,
                    lat=None,
                    object_id=None,
                    api='ALL',
                    only_one=False):
        available_regions = []
        if region_str and self.region_exists(region_str):
            available_regions = [region_str]
        elif lon and lat:
            available_regions = self._all_keys_of_coord(lon, lat)
        elif object_id:
            available_regions = self._all_keys_of_id(object_id)
        else:
            available_regions = self.instances.keys()

        valid_regions = self._filter_authorized_instances(
            available_regions, api)
        if valid_regions:
            return choose_best_instance(
                valid_regions) if only_one else valid_regions
        elif available_regions:
            authentication.abort_request(user=authentication.get_user())
        raise RegionNotFound(region=region_str,
                             lon=lon,
                             lat=lat,
                             object_id=object_id)
Пример #10
0
 def get_regions(self, region_str=None, lon=None, lat=None, object_id=None, api='ALL', only_one=False):
     valid_instances = self.get_instances(region_str, lon, lat, object_id, api)
     if not valid_instances:
         raise RegionNotFound(region=region_str, lon=lon, lat=lat, object_id=object_id)
     if only_one:
         return choose_best_instance(valid_instances).name
     else:
         return [i.name for i in valid_instances]
Пример #11
0
 def get_region(self, region_str=None, lon=None, lat=None, object_id=None):
     if region_str and self.region_exists(region_str):
         return region_str
     elif lon and lat:
         return self.key_of_coord(lon, lat)
     elif object_id:
         return self.key_of_id(object_id)
     else:
         raise RegionNotFound(region=region_str, lon=lon, lat=lat,
                              object_id=object_id)
Пример #12
0
    def _all_keys_of_id(self, object_id):
        instances = []
        futures = {}
        for name, instance in self.instances.items():
            futures[name] = gevent.spawn(instance.has_id, object_id)
        for name, future in futures.items():
            if future.get():
                instances.append(name)

        if not instances:
            raise RegionNotFound(object_id=object_id)
        return instances
Пример #13
0
    def key_of_coord(self, lon, lat):
        """ Étant donné une coordonnée, retourne à quelle clef NAViTiA cela
        correspond

        Retourne None si on a rien trouvé
        """
        p = geometry.Point(lon, lat)
        for key, instance in self.instances.iteritems():
            if instance.geom and instance.geom.contains(p):
                return key

        raise RegionNotFound(lon=lon, lat=lat)
Пример #14
0
    def key_of_id(self, object_id, only_one=True):
        """ Retrieves the key of the region of a given id
            if it's a coord calls key_of_coord
            Return one region key if only_one param is true, or None if it doesn't exists
            and the list of possible regions if only_one is set to False
        """
        if object_id.count(";") == 1 or object_id[:6] == "coord:":
            if object_id.count(";") == 1:
                lon, lat = object_id.split(";")
            else:
                lon, lat = object_id[6:].split(":")
            try:
                flon = float(lon)
                flat = float(lat)
            except:
                raise RegionNotFound(object_id=object_id)
            return self.key_of_coord(flon, flat, only_one)

        ptobject = models.PtObject.get_from_uri(object_id)
        if ptobject:
            instances = ptobject.instances()
            if len(instances) > 0:
                available_instances = []  #tmp debug, replace with list generator
                for r in instances:
                    if authentification.has_access(r, abort=False):
                        logging.warn("instance {i} available for user".format(i=r))
                        available_instances.append(r.name)
                    else:
                        logging.warn("instance {i} not available for user".format(i=r))

                if not available_instances:
                    raise RegionNotFound(custom_msg="id {i} exists but not in regions available for user"
                                         .format(i=object_id))

                if only_one:
                    return choose_best_instance(available_instances)
                return available_instances
                #return [i.name for i in instances if authentification.has_access(i, abort=False)]

        raise RegionNotFound(object_id=object_id)
Пример #15
0
 def dispatch(self, arguments, api, instance_obj=None, instance_name=None,
              request=None):
     if instance_obj:
         instance_name = instance_obj.name
     if instance_name in self.instances:
         instance = self.instances[instance_name]
         if api in instance.script.apis:
             api_func = getattr(instance.script, api)
             return api_func(arguments, instance)
         else:
             raise ApiNotFound(api)
     else:
         raise RegionNotFound(instance_name)
Пример #16
0
    def tz(self):
        if not self._tz:
            instance = i_manager.instances.get(self.region, None)

            if not instance:
                raise RegionNotFound(self.region)

            tz_name = instance.timezone  # TODO store directly the tz?

            if not tz_name:
                logging.Logger(__name__).warning("unknown timezone for region {}".format(self.region))
                return None
            self._tz = (pytz.timezone(tz_name),)
        return self._tz[0]
Пример #17
0
 def key_of_id(self, object_id):
     """ Retrieves the key of the region of a given id
         if it's a coord calls key_of_coord
         Return the region key, or None if it doesn't exists
     """
     # Il s'agit d'une coordonnée
     if object_id.count(";") == 1 or object_id[:6] == "coord:":
         if object_id.count(";") == 1:
             lon, lat = object_id.split(";")
         else:
             lon, lat = object_id[6:].split(":")
         try:
             flon = float(lon)
             flat = float(lat)
         except:
             raise RegionNotFound(object_id=object_id)
         return self.key_of_coord(flon, flat)
     else:
         ptobject = models.PtObject.get_from_uri(object_id)
         if ptobject:
             instances = ptobject.instances()
             if len(instances) > 0:
                 return instances[0].name
     raise RegionNotFound(object_id=object_id)
Пример #18
0
    def dispatch(self, arguments, api, instance_name=None):
        if instance_name not in self.instances:
            raise RegionNotFound(instance_name)

        instance = self.instances[instance_name]

        scenario = instance.scenario(arguments.get('_override_scenario'))
        if not hasattr(scenario, api) or not callable(getattr(scenario, api)):
            raise ApiNotFound(api)

        publication_date = instance.publication_date
        api_func = getattr(scenario, api)
        resp = api_func(arguments, instance)
        if instance.publication_date != publication_date:
            self._clear_cache()
        return resp
Пример #19
0
 def _all_keys_of_id(self, object_id):
     if object_id.count(";") == 1 or object_id[:6] == "coord:":
         if object_id.count(";") == 1:
             lon, lat = object_id.split(";")
         else:
             lon, lat = object_id[6:].split(":")
         try:
             flon = float(lon)
             flat = float(lat)
         except:
             raise InvalidArguments(object_id)
         return self._all_keys_of_coord(flon, flat)
     instances = [i.name for i in self.instances.values() if i.has_id(object_id)]
     if not instances:
         raise RegionNotFound(object_id=object_id)
     return instances
Пример #20
0
def compute_regions(args):
    """
    method computing the region the journey has to be computed on
    The complexity comes from the fact that the regions in jormungandr can overlap.

    return the kraken instance keys

    rules are easy:
    we fetch the different regions the user can use for 'origin' and 'destination'
    we do the intersection and sort the list
    """
    from_regions = set()
    to_regions = set()
    if args['origin']:
        from_regions = set(i_manager.get_instances(object_id=args['origin']))
        # Note: if get_regions does not find any region, it raises a RegionNotFoundException

    if args['destination']:
        to_regions = set(i_manager.get_instances(object_id=args['destination']))

    if not from_regions:
        # we didn't get any origin, the region is in the destination's list
        possible_regions = to_regions
    elif not to_regions:
        # we didn't get any origin, the region is in the destination's list
        possible_regions = from_regions
    else:
        # we need the intersection set
        possible_regions = from_regions.intersection(to_regions)
        logging.getLogger(__name__).debug(
            "orig region = {o}, dest region = {d} => set = {p}".format(
                o=from_regions, d=to_regions, p=possible_regions
            )
        )

    if not possible_regions:
        raise RegionNotFound(
            custom_msg="cannot find a region with {o} and {d} in the same time".format(
                o=args['origin'], d=args['destination']
            )
        )

    sorted_regions = list(possible_regions)

    regions = sorted(sorted_regions, key=cmp_to_key(instances_comparator))

    return [r.name for r in regions]
Пример #21
0
def compute_regions(args):
    """
    Method computing the possible regions on which the journey can be queried
    The complexity comes from the fact that the regions in Jormungandr can overlap.

    Rules are :
    - Fetch the different regions that can be used for 'origin' and 'destination'
    - Intersect both lists and sort it

    :return: Kraken instance keys
    """
    from_regions = set()
    to_regions = set()
    if args['origin']:
        from_regions = set(i_manager.get_instances(object_id=args['origin']))
        # Note: if get_regions does not find any region, it raises a RegionNotFoundException

    if args['destination']:
        to_regions = set(i_manager.get_instances(object_id=args['destination']))

    if not from_regions:
        # we didn't get any origin, the region is in the destination's list
        possible_regions = to_regions
    elif not to_regions:
        # we didn't get any origin, the region is in the destination's list
        possible_regions = from_regions
    else:
        # we need the intersection set
        possible_regions = from_regions.intersection(to_regions)
        logging.getLogger(__name__).debug(
            "orig region = {o}, dest region = {d} => set = {p}".format(
                o=from_regions, d=to_regions, p=possible_regions
            )
        )

    if not possible_regions:
        raise RegionNotFound(
            custom_msg="cannot find a region with {o} and {d} in the same time".format(
                o=args['origin'], d=args['destination']
            )
        )

    sorted_regions = list(possible_regions)

    regions = sort_regions(sorted_regions)

    return [r.name for r in regions]
Пример #22
0
def compute_regions(args):
    """
    method computing the region the journey has to be computed on
    The complexity comes from the fact that the regions in jormungandr can overlap.

    return the kraken instance key

    rules are easy:
    we fetch the different regions the user can use for 'origin' and 'destination'
    we do the intersection and sort the list
    """
    _region = None
    possible_regions = set()
    from_regions = set()
    to_regions = set()
    if args['origin']:
        from_regions = set(i_manager.key_of_id(args['origin'], only_one=False))
        #Note: if the key_of_id does not find any region, it raises a RegionNotFoundException

    if args['destination']:
        to_regions = set(
            i_manager.key_of_id(args['destination'], only_one=False))

    if not from_regions:
        #we didn't get any origin, the region is in the destination's list
        possible_regions = to_regions
    elif not to_regions:
        #we didn't get any origin, the region is in the destination's list
        possible_regions = from_regions
    else:
        #we need the intersection set
        possible_regions = from_regions.intersection(to_regions)

    logging.debug("orig region = {o}, dest region = {d} => set = {p}".format(
        o=from_regions, d=to_regions, p=possible_regions))

    if not possible_regions:
        raise RegionNotFound(
            custom_msg="cannot find a region with {o} and {d} in the same time"
            .format(o=args['origin'], d=args['destination']))

    sorted_regions = list(possible_regions)

    _region = choose_best_instance(sorted_regions)

    return _region
Пример #23
0
def has_access(region, api, abort, user):
    """
    Check the Authorization of the current user for this region and this API.
    If abort is True, the request is aborted with the appropriate HTTP code.
    Warning: Please this function is cached therefore it should not be
    dependent of the request context, so keep it as a pure function.
    """
    # if jormungandr is on public mode or database is not accessible, we skip the authentication process
    logging.getLogger(__name__).debug('User "has_access" to region/api not cached')

    if current_app.config.get('PUBLIC', False) or (not can_connect_to_database()):
        return True

    if not user:
        # no user --> no need to continue, we can abort, a user is mandatory even for free region
        # To manage database error of the following type we should fetch one more time from database
        # Can connect to database but at least one table/attribute is not accessible due to transaction problem
        if can_read_user():
            context = 'User is undefined, but table users is accessible in database'
            abort_request(user=user, context=context)
        else:
            return True
    try:
        model_instance = Instance.get_by_name(region)
    except Exception as e:
        logging.getLogger(__name__).error('No access to table Instance (error: {})'.format(e))
        g.can_connect_to_database = False
        return True

    if not model_instance:
        if abort:
            raise RegionNotFound(region)
        return False

    if (model_instance.is_free and user.have_access_to_free_instances) or user.has_access(
        model_instance.id, api
    ):
        return True
    else:
        if abort:
            context = 'User has no permission to access this api {} or instance {}'.format(
                api, model_instance.id
            )
            abort_request(user=user, context=context)
        else:
            return False
Пример #24
0
def choose_best_instance(instances):
    """
    chose the best instance
    we want first the non free instances then the free ones
    """
    best = None
    for i in instances:
        jormun_bdd_instance = models.Instance.get_by_name(i)
        #TODO the is_free should be in the instances, no need to fetch the bdd for this
        if not jormun_bdd_instance:
            raise RegionNotFound(custom_msg="technical problem, impossible "
                                            "to find region {i} in jormungandr database".format(i=i))
        if not best or not jormun_bdd_instance.is_free:
            #TODO what to do if we have 2 free instances or 2 private instances ?
            best = jormun_bdd_instance

    return best.name
Пример #25
0
def set_request_timezone(region):
    logger = logging.getLogger(__name__)
    instance = i_manager.instances.get(region, None)

    if not instance:
        raise RegionNotFound(region)

    if not instance.timezone:
        logger.warn("region {} has no timezone".format(region))
        g.timezone = None
        return

    tz = pytz.timezone(instance.timezone)

    if not tz:
        logger.warn("impossible to find timezone: '{}' for region {}".format(
            instance.timezone, region))

    g.timezone = tz
Пример #26
0
    def dispatch(self,
                 arguments,
                 api,
                 instance_obj=None,
                 instance_name=None,
                 request=None):
        if instance_obj:
            instance_name = instance_obj.name
        if instance_name not in self.instances:
            raise RegionNotFound(instance_name)

        instance = self.instances[instance_name]
        if not hasattr(instance.scenario, api) or not callable(
                getattr(instance.scenario, api)):
            raise ApiNotFound(api)

        api_func = getattr(instance.scenario, api)
        resp = api_func(arguments, instance)
        if resp.HasField("publication_date") and\
          instance.publication_date != resp.publication_date:
            self._clear_cache()
            instance.publication_date = resp.publication_date
        return resp
Пример #27
0
    def _all_keys_of_id(self, object_id):
        if object_id.count(";") == 1 or object_id[:6] == "coord:":
            if object_id.count(";") == 1:
                lon, lat = object_id.split(";")
            else:
                lon, lat = object_id[6:].split(":")
            try:
                flon = float(lon)
                flat = float(lat)
            except:
                raise InvalidArguments(object_id)
            return self._all_keys_of_coord(flon, flat)
        instances = []
        futures = {}
        for name, instance in self.instances.items():
            futures[name] = gevent.spawn(instance.has_id, object_id)
        for name, future in futures.items():
            if future.get():
                instances.append(name)

        if not instances:
            raise RegionNotFound(object_id=object_id)
        return instances
Пример #28
0
 def region_exists(self, region_str):
     if region_str in self.instances.keys():
         return True
     else:
         raise RegionNotFound(region=region_str)