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
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
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
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)
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)
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
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)
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)
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)
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
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