Ejemplo n.º 1
0
    def GET(self, request):
        form = SpotSearchForm(request.GET)
        has_valid_search_param = False

        if not form.is_valid():
            return HttpResponse('[]')

        if len(request.GET) == 0:
            return HttpResponse('[]')

        query = Spot.objects.all()

        day_dict = {"Sunday": "su",
                    "Monday": "m",
                    "Tuesday": "t",
                    "Wednesday": "w",
                    "Thursday": "th",
                    "Friday": "f",
                    "Saturday": "sa", }
        # Exclude things that get special consideration here, otherwise add a filter for the keys
        for key in request.GET:
            if re.search('^oauth_', key):
                pass
            elif key == "expand_radius":
                pass
            elif key == "distance":
                pass
            elif key == "center_latitude":
                pass
            elif key == "center_longitude":
                pass
            elif key == "limit":
                pass
            elif key == "open_now":
                if request.GET["open_now"]:

                    day_lookup = ["su", "m", "t", "w", "th", "f", "sa"]
                    day_num = int(strftime("%w", localtime()))
                    today = day_lookup[day_num]
                    now = datetime.time(datetime.now())
                    query = query.filter(spotavailablehours__day__iexact=today, spotavailablehours__start_time__lt=now, spotavailablehours__end_time__gt=now)
                    has_valid_search_param = True
            elif key == "open_until":
                if request.GET["open_until"] and request.GET["open_at"]:
                    until_day, until_time = request.GET["open_until"].split(',')
                    at_day, at_time = request.GET["open_at"].split(',')
                    until_day = day_dict[until_day]
                    at_day = day_dict[at_day]

                    if until_day == at_day:
                        query = query.filter(spotavailablehours__day__iexact=until_day, spotavailablehours__start_time__lte=at_time, spotavailablehours__end_time__gte=until_time)
                    else:
                        days_to_test = self.get_days_in_range(at_day, until_day)
                        last_day = days_to_test.pop()
                        days_to_test.reverse()
                        first_day = days_to_test.pop()

                        query = query.filter(spotavailablehours__day__iexact=first_day, spotavailablehours__start_time__lte=at_time, spotavailablehours__end_time__gte="23:59")
                        query = query.filter(spotavailablehours__day__iexact=last_day, spotavailablehours__start_time__lte="00:00", spotavailablehours__end_time__gte=until_time)

                        for day in days_to_test:
                            query = query.filter(spotavailablehours__day__iexact=day, spotavailablehours__start_time__lte="00:00", spotavailablehours__end_time__gte="23:59")
                    has_valid_search_param = True
            elif key == "open_at":
                if request.GET["open_at"]:
                    try:
                        request.GET["open_until"]
                    except:
                        day, time = request.GET['open_at'].split(',')
                        day = day_dict[day]
                        query = query.filter(spotavailablehours__day__iexact=day, spotavailablehours__start_time__lte=time, spotavailablehours__end_time__gt=time)
                        has_valid_search_param = True
            elif key == "extended_info:reservable":
                query = query.filter(spotextendedinfo__key="reservable", spotextendedinfo__value__in=['true', 'reservations'])
            elif key == "extended_info:noise_level":
                noise_levels = request.GET.getlist("extended_info:noise_level")

                exclude_silent = True
                exclude_quiet = True
                exclude_moderate = True
                exclude_loud = True
                exclude_variable = True

                for level in noise_levels:
                    if "silent" == level:
                        exclude_silent = False
                    if "quiet" == level:
                        exclude_quiet = False
                        exclude_variable = False
                    if "moderate" == level:
                        exclude_moderate = False
                        exclude_variable = False

                if exclude_silent:
                    query = query.exclude(spotextendedinfo__key="noise_level", spotextendedinfo__value__iexact="silent")
                if exclude_quiet:
                    query = query.exclude(spotextendedinfo__key="noise_level", spotextendedinfo__value__iexact="quiet")
                if exclude_moderate:
                    query = query.exclude(spotextendedinfo__key="noise_level", spotextendedinfo__value__iexact="moderate")
                if exclude_loud:
                    query = query.exclude(spotextendedinfo__key="noise_level", spotextendedinfo__value__iexact="loud")
                if exclude_variable:
                    query = query.exclude(spotextendedinfo__key="noise_level", spotextendedinfo__value__iexact="variable")


            elif key == "capacity":
                try:
                    limit = int(request.GET["capacity"])
                    with_limit = Q(capacity__gte=limit)
                    with_limit |= Q(capacity__isnull=True)
                    query = query.filter(with_limit)
                    has_valid_search_param = True
                except ValueError:
                    # This we don't care about - if someone passes "", or "twenty", just ignore it
                    pass
                except Exception as e:
                    # Do something to complain??
                    pass
            elif key == "type":
                type_values = request.GET.getlist(key)
                q_obj = Q()
                type_qs = [Q(spottypes__name__exact=v) for v in type_values]
                for type_q in type_qs:
                    q_obj |= type_q
                query = query.filter(q_obj).distinct()
                has_valid_search_param = True
            elif key == "building_name":
                building_names = request.GET.getlist(key)
                q_obj = Q()
                type_qs = [Q(building_name__exact=v) for v in building_names]
                for type_q in type_qs:
                    q_obj |= type_q
                query = query.filter(q_obj).distinct()
                has_valid_search_param = True
            elif re.search('^extended_info:', key):
                kwargs = {
                    'spotextendedinfo__key': key[14:],
                    'spotextendedinfo__value__in': request.GET.getlist(key)
                }
                query = query.filter(**kwargs)
                has_valid_search_param = True
            elif key == "id":
                query = query.filter(id__in=request.GET.getlist(key))
                has_valid_search_param = True
            else:
                try:
                    kwargs = {
                        '%s__icontains' % key: request.GET[key]
                    }
                    query = query.filter(**kwargs)
                    has_valid_search_param = True
                except Exception as e:
                    if not request.META['SERVER_NAME'] == 'testserver':
                        print >> sys.stderr, "E: ", e

        limit = 20
        if 'limit' in request.GET:
            if request.GET['limit'] == '0':
                limit = 0
            else:
                limit = int(request.GET['limit'])

        if 'distance' in request.GET and 'center_longitude' in request.GET and 'center_latitude' in request.GET:
            try:
                g = Geod(ellps='clrk66')
                top = g.fwd(request.GET['center_longitude'], request.GET['center_latitude'], 0, request.GET['distance'])
                right = g.fwd(request.GET['center_longitude'], request.GET['center_latitude'], 90, request.GET['distance'])
                bottom = g.fwd(request.GET['center_longitude'], request.GET['center_latitude'], 180, request.GET['distance'])
                left = g.fwd(request.GET['center_longitude'], request.GET['center_latitude'], 270, request.GET['distance'])

                top_limit = "%.8f" % top[1]
                bottom_limit = "%.8f" % bottom[1]
                left_limit = "%.8f" % left[0]
                right_limit = "%.8f" % right[0]

                distance_query = query.filter(longitude__gte=left_limit)

                distance_query = distance_query.filter(longitude__lte=right_limit)
                distance_query = distance_query.filter(latitude__gte=bottom_limit)
                distance_query = distance_query.filter(latitude__lte=top_limit)
                has_valid_search_param = True

                if len(distance_query) >  0 or 'expand_radius' not in request.GET:
                    query = distance_query
                else:
                    # If we're querying everything, let's make sure we only return a limited number of spaces...
                    limit = 10
            except Exception as e:
                if not request.META['SERVER_NAME'] == 'testserver':
                    print >> sys.stderr, "E: ", e
                #query = Spot.objects.all()



        if not has_valid_search_param:
            return HttpResponse('[]')

        if limit > 0 and limit < len(query):
            sorted_list = list(query)
            sorted_list.sort(lambda x, y: cmp(self.distance(x, request.GET['center_longitude'], request.GET['center_latitude']), self.distance(y, request.GET['center_longitude'], request.GET['center_latitude'])))
            query = sorted_list[:limit]

        response = []

        for spot in query:
            response.append(spot.json_data_structure())

        return HttpResponse(json.dumps(response))
Ejemplo n.º 2
0
    def GET(self, request):
        form = SpotSearchForm(request.GET)
        has_valid_search_param = False

        if not form.is_valid():
            return JSONResponse([])

        if len(request.GET) == 0:
            return JSONResponse([])
        chain = SearchFilterChain(request)
        query = Spot.objects.all()

        day_dict = {
            "Sunday": "su",
            "Monday": "m",
            "Tuesday": "t",
            "Wednesday": "w",
            "Thursday": "th",
            "Friday": "f",
            "Saturday": "sa",
        }
        # Exclude things that get special consideration here, otherwise add a filter for the keys
        for key in request.GET:
            if key.startswith('oauth_'):
                pass
            elif chain.filters_key(key):
                # this needs to happen early, before any
                # org_filter or extended_info
                pass
            elif key == "expand_radius":
                pass
            elif key == "distance":
                pass
            elif key == "center_latitude":
                pass
            elif key == "center_longitude":
                pass
            elif key == "limit":
                pass
            elif key == "open_now":
                if request.GET["open_now"]:

                    day_lookup = ["su", "m", "t", "w", "th", "f", "sa"]
                    day_num = int(strftime("%w", localtime()))
                    today = day_lookup[day_num]
                    now = datetime.time(datetime.now())
                    query = query.filter(
                        spotavailablehours__day__iexact=today,
                        spotavailablehours__start_time__lt=now,
                        spotavailablehours__end_time__gt=now)
                    has_valid_search_param = True
            elif key == "open_until":
                if request.GET["open_until"] and request.GET["open_at"]:
                    until_day, until_time = request.GET["open_until"].split(
                        ',')
                    at_day, at_time = request.GET["open_at"].split(',')
                    until_day = day_dict[until_day]
                    at_day = day_dict[at_day]

                    if until_day == at_day:
                        if strptime(until_time, "%H:%M") >= strptime(
                                at_time, "%H:%M"):
                            query = query.filter(
                                spotavailablehours__day__iexact=until_day,
                                spotavailablehours__start_time__lte=at_time,
                                spotavailablehours__end_time__gte=until_time)
                        else:
                            days_to_test = [
                                "su", "m", "t", "w", "th", "f", "sa"
                            ]
                            days_to_test.remove(at_day)

                            query = query.filter(
                                spotavailablehours__day__iexact=at_day,
                                spotavailablehours__start_time__lte=at_time,
                                spotavailablehours__end_time__gte="23:59")
                            query = query.filter(
                                spotavailablehours__day__iexact=until_day,
                                spotavailablehours__start_time__lte="00:00",
                                spotavailablehours__end_time__gte=until_time)

                            for day in days_to_test:
                                query = query.filter(
                                    spotavailablehours__day__iexact=day,
                                    spotavailablehours__start_time__lte="00:00",
                                    spotavailablehours__end_time__gte="23:59")
                    else:
                        days_to_test = self.get_days_in_range(
                            at_day, until_day)
                        last_day = days_to_test.pop()
                        days_to_test.reverse()
                        first_day = days_to_test.pop()

                        query = query.filter(
                            spotavailablehours__day__iexact=first_day,
                            spotavailablehours__start_time__lte=at_time,
                            spotavailablehours__end_time__gte="23:59")
                        query = query.filter(
                            spotavailablehours__day__iexact=last_day,
                            spotavailablehours__start_time__lte="00:00",
                            spotavailablehours__end_time__gte=until_time)

                        for day in days_to_test:
                            query = query.filter(
                                spotavailablehours__day__iexact=day,
                                spotavailablehours__start_time__lte="00:00",
                                spotavailablehours__end_time__gte="23:59")
                    has_valid_search_param = True
            elif key == "open_at":
                if request.GET["open_at"]:
                    try:
                        request.GET["open_until"]
                    except:
                        day, time = request.GET['open_at'].split(',')
                        day = day_dict[day]
                        query = query.filter(
                            spotavailablehours__day__iexact=day,
                            spotavailablehours__start_time__lte=time,
                            spotavailablehours__end_time__gt=time)
                        has_valid_search_param = True
            elif key == "capacity":
                try:
                    limit = int(request.GET["capacity"])
                    with_limit = Q(capacity__gte=limit)
                    with_limit |= Q(capacity__isnull=True)
                    query = query.filter(with_limit)
                    has_valid_search_param = True
                except ValueError:
                    # This we don't care about - if someone passes "", or "twenty", just ignore it
                    pass
                except Exception as e:
                    # Do something to complain??
                    pass
            elif key == "type":
                type_values = request.GET.getlist(key)
                q_obj = Q()
                type_qs = [Q(spottypes__name__exact=v) for v in type_values]
                for type_q in type_qs:
                    q_obj |= type_q
                query = query.filter(q_obj).distinct()
                has_valid_search_param = True
            elif key == "building_name":
                building_names = request.GET.getlist(key)
                q_obj = Q()
                type_qs = [Q(building_name__exact=v) for v in building_names]
                for type_q in type_qs:
                    q_obj |= type_q
                query = query.filter(q_obj).distinct()
                has_valid_search_param = True
            elif key.startswith('extended_info:'):
                kwargs = {
                    'spotextendedinfo__key': key[14:],
                    'spotextendedinfo__value__in': request.GET.getlist(key)
                }
                query = query.filter(**kwargs)
                has_valid_search_param = True
            elif key == "id":
                query = query.filter(id__in=request.GET.getlist(key))
                has_valid_search_param = True
            else:
                try:
                    kwargs = {'%s__icontains' % key: request.GET[key]}
                    query = query.filter(**kwargs)
                    has_valid_search_param = True
                except Exception as e:
                    if not request.META['SERVER_NAME'] == 'testserver':
                        print >> sys.stderr, "E: ", e

        # Always prefetch the related extended info
        query = query.select_related('SpotExtendedInfo')

        query = chain.filter_query(query)
        if chain.has_valid_search_param:
            has_valid_search_param = True

        limit = 20
        if 'limit' in request.GET:
            if request.GET['limit'] == '0':
                limit = 0
            else:
                limit = int(request.GET['limit'])

        if 'distance' in request.GET and 'center_longitude' in request.GET and 'center_latitude' in request.GET:
            try:
                g = Geod(ellps='clrk66')
                top = g.fwd(request.GET['center_longitude'],
                            request.GET['center_latitude'], 0,
                            request.GET['distance'])
                right = g.fwd(request.GET['center_longitude'],
                              request.GET['center_latitude'], 90,
                              request.GET['distance'])
                bottom = g.fwd(request.GET['center_longitude'],
                               request.GET['center_latitude'], 180,
                               request.GET['distance'])
                left = g.fwd(request.GET['center_longitude'],
                             request.GET['center_latitude'], 270,
                             request.GET['distance'])

                top_limit = "%.8f" % top[1]
                bottom_limit = "%.8f" % bottom[1]
                left_limit = "%.8f" % left[0]
                right_limit = "%.8f" % right[0]

                distance_query = query.filter(longitude__gte=left_limit)

                distance_query = distance_query.filter(
                    longitude__lte=right_limit)
                distance_query = distance_query.filter(
                    latitude__gte=bottom_limit)
                distance_query = distance_query.filter(latitude__lte=top_limit)
                has_valid_search_param = True

                if len(distance_query
                       ) > 0 or 'expand_radius' not in request.GET:
                    query = distance_query
                else:
                    # If we're querying everything, let's make sure we only return a limited number of spaces...
                    limit = 10
            except Exception as e:
                if not request.META['SERVER_NAME'] == 'testserver':
                    print >> sys.stderr, "E: ", e
                #query = Spot.objects.all()
        elif 'distance' in request.GET or 'center_longitude' in request.GET or 'center_latitude' in request.GET:
            if 'distance' not in request.GET or 'center_longitude' not in request.GET or 'center_latitude' not in request.GET:
                # If distance, lat, or long are specified in the server request; all 3 must be present.
                raise RESTException(
                    "Must specify latitude, longitude, and distance", 400)

        if not has_valid_search_param:
            return JSONResponse([])

        if limit > 0 and limit < len(query):
            sorted_list = list(query)
            try:
                sorted_list.sort(lambda x, y: cmp(
                    self.distance(x, request.GET['center_longitude'], request.
                                  GET['center_latitude']),
                    self.distance(y, request.GET['center_longitude'], request.
                                  GET['center_latitude'])))
                query = sorted_list[:limit]
            except KeyError:
                raise RESTException(
                    "missing required parameters for this type of search", 400)

        response = []
        spots = set(query)
        spots = chain.filter_results(spots)

        for spot in spots:
            response.append(spot.json_data_structure())

        return JSONResponse(response)
Ejemplo n.º 3
0
    def filter_on_request(self, get_request, chain, request_meta, api):
        form = SpotSearchForm(get_request)
        has_valid_search_param = False

        if not form.is_valid():
            return []

        if not get_request:
            # This is here to continue to allow the building api to request all
            # the buildings in the server.
            if api == 'buildings':
                return list(Spot.objects.all())
            return []
        query = Spot.objects.all()

        # This is here to allow only the building api to continue to be
        # contacted with the key 'campus' instead of 'extended_info:campus'
        if api == 'buildings' and 'campus' in get_request.keys():
            query = query.filter(spotextendedinfo__key='campus',
                                 spotextendedinfo__value=get_request['campus'])
            has_valid_search_param = True

        day_dict = {"Sunday": "su",
                    "Monday": "m",
                    "Tuesday": "t",
                    "Wednesday": "w",
                    "Thursday": "th",
                    "Friday": "f",
                    "Saturday": "sa", }

        # Q objects we need to chain together for the OR queries
        or_q_obj = Q()
        or_qs = []

        # Exclude things that get special consideration here, otherwise add a
        # filter for the keys
        for key in get_request:
            if key.startswith('oauth_'):
                pass
            elif key == 'campus':
                pass
            elif chain.filters_key(key):
                # this needs to happen early, before any
                # org_filter or extended_info
                pass
            elif key == "expand_radius":
                pass
            elif key == "distance":
                pass
            elif key == "center_latitude":
                pass
            elif key == "center_longitude":
                pass
            elif key == "limit":
                pass
            elif key == "open_now":
                if get_request["open_now"]:
                    today, now = self.get_datetime()
                    # Check to see if the request was made in minute
                    # gap before midnight during which no space is open,
                    # based on the server.
                    before_midnight = now.replace(hour=23,
                                                  minute=58,
                                                  second=59,
                                                  microsecond=999999)
                    right_before_midnight = now.replace(hour=23,
                                                        minute=59,
                                                        second=59,
                                                        microsecond=999999)
                    if before_midnight < now and now < right_before_midnight:
                        # Makes it so that all spaces that are open
                        # until midnight or overnight will be returned.
                        now = now.replace(hour=23,
                                          minute=58,
                                          second=0,
                                          microsecond=0)
                    query = \
                        query.filter(
                            spotavailablehours__day__iexact=today,
                            spotavailablehours__start_time__lt=now,
                            spotavailablehours__end_time__gt=now)
                    has_valid_search_param = True
            elif key == "open_until":
                if get_request["open_until"] and get_request["open_at"]:
                    until_day, until_t = \
                        get_request["open_until"].split(',')
                    at_day, at_t = get_request["open_at"].split(',')
                    until_day = day_dict[until_day]
                    at_day = day_dict[at_day]

                    if until_day == at_day:
                        if (strptime(until_t, "%H:%M") >=
                                strptime(at_t, "%H:%M")):
                            query = \
                                query.filter(
                                    spotavailablehours__day__iexact=until_day,
                                    spotavailablehours__start_time__lte=at_t,
                                    spotavailablehours__end_time__gte=until_t)
                        else:
                            days_to_test = ["su", "m",
                                            "t", "w", "th", "f", "sa"]
                            days_to_test.remove(at_day)

                            query = \
                                query.filter(
                                    spotavailablehours__day__iexact=at_day,
                                    spotavailablehours__start_time__lte=at_t,
                                    spotavailablehours__end_time__gte="23:59")
                            t1 = "00:00"
                            query = \
                                query.filter(
                                    spotavailablehours__day__iexact=until_day,
                                    spotavailablehours__start_time__lte=t1,
                                    spotavailablehours__end_time__gte=until_t)

                            for day in days_to_test:
                                t1 = "00:00"
                                t2 = "23:59"
                                query = \
                                    query.filter(
                                        spotavailablehours__day__iexact=day,
                                        spotavailablehours__start_time__lte=t1,
                                        spotavailablehours__end_time__gte=t2)
                    else:
                        days_to_test = self.get_days_in_range(
                            at_day, until_day)
                        last_day = days_to_test.pop()
                        days_to_test.reverse()
                        first_day = days_to_test.pop()

                        query = \
                            query.filter(
                                spotavailablehours__day__iexact=first_day,
                                spotavailablehours__start_time__lte=at_t,
                                spotavailablehours__end_time__gte="23:59")
                        query = \
                            query.filter(
                                spotavailablehours__day__iexact=last_day,
                                spotavailablehours__start_time__lte="00:00",
                                spotavailablehours__end_time__gte=until_t)

                        for day in days_to_test:
                            early = "00:00"
                            query = \
                                query.filter(
                                    spotavailablehours__day__iexact=day,
                                    spotavailablehours__start_time__lte=early,
                                    spotavailablehours__end_time__gte="23:59")
                    has_valid_search_param = True
            elif key == "open_at":
                if get_request["open_at"]:
                    try:
                        get_request["open_until"]
                    except MultiValueDictKeyError:
                        day, time = get_request['open_at'].split(',')
                        day = day_dict[day]
                        query = \
                            query.filter(
                                spotavailablehours__day__iexact=day,
                                spotavailablehours__start_time__lte=time,
                                spotavailablehours__end_time__gt=time)
                        has_valid_search_param = True
            elif key == "fuzzy_hours_end":
                # fuzzy search requires a start and end
                if "fuzzy_hours_start" not in get_request.keys():
                    raise RESTException("fuzzy_hours_end requires "
                                        "fuzzy_hours_start to be specified",
                                        400)
            elif key == "fuzzy_hours_start":
                # fuzzy search requires a start and end
                starts = get_request.getlist("fuzzy_hours_start")
                ends = get_request.getlist("fuzzy_hours_end")
                if ("fuzzy_hours_end" not in get_request.keys() or
                        not len(starts) is len(ends)):
                    raise RESTException("fuzzy_hours_start requires "
                                        "fuzzy_hours_end to be specified",
                                        400)

                or_small_q_obj = Q()
                for num, start in enumerate(starts):
                    start_day, start_time = start.split(',')
                    end_day, end_time = ends[num].split(',')
                    start_day = day_dict[start_day]
                    end_day = day_dict[end_day]

                    start_range_query = \
                        Q(spotavailablehours__day__iexact=start_day,
                          spotavailablehours__start_time__gte=start_time,
                          spotavailablehours__start_time__lt=end_time)
                    end_range_query = \
                        Q(spotavailablehours__day__iexact=end_day,
                          spotavailablehours__end_time__gt=start_time,
                          spotavailablehours__end_time__lte=end_time)
                    span_range_query = \
                        Q(spotavailablehours__day__iexact=end_day,
                          spotavailablehours__start_time__lte=start_time,
                          spotavailablehours__end_time__gt=end_time)
                    span_midnight_pre_query = \
                        Q(spotavailablehours__day__iexact=start_day,
                          spotavailablehours__start_time__gte=start_time,
                          spotavailablehours__start_time__lte="23:59")
                    span_midnight_post_query = \
                        Q(spotavailablehours__day__iexact=end_day,
                          spotavailablehours__end_time__lt=end_time,
                          spotavailablehours__end_time__gte="00:00")
                    span_midnight_pre_midnight_end_query = \
                        Q(spotavailablehours__day__iexact=end_day,
                          spotavailablehours__end_time__gte=start_time,
                          spotavailablehours__end_time__lte="23:59")
                    span_midnight_next_morning_query = \
                        Q(spotavailablehours__day__iexact=end_day,
                          spotavailablehours__start_time__lt=end_time,
                          spotavailablehours__start_time__gte="00:00")
                    if start_day is not end_day:
                        range_query = (start_range_query |
                                       end_range_query |
                                       span_midnight_pre_query |
                                       span_midnight_post_query |
                                       span_midnight_pre_midnight_end_query |
                                       span_midnight_next_morning_query)
                    else:
                        range_query = (start_range_query |
                                       end_range_query |
                                       span_range_query)
                    or_small_q_obj |= range_query
                query = query.filter(or_small_q_obj)
                has_valid_search_param = True
            elif key == "capacity":
                try:
                    limit = int(get_request["capacity"])
                    with_limit = Q(capacity__gte=limit)
                    with_limit |= Q(capacity__isnull=True)
                    query = query.filter(with_limit)
                    has_valid_search_param = True
                except ValueError:
                    # This we don't care about - if someone passes "", or
                    # "twenty", just ignore it
                    pass
                except Exception as e:
                    # Do something to complain??
                    pass
            elif key == "type":
                type_values = get_request.getlist(key)
                q_obj = Q()
                type_qs = [Q(spottypes__name__exact=v) for v in type_values]
                for type_q in type_qs:
                    q_obj |= type_q
                query = query.filter(q_obj).distinct()
                has_valid_search_param = True
            elif key == "building_name":
                building_names = get_request.getlist(key)
                q_obj = Q()
                type_qs = [Q(building_name__exact=v) for v in building_names]
                for type_q in type_qs:
                    q_obj |= type_q
                query = query.filter(q_obj).distinct()
                has_valid_search_param = True
            elif key.startswith('item:extended_info:'):
                try:
                    for value in get_request.getlist(key):
                        or_qs.append(Q(item__itemextendedinfo__key=key[19:],
                                       item__itemextendedinfo__value=value))
                    has_valid_search_param = True
                except Exception as e:
                    pass
            elif key.startswith('item:'):
                try:
                    for value in get_request.getlist(key):
                        if key[5:] == "id":
                            or_qs.append(Q(item__id=value))
                        elif key[5:] == "name":
                            or_qs.append(Q(item__name=value))
                        elif key[5:] == "category":
                            or_qs.append(Q(item__item_category=value))
                        elif key[5:] == "subcategory":
                            or_qs.append(Q(item__item_subcategory=value))
                    has_valid_search_param = True
                except Exception as e:
                    pass
            elif key.startswith('extended_info:or_group'):
                values = get_request.getlist(key)
                or_small_q_obj = Q()
                for value in values:
                    or_small_q_obj |= Q(spotextendedinfo__key=value,
                                        spotextendedinfo__value='true')
                query = query.filter(or_small_q_obj)
                has_valid_search_param = True
            elif key.startswith('extended_info:or'):
                or_qs.append(Q(spotextendedinfo__key=key[17:],
                               spotextendedinfo__value='true'))
                has_valid_search_param = True
            elif key.startswith('extended_info:'):
                kwargs = {
                    'spotextendedinfo__key': key[14:],
                    'spotextendedinfo__value__in': get_request.getlist(key)
                }
                query = query.filter(**kwargs)
                has_valid_search_param = True
            elif key == "id":
                query = query.filter(id__in=get_request.getlist(key))
                has_valid_search_param = True
            else:
                try:
                    kwargs = {
                        '%s__icontains' % key: get_request[key]
                    }
                    query = query.filter(**kwargs)
                    has_valid_search_param = True
                except Exception as e:
                    if not request_meta['SERVER_NAME'] == 'testserver':
                        print >> sys.stderr, "E: ", e

        for or_q in or_qs:
            or_q_obj |= or_q
        # This handles all of the OR queries on extended_info we've collected.
        query = query.filter(or_q_obj).distinct()
        # Always prefetch the related extended info
        query = query.prefetch_related('spotextendedinfo_set')

        query = chain.filter_query(query)
        if chain.has_valid_search_param:
            has_valid_search_param = True

        limit = int(get_request.get('limit', 20))

        if ('distance' in get_request and
                'center_longitude' in get_request and
                'center_latitude' in get_request):
            try:
                g = Geod(ellps='clrk66')
                lon = get_request['center_longitude']
                lat = get_request['center_latitude']
                dist = get_request['distance']
                # Get coordinates above/right/below/left our location
                top = g.fwd(lon, lat, 0, dist)
                right = g.fwd(lon, lat, 90, dist)
                bottom = g.fwd(lon, lat, 180, dist)
                left = g.fwd(lon, lat, 270, dist)
                # Get relevant lat or long from these points
                top_limit = "%.8f" % top[1]
                bottom_limit = "%.8f" % bottom[1]
                left_limit = "%.8f" % left[0]
                right_limit = "%.8f" % right[0]

                distance_query = query.filter(longitude__gte=left_limit,
                                              longitude__lte=right_limit,
                                              latitude__gte=bottom_limit,
                                              latitude__lte=top_limit)
                has_valid_search_param = True

                if distance_query or 'expand_radius' not in get_request:
                    query = distance_query
                else:
                    # If we're querying everything, let's make sure we only
                    # return a limited number of spaces...
                    limit = 10
            except Exception as e:
                if not request_meta['SERVER_NAME'] == 'testserver':
                    print >> sys.stderr, "E: ", e
                # query = Spot.objects.all()
        elif ('distance' in get_request or
                'center_longitude' in get_request or
                'center_latitude' in get_request):
            if ('distance' not in get_request or
                    'center_longitude' not in get_request or
                    'center_latitude' not in get_request):
                # If distance, lat, or long are specified in the server
                # request; all 3 must be present.
                raise RESTException(
                    "Must specify latitude, longitude, and distance", 400)

        # Only do this if spot api because buildings api
        # is able to not pass any valid filters
        if not has_valid_search_param and api == 'spot':
            raise RESTException(
                "missing required parameters for this type of search", 400)

        # Do this when spot api because building api is not required
        # to pass these parameters
        if limit > 0 and limit < len(query) and api == 'spot':
            try:
                lat = get_request['center_latitude']
                lon = get_request['center_longitude']
            except KeyError:
                raise RESTException(
                    "missing required parameters for this type of search", 400)

            def sortfunc(spot):
                return self.distance(spot, lon, lat)

            sorted_list = sorted(query, key=sortfunc)
            query = sorted_list[:limit]

        spots = set(query)
        spots = chain.filter_results(spots)

        return spots
Ejemplo n.º 4
0
    def GET(self, request):
        form = SpotSearchForm(request.GET)
        has_valid_search_param = False

        if not form.is_valid():
            return HttpResponse('[]')

        if len(request.GET) == 0:
            return HttpResponse('[]')

        query = Spot.objects.all()

        day_dict = {"Sunday": "su",
                    "Monday": "m",
                    "Tuesday": "t",
                    "Wednesday": "w",
                    "Thursday": "th",
                    "Friday": "f",
                    "Saturday": "sa", }
        # Exclude things that get special consideration here, otherwise add a filter for the keys
        for key in request.GET:
            if re.search('^oauth_', key):
                pass
            elif key == "expand_radius":
                pass
            elif key == "distance":
                pass
            elif key == "center_latitude":
                pass
            elif key == "center_longitude":
                pass
            elif key == "limit":
                pass
            elif key == "open_now":
                if request.GET["open_now"]:

                    day_lookup = ["su", "m", "t", "w", "th", "f", "sa"]
                    day_num = int(strftime("%w", localtime()))
                    today = day_lookup[day_num]
                    now = datetime.time(datetime.now())
                    query = query.filter(spotavailablehours__day__iexact=today, spotavailablehours__start_time__lt=now, spotavailablehours__end_time__gt=now)
                    has_valid_search_param = True
            elif key == "open_until":
                if request.GET["open_until"] and request.GET["open_at"]:
                    until_day, until_time = request.GET["open_until"].split(',')
                    at_day, at_time = request.GET["open_at"].split(',')
                    until_day = day_dict[until_day]
                    at_day = day_dict[at_day]

                    if until_day == at_day:
                        query = query.filter(spotavailablehours__day__iexact=until_day, spotavailablehours__start_time__lte=at_time, spotavailablehours__end_time__gte=until_time)
                    else:
                        days_to_test = self.get_days_in_range(at_day, until_day)
                        last_day = days_to_test.pop()
                        days_to_test.reverse()
                        first_day = days_to_test.pop()

                        query = query.filter(spotavailablehours__day__iexact=first_day, spotavailablehours__start_time__lte=at_time, spotavailablehours__end_time__gte="23:59")
                        query = query.filter(spotavailablehours__day__iexact=last_day, spotavailablehours__start_time__lte="00:00", spotavailablehours__end_time__gte=until_time)

                        for day in days_to_test:
                            query = query.filter(spotavailablehours__day__iexact=day, spotavailablehours__start_time__lte="00:00", spotavailablehours__end_time__gte="23:59")
                    has_valid_search_param = True
            elif key == "open_at":
                if request.GET["open_at"]:
                    try:
                        request.GET["open_until"]
                    except:
                        day, time = request.GET['open_at'].split(',')
                        day = day_dict[day]
                        query = query.filter(spotavailablehours__day__iexact=day, spotavailablehours__start_time__lte=time, spotavailablehours__end_time__gt=time)
                        has_valid_search_param = True
            elif key == "extended_info:reservable":
                query = query.filter(spotextendedinfo__key="reservable", spotextendedinfo__value__in=['true', 'reservations'])
            elif key == "extended_info:noise_level":
                noise_levels = request.GET.getlist("extended_info:noise_level")

                exclude_silent = True
                exclude_quiet = True
                exclude_moderate = True
                exclude_loud = True
                exclude_variable = True

                for level in noise_levels:
                    if "silent" == level:
                        exclude_silent = False
                    if "quiet" == level:
                        exclude_quiet = False
                        exclude_variable = False
                    if "moderate" == level:
                        exclude_moderate = False
                        exclude_variable = False

                if exclude_silent:
                    query = query.exclude(spotextendedinfo__key="noise_level", spotextendedinfo__value__iexact="silent")
                if exclude_quiet:
                    query = query.exclude(spotextendedinfo__key="noise_level", spotextendedinfo__value__iexact="quiet")
                if exclude_moderate:
                    query = query.exclude(spotextendedinfo__key="noise_level", spotextendedinfo__value__iexact="moderate")
                if exclude_loud:
                    query = query.exclude(spotextendedinfo__key="noise_level", spotextendedinfo__value__iexact="loud")
                if exclude_variable:
                    query = query.exclude(spotextendedinfo__key="noise_level", spotextendedinfo__value__iexact="variable")

            elif key == "capacity":
                try:
                    limit = int(request.GET["capacity"])
                    with_limit = Q(capacity__gte=limit)
                    with_limit |= Q(capacity__isnull=True)
                    query = query.filter(with_limit)
                    has_valid_search_param = True
                except ValueError:
                    # This we don't care about - if someone passes "", or "twenty", just ignore it
                    pass
                except Exception as e:
                    # Do something to complain??
                    pass
            elif key == "type":
                type_values = request.GET.getlist(key)
                q_obj = Q()
                type_qs = [Q(spottypes__name__exact=v) for v in type_values]
                for type_q in type_qs:
                    q_obj |= type_q
                query = query.filter(q_obj).distinct()
                has_valid_search_param = True
            elif key == "building_name":
                building_names = request.GET.getlist(key)
                q_obj = Q()
                type_qs = [Q(building_name__exact=v) for v in building_names]
                for type_q in type_qs:
                    q_obj |= type_q
                query = query.filter(q_obj).distinct()
                has_valid_search_param = True
            elif re.search('^extended_info:', key):
                kwargs = {
                    'spotextendedinfo__key': key[14:],
                    'spotextendedinfo__value__in': request.GET.getlist(key)
                }
                query = query.filter(**kwargs)
                has_valid_search_param = True
            elif key == "id":
                query = query.filter(id__in=request.GET.getlist(key))
                has_valid_search_param = True
            else:
                try:
                    kwargs = {
                        '%s__icontains' % key: request.GET[key]
                    }
                    query = query.filter(**kwargs)
                    has_valid_search_param = True
                except Exception as e:
                    if not request.META['SERVER_NAME'] == 'testserver':
                        print >> sys.stderr, "E: ", e

        limit = 20
        if 'limit' in request.GET:
            if request.GET['limit'] == '0':
                limit = 0
            else:
                limit = int(request.GET['limit'])

        if 'distance' in request.GET and 'center_longitude' in request.GET and 'center_latitude' in request.GET:
            try:
                g = Geod(ellps='clrk66')
                top = g.fwd(request.GET['center_longitude'], request.GET['center_latitude'], 0, request.GET['distance'])
                right = g.fwd(request.GET['center_longitude'], request.GET['center_latitude'], 90, request.GET['distance'])
                bottom = g.fwd(request.GET['center_longitude'], request.GET['center_latitude'], 180, request.GET['distance'])
                left = g.fwd(request.GET['center_longitude'], request.GET['center_latitude'], 270, request.GET['distance'])

                top_limit = "%.8f" % top[1]
                bottom_limit = "%.8f" % bottom[1]
                left_limit = "%.8f" % left[0]
                right_limit = "%.8f" % right[0]

                distance_query = query.filter(longitude__gte=left_limit)

                distance_query = distance_query.filter(longitude__lte=right_limit)
                distance_query = distance_query.filter(latitude__gte=bottom_limit)
                distance_query = distance_query.filter(latitude__lte=top_limit)
                has_valid_search_param = True

                if len(distance_query) > 0 or 'expand_radius' not in request.GET:
                    query = distance_query
                else:
                    # If we're querying everything, let's make sure we only return a limited number of spaces...
                    limit = 10
            except Exception as e:
                if not request.META['SERVER_NAME'] == 'testserver':
                    print >> sys.stderr, "E: ", e
                #query = Spot.objects.all()
        elif 'distance' in request.GET or 'center_longitude' in request.GET or 'center_latitude' in request.GET:
            if 'distance' not in request.GET or 'center_longitude' not in request.GET or 'center_latitude' not in request.GET:
                # If distance, lat, or long are specified in the server request; all 3 must be present.
                return HttpResponseBadRequest("Bad Request")

        if not has_valid_search_param:
            return HttpResponse('[]')

        if limit > 0 and limit < len(query):
            sorted_list = list(query)
            try:
                sorted_list.sort(lambda x, y: cmp(self.distance(x, request.GET['center_longitude'], request.GET['center_latitude']), self.distance(y, request.GET['center_longitude'], request.GET['center_latitude'])))
                query = sorted_list[:limit]
            except KeyError:
                response = HttpResponse('{"error":"missing required parameters for this type of search"}')
                response.status_code = 400
                return response

        response = []


# UIUC Residence Limits for Labs
# --------------------------------
# Remove any spots that the current user cannot use (i.e. login, print, etc)
        # TODO: Add to settings...
        # UIUC_REQUIRE_ADDRESS = settings.UIUC_REQUIRE_ADDRESS
        UIUC_REQUIRE_ADDRESS = 'uiuc_require_address'

# TODO: Net_ID needs to come from somehwere...

        # Prefect restrictions
        query = query.select_related('SpotExtendedInfo')

        all_the_spots = set(query)

        email = request.GET.get('email_address')

        full_address = ''
        if email:
            full_address = get_res_street_address(email)
        for spot in all_the_spots: 
            if email:
# User not logged in
                LOGGER.info("User is logged in. Show only spots they may access.")
                address_restrictions = spot.spotextendedinfo_set.get(
                    key=UIUC_REQUIRE_ADDRESS)
# This is not a restricted spot.
                if len(address_restrictions) == 0:
                    response.append(spot.json_data_structure())
                    LOGGER.debug("Not restricted.")
                else:
# Assume only one uiuc restriction per spot.
                    restrict_rule = address_restrictions[0]
                    regex_text = restrict_rule.value
                    if re.match(full_address, regex_text):
                        response.append(spot.json_data_structure())
                        LOGGER.debug("Restricted, user address matches.")
                    else:
                        LOGGER.debug("Restricted, no address match.")
            else:
                LOGGER.info("User is not logged in. Show all spots.")
                response.append(spot.json_data_structure())

        return HttpResponse(json.dumps(response))
Ejemplo n.º 5
0
    def GET(self, request):
        form = SpotSearchForm(request.GET)
        has_valid_search_param = False

        if not form.is_valid():
            return JSONResponse([])

        if len(request.GET) == 0:
            return JSONResponse([])
        chain = SearchFilterChain(request)
        query = Spot.objects.all()

        day_dict = {"Sunday": "su",
                    "Monday": "m",
                    "Tuesday": "t",
                    "Wednesday": "w",
                    "Thursday": "th",
                    "Friday": "f",
                    "Saturday": "sa", }
        # Exclude things that get special consideration here, otherwise add a filter for the keys
        for key in request.GET:
            if key.startswith('oauth_'):
                pass
            elif chain.filters_key(key):
                # this needs to happen early, before any
                # org_filter or extended_info
                pass
            elif key == "expand_radius":
                pass
            elif key == "distance":
                pass
            elif key == "center_latitude":
                pass
            elif key == "center_longitude":
                pass
            elif key == "limit":
                pass
            elif key == "open_anytime":
                pass
            elif key == "open_now":
                if request.GET["open_now"]:

                    day_lookup = ["su", "m", "t", "w", "th", "f", "sa"]
                    day_num = int(strftime("%w", localtime()))
                    today = day_lookup[day_num]
                    now = datetime.time(datetime.now())
                    query = query.filter(spotavailablehours__day__iexact=today, spotavailablehours__start_time__lt=now, spotavailablehours__end_time__gt=now)
                    has_valid_search_param = True
            elif key == "open_until":
                if request.GET["open_until"] and request.GET["open_at"]:
                    until_day, until_time = request.GET["open_until"].split(',')
                    at_day, at_time = request.GET["open_at"].split(',')
                    until_day = day_dict[until_day]
                    at_day = day_dict[at_day]

                    if until_day == at_day:
                        if strptime(until_time, "%H:%M") >= strptime(at_time, "%H:%M"):
                            query = query.filter(spotavailablehours__day__iexact=until_day, spotavailablehours__start_time__lte=at_time, spotavailablehours__end_time__gte=until_time)
                        else:
                            days_to_test = ["su", "m", "t", "w", "th", "f", "sa"]
                            days_to_test.remove(at_day)

                            query = query.filter(spotavailablehours__day__iexact=at_day, spotavailablehours__start_time__lte=at_time, spotavailablehours__end_time__gte="23:59")
                            query = query.filter(spotavailablehours__day__iexact=until_day, spotavailablehours__start_time__lte="00:00", spotavailablehours__end_time__gte=until_time)

                            for day in days_to_test:
                                query = query.filter(spotavailablehours__day__iexact=day, spotavailablehours__start_time__lte="00:00", spotavailablehours__end_time__gte="23:59")
                    else:
                        days_to_test = self.get_days_in_range(at_day, until_day)
                        last_day = days_to_test.pop()
                        days_to_test.reverse()
                        first_day = days_to_test.pop()

                        query = query.filter(spotavailablehours__day__iexact=first_day, spotavailablehours__start_time__lte=at_time, spotavailablehours__end_time__gte="23:59")
                        query = query.filter(spotavailablehours__day__iexact=last_day, spotavailablehours__start_time__lte="00:00", spotavailablehours__end_time__gte=until_time)

                        for day in days_to_test:
                            query = query.filter(spotavailablehours__day__iexact=day, spotavailablehours__start_time__lte="00:00", spotavailablehours__end_time__gte="23:59")
                    has_valid_search_param = True
            elif key == "open_at":
                if request.GET["open_at"]:
                    try:
                        request.GET["open_until"]
                    except:
                        day, time = request.GET['open_at'].split(',')
                        day = day_dict[day]
                        query = query.filter(spotavailablehours__day__iexact=day, spotavailablehours__start_time__lte=time, spotavailablehours__end_time__gt=time)
                        has_valid_search_param = True
            elif key == "capacity":
                try:
                    limit = int(request.GET["capacity"])
                    with_limit = Q(capacity__gte=limit)
                    with_limit |= Q(capacity__isnull=True)
                    query = query.filter(with_limit)
                    has_valid_search_param = True
                except ValueError:
                    # This we don't care about - if someone passes "", or "twenty", just ignore it
                    pass
                except Exception as e:
                    # Do something to complain??
                    pass
            elif key == "type":
                type_values = request.GET.getlist(key)
                q_obj = Q()
                type_qs = [Q(spottypes__name__exact=v) for v in type_values]
                for type_q in type_qs:
                    q_obj |= type_q
                query = query.filter(q_obj).distinct()
                has_valid_search_param = True
            elif key == "building_name":
                building_names = request.GET.getlist(key)
                q_obj = Q()
                type_qs = [Q(building_name__exact=v) for v in building_names]
                for type_q in type_qs:
                    q_obj |= type_q
                query = query.filter(q_obj).distinct()
                has_valid_search_param = True
            elif key.startswith('extended_info:'):
                kwargs = {
                    'spotextendedinfo__key': key[14:],
                    'spotextendedinfo__value__in': request.GET.getlist(key)
                }
                query = query.filter(**kwargs)
                has_valid_search_param = True
            elif key == "id":
                query = query.filter(id__in=request.GET.getlist(key))
                has_valid_search_param = True
            else:
                try:
                    kwargs = {
                        '%s__icontains' % key: request.GET[key]
                    }
                    query = query.filter(**kwargs)
                    has_valid_search_param = True
                except Exception as e:
                    if not request.META['SERVER_NAME'] == 'testserver':
                        print >> sys.stderr, "E: ", e

        # Always prefetch the related extended info
        query = query.select_related('SpotExtendedInfo')

        query = chain.filter_query(query)
        if chain.has_valid_search_param:
            has_valid_search_param = True

        limit = 20
        if 'limit' in request.GET:
            if request.GET['limit'] == '0':
                limit = 0
            else:
                limit = int(request.GET['limit'])

        if 'distance' in request.GET and 'center_longitude' in request.GET and 'center_latitude' in request.GET:
            try:
                g = Geod(ellps='clrk66')
                top = g.fwd(request.GET['center_longitude'], request.GET['center_latitude'], 0, request.GET['distance'])
                right = g.fwd(request.GET['center_longitude'], request.GET['center_latitude'], 90, request.GET['distance'])
                bottom = g.fwd(request.GET['center_longitude'], request.GET['center_latitude'], 180, request.GET['distance'])
                left = g.fwd(request.GET['center_longitude'], request.GET['center_latitude'], 270, request.GET['distance'])

                top_limit = "%.8f" % top[1]
                bottom_limit = "%.8f" % bottom[1]
                left_limit = "%.8f" % left[0]
                right_limit = "%.8f" % right[0]

                distance_query = query.filter(longitude__gte=left_limit)

                distance_query = distance_query.filter(longitude__lte=right_limit)
                distance_query = distance_query.filter(latitude__gte=bottom_limit)
                distance_query = distance_query.filter(latitude__lte=top_limit)
                has_valid_search_param = True

                if len(distance_query) > 0 or 'expand_radius' not in request.GET:
                    query = distance_query
                else:
                    # If we're querying everything, let's make sure we only return a limited number of spaces...
                    limit = 10
            except Exception as e:
                if not request.META['SERVER_NAME'] == 'testserver':
                    print >> sys.stderr, "E: ", e
                #query = Spot.objects.all()
        elif 'distance' in request.GET or 'center_longitude' in request.GET or 'center_latitude' in request.GET:
            if 'distance' not in request.GET or 'center_longitude' not in request.GET or 'center_latitude' not in request.GET:
                # If distance, lat, or long are specified in the server request; all 3 must be present.
                raise RESTException("Must specify latitude, longitude, and distance", 400)

        if not has_valid_search_param:
            return JSONResponse([])

        if limit > 0 and limit < len(query):
            sorted_list = list(query)
            try:
                sorted_list.sort(lambda x, y: cmp(self.distance(x, request.GET['center_longitude'], request.GET['center_latitude']), self.distance(y, request.GET['center_longitude'], request.GET['center_latitude'])))
                query = sorted_list[:limit]
            except KeyError:
                raise RESTException("missing required parameters for this type of search", 400)

        response = []
        spots = set(query)
        spots = chain.filter_results(spots)

        for spot in spots:
            response.append(spot.json_data_structure())

        return JSONResponse(response)
Ejemplo n.º 6
0
    def filter_on_request(self, get_request, chain, request_meta, api):
        form = SpotSearchForm(get_request)
        has_valid_search_param = False

        if not form.is_valid():
            return []

        if not get_request:
            # This is here to continue to allow the building api to request all
            # the buildings in the server.
            if api == 'buildings':
                return list(Spot.objects.all())
            return []
        query = Spot.objects.all()

        # This is here to allow only the building api to continue to be
        # contacted with the key 'campus' instead of 'extended_info:campus'
        if api == 'buildings' and 'campus' in get_request.keys():
            query = query.filter(spotextendedinfo__key='campus',
                                 spotextendedinfo__value=get_request['campus'])
            has_valid_search_param = True

        day_dict = {
            "Sunday": "su",
            "Monday": "m",
            "Tuesday": "t",
            "Wednesday": "w",
            "Thursday": "th",
            "Friday": "f",
            "Saturday": "sa",
        }

        # Q objects we need to chain together for the OR queries
        or_q_obj = Q()
        or_qs = []

        # Exclude things that get special consideration here, otherwise add a
        # filter for the keys
        for key in get_request:
            if key.startswith('oauth_'):
                pass
            elif key == 'campus':
                pass
            elif chain.filters_key(key):
                # this needs to happen early, before any
                # org_filter or extended_info
                pass
            elif key == "expand_radius":
                pass
            elif key == "distance":
                pass
            elif key == "center_latitude":
                pass
            elif key == "center_longitude":
                pass
            elif key == "limit":
                pass
            elif key == "open_now":
                if get_request["open_now"]:
                    today, now = self.get_datetime()
                    # Check to see if the request was made in minute
                    # gap before midnight during which no space is open,
                    # based on the server.
                    before_midnight = now.replace(hour=23,
                                                  minute=58,
                                                  second=59,
                                                  microsecond=999999)
                    right_before_midnight = now.replace(hour=23,
                                                        minute=59,
                                                        second=59,
                                                        microsecond=999999)
                    if before_midnight < now and now < right_before_midnight:
                        # Makes it so that all spaces that are open
                        # until midnight or overnight will be returned.
                        now = now.replace(hour=23,
                                          minute=58,
                                          second=0,
                                          microsecond=0)
                    query = \
                        query.filter(
                            spotavailablehours__day__iexact=today,
                            spotavailablehours__start_time__lt=now,
                            spotavailablehours__end_time__gt=now)
                    has_valid_search_param = True
            elif key == "open_until":
                if get_request["open_until"] and get_request["open_at"]:
                    until_day, until_t = \
                        get_request["open_until"].split(',')
                    at_day, at_t = get_request["open_at"].split(',')
                    until_day = day_dict[until_day]
                    at_day = day_dict[at_day]

                    if until_day == at_day:
                        if (strptime(until_t, "%H:%M") >= strptime(
                                at_t, "%H:%M")):
                            query = \
                                query.filter(
                                    spotavailablehours__day__iexact=until_day,
                                    spotavailablehours__start_time__lte=at_t,
                                    spotavailablehours__end_time__gte=until_t)
                        else:
                            days_to_test = [
                                "su", "m", "t", "w", "th", "f", "sa"
                            ]
                            days_to_test.remove(at_day)

                            query = \
                                query.filter(
                                    spotavailablehours__day__iexact=at_day,
                                    spotavailablehours__start_time__lte=at_t,
                                    spotavailablehours__end_time__gte="23:59")
                            t1 = "00:00"
                            query = \
                                query.filter(
                                    spotavailablehours__day__iexact=until_day,
                                    spotavailablehours__start_time__lte=t1,
                                    spotavailablehours__end_time__gte=until_t)

                            for day in days_to_test:
                                t1 = "00:00"
                                t2 = "23:59"
                                query = \
                                    query.filter(
                                        spotavailablehours__day__iexact=day,
                                        spotavailablehours__start_time__lte=t1,
                                        spotavailablehours__end_time__gte=t2)
                    else:
                        days_to_test = self.get_days_in_range(
                            at_day, until_day)
                        last_day = days_to_test.pop()
                        days_to_test.reverse()
                        first_day = days_to_test.pop()

                        query = \
                            query.filter(
                                spotavailablehours__day__iexact=first_day,
                                spotavailablehours__start_time__lte=at_t,
                                spotavailablehours__end_time__gte="23:59")
                        query = \
                            query.filter(
                                spotavailablehours__day__iexact=last_day,
                                spotavailablehours__start_time__lte="00:00",
                                spotavailablehours__end_time__gte=until_t)

                        for day in days_to_test:
                            early = "00:00"
                            query = \
                                query.filter(
                                    spotavailablehours__day__iexact=day,
                                    spotavailablehours__start_time__lte=early,
                                    spotavailablehours__end_time__gte="23:59")
                    has_valid_search_param = True
            elif key == "open_at":
                if get_request["open_at"]:
                    try:
                        get_request["open_until"]
                    except:
                        day, time = get_request['open_at'].split(',')
                        day = day_dict[day]
                        query = \
                            query.filter(
                                spotavailablehours__day__iexact=day,
                                spotavailablehours__start_time__lte=time,
                                spotavailablehours__end_time__gt=time)
                        has_valid_search_param = True
            elif key == "fuzzy_hours_end":
                # fuzzy search requires a start and end
                if "fuzzy_hours_start" not in get_request.keys():
                    raise RESTException(
                        "fuzzy_hours_end requires "
                        "fuzzy_hours_start to be specified", 400)
            elif key == "fuzzy_hours_start":
                # fuzzy search requires a start and end
                starts = get_request.getlist("fuzzy_hours_start")
                ends = get_request.getlist("fuzzy_hours_end")
                if ("fuzzy_hours_end" not in get_request.keys()
                        or not len(starts) is len(ends)):
                    raise RESTException(
                        "fuzzy_hours_start requires "
                        "fuzzy_hours_end to be specified", 400)

                or_small_q_obj = Q()
                for num, start in enumerate(starts):
                    start_day, start_time = start.split(',')
                    end_day, end_time = ends[num].split(',')
                    start_day = day_dict[start_day]
                    end_day = day_dict[end_day]

                    start_range_query = \
                        Q(spotavailablehours__day__iexact=start_day,
                          spotavailablehours__start_time__gte=start_time,
                          spotavailablehours__start_time__lt=end_time)
                    end_range_query = \
                        Q(spotavailablehours__day__iexact=end_day,
                          spotavailablehours__end_time__gt=start_time,
                          spotavailablehours__end_time__lte=end_time)
                    span_range_query = \
                        Q(spotavailablehours__day__iexact=end_day,
                          spotavailablehours__start_time__lte=start_time,
                          spotavailablehours__end_time__gt=end_time)
                    span_midnight_pre_query = \
                        Q(spotavailablehours__day__iexact=start_day,
                          spotavailablehours__start_time__gte=start_time,
                          spotavailablehours__start_time__lte="23:59")
                    span_midnight_post_query = \
                        Q(spotavailablehours__day__iexact=end_day,
                          spotavailablehours__end_time__lt=end_time,
                          spotavailablehours__end_time__gte="00:00")
                    span_midnight_pre_midnight_end_query = \
                        Q(spotavailablehours__day__iexact=end_day,
                          spotavailablehours__end_time__gte=start_time,
                          spotavailablehours__end_time__lte="23:59")
                    span_midnight_next_morning_query = \
                        Q(spotavailablehours__day__iexact=end_day,
                          spotavailablehours__start_time__lt=end_time,
                          spotavailablehours__start_time__gte="00:00")
                    if start_day is not end_day:
                        range_query = (start_range_query | end_range_query
                                       | span_midnight_pre_query
                                       | span_midnight_post_query
                                       | span_midnight_pre_midnight_end_query
                                       | span_midnight_next_morning_query)
                    else:
                        range_query = (start_range_query | end_range_query
                                       | span_range_query)
                    or_small_q_obj |= range_query
                query = query.filter(or_small_q_obj)
                has_valid_search_param = True
            elif key == "capacity":
                try:
                    limit = int(get_request["capacity"])
                    with_limit = Q(capacity__gte=limit)
                    with_limit |= Q(capacity__isnull=True)
                    query = query.filter(with_limit)
                    has_valid_search_param = True
                except ValueError:
                    # This we don't care about - if someone passes "", or
                    # "twenty", just ignore it
                    pass
                except Exception as e:
                    # Do something to complain??
                    pass
            elif key == "type":
                type_values = get_request.getlist(key)
                q_obj = Q()
                type_qs = [Q(spottypes__name__exact=v) for v in type_values]
                for type_q in type_qs:
                    q_obj |= type_q
                query = query.filter(q_obj).distinct()
                has_valid_search_param = True
            elif key == "building_name":
                building_names = get_request.getlist(key)
                q_obj = Q()
                type_qs = [Q(building_name__exact=v) for v in building_names]
                for type_q in type_qs:
                    q_obj |= type_q
                query = query.filter(q_obj).distinct()
                has_valid_search_param = True
            elif key.startswith('item:extended_info:'):
                try:
                    for value in get_request.getlist(key):
                        or_qs.append(
                            Q(item__itemextendedinfo__key=key[19:],
                              item__itemextendedinfo__value=value))
                    has_valid_search_param = True
                except Exception as e:
                    pass
            elif key.startswith('item:'):
                try:
                    for value in get_request.getlist(key):
                        if key[5:] == "id":
                            or_qs.append(Q(item__id=value))
                        elif key[5:] == "name":
                            or_qs.append(Q(item__name=value))
                        elif key[5:] == "category":
                            or_qs.append(Q(item__item_category=value))
                        elif key[5:] == "subcategory":
                            or_qs.append(Q(item__item_subcategory=value))
                    has_valid_search_param = True
                except Exception as e:
                    pass
            elif key.startswith('extended_info:or_group'):
                values = get_request.getlist(key)
                or_small_q_obj = Q()
                for value in values:
                    or_small_q_obj |= Q(spotextendedinfo__key=value,
                                        spotextendedinfo__value='true')
                query = query.filter(or_small_q_obj)
                has_valid_search_param = True
            elif key.startswith('extended_info:or'):
                or_qs.append(
                    Q(spotextendedinfo__key=key[17:],
                      spotextendedinfo__value='true'))
                has_valid_search_param = True
            elif key.startswith('extended_info:'):
                kwargs = {
                    'spotextendedinfo__key': key[14:],
                    'spotextendedinfo__value__in': get_request.getlist(key)
                }
                query = query.filter(**kwargs)
                has_valid_search_param = True
            elif key == "id":
                query = query.filter(id__in=get_request.getlist(key))
                has_valid_search_param = True
            else:
                try:
                    kwargs = {'%s__icontains' % key: get_request[key]}
                    query = query.filter(**kwargs)
                    has_valid_search_param = True
                except Exception as e:
                    if not request_meta['SERVER_NAME'] == 'testserver':
                        print >> sys.stderr, "E: ", e

        for or_q in or_qs:
            or_q_obj |= or_q
        # This handles all of the OR queries on extended_info we've collected.
        query = query.filter(or_q_obj).distinct()
        # Always prefetch the related extended info
        query = query.select_related('SpotExtendedInfo')

        query = chain.filter_query(query)
        if chain.has_valid_search_param:
            has_valid_search_param = True

        limit = int(get_request.get('limit', 20))

        if ('distance' in get_request and 'center_longitude' in get_request
                and 'center_latitude' in get_request):
            try:
                g = Geod(ellps='clrk66')
                lon = get_request['center_longitude']
                lat = get_request['center_latitude']
                dist = get_request['distance']
                # Get coordinates above/right/below/left our location
                top = g.fwd(lon, lat, 0, dist)
                right = g.fwd(lon, lat, 90, dist)
                bottom = g.fwd(lon, lat, 180, dist)
                left = g.fwd(lon, lat, 270, dist)
                # Get relevant lat or long from these points
                top_limit = "%.8f" % top[1]
                bottom_limit = "%.8f" % bottom[1]
                left_limit = "%.8f" % left[0]
                right_limit = "%.8f" % right[0]

                distance_query = query.filter(longitude__gte=left_limit,
                                              longitude__lte=right_limit,
                                              latitude__gte=bottom_limit,
                                              latitude__lte=top_limit)
                has_valid_search_param = True

                if distance_query or 'expand_radius' not in get_request:
                    query = distance_query
                else:
                    # If we're querying everything, let's make sure we only
                    # return a limited number of spaces...
                    limit = 10
            except Exception as e:
                if not request_meta['SERVER_NAME'] == 'testserver':
                    print >> sys.stderr, "E: ", e
                # query = Spot.objects.all()
        elif ('distance' in get_request or 'center_longitude' in get_request
              or 'center_latitude' in get_request):
            if ('distance' not in get_request
                    or 'center_longitude' not in get_request
                    or 'center_latitude' not in get_request):
                # If distance, lat, or long are specified in the server
                # request; all 3 must be present.
                raise RESTException(
                    "Must specify latitude, longitude, and distance", 400)

        # Only do this if spot api because buildings api
        # is able to not pass any valid filters
        if not has_valid_search_param and api == 'spot':
            return []

        # Do this when spot api because building api is not required
        # to pass these parameters
        if limit > 0 and limit < len(query) and api == 'spot':
            try:
                lat = get_request['center_latitude']
                lon = get_request['center_longitude']
            except KeyError:
                raise RESTException(
                    "missing required parameters for this type of search", 400)

            def sortfunc(spot):
                return self.distance(spot, lon, lat)

            sorted_list = sorted(query, key=sortfunc)
            query = sorted_list[:limit]

        spots = set(query)
        spots = chain.filter_results(spots)

        return spots