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'))
Esempio n. 2
0
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)
Esempio n. 3
0
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
Esempio n. 4
0
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'))
Esempio n. 5
0
    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)
Esempio n. 6
0
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)
Esempio n. 7
0
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)
Esempio n. 8
0
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])