示例#1
0
def timezone_at_coordinate(session, geom):
    area = session.execute(
        select(TimezoneArea.tzid).where(
            func.ST_Contains(TimezoneArea.geom, geom))).scalar_one_or_none()
    if area:
        return area.tzid
    return None
示例#2
0
def can_moderate_at(session, user_id, shape):
    """
    Returns True if the user_id can moderate a given geo-shape (i.e., if the shape is contained in any Node that the user is an admin of)
    """
    cluster_ids = list(
        session.query(Cluster.id).join(
            Node, Node.id == Cluster.parent_node_id).filter(
                Cluster.is_official_cluster).filter(
                    func.ST_Contains(Node.geom, shape)).all())
    return _can_moderate_any_cluster(session, user_id, cluster_ids)
示例#3
0
def get_parent_node_at_location(session, shape):
    """
    Finds the smallest node containing the shape.

    Shape can be any PostGIS geo object, e.g. output from create_coordinate
    """

    # Fin the lowest Node (in the Node tree) that contains the shape. By construction of nodes, the area of a sub-node
    # must always be less than its parent Node, so no need to actually traverse the tree!
    return session.query(Node).filter(func.ST_Contains(Node.geom, shape)).order_by(func.ST_Area(Node.geom)).first()
示例#4
0
def can_moderate_at(session, user_id, shape):
    """
    Returns True if the user_id can moderate a given geo-shape (i.e., if the shape is contained in any Node that the user is an admin of)
    """
    cluster_ids = [
        cluster_id for (cluster_id, ) in session.execute(
            select(Cluster.id).join(Node, Node.id == Cluster.parent_node_id).
            where(Cluster.is_official_cluster).where(
                func.ST_Contains(Node.geom, shape))).all()
    ]
    return _can_moderate_any_cluster(session, user_id, cluster_ids)
示例#5
0
def enforce_community_memberships_for_user(session, user):
    """
    Adds a given user to all the communities they belong in based on their location.
    """
    nodes = session.execute(
        select(Node).where(func.ST_Contains(Node.geom,
                                            user.geom))).scalars().all()
    for node in nodes:
        node.official_cluster.cluster_subscriptions.append(
            ClusterSubscription(
                user=user,
                role=ClusterRole.member,
            ))
    session.commit()
示例#6
0
def enforce_community_memberships():
    """
    Go through all communities and make sure every user in the polygon is also a member
    """
    with session_scope() as session:
        for node in session.execute(select(Node)).scalars().all():
            existing_users = select(ClusterSubscription.user_id).where(
                ClusterSubscription.cluster == node.official_cluster)
            users_needing_adding = (session.execute(
                select(User).where(User.is_visible).where(
                    func.ST_Contains(node.geom, User.geom)).where(
                        ~User.id.in_(existing_users))).scalars().all())
            for user in users_needing_adding:
                node.official_cluster.cluster_subscriptions.append(
                    ClusterSubscription(
                        user=user,
                        role=ClusterRole.member,
                    ))
            session.commit()
示例#7
0
 def ListNearbyUsers(self, request, context):
     with session_scope() as session:
         page_size = min(MAX_PAGINATION_LENGTH, request.page_size or MAX_PAGINATION_LENGTH)
         next_nearby_id = int(request.page_token) if request.page_token else 0
         node = session.execute(select(Node).where(Node.id == request.community_id)).scalar_one_or_none()
         if not node:
             context.abort(grpc.StatusCode.NOT_FOUND, errors.COMMUNITY_NOT_FOUND)
         nearbys = (
             session.execute(
                 select(User)
                 .where_users_visible(context)
                 .where(func.ST_Contains(node.geom, User.geom))
                 .where(User.id >= next_nearby_id)
                 .order_by(User.id)
                 .limit(page_size + 1)
             )
             .scalars()
             .all()
         )
         return communities_pb2.ListNearbyUsersRes(
             nearby_user_ids=[nearby.id for nearby in nearbys[:page_size]],
             next_page_token=str(nearbys[-1].id) if len(nearbys) > page_size else None,
         )
示例#8
0
 def st_contains(self, x, y):
     query = self.__session.query(NdtPose).filter(
         func.ST_Contains(NdtPose.geom,
                          WKTElement('POINT(%f %f)' % (x, y))))
     return self.__get_files(query)
示例#9
0
    def UserSearch(self, request, context):
        with session_scope() as session:
            query = session.query(User).filter(~User.is_banned)
            if request.HasField("query"):
                if request.query_name_only:
                    query = query.filter(
                        or_(User.name.ilike(f"%{request.query.value}%"),
                            User.username.ilike(f"%{request.query.value}%")))
                else:
                    query = query.filter(
                        or_(
                            User.name.ilike(f"%{request.query.value}%"),
                            User.username.ilike(f"%{request.query.value}%"),
                            User.city.ilike(f"%{request.query.value}%"),
                            User.hometown.ilike(f"%{request.query.value}%"),
                            User.about_me.ilike(f"%{request.query.value}%"),
                            User.my_travels.ilike(f"%{request.query.value}%"),
                            User.things_i_like.ilike(
                                f"%{request.query.value}%"),
                            User.about_place.ilike(f"%{request.query.value}%"),
                            User.additional_information.ilike(
                                f"%{request.query.value}%"),
                        ))

            if request.HasField("last_active"):
                raw_dt = to_aware_datetime(request.last_active)
                coarsened_dt = raw_dt.replace(minute=(raw_dt.minute // 15) *
                                              15,
                                              second=0,
                                              microsecond=0)
                query = query.filter(User.last_active >= coarsened_dt)

            if request.HasField("gender"):
                query = query.filter(
                    User.gender.ilike(f"%{request.gender.value}%"))

            if len(request.hosting_status_filter) > 0:
                query = query.filter(
                    User.hosting_status.in_([
                        hostingstatus2sql[status]
                        for status in request.hosting_status_filter
                    ]))
            if len(request.smoking_location_filter) > 0:
                query = query.filter(
                    User.smoking_allowed.in_([
                        smokinglocation2sql[loc]
                        for loc in request.smoking_location_filter
                    ]))
            if len(request.sleeping_arrangement_filter) > 0:
                query = query.filter(
                    User.sleeping_arrangement.in_([
                        sleepingarrangement2sql[arr]
                        for arr in request.sleeping_arrangement_filter
                    ]))
            if len(request.parking_details_filter) > 0:
                query = query.filter(
                    User.parking_details.in_([
                        parkingdetails2sql[det]
                        for det in request.parking_details_filter
                    ]))

            if request.HasField("guests"):
                query = query.filter(User.max_guests >= request.guests.value)
            if request.HasField("last_minute"):
                query = query.filter(User.last_minute == last_minute.value)
            if request.HasField("has_pets"):
                query = query.filter(User.has_pets == has_pets.value)
            if request.HasField("accepts_pets"):
                query = query.filter(User.accepts_pets == accepts_pets.value)
            if request.HasField("has_kids"):
                query = query.filter(User.has_kids == has_kids.value)
            if request.HasField("accepts_kids"):
                query = query.filter(User.accepts_kids == accepts_kids.value)
            if request.HasField("has_housemates"):
                query = query.filter(
                    User.has_housemates == has_housemates.value)
            if request.HasField("wheelchair_accessible"):
                query = query.filter(
                    User.wheelchair_accessible == wheelchair_accessible.value)
            if request.HasField("smokes_at_home"):
                query = query.filter(
                    User.smokes_at_home == smokes_at_home.value)
            if request.HasField("drinking_allowed"):
                query = query.filter(
                    User.drinking_allowed == drinking_allowed.value)
            if request.HasField("drinks_at_home"):
                query = query.filter(
                    User.drinks_at_home == drinks_at_home.value)
            if request.HasField("parking"):
                query = query.filter(User.parking == parking.value)
            if request.HasField("camping_ok"):
                query = query.filter(User.camping_ok == camping_ok.value)

            if request.HasField("search_in_area"):
                # EPSG4326 measures distance in decimal degress
                # we want to check whether two circles overlap, so check if the distance between their centers is less
                # than the sum of their radii, divided by 111111 m ~= 1 degree (at the equator)
                search_point = create_coordinate(request.search_in_area.lat,
                                                 request.search_in_area.lng)
                query = query.filter(
                    func.ST_DWithin(
                        User.geom, search_point,
                        (User.geom_radius + request.search_in_area.radius) /
                        111111))
            if request.HasField("search_in_community_id"):
                # could do a join here as well, but this is just simpler
                node = session.query(Node).filter(
                    Node.id == request.search_in_community_id).one_or_none()
                if not node:
                    context.abort(grpc.StatusCode.NOT_FOUND,
                                  errors.COMMUNITY_NOT_FOUND)
                query = query.filter(func.ST_Contains(node.geom, User.geom))

            if request.only_with_references:
                query = query.join(Reference, Reference.to_user_id == User.id)

            # TODO:
            # google.protobuf.StringValue language = 11;
            # bool friends_only = 13;
            # google.protobuf.UInt32Value age_min = 14;
            # google.protobuf.UInt32Value age_max = 15;

            page_size = min(MAX_PAGINATION_LENGTH, request.page_size
                            or MAX_PAGINATION_LENGTH)
            next_user_id = int(request.page_token) if request.page_token else 0

            users = query.filter(User.id >= next_user_id).order_by(
                User.id).limit(page_size + 1).all()

            return search_pb2.UserSearchRes(
                results=[
                    search_pb2.Result(
                        rank=1,
                        user=user_model_to_pb(user, session, context),
                    ) for user in users[:page_size]
                ],
                next_page_token=str(users[-1].id)
                if len(users) > page_size else None,
            )
示例#10
0
def get_observation_score():
    """
    .. :quickref: Profiles;

    Check an observation with the related profile
    Return alert when the observation do not match the profile
    """
    data = request.get_json()
    try:
        cd_ref = data["cd_ref"]
    except KeyError:
        raise BadRequest("No cd_ref provided")

    # Récupération du profil du cd_ref
    result = {}
    profile = (DB.session.query(VmValidProfiles).filter(
        VmValidProfiles.cd_ref == cd_ref).one_or_none())
    if not profile:
        raise NotFound("No profile for this cd_ref")
    check_life_stage = profile.active_life_stage

    result = {
        "valid_distribution": True,
        "valid_altitude": True,
        "valid_phenology": True,
        "valid_life_stage": None,
        "life_stage_accepted": [],
        "errors": [],
        "profil": profile.as_dict(),
        "check_life_stage": check_life_stage
    }

    # Calcul de la période correspondant à la date
    if data.get("date_min") and data.get("date_max"):
        date_min = datetime.datetime.strptime(data["date_min"], "%Y-%m-%d")
        date_max = datetime.datetime.strptime(data["date_max"], "%Y-%m-%d")
        # Calcul du numéro du jour pour les dates min et max
        doy_min = date_min.timetuple().tm_yday
        doy_max = date_max.timetuple().tm_yday
    else:
        raise BadRequest("Missing date min or date max")
    # Récupération des altitudes
    if data.get("altitude_min") and data.get("altitude_max"):
        altitude_min = data["altitude_min"]
        altitude_max = data["altitude_max"]
    else:
        raise BadRequest('Missing altitude_min or altitude_max')
    # Check de la répartition
    if "geom" in data:
        query = DB.session.query(
            func.ST_Contains(
                func.ST_Transform(profile.valid_distribution, 4326),
                func.ST_SetSRID(
                    func.ST_GeomFromGeoJSON(json.dumps(data["geom"])), 4326),
            ))

        check_geom = query.one_or_none()
        if not check_geom:
            result["valid_distribution"] = False
            result["errors"].append({
                "type":
                "geometry",
                "value":
                "Erreur lors du calcul de la géométrie valide"
            })
        if check_geom[0] is False:
            result["valid_distribution"] = False
            result["errors"].append({
                "type":
                "geom",
                "value":
                f"Le taxon n'a jamais été observé dans cette zone géographique"
            })
        else:
            result["valid_distribution"] = True

        # check de la periode
        q_pheno = DB.session.query(
            VmCorTaxonPhenology.id_nomenclature_life_stage).distinct()
        q_pheno = q_pheno.filter(VmCorTaxonPhenology.cd_ref == cd_ref)
        q_pheno = q_pheno.filter(
            VmCorTaxonPhenology.doy_min <= doy_min).filter(
                VmCorTaxonPhenology.doy_max >= doy_max)

        period_result = q_pheno.all()
        if len(period_result) == 0:
            result["valid_phenology"] = False
            result["errors"].append({
                "type":
                "period",
                "value":
                "Le taxon n'a jamais été observé à cette periode"
            })

        # check de l'altitude
        if altitude_max > profile.altitude_max or altitude_min < profile.altitude_min:
            result["valid_altitude"] = False
            result["errors"].append({
                "type":
                "altitude",
                "value":
                f"Le taxon n'a jamais été observé à cette altitude ({altitude_min}-{altitude_max}m)"
            })
        # check de l'altitude pour la période donnée
        if len(period_result) > 0:
            peridod_and_altitude = q_pheno.filter(
                VmCorTaxonPhenology.calculated_altitude_min <= altitude_min)
            peridod_and_altitude = peridod_and_altitude.filter(
                VmCorTaxonPhenology.calculated_altitude_max >= altitude_max)
            peridod_and_altitude_r = peridod_and_altitude.all()
            if len(peridod_and_altitude_r) > 0:
                result["valid_altitude"] = True
                result["valid_phenology"] = True
                for row in peridod_and_altitude_r:
                    # Construction de la liste des stade de vie potentielle
                    if row.id_nomenclature_life_stage:
                        result["life_stage_accepted"].append(
                            row.id_nomenclature_life_stage)
            else:
                result["valid_altitude"] = False
                result["valid_phenology"] = False
                if altitude_max <= profile.altitude_max and altitude_min >= altitude_min:
                    result["errors"].append({
                        "type":
                        "period",
                        "value":
                        f"Le taxon a déjà été observé à cette altitude ({altitude_min}-{altitude_max}m), mais pas à cette periode de l'année"
                    })
                if result["valid_phenology"]:
                    result["errors"].append({
                        "type":
                        "period",
                        "value":
                        f"Le taxon a déjà été observé à cette periode de l'année, mais pas à cette altitude ({altitude_min}-{altitude_max}m)"
                    })

        # check du stade de vie pour la periode donnée
        if check_life_stage and "life_stages" in data:
            if type(data["life_stages"]) is not list:
                raise BadRequest("life_stages must be a list")
            for life_stage in data["life_stages"]:
                life_stage_value = TNomenclatures.query.get(life_stage)
                q = q_pheno.filter(VmCorTaxonPhenology.
                                   id_nomenclature_life_stage == life_stage)
                r_life_stage = q.all()
                if len(r_life_stage) == 0:
                    result["valid_life_stage"] = False
                    result["valid_phenology"] = False
                    result["errors"].append({
                        "type":
                        "life_stage",
                        "value":
                        f"Le taxon n'a jamais été observé à cette periode pour le stade de vie {life_stage_value.label_default}"
                    })

                # check du stade de vie pour la période et l'altitude
                else:
                    if altitude_min and altitude_max:
                        q = q.filter(VmCorTaxonPhenology.
                                     calculated_altitude_min <= altitude_min)
                        q = q.filter(VmCorTaxonPhenology.
                                     calculated_altitude_max >= altitude_max)
                        r_life_stage_altitude = q.all()
                        if len(r_life_stage_altitude) == 0:
                            result["valid_life_stage"] = False
                            result["valid_altitude"] = False
                            result["valid_phenology"] = False
                            result["errors"].append({
                                "type":
                                "life_stage",
                                "value":
                                f"""
                                Le taxon n'a jamais été observé à cette periode et à cette altitude ({altitude_min}-{altitude_max}m) 
                                pour le stade de vie {life_stage_value.label_default}"""
                            })
    return result