def create_snack(selected_brand): # Get snacks from the database. if current_user.is_authenticated: print(f"User is authenticated", file=sys.stdout) create_snack_form = CreateSnackForm(request.form) new_snack = None selected_brand = selected_brand.split("=")[1] print(selected_brand) if request.method == "POST": snack_brand = request.form['snack_brand'] snack_name = request.form['snack_name'] print(f"{snack_name}", file=sys.stdout) # Add snack to db print(f"{current_user}", file=sys.stdout) try: new_snack = Snack(snack_name=request.form['snack_name'], available_at_locations=[ request.form['available_at_locations'] ], snack_brand=request.form['snack_brand'], category=request.form['category'], description=request.form['description'], is_verified=hasattr(current_user, 'company_name'), avg_overall_rating=0, avg_sourness=0, avg_spiciness=0, avg_bitterness=0, avg_sweetness=0, avg_saltiness=0, review_count=0) new_snack.save() except Exception as e: raise Exception( f"Error {e}. \n Couldn't add {new_snack},\n with following creation form: {create_snack_form}" ) print( f"A new snack submitted the creation form: {snack_brand} => {snack_name}", file=sys.stdout) return redirect(url_for('index')) # For frontend purposes context_dict = { "title": "Add Snack", "selected_snack_brand": selected_brand, "form": create_snack_form, "user": current_user } return render_template("create_snack.html", **context_dict) else: # Go back to index if not authenticated return redirect(url_for('index'))
def find_wishlist(): """ Return all snacks in wishlist of current user """ result = [] for wish in current_user.wish_list: result.extend(Snack.objects(id=wish)) print(f"{result}\n", file=sys.stdout) title = "Wishlist" if hasattr(current_user, 'company_name'): title = "Watchlist" context_dict = {"title": title, "query": result, "user": current_user} return render_template('my_list.html', **context_dict)
def serve_img(snack_id): """ Given a snack id, get the image and render it Example in file display_snack.html""" placeholder = "static/images/CrunchyCheesyFlavouredCheetos.jpg" get_mimetype = lambda filename: mimetypes.MimeTypes().guess_type(filename)[ 0] sample_snack = Snack.objects(id=snack_id)[0] if sample_snack.photo_files == []: return Response(open(placeholder, "rb").read(), mimetype=get_mimetype(placeholder)) photo = sample_snack.photo_files[0].img # resp=Response(photo.read(), mimetype=mimetype) # Returning the thumbnail for now resp = Response(photo.thumbnail.read(), mimetype=get_mimetype(photo.filename)) return resp
def verify_snack(): if current_user.is_authenticated and hasattr(current_user, 'company_name'): print(f"User is authenticated", file=sys.stdout) if request.method == "POST": snack_id = request.form["snack_id"] snack_object = Snack.objects(id=snack_id) company_user_object = CompanyUser.objects(id=current_user.id) snack = "snack_id=" + str(snack_id) if snack_object[0].snack_brand in company_user_object[ 0].company_snackbrands: print(f"ddd Jay\n", file=sys.stdout) try: snack_object.update(set__is_verified=True) print("ayyyyy") except Exception as e: raise Exception( f"Error {e}. \n Couldn't verify {snack_id}") print(f"The company user verified this snack: {snack_id}", file=sys.stdout) response = make_response(json.dumps(snack_id)) response.status_code = 200 print(f"{response}\n", file=sys.stdout) return response else: print(f"User is not the snack's company: {current_user.id}", file=sys.stdout) # we want to give the user an error message return redirect( url_for('find_reviews_for_snack', filters=snack)) else: return redirect(url_for('find_reviews_for_snack')) else: # Go back to index if not authenticated or if user is not company user return redirect(url_for('index'))
def recommend_snacks(self, user, review_from_user, country, num_snacks=10, msgs=list()): """recommend_snacks Keyword Arguments: user {User} -- A user instance from mongoengine review_from_user {list} -- All reviews made by that user country {str} -- The country in which the user last logged in num_snacks {int} -- Number of new snacks to recommend (default: {10}) """ # Remove 'none' from a set, to prevent 'None' errors in the dictionary filt_none = lambda set_obj: set(filter(None, set_obj)) user_id = str(user.id) # Get snacks from the current country # If no country provided, search for everything! snacks_in_current_country = Snack.objects( Q(available_at_locations__in=[country ])) if country else Snack.objects calculated_recommendation = [] # Check if the current user is in the trained model user_is_trained = user_id in self.userID_to_index.keys() # Check if all the snacks the user reviewed are in the trained model (they should be) snacks_are_trained = all((str(r["snack_id"]) in self.snackID_to_index.keys() for r in review_from_user)) # Check if user has reviewed at least 10 snacks! user_review_at_least_10 = len(review_from_user) >= 10 num_remaining = num_snacks if user_review_at_least_10 and user_is_trained and snacks_are_trained: """ Need to ignore irrelevant snacks to make the correct recommendation!""" # User index in the model matrix user_idx = self.userID_to_index[user_id] # Get idx of all snacks the current user already reviewed (to be removed) snacks_idx_already_reviewed = set( self.snackID_to_index.get(str(r["snack_id"])) for r in review_from_user) snacks_idx_already_reviewed = filt_none( snacks_idx_already_reviewed) # Get idx of all snacks from the current country snacks_idx_current_country = set( self.snackID_to_index.get(str(s.id)) for s in snacks_in_current_country) snacks_idx_current_country = filt_none(snacks_idx_current_country) # Snacks with no image don't go to recommendation :) snacks_without_image = set( self.snackID_to_index.get(str(s.id)) for s in snacks_in_current_country if not s.photo_files) snacks_without_image = filt_none(snacks_without_image) # The snacks to be KEPT in the matrix is the set difference of them: to_be_kept = np.array( list((snacks_idx_current_country - snacks_idx_already_reviewed) - snacks_without_image)) # To recommend, we will sort all snacks which are 'to_be_kept': # Snacks which are not reviewed by the current user, but are from the same country if len(to_be_kept) != 0: temp_argindex_from_country = np.argsort( self.recc[user_idx][to_be_kept])[::-1] recommended_snacks_from_country = to_be_kept[ temp_argindex_from_country] recommended_snacks_from_country = [ self.index_to_snackID[s_idx] for s_idx in recommended_snacks_from_country ] # FROM HERE, I have list of snack ids: e.g. [qsduaiu12312. 12en1j23u12o] recommended_snacks_from_country = Snack.objects( Q(id__in=recommended_snacks_from_country)) # Finally, generate the user snack recommendation! calculated_recommendation = list( recommended_snacks_from_country[:num_snacks]) num_remaining = num_snacks - len(calculated_recommendation) # If we need to get more snacks to recommend, get from outside_country if num_remaining > 0: snacks_without_image = set( self.snackID_to_index.get(str(s.id)) for s in Snack.objects if not s.photo_files) snacks_without_image = filt_none(snacks_without_image) # Snacks which are not reviewed by the current user, but are not bound by the country to_be_kept_other_countries = set(range( self.index_snack)) - snacks_idx_already_reviewed to_be_kept_other_countries = np.array( list(to_be_kept_other_countries - snacks_without_image)) if len(to_be_kept_other_countries) != 0: temp_argindex_outside_country = np.argsort( self.recc[user_idx][to_be_kept_other_countries])[::-1] recommended_snacks_outside_country = to_be_kept_other_countries[ temp_argindex_outside_country] recommended_snacks_outside_country = [ self.index_to_snackID[s_idx] for s_idx in recommended_snacks_outside_country ] recommended_snacks_outside_country = Snack.objects( Q(id__in=recommended_snacks_outside_country)) calculated_recommendation += list( recommended_snacks_outside_country[:num_remaining]) return calculated_recommendation else: if not user_is_trained or not snacks_are_trained: msgs.append( "your recommendations aren't ready yet, check these snacks instead!" ) elif not user_review_at_least_10: msgs.append( f"your need to review at least {10 - len(review_from_user)} more snacks to get recommendations!" ) # If we have enough snacks from the current country, just return best snacks from current country if len(snacks_in_current_country) >= num_snacks: return rnd.sample(list(snacks_in_current_country), num_snacks) else: # Not enough snacks in current country calculated_recommendation = list(snacks_in_current_country) num_remaining = num_snacks - len(calculated_recommendation) # We need to get 'num_remaining' more snacks to recomend to the user, from other countries snacks_notin_current_country = Snack.objects( Q(available_at_locations__nin=[country])) # Concatenate both lists and return them return calculated_recommendation + rnd.sample( list(snacks_notin_current_country), num_remaining)
def find_reviews_for_snack(filters): """ Find all reviews given filter For overall rating, and the metrics, all reviews with greater or equal to the given value will be returned Results currently ordered by descending overall rating /snack_reviews/snack_id=abc+overall_rating=3... """ print(f"FILTER IN FIND_REVIEWS {filters}\n", file=sys.stdout) all_filters = filters.split("+") print(f"{all_filters}\n", file=sys.stdout) queryset = Review.objects snack_query = None reviewed = False # all reviews will be returned if nothing specified if "=" in filters: for individual_filter in all_filters: this_filter = individual_filter.split("=") query_index = this_filter[0] query_value = this_filter[1] if query_index == "user_id": queryset = queryset.filter(user_id=query_value) elif query_index == "snack_id": queryset = queryset.filter(snack_id=query_value) snack_query = Snack.objects(id=query_value) elif query_index == "overall_rating": queryset = queryset.filter(overall_rating__gte=query_value) elif query_index == "geolocation": queryset = queryset.filter(geolocation=query_value) elif query_index == "sourness": queryset = queryset.filter(sourness__gte=query_value) elif query_index == "spiciness": queryset = queryset.filter(spiciness__gte=query_value) elif query_index == "bitterness": queryset = queryset.filter(bitterness__gte=query_value) elif query_index == "sweetness": queryset = queryset.filter(sweetness__gte=query_value) elif query_index == "saltiness": queryset = queryset.filter(saltiness__gte=query_value) num_reviews_to_display = 15 # Display a maximum 'num_reviews_to_display' queryset = queryset.order_by("-description", "-overall_rating") print(f"snack_reviews: {queryset}", file=sys.stdout) print(f"snack_reviews: {snack_query}", file=sys.stdout) review_form = CreateReviewForm(request.form) if current_user.is_authenticated: print(len(queryset.filter(user_id=current_user.id))) if len(queryset.filter(user_id=current_user.id)): reviewed = True # Get best and worst reviews! queryset_list = list(queryset) if len(queryset_list) >= 2 * int(1 + num_reviews_to_display / 2): # If we have enough reviews, divide queryset_list = queryset_list[:int(1 + num_reviews_to_display / 2)] + queryset_list[::-1][:int( 1 + num_reviews_to_display / 2)] else: # Just get whatever we can from the best queryset_list = queryset_list[:num_reviews_to_display] # Return results in a table, the metrics such as sourness are not displayed because if they are null, they give # the current simple front end table an error, but it is there for use # Finds reviewers first and last name using their ids # Stored in username as first_name + last_name usernames = {} users = User.objects for review in queryset_list[:num_reviews_to_display]: user_id = review.user_id user = users.with_id(user_id) usernames[user_id] = user.first_name + " " + user.last_name context_dict = { "title": "Delicious Snack", "form": review_form, "query": snack_query, "num_reviews_to_display": num_reviews_to_display, "reviews": queryset_list, "reviewed": reviewed, "usernames": usernames, "user": current_user } return render_template('reviews_for_snack.html', **context_dict)
def create_review(snack): # check authenticated if not current_user.is_authenticated: return redirect(url_for('index')) print(f"is_authenticated\n", file=sys.stdout) review_form = CreateReviewForm(request.form) # post to db if request.method == "POST": user_id = current_user.id snack_id = snack.split('=')[1] snackObject = Snack.objects(id=snack_id) saltiness_review = request.form['saltiness'] sweetness_review = request.form['sweetness'] spiciness_review = request.form['spiciness'] bitterness_review = request.form['bitterness'] sourness_review = request.form['sourness'] overall_rating_review = request.form['overall_rating'] # check if metric review if saltiness_review == 0 and sourness_review == 0 and spiciness_review == 0 \ and bitterness_review == 0 and sweetness_review == 0: try: # user_id comes from current_user # snack_id should come from request sent by frontend # geolocation is found by request new_review = Review(user_id=user_id, snack_id=snack_id, description=request.form['description'], geolocation=request.form['review_country'], overall_rating=overall_rating_review) new_review.save() avg_overall_rating = Review.objects.filter( snack_id=snack_id).average('overall_rating') snackObject.update(set__avg_overall_rating=avg_overall_rating) review_count = snackObject[0].review_count + 1 snackObject.update(set__review_count=review_count) if review_count > 10: snackObject.update(set__is_verified=True) snackObject.update(add_to_set__available_at_locations=request. form['review_country']) except Exception as e: raise Exception( f"Error {e}. \n Couldn't add review {new_review},\n with following review form: {review_form}" ) print(f"A new user submitted the review form: {user_id}", file=sys.stdout) return redirect(url_for('find_reviews_for_snack', filters=snack)) else: try: # user_id comes from current_user # snack_id should come from request sent by frontend # geolocation is found by request snack_metric_review = MetricReview( user_id=user_id, snack_id=snack_id, description=request.form['description'], geolocation=request.form['review_country'], overall_rating=overall_rating_review, sourness=sourness_review, spiciness=spiciness_review, saltiness=saltiness_review, bitterness=bitterness_review, sweetness=sweetness_review) snack_metric_review.save() avg_overall_rating = Review.objects.filter( snack_id=snack_id).average('overall_rating') avg_sourness = Review.objects.filter \ (Q(snack_id=snack_id) & Q(sourness__exists=True)).average("sourness") avg_spiciness = Review.objects.filter \ (Q(snack_id=snack_id) & Q(spiciness__exists=True)).average("spiciness") avg_bitterness = Review.objects.filter \ (Q(snack_id=snack_id) & Q(bitterness__exists=True)).average("bitterness") avg_sweetness = Review.objects.filter \ (Q(snack_id=snack_id) & Q(sweetness__exists=True)).average("sweetness") avg_saltiness = Review.objects.filter \ (Q(snack_id=snack_id) & Q(saltiness__exists=True)).average("saltiness") snackObject.update(set__avg_overall_rating=avg_overall_rating) snackObject.update(set__avg_sourness=avg_sourness) snackObject.update(set__avg_spiciness=avg_spiciness) snackObject.update(set__avg_bitterness=avg_bitterness) snackObject.update(set__avg_sweetness=avg_sweetness) snackObject.update(set__avg_saltiness=avg_saltiness) review_count = snackObject[0].review_count + 1 snackObject.update(set__review_count=review_count) if review_count > 10: snackObject.update(set__is_verified=True) snackObject.update(add_to_set__available_at_locations=request. form['review_country']) except Exception as e: raise Exception( f"Error {e}. \n Couldn't add metric review {snack_metric_review},\n with following review form: {review_form}" ) print(f"A new user submitted the review form: {user_id}", file=sys.stdout) return redirect(url_for('find_reviews_for_snack', filters=snack)) context_dict = { "title": "Create Review", "form": review_form, "user": current_user } # frontend stuff return render_template("reviews_for_snack.html", **context_dict)
def create_snack(selected_brand): # Get snacks from the database. if current_user.is_authenticated: print(f"User is authenticated", file=sys.stdout) create_snack_form = CreateSnackForm(request.form) parts = selected_brand.split("=") selected_brand = "" if len(parts) == 2: selected_brand = parts[1] print(selected_brand) if request.method == "POST": snack_brand = request.form['snack_brand'] snack_name = request.form['snack_name'] try: photo = None file = request.files['file'] filename = secure_filename(file.filename) if filename != "": file.save(os.path.join(UPLOAD_FOLDER, filename)) # This works! with open(os.path.join(UPLOAD_FOLDER, filename), "rb") as image_file: photo = SnackImage() photo.img.put(os.path.join(UPLOAD_FOLDER, filename), filename=filename) new_snack = Snack( snack_name=request.form['snack_name'], available_at_locations=[ request.form['available_at_locations'] ], snack_brand=request.form['snack_brand'], category=request.form['category'], description=request.form['description'], is_verified=hasattr(current_user, 'company_name'), avg_overall_rating=0, avg_sourness=0, avg_spiciness=0, avg_bitterness=0, avg_sweetness=0, avg_saltiness=0, review_count=0, ) if photo: new_snack.photo_files.append(photo) new_snack.save() snack = "snack_id=" + str(new_snack.id) except Exception as e: raise Exception( f"Error {e}. \n Couldn't add a new snack,\n with following creation form: {create_snack_form}" ) # Make the server generate a new countries list when a new snack is added (it will be generated when a user acces index) if request.form['available_at_locations'] not in COUNTRIES_LIST: ALREADY_GENERATED = False print( f"A new snack submitted the creation form: {snack_brand} => {snack_name}", file=sys.stdout) response = make_response(json.dumps(snack)) response.status_code = 200 print(f"{response}", file=sys.stdout) return response # For frontend purposes context_dict = { "title": "Add Snack", "selected_snack_brand": selected_brand, "form": create_snack_form, "user": current_user } return render_template("create_snack.html", **context_dict) else: # Go back to index if not authenticated return redirect(url_for('index'))
def find_reviews_for_snack(filters): """ Find all reviews given filter For overall rating, and the metrics, all reviews with greater or equal to the given value will be returned Results currently ordered by descending overall rating /snack_reviews/snack_id=abc+overall_rating=3... """ all_filters = filters.split("+") print(f"{all_filters}\n", file=sys.stdout) queryset = Review.objects snack_query = None reviewed = False verified = False # all reviews will be returned if nothing specified if "=" in filters: for individual_filter in all_filters: this_filter = individual_filter.split("=") query_index = this_filter[0] query_value = this_filter[1] if query_index == "user_id": queryset = queryset.filter(user_id=query_value) elif query_index == "snack_id": queryset = queryset.filter(snack_id=query_value) snack_query = Snack.objects(id=query_value) if Snack.objects(id=query_value)[0].is_verified: verified = True elif query_index == "overall_rating": queryset = queryset.filter(overall_rating__gte=query_value) elif query_index == "geolocation": queryset = queryset.filter(geolocation=query_value) elif query_index == "sourness": queryset = queryset.filter(sourness__gte=query_value) elif query_index == "spiciness": queryset = queryset.filter(spiciness__gte=query_value) elif query_index == "bitterness": queryset = queryset.filter(bitterness__gte=query_value) elif query_index == "sweetness": queryset = queryset.filter(sweetness__gte=query_value) elif query_index == "saltiness": queryset = queryset.filter(saltiness__gte=query_value) queryset = queryset.order_by("-overall_rating") print(f"snack_reviews: {queryset}", file=sys.stdout) print(f"snack_reviews: {snack_query}", file=sys.stdout) review_form = CreateReviewForm(request.form) if current_user.is_authenticated: if len(queryset.filter(user_id=current_user.id)): reviewed = True # Return results in a table, the metrics such as sourness are not displayed because if they are null, they give # the current simple front end table an error, but it is there for use context_dict = { "title": "Delicious Snack", "form": review_form, "query": snack_query, "reviews": queryset, "reviewed": reviewed, "verified": verified, "user": current_user } return render_template('reviews_for_snack.html', **context_dict)
def add_snacks(): return "nothing to add" # Open database and parse json my_database = mongo[DATABASE] my_file = open("snacks/snacks.json", "rb") parsed = json.loads(my_file.read().decode('unicode-escape')) snacks = parsed s = snacks # For demonstration purposes, this delete every entry in the Snack collection # Snack.objects.delete() for s in snacks: new_snack = Snack(snack_name=s["title"], available_at_locations=[s["country"]]) if s.get("description"): new_snack.description = s["description"] if s.get("company"): new_snack.snack_brand = s["company"] else: continue new_snack.avg_overall_rating = 0 new_snack.avg_bitterness = 0 new_snack.avg_saltiness = 0 new_snack.avg_sourness = 0 new_snack.avg_spiciness = 0 new_snack.avg_sweetness = 0 new_snack.review_count = 0 # Insert images read from folder (snacks/image/snack_name) if s.get("folder_name"): i = SnackImage() for entry in os.scandir("snacks/image/" + s.get("folder_name")): with open(entry.path, "rb") as image_file: img_name = os.path.basename(image_file.name) i.img.put(image_file, filename=img_name) new_snack.photo_files.append(i) # Save the new snacks into the database try: new_snack.save() except Exception as e: print("Error \n %s" % e, file=sys.stdout) # Retrieving snacks from database max_show = 100 # Maximum number of snacks to send to view sl = [] for s in Snack.objects[:max_show]: if s.photo_files: sl.append(s) for file in s.photo_files: photo = file.img # Guess the type of the mimetype to send a good response # mimetype = mimetypes.MimeTypes().guess_type(photo.filename)[0] # resp=Response(photo.read(), mimetype=mimetype) # photo.read() # This is image itself # photo.filename # This is the name of the image # photo.format # This is the format of the image (png, jpg, etc) # photo.thumbnail.read() # This is the thumbnail of the image print("Finished.") print(f"{len(sl)}") return str(sl[:10])