def delete_user_image(user_id): # Check to see if the user exists u = User.get_by_id(user_id) if u is None: raise InvalidUsage('UserID does not match any existing user', status_code=400) path = u.profile_picture_path if path is None: raise InvalidUsage('User has no profile picture.', status_code=400) # Create client for interfacing with Cloud Storage API client = storage.Client() bucket = client.get_bucket(global_vars.USER_IMG_BUCKET) bucket.delete_blob(path) u.profile_picture_path = None u.put() now = datetime.datetime.now() # Return response resp = jsonify({'picture_id deleted': path, 'date_deleted': now}) resp.status_code = 200 return resp
def reactivate_user(user_id): # Get the user u = User.get_by_id(user_id) if u is None: raise InvalidUsage('User ID does not match any existing user', 400) if u.status == 'Active': raise InvalidUsage('User is already active!', 400) # Set user status to 'Active' u.status = 'Active' u.is_phone_number_verified = False u.is_email_verified = False first_name = u.first_name last_name = u.last_name email = u.email phone_number = u.phone_number date_created = u.date_created # Add the updated user status to the Datastore try: u.put() except: abort(500) # Add reactivated user to the Search App reactivated_user = search.Document( doc_id=str(user_id), fields=[ search.TextField(name='name', value=first_name + ' ' + last_name), search.TextField(name='phone_number', value=phone_number), search.TextField(name='email', value=email) ]) try: index = search.Index(name='User') index.put(reactivated_user) except: abort(500) data = { 'user_id': user_id, 'date_created': date_created, 'date_last_modified': u.date_last_modified } resp = jsonify(data) resp.status_code = 201 return resp
def get_advertised_listings_partial_snapshots(user_id, radius_miles, page_number): # Get the user u = User.get_by_id(user_id) if u is None: raise InvalidUsage('UserID does not match any existing user', status_code=400) # Calculate radius in meters radius_meters = radius_miles*METERS_PER_MILE # Get all of the Listings local to the current user index = search.Index(name='Listing') query_string = 'distance(location, geopoint('+str(u.last_known_location.lat)+','+str(u.last_known_location.lon)+')) < '+str(radius_meters)+' AND NOT owner_id='+str(user_id) # get the first set of results # results = index.search(search.Query(query_string=query_string, # options=search.QueryOptions(limit=ListingsPerPage, ids_only=True))) # user chooses page and hence an offset into results next_page = page_number * ListingsPerPage # get the search results for that page results = index.search(search.Query(query_string=query_string, options=search.QueryOptions(limit=ListingsPerPage, offset=next_page, ids_only=True))) # calculate pages pages = results.number_found / ListingsPerPage if next_page > pages: raise InvalidUsage('No more pages exist!', status_code=400) # FIXME: Currently returns only 20 items at a time (search limit). Also, return ids_only! # try: # # FIXME: add limit to the number of items returned # results = index.search(query_string) # except search.Error: # abort(500) matched_listings = get_matched_listings(u, radius_miles, results) resp = jsonify({'current_page':next_page+1,'total_pages':pages+1,'listings':matched_listings}) resp.status_code = 200 return resp
def update_meeting_location(location_id): json_data = request.get_json() google_places_id = json_data.get('google_places_id', '') address = json_data.get('address', '') name = json_data.get('name', '') is_private = bool(json_data.get('is_private', '')) l = Meeting_Location.get_by_id(location_id) if l is None: raise InvalidUsage('LocationID does not match any existing location.', status_code=400) l.google_places_id = google_places_id l.address = address l.name = name l.is_private = is_private try: location_key = l.put() except: abort(500) data = { 'location_id': location_key.id(), 'date_created': l.date_created, 'date_last_modified': l.date_last_modified } resp = jsonify(data) resp.status_code = 200 return resp
def create_meeting_location(user_id): json_data = request.get_json() google_places_id = json_data.get('google_places_id', '') address = json_data.get('address', '') name = json_data.get('name', '') is_private = bool(json_data.get('is_private', '')) u = User.get_by_id(user_id) if u is None: raise InvalidUsage('UserID does not match any existing user', status_code=400) u_key = ndb.Key('User', user_id) l = Meeting_Location(user=u_key, google_places_id=google_places_id, address=address, name=name, is_private=is_private) try: location_key = l.put() except: abort(500) data = { 'location_id': location_key.id(), 'date_created': l.date_created, 'date_last_modified': l.date_last_modified } resp = jsonify(data) resp.status_code = 201 return resp
def validate_email(email): if email is not None: q = User.query(ndb.AND(User.email == email, User.status == 'Active')) u = q.get() if u is not None: raise InvalidUsage('Email address is already registered.', status_code=400)
def delete_listing(listing_id): # Edit Datastore entity # Get the listing l = Listing.get_by_id(listing_id) if l is None: raise InvalidUsage('Listing ID does not match any existing listing.', 400) # Set listing status to 'Deleted' l.status = 'Deleted' # Add the updated listing status to the Datastore try: l.put() except: abort(500) # Delete Search App entity try: index = search.Index(name='Listing') index.delete(str(listing_id)) except: abort(500) # Return response data = { 'listing_id deleted': listing_id, 'date_deleted': l.date_last_modified } resp = jsonify(data) resp.status_code = 200 return resp
def get_user_rented_listings(user_id): u = User.get_by_id(user_id) if u is None: raise InvalidUsage('User ID does not match any existing user', 400) u_key = ndb.Key('User', user_id) qry = Listing.query(Listing.renter == u_key) listings = qry.fetch() data = [] for l in listings: listing_data = { 'listing_id': l.key.id(), 'name': l.name, 'owner_id': l.owner.id(), 'renter_id': l.renter.id() if l.renter else None, 'status': l.status, 'item_description': l.item_description, 'rating': l.rating, 'total_value': l.total_value, 'hourly_rate': l.hourly_rate, 'daily_rate': l.daily_rate, 'weekly_rate': l.weekly_rate, 'date_last_modified': l.date_last_modified, 'image_media_links': get_listing_images(l.key.id()) } data += [listing_data] resp = jsonify({'listings': data}) resp.status_code = 200 return resp
def get_listing_info(listing_id): l = Listing.get_by_id(listing_id) if l is None: raise InvalidUsage('Listing does not exist!', status_code=400) listing_img_media_links = get_listing_images(listing_id) # Add function for related items? # Return the attributes of the new item listing_data = { 'listing_id': l.key.id(), 'name': l.name, 'owner_id': l.owner.id(), 'renter_id': l.renter.id() if l.renter else None, 'status': l.status, 'item_description': l.item_description, 'rating': l.rating, 'total_value': l.total_value, 'hourly_rate': l.hourly_rate, 'daily_rate': l.daily_rate, 'weekly_rate': l.weekly_rate, 'date_last_modified': l.date_last_modified, 'image_media_links': listing_img_media_links } resp = jsonify(listing_data) resp.status_code = 200 return resp
def new_listing_image(listing_id): # user_id = request.form['user_id'] # listing_id = request.form['listing_id'] userfile = request.files['userfile'] filename = userfile.filename # Check if listing exists l = Listing.get_by_id(listing_id) if l is None: raise InvalidUsage('Listing does not exist!', status_code=400) # Create client for interfacing with Cloud Storage API client = storage.Client() bucket = client.get_bucket(global_vars.LISTING_IMG_BUCKET) # Calculating size this way is not very efficient. Is there another way? userfile.seek(0, 2) size = userfile.tell() userfile.seek(0) # upload the item image path = str(listing_id) + '/' + filename image = bucket.blob(blob_name=path) image.upload_from_file(file_obj=userfile, size=size, content_type='image/jpeg') # Hacky way of making the image public.. image.acl.all().grant_read() image.acl.save() resp = jsonify({'image_path': path, 'image_media_link': image.media_link}) resp.status_code = 201 return resp
def get_user_rent_requests(user_id): u = User.get_by_id(user_id) if u is None: raise InvalidUsage('User ID does not match any existing user', 400) u_key = ndb.Key('User', user_id) # rent_requests = Rent_Event.query(Rent_Event.owner == u_key).fetch() rent_requests = Rent_Event.query(Rent_Event.owner == u_key, Rent_Event.status == 'Proposed').fetch() data = [] for re in rent_requests: re_data = { 'listing_id': re.listing.id(), 'date_received': re.date_created, 'renter_id': re.renter.id(), 'rental_time': re.rental_time, 'rental_time_frame': re.rental_time_frame, 'rental_rate': re.rental_rate } data += [re_data] resp = jsonify({'listings': data}) resp.status_code = 200 return resp
def deactivate_user(user_id): # Edit Datastore entity # Get the user u = User.get_by_id(user_id) if u is None: raise InvalidUsage('User ID does not match any existing user', 400) if u.status == 'Deactivated': raise InvalidUsage('User is already deactivated!', 400) # Set user status to 'Deactivated' u.status = 'Deactivated' # Set all of the user's listings to 'Deactivated' u_key = ndb.Key('User', user_id) qry = Listing.query(Listing.owner == u_key) listings = qry.fetch() for l in listings: if l.status != 'Deleted': l.status = 'Deactivated' try: l.put() except: abort(500) # Add the updated user status to the Datastore try: u.put() except: abort(500) # Delete Search App entity try: index = search.Index(name='User') index.delete(str(user_id)) except: abort(500) # Return response data = { 'user_id deactivated': user_id, 'date_deactivated': u.date_last_modified } resp = jsonify(data) resp.status_code = 200 return resp
def validate_phone(phone_number): if phone_number is not None: q = User.query( ndb.AND(User.phone_number == phone_number, User.status == 'Active')) u = q.get() if u is not None: raise InvalidUsage('Phone number is already registered.', status_code=400)
def search_advertised_listings(user_id, radius_miles, search_string): # Get the user u = User.get_by_id(user_id) if u is None: raise InvalidUsage('UserID does not match any existing user', status_code=400) # Calculate radius in meters radius_meters = radius_miles*METERS_PER_MILE query_string = 'distance(location, geopoint('+str(u.last_known_location.lat)+','+str(u.last_known_location.lon)+')) < '+str(radius_meters)+' AND NOT owner_id='+str(user_id)+' AND name: '+search_string listing_ids, num_results = get_matched_listings_ids(query_string) resp = jsonify({'num_results':num_results,'listing_ids':listing_ids}) resp.status_code = 200 return resp
def get_listing_snapshot(listing_id): l = Listing.get_by_id(listing_id) if l is None: raise InvalidUsage('Listing does not exist!', status_code=400) listing_img_media_links = get_listing_images(listing_id) # Add function for related items? # Return the attributes of the new item # Figure out what we want to send in a snapshot.. listing_data = {'name':l.name,'rating':l.rating,'hourly_rate':l.hourly_rate, 'daily_rate':l.daily_rate,'weekly_rate':l.weekly_rate, 'image_media_links':listing_img_media_links} resp = jsonify(listing_data) resp.status_code = 200 return resp
def get_user_info(user_id): u = User.get_by_id(user_id) if u is None: raise InvalidUsage('User ID does not match any existing user', 400) # Get user data from Datastore first_name = u.first_name last_name = u.last_name phone_number = u.phone_number email = u.email path = u.profile_picture_path # Get user's profile picture if path != None: client = storage.Client() bucket = client.get_bucket(global_vars.USER_IMG_BUCKET) # path = str(user_id) + '/profile_picture.jpg' user_img = bucket.get_blob(path) else: user_img = None if user_img == None: user_img_media_link = None image_path = None else: user_img_media_link = user_img.media_link image_path = user_img.path data = { 'user_id': str(user_id), 'first_name': first_name, 'last_name': last_name, 'phone_number': phone_number, 'email': email, 'image_path': image_path, 'image_media_link': user_img_media_link } resp = jsonify(data) resp.status_code = 200 return resp
def new_user_image(user_id): userfile = request.files['userfile'] filename = userfile.filename # Check to see if the user exists u = User.get_by_id(user_id) if u is None: raise InvalidUsage('UserID does not match any existing user', status_code=400) # Create client for interfacing with Cloud Storage API client = storage.Client() bucket = client.get_bucket(global_vars.USER_IMG_BUCKET) # Calculating size this way is not very efficient. Is there another way? userfile.seek(0, 2) size = userfile.tell() userfile.seek(0) # Upload the user's profile image # image = bucket.blob(blob_name=str(user_id)+'/'+filename) # path = str(user_id)+'/profile_picture.jpg' path = str(user_id) + '/' + filename image = bucket.blob(blob_name=path) image.upload_from_file(file_obj=userfile, size=size, content_type='image/jpeg') # Hacky way of making our files public.. image.acl.all().grant_read() image.acl.save() u.profile_picture_path = path u.put() resp = jsonify({'image_path': path, 'image_media_link': image.media_link}) resp.status_code = 201 return resp
def get_user_meeting_locations(user_id): u = User.get_by_id(user_id) if u is None: raise InvalidUsage('User ID does not match any existing user', 400) u_key = ndb.Key('User', user_id) qry = Meeting_Location.query(Meeting_Location.user == u_key) listings = qry.fetch() data = [] for l in listings: listing_data = { 'location_id': l.key.id(), 'name': l.name, 'google_places_id': l.google_places_id, 'address': l.address, 'is_private': l.is_private } data += [listing_data] resp = jsonify({'meeting locations': data}) resp.status_code = 200 return resp
def search_listings(user_id, radius_miles, search_string): # Get the user u = User.get_by_id(user_id) if u is None: raise InvalidUsage('UserID does not match any existing user', status_code=400) # Calculate radius in meters radius_meters = radius_miles*METERS_PER_MILE index = search.Index(name='Listing') query_string = 'distance(location, geopoint('+str(u.last_known_location.lat)+','+str(u.last_known_location.lon)+')) < '+str(radius_meters)+' AND NOT owner_id='+str(user_id)+' AND name: '+search_string # FIXME: Currently returns only 20 items at a time (search limit). Also, return ids_only! try: # FIXME: add limit to the number of items returned results = index.search(query_string) except search.Error: abort(500) matched_listings = get_matched_listings(u, radius_miles, results) resp = jsonify({'results matching '+search_string:matched_listings}) resp.status_code = 200 return resp
def update_listing(listing_id): json_data = request.get_json() name = json_data.get('name', '') total_value = float(json_data.get('total_value', '')) hourly_rate = float(json_data.get('hourly_rate', '')) daily_rate = float(json_data.get('daily_rate', '')) weekly_rate = float(json_data.get('weekly_rate', '')) status = json_data.get('status', '') item_description = json_data.get('item_description', '') # Get the listing l = Listing.get_by_id(listing_id) if l is None: raise InvalidUsage('ItemID does not match any existing item', status_code=400) # Update the item attributes l.name = name l.total_value = total_value l.hourly_rate = hourly_rate l.daily_rate = daily_rate l.weekly_rate = weekly_rate l.item_description = item_description l.status = status # Add the updated item to the Datastore try: l.put() except: abort(500) # Add the updated item to the Search API if l.status == 'Available': updated_item = search.Document( doc_id=str(listing_id), fields=[ search.TextField(name='name', value=name), search.GeoField(name='location', value=search.GeoPoint(l.location.lat, l.location.lon)), search.TextField(name='owner_id', value=str(l.owner.id())) ]) try: index = search.Index(name='Listing') index.put(updated_item) except: abort(500) else: try: index = search.Index(name='Listing') index.delete(str(listing_id)) except: abort(500) # Return the attributes of the new item data = { 'name': name, 'total_value': total_value, 'hourly_rate': hourly_rate, 'daily_rate': daily_rate, 'weekly_rate': weekly_rate, 'status': status, 'item_description': item_description } resp = jsonify(data) resp.status_code = 200 return resp
def create_new_listing(user_id): json_data = request.get_json() name = json_data.get('name', '') item_description = json_data.get('item_description', '') total_value = float(json_data.get('total_value', '')) # location_lat = float(json_data.get('location_lat','')) # location_lon = float(json_data.get('location_lon','')) # Check to see if the user exists u = User.get_by_id(user_id) if u is None: raise InvalidUsage('UserID does not match any existing user', status_code=400) u_key = ndb.Key('User', user_id) # if total_value > MAX_ITEM_VALUE: # raise InvalidUsage('Total value is too large', status_code=400) status = 'Available' rating = -1.0 location = ndb.GeoPt(40.112814, -88.231786) # INSERT FUNCTION TO CALCULATE RENTAL RATES HERE hourly_rate, daily_rate, weekly_rate = get_rates(total_value) # Add listing to Datastore l = Listing(owner=u_key, status=status, name=name, item_description=item_description, rating=rating, total_value=total_value, hourly_rate=hourly_rate, daily_rate=daily_rate, weekly_rate=weekly_rate, location=location) try: listing_key = l.put() listing_id = str(listing_key.id()) except: abort(500) # Add listing to Search App new_item = search.Document(doc_id=listing_id, fields=[ search.TextField(name='name', value=name), search.GeoField(name='location', value=search.GeoPoint( location.lat, location.lon)), search.TextField(name='owner_id', value=str(user_id)) ]) try: index = search.Index(name='Listing') index.put(new_item) except: abort(500) data = { 'listing_id': listing_id, 'date_created': l.date_created, 'date_last_modified': l.date_last_modified, 'status': status } resp = jsonify(data) resp.status_code = 201 return resp
def validate_password(password): if password is not None and len(password) < MIN_PASSWORD_SIZE: raise InvalidUsage('Password is too short.', status_code=400)
def propose_rent_request(listing_id, renter_id): json_data = request.get_json() rental_rate = float(json_data.get('rental_rate', '')) rental_time = int(json_data.get('rental_time', '')) rental_time_frame = json_data.get('rental_time_frame', '') message = json_data.get('message', '') proposed_meeting_times_data = json_data.get('proposed_meeting_times', '') proposed_meeting_location_ids = json_data.get('proposed_meeting_location', '') # Check to see if the listing exists l = Listing.get_by_id(listing_id) if l is None: raise InvalidUsage('ListingID does not match any existing listing', status_code=400) o_key = l.owner r_key = ndb.Key('User', renter_id) # Check to see if owner == renter if o_key == r_key: raise InvalidUsage("Cannot request to an item that you own", 400) # Check to see if owner and renter exists o = o_key.get() if o is None: raise InvalidUsage('OwnerID does not match any existing user', status_code=400) r = r_key.get() if r is None: raise InvalidUsage('RenterID does not match any existing user', status_code=400) # Check that a proposed Rent_Event does not already exist with this listing_id and this renter_id rent_events = Rent_Event.query(Rent_Event.listing == l.key).fetch() # rent_events = qry.fetch(projection=[Rent_Event.renter,Rent_Event.status]) # qry1 = qry.filter(Rent_Event.renter == r_key) # qry2 = qry1.filter(Rent_Event.status == 'Proposed') # re = qry2.fetch() for re in rent_events: if re.renter == r_key and re.status == 'Proposed': raise InvalidUsage('Rent request already proposed!', status_code=400) re = Rent_Event(owner=o.key, renter=r.key, listing=l.key, rental_rate=rental_rate, rental_time=rental_time, rental_time_frame=rental_time_frame, message=message, status='Proposed') proposed_meeting_times = [] for proposed_meeting_time_data in proposed_meeting_times_data: time_str = proposed_meeting_time_data['time'] time = datetime.datetime.strptime(time_str, '%Y %m %d %H:%M:%S') duration = float(proposed_meeting_time_data['duration']) is_available = bool(proposed_meeting_time_data['is_available']) proposed_meeting_time = Proposed_Meeting_Time( time=time, duration=duration, is_available=is_available) proposed_meeting_times.append(proposed_meeting_time) proposed_meeting_locations = [] for location_id in proposed_meeting_location_ids: location_key = ndb.Key('Meeting_Location', int(location_id)) proposed_meeting_locations.append(location_key) # Create start_meeting_event sme = Meeting_Event(owner=o.key, renter=r.key, listing=l.key, deliverer='Owner', status='Proposed', proposed_meeting_times=proposed_meeting_times, proposed_meeting_locations=proposed_meeting_locations) start_meeting_event_key = sme.put() re.start_meeting_event = start_meeting_event_key rent_event_key = re.put() # TODO: Ask Nick how push notification stuff works.. # Send Push Notification to the Owner informing them of the new Rent Request # if owner.notification_tokens is not None: # if len(o.notification_tokens) > 0: # message_url = 'http://gcm-http.googleapis.com/gcm/send' # message_headers = {'Authorization':'key=AIzaSyBca5FNN9IUIwZuZFECDWL-jEkgMRQofW0', 'Content-Type':'application/json'} # message_title = 'New Rent Request' # message_body = renter.first_name + ' wants to borrow your ' + listing.name # message_sound = 'default' # m_data = {'type':'Rent_Request_Proposed', 'meeting_id':start_meeting_event_key.id(), 'event_id':str(event_id)} # message_note = {'title':message_title, 'body':message_body, 'sound':message_sound, 'badge':1} # message_data = {'data':m_data, 'content_available':True, 'priority':'high', 'to':owner.notification_tokens[0], 'notification':message_note} # message_response = requests.post(message_url, headers=message_headers, json=message_data) data = { 'event_id': rent_event_key.id(), 'start_meeting_id': start_meeting_event_key.id(), 'date_created': re.date_created } resp = jsonify(data) resp.status_code = 201 return resp
def update_user(user_id): json_data = request.get_json() first_name = json_data.get('first_name', '') last_name = json_data.get('last_name', '') email = json_data.get('email', '') phone_number = json_data.get('phone_number', '') if not bool(first_name): raise InvalidUsage('First name cannot be left empty.', 400) if not bool(last_name): raise InvalidUsage('Last name cannot be left empty.', 400) if not bool(email): raise InvalidUsage('Email cannot be left empty.', 400) if not bool(phone_number): raise InvalidUsage('Phone number cannot be left empty.', 400) # Get the user u = User.get_by_id(user_id) if u is None: raise InvalidUsage('User ID does not match any existing user', 400) # Validate email and phone number before updating anything if u.email != email: validate_email(email) if u.phone_number != phone_number: validate_phone(phone_number) # If the phone number is different, phone number is no longer verified if phone_number != u.phone_number: u.is_phone_number_verified = False # If the email is different, email is no longer verified if email != u.email: u.is_email_verified = False # Update user attributes u.first_name = first_name u.last_name = last_name u.email = email u.phone_number = phone_number # Add the updated user to the Datastore try: u.put() except: abort(500) # Add updated user to the Search App updated_user = search.Document(doc_id=str(user_id), fields=[ search.TextField(name='name', value=first_name + ' ' + last_name), search.TextField(name='phone_number', value=phone_number), search.TextField(name='email', value=email) ]) try: index = search.Index(name='User') index.put(updated_user) except: abort(500) # Return the fields of the new user data = { 'first_name': first_name, 'last_name': last_name, 'phone_number': phone_number, 'is_phone_number_verified': u.is_phone_number_verified, 'email': email, 'is_email_verified': u.is_email_verified, 'date_last_modified': u.date_last_modified } resp = jsonify(data) resp.status_code = 200 return resp
def create_user(): json_data = request.get_json() first_name = json_data.get('first_name', '') last_name = json_data.get('last_name', '') email = json_data.get('email', '') phone_number = json_data.get('phone_number', '') facebook_id = json_data.get('facebook_id', '') password = json_data.get('password', '') signup_method = json_data.get('signup_method', '') # location_lat = float(json_data.get('location_lat','')) # location_lon = float(json_data.get('location_lon','')) # TODO: get location from client # If object string is empty '', then set object = None if not bool(password): password = None if not bool(phone_number): phone_number = None if not bool(email): email = None if not bool(facebook_id): facebook_id = None if signup_method != 'Facebook': if not phone_number: raise InvalidUsage('Phone number is required!', 400) if not password: raise InvalidUsage('Password is required!', 400) else: if not facebook_id: raise InvalidUsage('No facebook id given!', 400) # Validate password, email, and phone_number validate_password(password) validate_email(email) validate_phone(phone_number) # Create category weight vector # category_weights = [] # categories = Category.query() # for cat in categories.iter(): # cat_weight = CategoryWeight(category=cat.key, weight=1.0) # category_weights.append(cat_weight) # Add user to Datastore u = User(first_name=first_name, last_name=last_name, phone_number=phone_number, email=email, password=password, facebook_id=facebook_id, signup_method=signup_method) try: user_key = u.put() user_id = str(user_key.id()) except: abort(500) # Add user to Search App new_user = search.Document(doc_id=user_id, fields=[ search.TextField(name='name', value=first_name + ' ' + last_name), search.TextField(name='phone_number', value=phone_number), search.TextField(name='email', value=email) ]) try: index = search.Index(name='User') index.put(new_user) except: abort(500) data = { 'user_id': user_id, 'date_created': u.date_created, 'date_last_modified': u.date_last_modified } resp = jsonify(data) resp.status_code = 201 return resp