Exemple #1
0
    def GET(self, request, spot_id, image_id, thumb_dimensions=None, constrain=False):
        img = SpotImage.objects.get(pk=image_id)
        spot = img.spot

        if int(spot.pk) != int(spot_id):
            raise RESTException("Image Spot ID doesn't match spot id in url", 404)

        if thumb_dimensions is None:
            raise RESTException("Image constraints required", 400)

        thumb_width = None
        thumb_height = None
        if constrain is True:
            m = RE_WIDTH.search(thumb_dimensions)
            if m:
                thumb_width = m.group(1)
            m = RE_HEIGHT.search(thumb_dimensions)
            if m:
                thumb_height = m.group(1)

            if thumb_width is None and thumb_height is None:
                raise RESTException("Image constraints required", 400)
            elif thumb_width is None:
                thumb_width = img.width
            elif thumb_height is None:
                thumb_height = img.height
        else:
            m = RE_WIDTHxHEIGHT.match(thumb_dimensions)
            if not m:
                raise RESTException("Image constraints required", 400)
            else:
                thumb_width = m.group(1)
                thumb_height = m.group(2)

        thumb_width = int(thumb_width)
        thumb_height = int(thumb_height)

        if thumb_height <= 0 or thumb_width <= 0:
            raise RESTException("Bad image constraints", 400)

        image = img.image
        im = Image.open(image.path)

        if constrain is True:
            im.thumbnail((thumb_width, thumb_height, Image.ANTIALIAS))
            thumb = im
        else:
            thumb = im.resize((thumb_width, thumb_height), Image.ANTIALIAS)

        tmp = StringIO()
        thumb.save(tmp, im.format, quality=95)
        tmp.seek(0)

        response = HttpResponse(tmp.getvalue(), content_type=img.content_type)
        # 7 day timeout?
        response['Expires'] = http_date(time.time() + 60 * 60 * 24 * 7)
        return response
Exemple #2
0
    def POST(self, request, spot_id):
        spot = Spot.objects.get(pk=spot_id)

        if "image" not in request.FILES:
            raise RESTException("No image", 400)

        args = {
            'upload_application': request.META.get('SS_OAUTH_CONSUMER_NAME',
                                                   ''),
            'upload_user': request.META.get('SS_OAUTH_USER', ''),
            'description': request.POST.get('description', ''),
            'display_index': request.POST.get('display_index'),
            'image': request.FILES['image']
        }
        if args['display_index'] is None:
            # TODO: is there a better way?
            # get display_indexes for all of the existing images
            # and set the new one to the biggest + 1
            indices = [img.display_index for img in spot.spotimage_set.all()]
            if indices:
                args['display_index'] = max(indices) + 1
            else:
                args['display_index'] = 0

        image = spot.spotimage_set.create(**args)

        response = HttpResponse(status=201)
        response["Location"] = image.rest_url()

        return response
    def POST(self, request, spot_id):
        spot = Spot.objects.get(pk=spot_id)

        if not "image" in request.FILES:
            raise RESTException("No image", 400)

        args = {}
        args['upload_application'] = request.META.get('SS_OAUTH_CONSUMER_NAME', '')
        args['upload_user'] = request.META.get('SS_OAUTH_USER', '')
        args['description'] = request.POST.get('description', '')

        args['display_index'] = request.POST.get('display_index')
        if args['display_index'] is None:
            #TODO: is there a better way?
            # get display_indexes for all of the existing images and set the new one to the biggest + 1
            indexes = []
            for img in spot.spotimage_set.all():
                indexes.append(img.display_index)
            indexes.sort()
            try:
                args['display_index'] = indexes[-1] + 1
            except IndexError:
                args['display_index'] = 0

        args['image'] = request.FILES['image']

        image = spot.spotimage_set.create(**args)

        response = HttpResponse(status=201)
        response["Location"] = image.rest_url()

        return response
Exemple #4
0
    def POST(self, request, spot_id):
        user = self._get_user(request)
        space = Spot.objects.get(pk=spot_id)

        body = request.read()
        try:
            json_values = json.loads(body)
        except Exception as e:
            raise RESTException("Unable to parse JSON", status_code=400)

        rating = json_values['rating']
        review = json_values['review']

        if rating > 5 or rating < 1:
            return HttpResponse(status=400)

        new_review = SpaceReview.objects.create(space = space,
                                                reviewer = user,
                                                original_review = review,
                                                rating = rating,
                                                is_published = False,
                                                is_deleted = False)

        response = HttpResponse("OK", status=201)
        return response
Exemple #5
0
    def DELETE(self, request, item_id, image_id):
        img = ItemImage.objects.get(pk=image_id)
        item = img.item

        if int(item.pk) != int(item_id):
            raise RESTException("Image Item ID doesn't match item id in url",
                                404)

        img.delete()

        return HttpResponse(status=200)
Exemple #6
0
    def DELETE(self, request, spot_id, image_id):
        img = SpotImage.objects.get(pk=image_id)
        spot = img.spot

        if int(spot.pk) != int(spot_id):
            raise RESTException("Image Spot ID doesn't match spot id in url",
                                404)

        self.validate_etag(request, img)

        img.delete()

        return HttpResponse(status=200)
    def PUT(self, request, spot_id):
        user = None
        try:
            authenticate_user(self, request)
            user = self._get_user(request)
        except:
            pass

        body = request.read()
        try:
            json_values = json.loads(body)
        except Exception:
            raise RESTException("Unable to parse JSON", status_code=400)

        if 'hash' not in json_values:
            raise RESTException("Missing 'hash'", status_code=400)

        try:
            recipient = SharedSpaceRecipient.objects.get(
                hash_key=json_values['hash'])
        except ObjectDoesNotExist:
            return JSONResponse("{error: 'shared spot not found'}", status=401)

        if recipient.shared_space.space.pk == int(spot_id):
            recipient.viewed_count = recipient.viewed_count + 1

            if not recipient.date_first_viewed:
                recipient.date_first_viewed = timezone.now()

            if user and user.username:
                recipient.user = user.username

            recipient.save()
        else:
            return JSONResponse("{error: 'spot mismatch'}", status=401)

        return JSONResponse(True)
Exemple #8
0
    def GET(self, request, spot_id, image_id):
        img = SpotImage.objects.get(pk=image_id)
        spot = img.spot

        if int(spot.pk) != int(spot_id):
            raise RESTException("Image Spot ID doesn't match spot id in url",
                                404)

        response = HttpResponse(FileWrapper(img.image))
        response["ETag"] = img.etag

        # 7 day timeout?
        response['Expires'] = http_date(time.time() + 60 * 60 * 24 * 7)
        response["Content-length"] = img.image.size
        response["Content-type"] = img.content_type
        return response
Exemple #9
0
    def PUT(self, request, spot_id, image_id):
        img = SpotImage.objects.get(pk=image_id)
        spot = img.spot

        if int(spot.pk) != int(spot_id):
            raise RESTException("Image Spot ID doesn't match spot id in url",
                                404)

        self.validate_etag(request, img)

        request.method = "POST"
        request._load_post_and_files()
        request.method = "PUT"

        if "image" in request.META['files']:
            img.image = ImageFile(request.META['files']["image"])
        if "description" in request.META['files']:
            img.description = request.META['files']["description"]
        if "display_index" in request.META['files']:
            img.display_index = request.META['files']["display_index"]
        img.save()

        return self.GET(request, spot_id, image_id)
Exemple #10
0
    def PUT(self, request, spot_id, image_id):
        img = SpotImage.objects.get(pk=image_id)
        spot = img.spot

        if int(spot.pk) != int(spot_id):
            raise RESTException("Image Spot ID doesn't match spot id in url",
                                404)

        self.validate_etag(request, img)

        # This trick was taken from piston
        request.method = "POST"
        request._load_post_and_files()
        request.method = "PUT"

        if "image" in request.FILES:
            img.image = request.FILES["image"]
        if "description" in request.POST:
            img.description = request.POST["description"]
        if "display_index" in request.POST:
            img.display_index = request.POST["display_index"]
        img.save()

        return self.GET(request, spot_id, image_id)
Exemple #11
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)
    def PUT(self, request, spot_id):
        user = self._get_user(request)
        spot = Spot.objects.get(pk=spot_id)

        body = request.read()
        try:
            json_values = json.loads(body)
        except Exception:
            logger.error('Unable to parse JSON body: %s' % (body))
            raise RESTException("Unable to parse JSON", status_code=400)

        if 'to' not in json_values:
            logger.error('Missing To in JSON: %s' % (body))
            raise RESTException("Missing 'To'", status_code=400)

        raw_send_to = json_values['to']
        if type(raw_send_to) is not list:
            raw_send_to = [raw_send_to]

        has_valid_to = False
        send_to = []
        for address in raw_send_to:
            if '@' in address:
                send_to.append(address)
                has_valid_to = True

        if not has_valid_to:
            logger.error('Invalid To field:  %s' % (body))
            raise RESTException("Invalid 'To'", status_code=400)

        send_from = json_values['from'] if 'from' in json_values else None
        if send_from and '@' not in send_from:
            logger.error('Invalid From field:  %s' % (body))
            raise RESTException("Invalid 'from'", status_code=400)

        comment = ''
        if 'comment' in json_values:
            comment = json_values['comment']

        try:
            share = SharedSpace.objects.get(space=spot,
                                            sender=send_from,
                                            user=user.username)
        except ObjectDoesNotExist:
            share = SharedSpace(space=spot,
                                sender=send_from,
                                user=user.username)
            share.save()

        for to in send_to:
            try:
                server = getattr(settings, 'SS_APP_SERVER',
                                 socket.gethostname())
                path = getattr(settings, 'SS_APP_SPACE_PATH',
                               '/space/{{ spot_id }}/{{ spot_name }}')
                path = re.sub(r'{{\s*spot_id\s*}}', spot_id, path)
                path = re.sub(r'{{\s*spot_name\s*}}', urlquote(spot.name),
                              path)
                hash_val = hashlib.md5("%s|%s|%s" %
                                       (spot.pk, send_from, to)).hexdigest()
                share_url = "http://%s%s/%s" % (server, path, hash_val)

                try:
                    recipient = SharedSpaceRecipient.objects.get(
                        hash_key=hash_val)
                    recipient.shared_count = recipient.shared_count + 1
                except ObjectDoesNotExist:
                    recipient = SharedSpaceRecipient(shared_space=share,
                                                     hash_key=hash_val,
                                                     recipient=to,
                                                     shared_count=1,
                                                     viewed_count=0)

                recipient.save()

                location_description = None
                try:
                    location_description = SpotExtendedInfo.objects.get(
                        spot=spot, key='location_description').value
                except ObjectDoesNotExist:
                    pass

                spottypes = spot.spottypes.all()
                spottypes = ["server_%s" % x for x in spottypes]

                context = Context({
                    'user_name': user.username,
                    'spot_name': spot.name,
                    'spot_type': spottypes,
                    'spot_building': spot.building_name,
                    'spot_location': location_description,
                    'spot_floor': spot.floor,
                    'share_url': share_url,
                    'comment': comment,
                })

                subject_template = get_template(
                    'email/share_space/subject.txt')
                text_template = get_template(
                    'email/share_space/plain_text.txt')
                html_template = get_template('email/share_space/html.html')

                subject = json_values[
                    'subject'] if 'subject' in json_values else subject_template.render(
                        context).rstrip()
                text_content = text_template.render(context)
                html_content = html_template.render(context)
                from_email = getattr(settings, 'SPACESCOUT_SUGGEST_FROM',
                                     '*****@*****.**')

                headers = {}
                if send_from:
                    headers['Sender'] = getattr(settings,
                                                'SPACESCOUT_SUGGEST_FROM',
                                                '*****@*****.**')
                    from_email = send_from
                else:
                    from_email = getattr(settings, 'SPACESCOUT_SUGGEST_FROM',
                                         '*****@*****.**')

                msg = EmailMultiAlternatives(subject,
                                             text_content,
                                             from_email, [to],
                                             headers=headers)
                msg.attach_alternative(html_content, "text/html")
                msg.send()
            except Exception as e:
                logger.exception('Share Send Failure: %s' % (e))
                raise RESTException("Cannot share space at this time: %s" %
                                    (e),
                                    status_code=500)

        return JSONResponse(True)
Exemple #13
0
    def build_and_save_from_input(self, request, spot):
        body = request.read()
        try:
            json_values = json.loads(body)
        except Exception as e:
            raise RESTException("Unable to parse JSON", status_code=400)

        partial_update = False
        stash = {}
        is_new = spot is None

        spot_pre_build.send(sender=SpotForm.implementation(),
                            request=request,
                            json_values=json_values,
                            spot=spot,
                            partial_update=partial_update,
                            stash=stash)

        self._build_spot_types(json_values, spot, partial_update)
        self._build_spot_location(json_values)

        spot_pre_save.send(sender=SpotForm.implementation(),
                           request=request,
                           json_values=json_values,
                           spot=spot,
                           partial_update=partial_update,
                           stash=stash)

        # Remve excluded fields
        excludefields = set(SpotForm.implementation().Meta.exclude)
        for fieldname in excludefields:
            if fieldname in json_values:
                del json_values[fieldname]

        if spot is not None and partial_update:
            # Copy over the existing values
            for field in spot._meta.fields:
                if field.name in excludefields:
                    continue
                if not field.name in json_values:
                    json_values[field.name] = getattr(spot, field.name)

            # spottypes is not included in the above copy, do it manually
            if not 'spottypes' in json_values:
                json_values['spottypes'] = [t.pk for t in spot.spottypes.all()]

        form = SpotForm(json_values, instance=spot)
        if not form.is_valid():
            raise RESTFormInvalidError(form)

        spot = form.save()

        spot_post_save.send(sender=SpotForm.implementation(),
                            request=request,
                            spot=spot,
                            partial_update=partial_update,
                            stash=stash)

        # gets the current etag
        spot = Spot.get_with_external(spot.pk)

        if is_new:
            response = HttpResponse(status=201)
            response['Location'] = spot.rest_url()
        else:
            response = JSONResponse(spot.json_data_structure(), status=200)
        response["ETag"] = spot.etag

        spot_post_build.send(sender=SpotForm.implementation(),
                             request=request,
                             response=response,
                             spot=spot,
                             partial_update=partial_update,
                             stash=stash)

        return response
Exemple #14
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