diff --git a/main.py b/main.py index d49c7e5..c22931f 100644 --- a/main.py +++ b/main.py @@ -3,5 +3,56 @@ Portfolio Project for CS361 Spring 2022 Written by Lucas Jensen Last updated 3/29/22 for Assignment 1 """ +import json +from flask import Flask, redirect, flash, render_template, request, jsonify +from markupsafe import escape -print("Hello, CS361!") +from recipe import Recipe, RecipeBook, open_json + +app = Flask(__name__) + + +@app.route("/") +def home(): + return render_template("index.html") + + +@app.route('/recipes', methods=['GET']) +def ReturnJSON(): + return render_template("recipe.html", content=open_json()) + + +@app.route('/recipes/<_id>', methods=['GET']) +def recipe_page(_id): + if request.method == 'GET': + # recipe = book.find_by_id(int(_id)) + # return jsonify(recipe.get_recipe()) + recipe = open_json()[_id] + return recipe + + +@app.route('/add', methods=['GET', 'POST']) +def add_recipe(): + if request.method == "POST": + flour = request.form.get("flour_weight") + water = request.form.get("water_weight") + salt = request.form.get("salt_weight") + loaves = request.form.get("yield") + name = request.form.get("name") + + new_recipe = Recipe(name, loaves, flour, water, salt) + book.add_recipes(new_recipe) + + # flash("Recipe Added!") + return redirect("/recipes") + return render_template("new.html") + + +if __name__ == "__main__": + # testing + # recipes = default_recipes() + book = RecipeBook() + # for recipe in recipes: + # book.add_recipes(recipe) + + app.run(debug=True) diff --git a/recipe.py b/recipe.py new file mode 100644 index 0000000..f406aca --- /dev/null +++ b/recipe.py @@ -0,0 +1,179 @@ +""" +Written by Lucas Jensen +Portfolio Project for CS361 +The main logic behind a recipe +""" +import json + + +class RecipeBook: + """ + Represents a recipe book containing several bread recipes + """ + def __init__(self): + self._count = 0 + self._recipes = {} + + def add_recipes(self, recipe: object) -> None: + """ + Adds a recipe to the book + :param recipe: bread recipe object + :return: nothing + """ + keys = open_json() + for key in keys: + if int(key) > self._count: + self._count = int(key) + self._count += 1 + self._recipes[self._count] = recipe + self.save(self._count, recipe) + # self._count += 1 + + def get_recipes(self) -> list: + """ + get the dict of recipes + :return: the dict of recipes + """ + return self._recipes + + def find_by_id(self, _id: int) -> object: + """ + Finds a recipe object by its assigned id + :param _id: int, the id of the recipe + :return: recipe object + """ + return self._recipes[_id] + + def save(self, _id: int, recipe: object) -> None: + """ + Saves a recipe to the JSON file + :param _id: int + :return: nothing + """ + a_dict = {str(_id): recipe.get_recipe()} + + with open('recipes/recipes.json') as f: + data = json.load(f) + + data.update(a_dict) + + with open('recipes/recipes.json', 'w') as f: + json.dump(data, f) + + +class Recipe: + """ + Represents a bread recipe + """ + def __init__(self, name, num_loaves, ap_flour, water, salt): + self._name = name + self._num_loaves = num_loaves + self._ingredients = { + 'ap_flour': ap_flour, + 'water': water, + 'salt': salt + } + + def get_name(self) -> str: + """ + Gets the name of a recipe + :return: + """ + return self._name + + def get_recipe(self) -> dict: + """ + :return: returns the whole recipe as a dict, including quantity + """ + recipe_dict = { + 'quantity': self._num_loaves, + 'name': self._name + } + + for ingredient in self._ingredients: + recipe_dict[ingredient] = self._ingredients[ingredient] + + return recipe_dict + + def get_num_loaves(self) -> int: + """ + :return: int: number of loaves the recipe calls for + """ + return self._num_loaves + + def get_ingredients(self) -> dict: + """ + :return: dictionary of all ingredients + """ + return self._ingredients + + def add_ingredient(self, name: str, mass: int) -> None: + """ + Adds an ingredient to the recipe. Mass in grams. + :param name: string, the name of the ingredient + :param mass: int, the mass of the ingredient, in grams + :return: + """ + self._ingredients[name] = mass + + def scale(self, new_num: int) -> object: + """ + Scales the recipe by a given factor + :param new_num: integer, the number of desired loaves + :return: Recipe object, now scaled + """ + scale = new_num / self._num_loaves + + ap_flour = self._ingredients['ap_flour'] * scale + water = self._ingredients['water'] * scale + salt = self._ingredients['salt'] * scale + name = f"{self._name} * {scale}" + + scaled_recipe = Recipe(name, new_num, ap_flour, water, salt) + + for ingredient in self._ingredients: + if ingredient not in ['ap_flour', 'water', 'salt']: + mass = self._ingredients[ingredient] * scale + scaled_recipe.add_ingredient(ingredient, mass) + + return scaled_recipe + + +def build_recipe(infile) -> None: + """ + Builds a recipe object from a JSON file + :param infile: filename + :return: nothing + """ + # TODO + pass + + +def default_recipes(): + recipe_1 = Recipe('Country Brown', 1, 600, 300, 13) + recipe_2 = Recipe('Conventional White', 2, 1000, 700, 25) + recipe_3 = recipe_2.scale(4) + + return [recipe_1, recipe_2, recipe_3] + + +def open_json(): + """TODO""" + with open('recipes/recipes.json') as json_file: + data = json.load(json_file) + + return data + + +if __name__ == "__main__": + recipes = default_recipes() + book = RecipeBook() + for recipe in recipes: + book.add_recipes(recipe) + + for recipe in book.get_recipes(): + print(book.get_recipes()[recipe]) + + rec = Recipe('sandwich loaf', 2, 1000, 700, 25) + rec.add_ingredient('ww flour', 500) + # rec.save('recipes.json') diff --git a/recipes/recipes.json b/recipes/recipes.json new file mode 100644 index 0000000..a22dd1a --- /dev/null +++ b/recipes/recipes.json @@ -0,0 +1 @@ +{"0": {"quantity": "1", "name": "bread", "ap_flour": "1", "water": "1", "salt": "1"}, "1": {"quantity": 2, "name": "Conventional White", "ap_flour": 1000, "water": 700, "salt": 25}, "2": {"quantity": 4, "name": "Conventional White * 2.0", "ap_flour": 2000.0, "water": 1400.0, "salt": 50.0}, "3": {"quantity": "1", "name": "sourdough", "ap_flour": "100", "water": "1001", "salt": "1001"}, "4": {"quantity": "11", "name": "milk", "ap_flour": "10101", "water": "10", "salt": "10"}, "5": {"quantity": "1", "name": "white", "ap_flour": "100", "water": "50", "salt": "2"}} \ No newline at end of file diff --git a/static/favicon-16x16.png b/static/favicon-16x16.png new file mode 100644 index 0000000..c7530e9 Binary files /dev/null and b/static/favicon-16x16.png differ diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..3ef29eb --- /dev/null +++ b/static/style.css @@ -0,0 +1,62 @@ +body { + margin: 0; + text-align: left; + font-family: 'Akshar', sans-serif; + background-color: slategray; + color: cornsilk; +} + +a { + color: lightblue; +} + +a:visited { + color: lightblue; +} + +a:hover { + color: lightskyblue; +} + +h1 { + margin-left: 10px; +} + +p { + margin-left: 10px; +} + +#footer { + margin-left: 10px; + position: absolute; +} + +nav ul { + list-style-type: none; + margin: 0; + padding: 0; + overflow: hidden; + background-color: #333; +} + +.nav { + float: left; +} + +.nav a { + display: block; + color: white; + text-align: center; + padding: 14px 16px; + text-decoration: none; + color: cornsilk; +} + +/* Change the link color to #111 (black) on hover */ +.nav a:hover { + background-color: #111; +} + +ul { + list-style-type: none; +} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..3f2120d --- /dev/null +++ b/templates/base.html @@ -0,0 +1,29 @@ + + +
+ + + + +Add, scale, and convert all your bread recipes here.
+ +{% endblock %} \ No newline at end of file diff --git a/templates/new.html b/templates/new.html new file mode 100644 index 0000000..2c033b5 --- /dev/null +++ b/templates/new.html @@ -0,0 +1,30 @@ +{% extends "base.html" %} +{% block title %}Add Recipe{% endblock %} + +{% block html_head %} + +{% endblock %} + +{% block content %} + +