示例#1
0
    def get_queryset(self):
        base_queryset = self.get_base_queryset()

        location = self.get_location()
        if not location:
            return base_queryset.none()

        queryset = base_queryset.annotate(distance=DistanceFunction(
            "coordinates", location)).order_by("distance")

        return queryset
示例#2
0
    def filter_queryset(self, request, queryset, view):
        if not 'order_by_distance_to' in request.query_params:
            return queryset

        try:
            coordinates = json.loads(request.query_params['order_by_distance_to'])
        except JSONDecodeError:
            raise DRFValidationError(detail=self.error_message)

        if not check_coordinates(coordinates):
            raise DRFValidationError(detail=self.error_message)

        return queryset.annotate(distance=DistanceFunction('coordinates', Point(coordinates, srid=4326))).order_by('distance')
示例#3
0
    def handle(
        self,
        event,
        coordinates,
        number,
        distance,
        departement,
        region,
        segment,
        sentfile,
        at,
        exclude_telegram,
        export_file,
        **options,
    ):
        if (sum(0 if arg is None else 1
                for arg in [event, coordinates, departement, region, segment])
                != 1):
            raise CommandError(
                "Vous devez indiquer soit un événemnet, soit des coordonnées, soit un département, une région ou un segment."
            )

        if (event or coordinates) and number is None and distance is None:
            raise CommandError(
                "Vous devez indiquer soit un nombre de personnes, soit une distance max."
            )

        if event:  # we generate coordinates from event
            if event.coordinates is None:
                raise CommandError(
                    "Cet événement n'a pas de coordonnées géographiques.")

            coordinates = event.coordinates

            self.stdout.write(f"Événement : {event.name}")
            self.stdout.write(event.short_location())
            self.stdout.write(
                event.start_time.astimezone(
                    timezone.get_default_timezone()).strftime(
                        "Le %d/%m/%Y à %H:%M"))
            self.stdout.write("\n")  # ligne vide

        if coordinates:  # two case : central point coordinates or any other
            ps = (Person.objects.filter(subscribed_sms=True).exclude(
                contact_phone="").annotate(distance=DistanceFunction(
                    "coordinates", coordinates)).order_by("distance"))

            if distance is not None:
                ps = ps.filter(distance__lte=distance)

            if exclude_telegram:
                ps = ps.exclude(meta__has_telegram=True)

            res = list(
                drop_duplicate_numbers(
                    ((p.contact_phone, p.distance)
                     for p in ps.iterator() if self.can_send(p.contact_phone)),
                    number,
                ))

            numbers = [n for n, _ in res]
            max_distance = res[-1][1]
            self.stdout.write(f"Distance maximale : {max_distance}")
        else:
            if segment:
                ps = (segment.get_subscribers_queryset().exclude(
                    contact_phone="").distinct())
                self.stdout.write(f"Segment : {segment.name}")
            else:
                ps = Person.objects.filter(
                    region or departement,
                    subscribed_sms=True).exclude(contact_phone="")

            if exclude_telegram:
                ps = ps.exclude(meta__has_telegram=True)

            numbers = set(p.contact_phone for p in ps.iterator()
                          if self.can_send(p.contact_phone))

        self.stdout.write(f"Nombre de numéros : {len(numbers)}")

        if export_file is not None:
            export_file.write("\n".join(str(number) for number in numbers))
            return

        if sentfile is not None:
            sent_numbers = self.read_numbers(sentfile)
            numbers.difference_update(sent_numbers)
            self.stdout.write(
                f"{len(numbers)} après prise en compte des numéros déjà envoyés."
            )

        self.stdout.write("\n")  # empty line

        self.stdout.write(
            "Entrez votre message (deux lignes vides pour terminer)")

        message = ""
        last_line = None
        while True:
            current_line = input("")
            message += "\n" + current_line
            if current_line == "" and last_line == "":
                break
            last_line = current_line

        message = message.strip()

        self.stdout.write("Message enregistré")
        sms_info = compute_sms_length_information(message)
        self.stdout.write(
            f"Encodé en {sms_info.encoding}, {len(message)} caractères, {sms_info.byte_length} octets pour un total de"
            f" {sms_info.messages} SMS.")

        self.stdout.write("")
        self.stdout.write("Prêt pour envoi.")

        answer = ""
        while answer not in ["ENVOYER", "ANNULER"]:
            answer = input("Indiquer ENVOYER ou ANNULER : ")

        if answer == "ANNULER":
            return

        token = secrets.token_urlsafe(4)
        sent_filename = Path(f"sent.{token}")
        invalid_filename = Path(f"invalid.{token}")

        try:
            sent, invalid = send_bulk_sms(message, tqdm(numbers), at=at)
        except SMSSendException as e:
            self.stderr.write("Erreur lors de l'envoi des SMS.")
            self.stderr.write(
                f"{len(e.sent)} SMS ont déjà été envoyés ({len(e.invalid)} numéros invalides)."
            )

            try:
                self.write_numbers(sent_filename, e.sent)
                self.write_numbers(invalid_filename, e.invalid)
            except OSError:
                self.stderr.write(
                    "Impossible d'écrire les fichiers avec les numéros testés."
                )
                raise

            self.stderr.write(
                f"Fichiers {sent_filename} et {invalid_filename} écrits.")
            return 1

        self.stdout.write(f"{len(sent)} SMS envoyés")

        if invalid:
            self.stdout.write(f"{len(invalid)} numéros invalides")
            self.write_numbers(invalid_filename, invalid)
            self.stdout.write(f"{invalid_filename} écrit.")
示例#4
0
def get_tweets(request):
    """
    Get all the coords + sentiments of tweets
    in range of the given latlng + distance
    :param request:
    :return:
    """
    t1 = time.time()
    default_limit = 200
    default_dist = 1
    if not request.GET:
        return HttpResponse(status=400)
    else:
        # If latlng is None, then we get all the data points
        latlng = request.GET.get('latlng')
        dist = request.GET.get('dist')
        limit = request.GET.get('limit')
        return_text = request.GET.get('return_text')
        lang = request.GET.get('lang')

        # Default distance of 1 km
        if dist is None:
            dist = default_dist
        # Default limit of 50 tweets
        if limit is None:
            limit = default_limit
        if return_text is None:
            return_text = False
        else:
            return_text = return_text.lower() == 'true' or str(
                return_text) == "1"
        if lang is None:
            lang = ''

        try:
            if latlng is not None:
                latlng = latlng.split(',')
                lat = float(latlng[0])
                lng = float(latlng[1])
            dist = float(dist)
            limit = int(limit)
            limit = min(max(limit, 1), default_limit)
            dist = max(dist, default_dist)

        except ValueError:
            return HttpResponse(status=400)

        if latlng is not None:
            # see: https://stackoverflow.com/questions/19703975/django-sort-by-distance
            # and: https://stackoverflow.com/questions/8464666/distance-between-2-points-in-postgis-in-srid-4326-in-metres
            degrees_distance = round((dist * 0.01), 2) + 0.01

            point = Point(lng, lat)
            tweets = Tweet.objects.filter(
                coords__dwithin=(point, degrees_distance)).annotate(
                    distance=DistanceFunction('coords', point)).order_by(
                        'distance')
            if lang == '':
                tweets = tweets[:limit]

        else:
            tweets = Tweet.objects.filter(coords__isnull=False)

        if lang != '':
            tweets = tweets.filter(lang=lang)
            tweets = tweets[:limit]

        if return_text:
            res = [{
                'coords': t.get_coords(),
                'tweet_id': t.uid,
                'polarity': t.polarity,
                'lang': t.lang,
                'timestamp': t.timestamp.date(),
                'country': t.country,
                'text': t.text
            } for t in tweets]
        else:
            res = [{
                'coords': t.get_coords(),
                'tweet_id': t.uid,
                'polarity': t.polarity,
                'lang': t.lang,
                'timestamp': t.timestamp.date(),
                'country': t.country
            } for t in tweets]

        print('Elapsed:', time.time() - t1)
        return JsonResponse({'tweets': res})