def get(self, username=None): """ Render the public recipe list for a user or all users. """ show_owners = False if username: publicuser = UserPrefs.all().filter('name =', username).get() recipes = Recipe.all()\ .filter('owner =', publicuser)\ .order('-grade') def setowner(recipe): recipe.owner = publicuser return recipe recipes = map(setowner, recipes) else: publicuser = None recipes = Recipe.all().order('-grade') recipes = [r for r in recipes] show_owners = True self.render('recipes.html', { 'publicuser': publicuser, 'recipes': recipes, 'show_owners': show_owners })
def get_recipes(self, request): """ Get a list of recipes, optionally filtered by user name. """ offset, limit = get_limits(request) if request.user_name: publicuser = UserPrefs.all().filter('name =', request.user_name).get() if not publicuser: raise endpoints.NotFoundException(USER_NOT_FOUND) query = Recipe.all()\ .filter('owner =', publicuser) else: query = Recipe.all() if request.order == apimessages.RecipeOrder.NAME: query = query.order('name') elif request.order == apimessages.RecipeOrder.CREATED: query = query.order('-created') elif request.order == apimessages.RecipeOrder.EDITED: query = query.order('-edited') elif request.order == apimessages.RecipeOrder.LIKES: query = query.order('-likes_count') recipes = query.fetch(limit, offset=offset) items = [] for recipe in recipes: items.append(recipe_to_response(recipe)) return apimessages.RecipeListResponse(**{ 'items': items })
def get(self, username): """ Render a user page. """ publicuser = UserPrefs.all().filter('name =', username).get() if not publicuser: self.abort(404) recipes = Recipe.all()\ .filter('owner =', publicuser)\ .order('name')\ .run(limit=25) actions = UserAction.all()\ .filter('owner =', publicuser)\ .order('-created')\ .fetch(15) object_ids = UserAction.gather_object_ids(actions) user_map = { publicuser.key().id(): publicuser } for user in UserPrefs.get_by_id(object_ids['users']): user_map[user.key().id()] = user recipes = [r for r in recipes] recipe_ids = [recipe.key().id() for recipe in recipes] object_ids['recipes'] = [id for id in object_ids['recipes'] if id not in recipe_ids] recipe_map = {} for recipe in recipes: recipe.owner = publicuser recipe_map[recipe.key().id()] = recipe for recipe in Recipe.get_by_id(object_ids['recipes']): recipe_map[recipe.key().id()] = recipe brew_map = {} for brew in Brew.get_by_id(object_ids['brews']): brew_map[brew.key().id()] = brew self.render('user.html', { 'publicuser': publicuser, 'recipes': recipes, 'actions': actions, 'user_map': user_map, 'recipe_map': recipe_map, 'brew_map': brew_map })
def test_parse_incomplete_ingredients(self): s = textwrap.dedent("""\ 2 cup 3 tbsp rice""") result = Recipe.parse_ingredients(s) self.assertEqual(len(result), 1)
def process(self, username=None, recipe_slug=None, brew_slug=None): publicuser = UserPrefs.all()\ .filter('name =', username)\ .get() if not publicuser: return [None, None, None] recipe = Recipe.all()\ .filter('owner =', publicuser)\ .filter('slug = ', recipe_slug)\ .get() if not recipe: return [publicuser, None, None] if brew_slug is not None: brew = Brew.all()\ .filter('owner =', publicuser)\ .filter('recipe =', recipe)\ .filter('slug =', brew_slug)\ .get() if not brew: return [publicuser, recipe, None] else: brew = Brew() brew.owner = self.user brew.recipe = recipe return [publicuser, recipe, brew]
def get(self, username, recipe_slug): publicuser = UserPrefs.all().filter('name = ', username).get() if publicuser: recipe = Recipe.all()\ .filter('owner =', publicuser)\ .filter('slug =', recipe_slug)\ .get() else: recipe = None width = 260 try: width = int(self.request.get('width')) except: pass if publicuser and recipe: self.render('recipe-embed.html', { 'publicuser': publicuser, 'recipe': recipe, 'width': width, }) else: self.render('recipe-embed-404.html', { 'publicuser': publicuser, 'width': width, })
def generate_usable_slug(recipe): """ Generate a usable slug for a given recipe. This method will try to slugify the recipe name and then append an integer if needed, increasing this integer until no existing recipe would be overwritten. """ slug = slugify(recipe.name) # Reuse existing slug if we can if recipe.slug and recipe.slug == slug: return recipe.slug append = 0 while True: count = Recipe.all()\ .filter('owner =', recipe.owner)\ .filter('slug =', slug)\ .count() if not count: break append += 1 slug = slugify(recipe.name) + str(append) return slug
def object(self): if self.type in [self.TYPE_USER_FOLLOWED]: return UserPrefs.get_by_id(self.object_id) elif self.type in [self.TYPE_RECIPE_CREATED, self.TYPE_RECIPE_EDITED, self.TYPE_RECIPE_CLONED, self.TYPE_RECIPE_LIKED]: from models.recipe import Recipe return Recipe.get_by_id(self.object_id)
def recent_recipes(): page = request.args.get('page', default=1, type=int) limit = 8 recipes, page_count, recipe_count = Recipe.load_recipes(g.current_user, page=page, limit=limit) return render_template('recipes.html', recipes=recipes, page_count=page_count, page=page, current_query_params={})
def recipe(recipe_id=None): if recipe_id: recipe = Recipe.load_recipe(long(recipe_id), g.current_user) if recipe: return render_template('recipe.html', recipe=recipe) else: abort(404) else: abort(404)
def favorites(): page = request.args.get('page', default=1, type=int) limit = 16 recipes, page_count, recipe_count = Recipe.load_recipes(g.current_user, page=page, limit=limit, order_by='saved.saved_at DESC', join=['saved']) return render_template('recipes.html', recipes=recipes, page_count=page_count, page=page, current_query_params={})
def test_parse_steps(self): s = textwrap.dedent("""\ Do something Do something else You are done""") expected_result = [ {'step': 'Do something'}, {'step': 'Do something else'}, {'step': 'You are done'}] result = Recipe.parse_steps(s) self.assertEqual(result, expected_result)
def test_parse_ingredients(self): s = textwrap.dedent("""\ 1 oz cardimom 2 cup flour 3 tbsp rice""") expected_result = [ {'name': 'cardimom', 'unit': 'oz', 'quantity': '1'}, {'name': 'flour', 'unit': 'cup', 'quantity': '2'}, {'name': 'rice', 'unit': 'tbsp', 'quantity': '3'}] result = Recipe.parse_ingredients(s) self.assertEqual(result, expected_result)
def get(self, username, recipe_slug): publicuser = UserPrefs.all().filter('name = ', username).get() if not publicuser: self.abort(404) recipe = Recipe.all()\ .filter('owner =', publicuser)\ .filter('slug =', recipe_slug)\ .get() if not recipe: self.abort(404) self.render_xml(recipe.beerxml)
def highest_rated_recipes(): page = request.args.get('page', default=1, type=int) limit = 8 recipes, page_count, recipe_count = Recipe.load_recipes(g.current_user, page=page, limit=limit, order_by='avg_ratings.avg_rating DESC', join=['avg_ratings'], where=['avg_ratings.avg_rating IS NOT NULL', 'avg_ratings.avg_rating >=3']) return render_template('recipes.html', recipes=recipes, page_count=page_count, page=page, current_query_params={})
def top_interesting_recipes(self): """ Get a list of the top recipes that are interesting for this user, meaning that either the recipes belong to this user or any user that she is following. The list is ranked by the number of likes that each recipe has. """ from models.recipe import Recipe following = self.following_users.run(batch_size=100) return Recipe.all()\ .filter('owner IN', [self] + list(following))\ .order('-likes_count')\ .fetch(15)
def post(self, username=None, recipe_slug=None): publicuser = UserPrefs.all()\ .filter('name = ', username)\ .get() if not publicuser: self.render_json({ 'status': 'error', 'error': 'User not found' }) return recipe = Recipe.all()\ .filter('owner =', publicuser)\ .filter('slug =', recipe_slug)\ .get() if not recipe: self.render_json({ 'status': 'error', 'error': 'Recipe not found' }) return new_recipe = Recipe(**{ 'owner': UserPrefs.get(), 'cloned_from': recipe, 'color': recipe.color, 'ibu': recipe.ibu, 'alcohol': recipe.alcohol, 'name': recipe.name, 'description': recipe.description, 'type': recipe.type, 'style': recipe.style, 'batch_size': recipe.batch_size, 'boil_size': recipe.boil_size, 'bottling_temp': recipe.bottling_temp, 'bottling_pressure': recipe.bottling_pressure, '_ingredients': recipe._ingredients }) new_recipe.slug = generate_usable_slug(new_recipe) new_recipe.put() action = UserAction() action.owner = UserPrefs.get() action.type = action.TYPE_RECIPE_CLONED action.object_id = new_recipe.key().id() action.put() return self.render_json({ 'status': 'ok', 'redirect': new_recipe.url })
def delete(self, username=None, recipe_slug=None): """ Handle recipe delete. This will remove a recipe and return success or failure. """ user = self.user if not user: self.render_json({ 'status': 'error', 'error': 'User not logged in' }) recipe = Recipe.all()\ .filter('slug = ', recipe_slug)\ .filter('owner =', user)\ .get() if recipe: # Delete all actions pointing to this recipe actions = UserAction.all()\ .filter('type IN', [UserAction.TYPE_RECIPE_CREATED, UserAction.TYPE_RECIPE_EDITED, UserAction.TYPE_RECIPE_CLONED, UserAction.TYPE_RECIPE_LIKED])\ .filter('object_id =', recipe.key().id())\ .fetch(1000) for action in actions: action.delete() # Delete the actual recipe itself recipe.delete() self.render_json({ 'status': 'ok', 'redirect': '/users/%(username)s/recipes' % { 'username': user.name } }) else: self.render_json({ 'status': 'error', 'error': 'Unable to delete recipe' })
def get_recipe(self, request): """ Get a recipe by user name and recipe slug. """ publicuser = UserPrefs.all().filter('name =', request.user_name).get() if not publicuser: raise endpoints.NotFoundException(USER_NOT_FOUND) recipe = Recipe.all()\ .filter('owner =', publicuser)\ .filter('slug =', request.slug)\ .get() if not recipe: raise endpoints.NotFoundException(RECIPE_NOT_FOUND) return recipe_to_response(recipe)
def get(self): """ Render the index page. Currently this renders a 'Coming soon' landing page that will eventually be replaced with a proper home page. """ # Try to get recipes list from memcache instead of datastore recipes_html = memcache.get('index-recipes') if not recipes_html or settings.DEBUG: # No such luck... query the data store recipes = Recipe.all()\ .order('-grade')\ .run(limit=15) recipes_html = self.render('index-recipes.html', { 'recipes': recipes }, write_to_stream=False) memcache.set('index-recipes', recipes_html, self.CACHE_TIME) self.render('index.html', { 'recipes_html': recipes_html })
def search_results(query=''): page = request.args.get('page', default=1, type=int) limit = 8 where_clause = "recipes.name ILIKE '%%%%%s%%%%'" % adapt(str(query.replace('+','%%'))).getquoted()[1:-1] start_time = timer() recipes, page_count, recipe_count = Recipe.load_recipes(g.current_user, page=page, limit=limit, where=[where_clause]) end_time = timer() natural_search_string = ' '.join(query.split('+')) return render_template('recipes.html', recipes=recipes, page_count=page_count, page=page, current_query_params={'query':query}, search_string=natural_search_string, success="We found %i result%s for '%s' (%.4f seconds)" % (recipe_count, ('s' if recipe_count != 1 else ''), natural_search_string, end_time - start_time))
def post(self): """ Import a new recipe or list of recipes from BeerXML to the currently logged in user's account. """ user = self.user recipesxml = self.request.POST['file'].value for recipe in Recipe.new_from_beerxml(recipesxml): recipe.owner = user recipe.slug = generate_usable_slug(recipe) recipe.update_cache(); key = recipe.put() action = UserAction() action.owner = user action.object_id = key.id() action.type = action.TYPE_RECIPE_CREATED action.put() self.redirect('/users/' + user.name + '/recipes')
def put(self, recipe_id): json_data = request.get_json() recipe = Recipe.get_by_id(recipe_id=recipe_id) if recipe is None: return {'message': 'Recipe not found'}, HTTPStatus.NOT_FOUND current_user = get_jwt_identity() if current_user != recipe.user_id: return {'message': 'Access is not allowed'}, HTTPStatus.FORBIDDEN recipe.name = json_data['name'] recipe.description = json_data['description'] recipe.num_of_servings = json_data['num_of_servings'] recipe.cook_time = json_data['cook_time'] recipe.directions = json_data['directions'] recipe.save() return recipe.data(), HTTPStatus.OK
def get(self, username, page, per_page, visibility): user = User.get_by_username(username=username) user = User.get_by_username(username=username) if user is None: return {'message': 'User not found'}, HTTPStatus.NOT_FOUND current_user = get_jwt_identity() if current_user == user.id and visibility in ['all', 'private']: pass else: visibility = 'public' # gets the paginated recipes by a particular author # lets recipe_pagination_schema serialize the paginated object. paginated_recipes = Recipe.get_all_by_user(user_id=user.id, page=page, per_page=per_page, visibility=visibility) return recipe_pagination_schema.dump( paginated_recipes).data, HTTPStatus.OK
def put(self, recipe_id): """ Gets the cover image in request.files and verifies whether it exists and if the file extension is permitted """ file = request.files.get('cover') if not file: return {'message': 'Not a valid image'}, HTTPStatus.BAD_REQUEST if not image_set.file_allowed(file, file.filename): return {'message': 'File type not allowed'}, HTTPStatus.BAD_REQUEST # Check whether user hs the right to modify the recipe recipe = Recipe.get_by_id(recipe_id=recipe_id) if recipe is None: return {'message': 'Recipe not found'}, HTTPStatus.NOT_FOUND current_user = get_jwt_identity() if current_user != recipe.user_id: return {'message': 'Access in not allowed'}, HTTPStatus.FORBIDDEN # If the user has the right to, we will go # ahead and modify the cover image of the recipe if recipe.cover_image: cover_path = image_set.path(folder='recipes', filename=recipe.cover_image) if os.path.exists(cover_path): os.remove(cover_path) # User the save_image function to save the uploaded image filename = save_image(image=file, folder='recipes') recipe.cover_image = filename recipe.save() clear_cache('/recipes') # clears old cache data when updated return recipe_cover_schema.dump(recipe).data, HTTPStatus.OK
def show_recipe_ingredient(cuisine_name, recipe_name): cuisine = Cuisine.get_or_none(name=cuisine_name) if cuisine: recipe = Recipe.get_or_none(name=recipe_name) if recipe: if recipe.cuisine_id == cuisine.id: ingredient = RecipeIngredient.select().where( RecipeIngredient.recipe_id == recipe.id) results = [] for i in ingredient: ingredient_data = {"name": i.name, "quantity": i.quantity} results.append(ingredient_data) return jsonify({"data": results}) else: return jsonify({ "errors": recipe_name + " is not found in " + cuisine_name + " cuisine." }) else: return jsonify({"errors": "Recipe not exists"}) else: return jsonify({"errors": cuisine_name + " cusine is not exist"})
def put(self, recipe_id): json_data = request.get_json() # recipe = next((recipe for recipe in recipe_list if recipe.id == recipe_id), None) recipe = Recipe.get_by_id(recipe_id=recipe_id) if recipe is None: return {'message': 'recipe not found'}, HTTPStatus.NOT_FOUND # we will further check whether it matches the identity of the user ID in the JWT current_user = get_jwt_identity() if current_user != recipe.user_id: return {'message': 'Access is not allowed'}, HTTPStatus.FORBIDDEN recipe.name = json_data['name'] recipe.description = json_data['description'] recipe.num_of_servings = json_data['num_of_servings'] recipe.cook_time = json_data['cook_time'] recipe.directions = json_data['directions'] recipe.save() return recipe.data, HTTPStatus.OK
def _populate_recipes(db_engine): session_maker = sessionmaker(bind=db_engine) session = session_maker() session.query(Recipe).delete() session.query(RecipeIngredient).delete() # Basic Pickaxe basic_pickaxe = Recipe(id=1, name='Basic Pickaxe') session.add(basic_pickaxe) session.query(Recipe).delete() stone_item = session.query(Item).filter(Item.name == 'stone').first() stick_item = session.query(Item).filter(Item.name == 'stick').first() basic_pickaxe_ingredient_1 = RecipeIngredient(recipe_id=basic_pickaxe.id, item=stone_item, item_amount=7) session.add(basic_pickaxe_ingredient_1) basic_pickaxe_ingredient_2 = RecipeIngredient(recipe_id=basic_pickaxe.id, item=stick_item, item_amount=4) session.add(basic_pickaxe_ingredient_2) session.commit() return
def __init__(self, data: List[dict]) -> None: """ Initializes a RecipeDatabase instance. :param data: list of recipes to store """ super().__init__() # parse the dates to store them as datetime objects for recipe in data: recipe.update({ 'created_at': parse(recipe['created_at']), 'updated_at': parse(recipe['updated_at']), }) recipes = [Recipe(**recipe_data) for recipe_data in data] # provides a constant reading & updating time self._recipes_by_id = {recipe.id: recipe for recipe in recipes} # allows an easy filtering on recipes by cuisine self._recipes_by_cuisine = defaultdict(list) for recipe in recipes: self._recipes_by_cuisine[recipe.recipe_cuisine].append(recipe)
def put(self, recipe_id): file = request.files.get('cover_image') if not file: return {'message': 'Not a valid image'}, HTTPStatus.BAD_REQUEST if not image_set.file_allowed(file, file.filename): return { 'message': 'File type not supported' }, HTTPStatus.BAD_REQUEST recipe = Recipe.get_by_id(recipe_id) if recipe is None: return {'message': 'Recipe not found'}, HTTPStatus.NOT_FOUND if recipe.user_id != get_jwt_identity(): return {'message': 'Access is not allowed'}, HTTPStatus.FORBIDDEN if recipe.cover_image: cover_image_path = image_set.path(recipe.cover_image, folder='cover_images') if os.path.exists(cover_image_path): os.remove(cover_image_path) filename = save_image(file, 'cover_images') recipe.cover_image = filename recipe.save() clear_cache('/recipes') return recipe_cover_schema.dump(recipe).data, HTTPStatus.OK
def post(self, username=None, recipe_slug=None): publicuser = UserPrefs.all()\ .filter('name = ', username)\ .get() if not publicuser: self.render_json({ 'status': 'error', 'error': 'User not found' }) return recipe = Recipe.all()\ .filter('owner =', publicuser)\ .filter('slug =', recipe_slug)\ .get() if not recipe: self.render_json({ 'status': 'error', 'error': 'Recipe not found' }) return new_recipe = Recipe(**{ 'owner': self.user, 'cloned_from': recipe, 'color': recipe.color, 'ibu': recipe.ibu, 'alcohol': recipe.alcohol, 'name': recipe.name, 'description': recipe.description, 'type': recipe.type, 'category': recipe.category, 'style': recipe.style, 'batch_size': recipe.batch_size, 'boil_size': recipe.boil_size, 'bottling_temp': recipe.bottling_temp, 'bottling_pressure': recipe.bottling_pressure, 'steep_efficiency': recipe.steep_efficiency, 'mash_efficiency': recipe.mash_efficiency, 'primary_days': recipe.primary_days, 'primary_temp': recipe.primary_temp, 'secondary_days': recipe.secondary_days, 'secondary_temp': recipe.secondary_temp, 'tertiary_days': recipe.tertiary_days, 'tertiary_temp': recipe.tertiary_temp, 'aging_days': recipe.aging_days, '_ingredients': recipe._ingredients }) new_recipe.slug = generate_usable_slug(new_recipe) new_recipe.put() new_recipe.update_grade() new_recipe.put() # Update recipe ranking for sorting recipe.update_grade() recipe.put() action = UserAction() action.owner = self.user action.type = action.TYPE_RECIPE_CLONED action.object_id = new_recipe.key().id() action.put() return self.render_json({ 'status': 'ok', 'redirect': new_recipe.url })
class RecipeTest(unittest.TestCase, Categories): """ Class performing unit testing for class Recipe""" def setUp(self): """Defining setUp() method that runs prior to each test.""" self.newRecipe = Recipe() self.newCategory = Categories() self.recipe_register = self.newRecipe.recipe_register( "category", "recipe", "*****@*****.**", "recipe_ingredients", "recipe_methods") self.newCategory.category_register("category_one", "*****@*****.**") app.config['TESTING'] = True self.test_app = app.test_client() def test_recipe_register_route(self): """ Test to check if recipe register route works""" response = self.test_app.get('/recipe_register') self.assertEqual(response.status_code, 200) def test_recipe_registration(self): """ Test for method create recipe """ recipe_success_registration = self.newRecipe.recipe_register( "category_one", "recipee", "*****@*****.**", "recipe_ingredients", "recipe_methods") self.assertEqual("successfully created recipe", recipe_success_registration) def test_recipe_regex_match(self): """ Test for recipe name regex match """ recipe_name_regex_format = self.newRecipe.recipe_register( "category", "@@@", "*****@*****.**", "recipe_ingredients", "recipe_methods") self.assertEqual("Recipe name has special characters", recipe_name_regex_format) def test_recipe_null_name(self): """ Test for null recipe name """ recipe_null_name = self.newRecipe.recipe_register( "category", "", "*****@*****.**", "recipe_ingredients", "recipe_methods") self.assertEqual("Null recipe name", recipe_null_name) def test_recipe_null_ingredients(self): """ Test for null recipe ingredients """ recipe_null_ingredients = self.newRecipe.recipe_register( "category", "recipe_name", "*****@*****.**", "", "recipe_methods") self.assertEqual("Null recipe ingredients", recipe_null_ingredients) def test_recipe_null_methods(self): """ Test for null recipe preparation methods """ recipe_null_methods = self.newRecipe.recipe_register( "category", "recipe_name", "*****@*****.**", "recipe_ingredients", "") self.assertEqual("Null recipe method", recipe_null_methods) def test_recipe_exists(self): """ Test for method if recipe exists """ recipe_exists = self.newRecipe.recipe_register("category", "recipe", "*****@*****.**", "recipe_ingredients", "recipe_methods") self.assertEqual("Recipe exists", recipe_exists) def test_recipe_edit_route(self): """ Test to check if recipe edit route works""" response = self.test_app.get('/recipe_edit/Panckakes') self.assertEqual(response.status_code, 200) def test_edit_recipe_regex_format(self): """ Test for recipe name regex pattern name on update """ edit_recipe_regex = self.newRecipe.recipe_edit("@@@", "recipe_name", "category_one", "mwaz", "recipe_ingredients", "recipe_methods") self.assertEqual("Recipe name has special characters", edit_recipe_regex) def test_edit_recipe_is_null(self): """ Test for null recipe name on update """ recipe_edit_is_null = self.newRecipe.recipe_edit( "", "categoryone", "recipe_name", "mwaz", "recipe_ingredients", "recipe_methods") self.assertEqual("Null recipe name", recipe_edit_is_null) def succss_recipe_name_edit(self): """ Test for successful recipe name on update """ recipe_edit_success = self.newRecipe.recipe_edit( "new_recipe", "categoryone", "recipe_name", "mwaz", "recipe_ingredients", "recipe_methods") self.assertEqual("Successfully edited recipe", recipe_edit_success) def test_recipe_delete_route(self): """ Test to check if recipe delete route works""" response = self.test_app.get('/recipe_delete') self.assertEqual(response.status_code, 200)
def get(self, q, page, per_page): paginated_recipes = Recipe.get_all_published(q, page, per_page) return recipe_pagination_schema.dump( paginated_recipes).data, HTTPStatus.OK
def process(self, action, username=None, recipe_slug=None): """ Process a request to add or remove a user from the liked list. """ user = UserPrefs.get() publicuser = UserPrefs.all()\ .filter('name = ', username)\ .get() if not publicuser: self.render_json({ 'status': 'error', 'error': 'User not found' }) return recipe = Recipe.all()\ .filter('owner =', publicuser)\ .filter('slug =', recipe_slug)\ .get() if not recipe: self.render_json({ 'status': 'error', 'error': 'Recipe not found' }) return if action == 'post': if user.user_id not in recipe.likes: recipe.likes.append(user.user_id) recipe.put() existing = UserAction.all()\ .filter('owner =', user)\ .filter('type =', UserAction.TYPE_RECIPE_LIKED)\ .filter('object_id =', recipe.key().id())\ .count() if not existing: user_action = UserAction() user_action.owner = user user_action.type = user_action.TYPE_RECIPE_LIKED user_action.object_id = recipe.key().id() user_action.put() elif action == 'delete': if user.user_id in recipe.likes: recipe.likes.remove(user.user_id) recipe.put() existing = UserAction.all()\ .filter('owner =', user)\ .filter('type =', UserAction.TYPE_RECIPE_LIKED)\ .filter('object_id =', recipe.key().id())\ .get() if existing: existing.delete() return self.render_json({ 'status': 'ok', 'likes': len(recipe.likes) })
def seed_database(debug=False): """ WARNING: This will NOT create the tables for you if you dropped your entire database. You must re-create the database then run 'Base.metadata.create_all(<engine>)' to create your tables then you can run this without an issue! IMPORTANT: You need to import Base from models.models or else SQLAlchemy won't know about the models and therefore will NOT create the proper tables in your database which will cause this function to fail. Create data in the database by randomly generating values. Once this function is complete, it will write data that is likely to be used in testing to the 'seeded_objects_info.txt' file with separators and linebreaks to make it easier to read. When a user instance is created, its subsequent Profile is created as well and then they are associated with one another. After the user and profile objects are created, create some recipe objects to be associated with the profile object. Leave some profile objects without any recipes for filter testing. """ if debug: # If something happened during object creation # we'll get a UNIQUE CONSTRAINT FAILED error # when trying again so, delete all the records # in the database and try to create the objects. # so we can preserve the existing tables from models.base_model import Base from db import engine for tbl in reversed(Base.metadata.sorted_tables): engine.execute(tbl.delete()) # Create how ever many user and profile objects the user defined user_dicts = [ { 'street_address': "777 Brockton Avenue", 'city': "Abington", "state_or_province": "Massachusetts", 'country': "United States", 'zip_code': "01001", 'email': "*****@*****.**", 'password': "******", }, { 'street_address': "30 Memorial Drive", 'city': "Avon", 'state_or_province': "Massachusetts", 'country': "United States", 'zip_code': "20194", 'email': "*****@*****.**", 'password': "******" }, { 'street_address': "250 Hartford Avenue", 'city': "Toronto", 'state_or_province': "Ontario", 'country': "Canada", 'zip_code': "A1A 1A1", 'email': "*****@*****.**", 'password': "******" }, ] profile_dicts = [{ 'name': "Giuseppe", "is_chef": True, "about_me": "I love to cook and have been doing so for 15 years. My specialty is Italian food", "location": "Massachusettes, United States", 'profile_image': "https://images.unsplash.com/photo-1600565193348-f74bd3c7ccdf?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80", 'favourite_recipe': "Spicy Pork Tenderloin with Apples and Sweet Potatoes", 'favourite_cuisine': "italian,", }, { 'name': "Mario", "is_chef": False, 'about_me': "I love food, if I could eat every hour of the day I would.", "location": "Massachusettes, United States", 'profile_image': "https://images.unsplash.com/photo-1521341057461-6eb5f40b07ab?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=634&q=80", 'favourite_cuisine': "thai,", }, { 'name': "Tessa", "is_chef": False, 'about_me': "I'm not a chef but wish I was, I couldn't boil noodles without burning them!", "location": "Ontario, Canada", 'profile_image': "https://images.unsplash.com/photo-1505999407077-7937810b98ae?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1188&q=80", 'favourite_cuisine': "Mexican," }] recipe_dicts = [ { 'name': 'Spicy Pork Tenderloin with Apples and Sweet Potatoes', 'description': "A spicy pork tenderloin with delicious green apples and sweet potatoes", 'available': True, 'cuisine': "french", 'price': 1000, 'ingredients': "Pork Tenderloin,Green Apples,Sweet Potatoes,Rosemary", 'required_items': "Dinner Plate, Kitchen Table, Oven", 'image_urls': "https://images.unsplash.com/photo-1598514982205-f36b96d1e8d4?ixid=MXwxMjA3fDB8MHxzZWFyY2h8M3x8cG9yayUyMHRlbmRlcmxvaW58ZW58MHx8MHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=60https://images.unsplash.com/photo-1598514982205-f36b96d1e8d4?ixid=MXwxMjA3fDB8MHxzZWFyY2h8M3x8cG9yayUyMHRlbmRlcmxvaW58ZW58MHx8MHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=60," }, { 'name': "Al's Burmese Chicken Curry", 'description': "Chicken", 'available': False, 'cuisine': "indian", 'price': 1000, 'ingredients': "Pork Tenderloin,Green Apples,Sweet Potatoes,Rosemary", 'required_items': "Dinner Plate,Kitchen Table,Oven", 'image_urls': "https://images.unsplash.com/photo-1501200291289-c5a76c232e5f?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxleHBsb3JlLWZlZWR8M3x8fGVufDB8fHw%3D&auto=format&fit=crop&w=1000&q=60," }, { 'name': "Sweet Potato and Venison Shepherd's Pie", 'description': "Shepherds Pie stuffed with sweet potatoes and venison, cooked to golden perfection", 'available': True, 'cuisine': "french", 'price': 2000, 'ingredients': "Venison,Sweet potatoes,Gravy", 'required_items': "Dinner Plate,Oven", 'image_urls': "https://images.unsplash.com/photo-1600626336264-60ef2a55bd33?ixid=MXwxMjA3fDB8MHxzZWFyY2h8NHx8c2hlcGhlcmRzJTIwcGllfGVufDB8fDB8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=60," }, { 'name': "Gemelli Pasta with Roasted Pumpkin and Pancetta", "description": "Delicious pasta smothered in Pancetta with Roasted Pumpkin", 'available': False, 'cuisine': "italian", 'price': 1500, 'ingredients': "Roasted Pumpkin,Pasta,Pancetta", 'required_items': "Large Pot,Stove,Dinner Table", 'image_urls': "https://images.unsplash.com/photo-1579631542720-3a87824fff86?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80," }, { 'name': "Beef Stroganoff with Ground Beef", 'description': "Beef stroganoff filled with ground beef, served with a delicious buttery dinner roll", 'available': True, 'cuisine': "turkish", 'price': 2500, 'ingredients': "Ground Beef,Brown Gravy,Wide Egg Noodles,", 'required_items': "Large Pot,Stove Top,Oven", 'image_urls': "https://images.unsplash.com/photo-1504669221159-56caf7b07f57?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80,", }, ] last_user = None for index in range(len(user_dicts)): print(index) new_user = User.create(**user_dicts[index]) # Create profile new_profile = Profile() new_profile = new_profile.create(**profile_dicts[index]) # Assign the new profile to the new user new_user.assign_one_to_one('profile', new_profile) # If we have another user, create messages between the # last one and the new one if last_user != None: new_conversation = Conversation.create(**{ 'user_one': last_user, 'user_two': new_user }) # Create messages for the two users last_users_message = Message.create( **{ 'sender': last_user, 'content': "Hello %s how are you?" % (new_user.profile.name) }) new_users_message = Message.create( **{ 'sender': new_user, 'content': "I'm good %s how about you?" % (last_user.profile.name) }) # Add messages to the conversation new_conversation.add_to_relationship('messages', last_users_message) new_conversation.add_to_relationship('messages', new_users_message) # Create 5 recipes for each user/profile new_recipe = Recipe.create(**recipe_dicts[index]) # Add the new recipe to the One to Many field in the Profile model new_profile.add_to_relationship('recipes', new_recipe) last_user = new_user print_info(user_dicts, profile_dicts, recipe_dicts)
def recipes_view(): recipe_list = Recipe.get_by_owner(g.user.username) return render_template('view_recipes.html', recipe_list=recipe_list)
def delete_recipe(**kwargs): response_dict = {} recipe_id = request.get_json().get('recipe_id') try: recipe = Recipe.get_instance(**{'id': recipe_id}) kwargs['user'].profile.remove_from_relationship('recipes', recipe) Recipe.delete(recipe_id) response_dict['status'] = 200 response_dict['message'] = "Recipe successfully deleted" return jsonify(response_dict), 200 except AssertionError as e: response_dict['status'] = 400 response_dict['message'] = "%s" % (e) return jsonify(response_dict), 400 # The following 2 endpoints could possibly be # merged into one. This depends on the front # end design when it comes to editing information @app.route("/user/edit",methods=["PUT"]) @authenticate def edit_user(): """ I'm not sure if I need to return the updated information or not. The front end can use the given values to udpate the display as long as the status is 200. If the front end will re-render, this is not a concern. Otherwise this needs to return a new user information dictionary """ request_dict = request.form.to_dict() user_info = {} for field in User.get_fields(): if request_dict.get(field, None) != None: user_info[field] = request_dict.get(field) try: User.update(user.id,**user_info) # An updated user information dictionary will # be returned on next re-render response_dict['status'] = 200 response_dict['message'] = "Successfully updated information" return jsonify(response_dict), 200 except AssertionError as e: # Validation problem response_dict['status'] = 400 response_dict['message'] = "%s" % (e) return jsonify(response_dict), 400 @app.route('/profile/edit', methods=["PUT"]) @authenticate def edit_profile(**kwargs): response_dict = {} request_dict = request.get_json() new_info = {} for field in Profile.get_fields(): if request_dict.get(field, None) != None: new_info[field] = request_dict.get(field) try: Profile.update(user.profile.id, **new_info) response_dict['status'] = 200 response_dict['message'] = "Successfully updated profile" return jsonify(response_dict), 200 except AssertionError as e: response_dict['status'] = 400 response_dict['message'] = "%s" % (e) return jsonify(response_dict), 400
# Parse the JSON into Python objects try: recipe_data = json.loads(recipe_json) except Exception, e: self.render_json({ 'status': 'error', 'error': str(e), 'input': recipe_json }) return # Load recipe from db or create a new one new_recipe = False if not recipe_slug: recipe = Recipe() recipe.owner = user new_recipe = True else: recipe = Recipe.all()\ .filter('owner =', user)\ .filter('slug =', recipe_slug)\ .get() if not recipe: self.render_json({ 'status': 'error', 'error': 'Recipe not found' }) return
# CREATING A USER AND A RECIPE from app import * from models.user import User from models.recipe import Recipe app = create_app() with app.app_context(): user = User(username='******', email='*****@*****.**', password='******') db.session.add(user) db.session.commit() encebollado = Recipe(name='Encebollado', description='El encebollado es un plato típico ecuatoriano originario de la región costa', num_of_servings=1, cook_time=30, directions='hay que conseguir albacora', user_id=user.id) lasagnia = Recipe(name='lasaña', description='La lasaña es un tipo de pasta que se sirve en láminas para denominarse lasaña ha de llevar ', num_of_servings=1, cook_time=30, directions='Las laminas paso 1', user_id=user.id) db.session.add(encebollado) db.session.add(lasagnia) db.session.commit() user = User.query.filter_by(username='******').first() for recipe in user.recipes: print('{} recipe made by {} can serve {} people.'.format(recipe.name, recipe.user.username, recipe.num_of_servings))
def get(self): user = self.user # Try to get rendered output from memcache rendered = memcache.get('dashboard-' + user.user_id) if rendered and not settings.DEBUG: return self.response.out.write(rendered) # Fetch following users following = user.following_users\ .order('name')\ .fetch(100) user_keys = [user.key()] + [u.key() for u in following] # Start async fetch of top recipes top_recipes = Recipe.all()\ .filter('owner IN', user_keys)\ .order('-grade')\ .run(limit=15) # Get and process interesting events interesting_events = UserAction.all()\ .filter('owner IN', user_keys)\ .order('-created')\ .fetch(15) object_ids = UserAction.gather_object_ids(interesting_events) object_ids['users'] = [id for id in object_ids['users'] if id not in [user.key().id()] + user.following] # Start async fetch of relevant recipes recipes = db.get_async([Key.from_path('Recipe', id) for id in object_ids['recipes']]) # Start async fetch of relevant brews brews = db.get_async([Key.from_path('Brew', id) for id in object_ids['brews']]) # Convert iterators to lists of items in memory and setup a map # of user id -> user for easy lookups following = list(following) top_recipes = list(top_recipes) user_map = { user.key().id(): user } for u in following: user_map[u.key().id()] = u if object_ids['users']: for u in UserPrefs.get_by_id(object_ids['users']): user_map[u.key().id()] = u # Setup a map of brew id -> brew for easy lookups brew_map = {} brew_recipe_ids = set() for b in brews.get_result(): brew_recipe_ids.add(b.recipe_key.id()) brew_map[b.key().id()] = b # Async fetch of any recipes brews reference that weren't # included in the recipe fetch above... brew_recipes = db.get_async([Key.from_path('Recipe', id) for id in brew_recipe_ids if id not in object_ids['recipes']]) # Setup a map of recipe id -> recipe for easy lookups recipe_map = {} for r in recipes.get_result(): recipe_map[r.key().id()] = r for r in brew_recipes.get_result(): recipe_map[r.key().id()] = r # Render and cache for 1 minute memcache.set('dashboard-' + user.user_id, self.render('dashboard.html', { 'following': following, 'user_map': user_map, 'recipe_map': recipe_map, 'brew_map': brew_map, 'top_recipes': top_recipes, 'interesting_events': interesting_events }), self.CACHE_TIME)
def edit(recipe_id): recipe = Recipe.get_or_none(Recipe.id == recipe_id) return render_template('recipes/edit.html', recipe_id=recipe.id)
def index(): recipes = Recipe.select() return render_template("index.html", recipes=recipes)
def read_recipe(recipe_id): form = UpdateRecipeForm() that_recipe = Recipe.get_or_none(Recipe.id == recipe_id) recipe_user_id = that_recipe.user_id return render_template('read_that_recipe.html', recipe=that_recipe, form=form, user=recipe_user_id)
def get(self): user = self.user # Try to get rendered output from memcache rendered = memcache.get('dashboard-' + user.user_id) if rendered and not settings.DEBUG: return self.response.out.write(rendered) # Fetch following users following = user.following_users\ .order('name')\ .fetch(100) user_keys = [user.key()] + [u.key() for u in following] # Start async fetch of top recipes top_recipes = Recipe.all()\ .filter('owner IN', user_keys)\ .order('-grade')\ .run(limit=15) # Get and process interesting events interesting_events = UserAction.all()\ .filter('owner IN', user_keys)\ .order('-created')\ .fetch(15) object_ids = UserAction.gather_object_ids(interesting_events) object_ids['users'] = [ id for id in object_ids['users'] if id not in [user.key().id()] + user.following ] # Start async fetch of relevant recipes recipes = db.get_async( [Key.from_path('Recipe', id) for id in object_ids['recipes']]) # Start async fetch of relevant brews brews = db.get_async( [Key.from_path('Brew', id) for id in object_ids['brews']]) # Convert iterators to lists of items in memory and setup a map # of user id -> user for easy lookups following = list(following) top_recipes = list(top_recipes) user_map = {user.key().id(): user} for u in following: user_map[u.key().id()] = u if object_ids['users']: for u in UserPrefs.get_by_id(object_ids['users']): user_map[u.key().id()] = u # Setup a map of brew id -> brew for easy lookups brew_map = {} brew_recipe_ids = set() for b in brews.get_result(): brew_recipe_ids.add(b.recipe_key.id()) brew_map[b.key().id()] = b # Async fetch of any recipes brews reference that weren't # included in the recipe fetch above... brew_recipes = db.get_async([ Key.from_path('Recipe', id) for id in brew_recipe_ids if id not in object_ids['recipes'] ]) # Setup a map of recipe id -> recipe for easy lookups recipe_map = {} for r in recipes.get_result(): recipe_map[r.key().id()] = r for r in brew_recipes.get_result(): recipe_map[r.key().id()] = r # Render and cache for 1 minute memcache.set( 'dashboard-' + user.user_id, self.render( 'dashboard.html', { 'following': following, 'user_map': user_map, 'recipe_map': recipe_map, 'brew_map': brew_map, 'top_recipes': top_recipes, 'interesting_events': interesting_events }), self.CACHE_TIME)
def get(self, username=None, recipe_slug=None, version=None): """ Render the recipe view. If no slug is given then create a new recipe and render it in edit mode. """ # Create a new recipe if we have no slug, otherwise query if not recipe_slug: publicuser = self.user recipe = Recipe() recipe.owner = publicuser recipe.new = True brews = [] else: publicuser = UserPrefs.all().filter('name =', username).get() if not publicuser: self.abort(404) recipe = Recipe.all()\ .filter('owner =', publicuser)\ .filter('slug =', recipe_slug)\ .get() if not recipe: self.abort(404) brews = recipe.brews.order('-started').fetch(3) if version: try: version = int(version) except: self.abort(404) history = RecipeHistory.get_by_id(version, recipe) if not history: self.abort(404) recipe.old = True recipe.oldname = history.name recipe.description = history.description recipe.type = history.type recipe.category = history.category recipe.style = history.style recipe.batch_size = history.batch_size recipe.boil_size = history.boil_size recipe.bottling_temp = history.bottling_temp recipe.bottling_pressure = history.bottling_pressure recipe.mash_efficiency = history.mash_efficiency recipe.steep_efficiency = history.steep_efficiency recipe.primary_days = history.primary_days recipe.secondary_days = history.secondary_days recipe.tertiary_days = history.tertiary_days recipe.aging_days = history.aging_days recipe._ingredients = history._ingredients cloned_from = None try: cloned_from = recipe.cloned_from except Exception, e: pass
def new(): name = request.form.get('name', None) directions = request.form.get('directions', None) ingredients = request.form.get('ingredients', None) countrys = request.form.get('countrys', None) hour = request.form.get('hour', None) sec = request.form.get('sec', None) time = request.form.get('time', None) numHour = int(hour) numMin = int(sec) / 100 prepTime = numHour + numMin photo = request.files['photo'] photoName = time + photo.filename client = storage.Client() bucket = client.get_bucket('foody-project') myBlob = bucket.blob(photoName) myBlob.upload_from_string(photo.read()) id = get_jwt_identity() recipe = Recipe( name=name, photo=myBlob.public_url, directions=directions, ingredients=ingredients, hour=hour, sec=sec, prep=prepTime, countrys=countrys, time=time, user=id, ) recipe.save() user = User.get_or_none(User.id == id) recipes = Recipe.select().where(Recipe.user_id == id) # url_photo = recipe.photo my_recipes = Recipe.select().where(Recipe.user_id == id) recipesNum = len([c.id for c in my_recipes]) return jsonify({ "status": "success", "recipesNum": recipesNum, "recipes": [{ "id": recipe.id, "name": recipe.name, "photo": recipe.photo, "countrys": recipe.countrys, "hour": recipe.hour, "sec": recipe.sec, "directions": recipe.directions, "ingredients": recipe.ingredients, "time": recipe.time, "username": user.username, "user_id": user.id, "user_photo": user.photo } for recipe in recipes] }), 200
def get(self, username=None, recipe_slug=None): """ Render the basic recipe history list for the given recipe. """ if not username or not recipe_slug: self.abort(404) publicuser = UserPrefs.all().filter('name =', username).get() if not publicuser: self.abort(404) recipe = Recipe.all()\ .filter('slug = ', recipe_slug)\ .filter('owner =', publicuser)\ .get() if not recipe: self.abort(404) history = RecipeHistory.all()\ .ancestor(recipe)\ .order('-created')\ .fetch(20) # The list of entries we'll use to populate the template along with # the current recipe as the first entry entries = [{ 'recipe': recipe, 'edited': recipe.edited, 'slug': recipe.slug, 'customtag': 'Most Recent', 'show_snippet': True }] # Check if there is any history to diff with if len(history) > 0: entries[0]['differences'] = self.delete_ignored_keys(recipe.diff(history[0])) else: entries[0]['first'] = True # Get a list of differences in the history. Use reduce with a function # that returns the right operand to simply find pairwise differences. differences = [] def diff(left, right): differences.append(left.diff(right)) return right # Make sure reduce isn't called with no history (throws exception) reduce(diff, history) if len(history) > 0 else None # Start going through the history looking at differences to decide how # we plan on displaying the info to the user (using a snippet or not) for i in range(len(differences)): # Make sure this entry has differences before further processing if self.is_empty(differences[i]): continue # Set some required properties for the snippet to work history[i].owner = publicuser history[i].slug = recipe.slug + '/history/' + str(history[i].key().id()) # Create the entry entry = { 'recipe': history[i], 'differences': self.delete_ignored_keys(differences[i]), 'edited': history[i].created, 'slug': history[i].slug, 'show_snippet': False } # Check if the name or description changed and we should show # a snippet for snippetItem in RecipeHistoryHandler.SNIPPET_ITEMS: if snippetItem in differences[i][2]: entry['show_snippet'] = True # Make sure the color, ibu, and alcohol were created if not hasattr(history[i], 'color'): history[i].update_cache() break # Save the entry entries.append(entry) # Add the final entry only if it's the original recipe, otherwise it # will be a version that should have diffs but we didn't generate any. if len(history) > 0: last = history[-1] delta = timedelta(seconds=1) if recipe.created - delta < last.created < recipe.created + delta: last.owner = publicuser last.slug = recipe.slug + '/history/' + str(last.key().id()) if not hasattr(last, 'color'): last.update_cache() entries.append({ 'recipe': last, 'edited': last.created, 'slug': last.slug, 'customtag': 'Original', 'first': True }) # Perform a second pass in reverse to check for large changes that # should show up as a snippet but were missed in the pairwise # checking above. entries[-1]['show_snippet'] = True for i in range(len(entries) - 1, 0, -1): # Check if the snippet is already showing if entries[i]['show_snippet']: last_snippet = entries[i]['recipe'] continue # Check if the name, description, color, ibu, or alcohol changed # and we should show a snippet for snippetItem in RecipeHistoryHandler.IGNORED_KEYS: if not hasattr(entries[i]['recipe'], snippetItem): continue attr = getattr(entries[i]['recipe'], snippetItem) if type(attr) != int and type(attr) != float: continue # See if the change was more than 10%, then show the # snippet, else show the orb try: change = float(attr) / getattr(last_snippet, snippetItem) except: change = 2 logging.info(snippetItem) logging.info(change) if change < 0.9 or change > 1.1: last_snippet = entries[i]['recipe'] entries[i]['show_snippet'] = True break # Stop the template from performing another query for the username # when it tries to render the recipe recipe.owner = publicuser self.render('recipe-history.html', { 'publicuser': publicuser, 'recipe': recipe, 'entries': entries })
def show_search(): id = get_jwt_identity() favorites = Favorite.select().join( User, on=Favorite.user_id).switch(Favorite).where(Favorite.user_id == id) excluded_chefs = [c.chef_id for c in favorites] hour = request.args.get('hour') sec = request.args.get('sec') country = request.args.get('country') order = request.args.get('order') if order == "Time to prepare": ooo = Recipe.prep elif order == "": ooo = Recipe elif order == "Recently": ooo = Recipe.created_at.desc() prepTime = None if sec and hour: prepTime = int(hour) + (int(sec) / 100) elif sec: prepTime = (int(sec) / 100) elif hour: prepTime = int(hour) recipes = False if country and prepTime: recipes = Recipe.select().where( (Recipe.countrys == country) & (Recipe.user_id != id) & (Recipe.prep <= prepTime) & Recipe.user_id.not_in(excluded_chefs)).order_by(ooo) elif country: recipes = Recipe.select().where( (Recipe.countrys == country) & (Recipe.user_id != id) & Recipe.user_id.not_in(excluded_chefs)).order_by(ooo) elif prepTime: recipes = Recipe.select().where( (Recipe.prep <= prepTime) & (Recipe.user_id != id) & Recipe.user_id.not_in(excluded_chefs)).order_by(ooo) else: recipes = Recipe.select().where( (Recipe.user_id != id) & Recipe.user_id.not_in(excluded_chefs)).order_by(ooo) if recipes: return jsonify({ "status": "success", "recipe": [{ "id": recipe.id, "name": recipe.name, "photo": recipe.photo, "countrys": recipe.countrys, "hour": recipe.hour, "sec": recipe.sec, "directions": recipe.directions, "ingredients": recipe.ingredients, "time": recipe.time, "username": recipe.user.username, "user_id": recipe.user.id, "id_owner": recipe.user.id, "user_photo": recipe.user.photo } for recipe in recipes] }), 200 else: return jsonify({"recipe": [], "status": "no recipe"}), 200
recipe_json = cgi.escape(self.request.get('recipe')) # Parse the JSON into Python objects try: recipe_data = json.loads(recipe_json) except Exception, e: self.render_json({ 'status': 'error', 'error': str(e), 'input': recipe_json }) return # Load recipe from db or create a new one if not recipe_slug: recipe = Recipe() recipe.owner = user else: recipe = Recipe.all()\ .filter('owner =', user)\ .filter('slug =', recipe_slug)\ .get() if not recipe: self.render_json({ 'status': 'error', 'error': 'Recipe not found' }) return # Ensure you own this recipe
def get(self): recipes = Recipe.get_all_published() return recipe_list_schema.dump(recipes).data, HTTPStatus.OK
blueberries = Ingredient( name='blueberries', image= 'https://images.unsplash.com/photo-1520605363242-1012f0ae0c15?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=925&q=80', nutrition_information= '3.6 g dietary fiber, or 14.4 percent of your daily value (DV), 9 milligrams (mg) calcium, 0.9 percent DV., 9 mg magnesium, 2.25 percent DV., 114 mg potassium, 2.42 percent DV., 14.4 mg vitamin C, 24 percent DV., 9 micrograms (mcg) folate, 2.25 percent DV.' ) db.session.add(blueberries) #RECIPES banana_carrot_seed_bread = Recipe( name='Banana, Carrot and Seed Bread', image= 'https://images.unsplash.com/photo-1547033964-1be30700c397?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80', extra_ingredients= '150g / 5oz softened unsalted butter, 2 large eggs, 200g/ 7oz ripe bananas, peeled and mashed, 125g / 4½oz grated carrot, 25g / 1oz sultanas, 125g / 4½oz soft dark brown sugar, 225g / 8oz self-raising flour, ½ teaspoon ground cinnamon, 1 teaspoon mixed spice, 1 teaspoon ground ginger, 25g / 1oz pumpkin seeds, 25g / 1oz sunflower seeds, Butter, for spreading and greasing', method= '1.Preheat the oven to 170°C/340°F/Gas 3, grease a 900 g/2 lb loaf tin and line it with baking parchment.2.Place all of the ingredients, except the topping, in a large mixing bowl. Whisk together with an electric hand-held whisk for 1–2 minutes until light and fluffy. Alternatively, use a stand mixer fitted with the paddle or whisk attachment. 3.Spoon the mixture into the tin and level out the top. 4.Sprinkle with the extra seeds and bake for 1–1¼ hours until golden, well risen and a skewer inserted comes out clean. 5.Remove from the oven and leave to cool on a wire rack, then remove from the tin. Dust with icing sugar (if using), cut into slices, spread with butter and serve.', ingredients=[banana, carrot]) db.session.add(banana_carrot_seed_bread) carrot_cheese_muffins = Recipe( name='Carrot & Cheese Muffins', image= 'https://images.unsplash.com/photo-1548693563-25dc13e7b2c1?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80', extra_ingredients= '2 eggs, 175g self raising flour, 1 tsp baking powder, 100 ml milk,100g carrot, peeled and grated, 3 tbsp sunflower oil,1 tbsp chives, chopped,6 spring onions, sliced,1 tbsp fresh basil , chopped,50g parmesan, grated', method= '1.Preheat the oven to 180C Fan. Line a muffin tin with 10 muffin cases.2.Whisk the egg, flour, baking powder, milk and oil together in a large bowl. Add the carrot, herbs, spring onion and cheese and fold together. Spoon into the cases.3.Bake in the oven for 18 minutes until sell risen and lightly golden brown.', ingredients=[carrot, muffins])
def post(self, username=None, recipe_slug=None): publicuser = UserPrefs.all()\ .filter('name = ', username)\ .get() if not publicuser: self.render_json({'status': 'error', 'error': 'User not found'}) return recipe = Recipe.all()\ .filter('owner =', publicuser)\ .filter('slug =', recipe_slug)\ .get() if not recipe: self.render_json({'status': 'error', 'error': 'Recipe not found'}) return new_recipe = Recipe( **{ 'owner': self.user, 'cloned_from': recipe, 'color': recipe.color, 'ibu': recipe.ibu, 'alcohol': recipe.alcohol, 'name': recipe.name, 'description': recipe.description, 'type': recipe.type, 'category': recipe.category, 'style': recipe.style, 'batch_size': recipe.batch_size, 'boil_size': recipe.boil_size, 'bottling_temp': recipe.bottling_temp, 'bottling_pressure': recipe.bottling_pressure, 'steep_efficiency': recipe.steep_efficiency, 'mash_efficiency': recipe.mash_efficiency, 'primary_days': recipe.primary_days, 'primary_temp': recipe.primary_temp, 'secondary_days': recipe.secondary_days, 'secondary_temp': recipe.secondary_temp, 'tertiary_days': recipe.tertiary_days, 'tertiary_temp': recipe.tertiary_temp, 'aging_days': recipe.aging_days, '_ingredients': recipe._ingredients }) new_recipe.slug = generate_usable_slug(new_recipe) new_recipe.put() new_recipe.update_grade() new_recipe.put() # Update recipe ranking for sorting recipe.update_grade() recipe.put() action = UserAction() action.owner = self.user action.type = action.TYPE_RECIPE_CLONED action.object_id = new_recipe.key().id() action.put() return self.render_json({'status': 'ok', 'redirect': new_recipe.url})
def get_all_recipes(self): response = [] for rec in Recipe.objects(): info = self._recipe_to_dict(rec) response.append(info) return json.dumps(response)
def show(): recipes = Recipe.select() return render_template('recipes/show.html', recipes=recipes)
spring = Tag(name='Spring') autumn = Tag(name='Autumn') picnic = Tag(name='Picnic') easy = Tag(name='Easy') slowcooker = Tag(name='Slow cooker') onepot = Tag(name='One-pot') omelette = Recipe( name='Cheese and Spinach Omelette', cuisine=[french], ingredients= '["3 large eggs", "1 handful grated cheese of your choice", "small knob of butter", "salt & pepper to taste"]', chef=izzi, instructions= '["1. Whisk three large eggs in a bowl, salt and pepper to taste", "2. Grate the cheese and wash the spinach (if required)", "3. Heat the butter in a large frying pan over a medium heat. When the butter is fully melted and just starting to bubble, pour in the eggs. Ensure the mixture spreads evenly across the pan. Use a spatula to lift the edges slightly to let any liquid run under the omlette.", "4. When the base of the omlette is set but the top is still runny, add the cheese and allow to melt.", "5. Carefully lift one edge of the omlette - the underneath should be lightly browned. Add the spinach, fold the omlette in half and serve immediately."]', img= 'https://www.cookforyourlife.org/wp-content/uploads/2018/08/Spinach-Omlette-696x465.jpg', video='video.link', liked_by=[charlie], tags=[quick, easy, budget], serves=1, prep_time_min=15, cook_time_min=15, description="A quick, easy lunch or dinner for any night of the week!") tuna_salad = Recipe( name='Tuna pasta salad', cuisine=[italian], chef=charlie, ingredients= '[ "200g dried pasta (approx 400g cooked)", "2 handfuls fresh rocket", "10 Peppadew or other sweet peppers", "150g cherry tomatoes", "Olive oil and balsamic for dressing"]', instructions=
def get(self, username=None, recipe_slug=None): """ Render the basic recipe history list for the given recipe. """ if not username or not recipe_slug: self.abort(404) publicuser = UserPrefs.all().filter('name =', username).get() if not publicuser: self.abort(404) recipe = Recipe.all()\ .filter('slug = ', recipe_slug)\ .filter('owner =', publicuser)\ .get() if not recipe: self.abort(404) history = RecipeHistory.all()\ .ancestor(recipe)\ .order('-created')\ .fetch(20) # The list of entries we'll use to populate the template along with # the current recipe as the first entry entries = [{ 'recipe': recipe, 'edited': recipe.edited, 'slug': recipe.slug, 'customtag': 'Most Recent', 'show_snippet': True }] # Check if there is any history to diff with if len(history) > 0: entries[0]['differences'] = self.delete_ignored_keys( recipe.diff(history[0])) else: entries[0]['first'] = True # Get a list of differences in the history. Use reduce with a function # that returns the right operand to simply find pairwise differences. differences = [] def diff(left, right): differences.append(left.diff(right)) return right # Make sure reduce isn't called with no history (throws exception) reduce(diff, history) if len(history) > 0 else None # Start going through the history looking at differences to decide how # we plan on displaying the info to the user (using a snippet or not) for i in range(len(differences)): # Make sure this entry has differences before further processing if self.is_empty(differences[i]): continue # Set some required properties for the snippet to work history[i].owner = publicuser history[i].slug = recipe.slug + '/history/' + str( history[i].key().id()) # Create the entry entry = { 'recipe': history[i], 'differences': self.delete_ignored_keys(differences[i]), 'edited': history[i].created, 'slug': history[i].slug, 'show_snippet': False } # Check if the name or description changed and we should show # a snippet for snippetItem in RecipeHistoryHandler.SNIPPET_ITEMS: if snippetItem in differences[i][2]: entry['show_snippet'] = True # Make sure the color, ibu, and alcohol were created if not hasattr(history[i], 'color'): history[i].update_cache() break # Save the entry entries.append(entry) # Add the final entry only if it's the original recipe, otherwise it # will be a version that should have diffs but we didn't generate any. if len(history) > 0: last = history[-1] delta = timedelta(seconds=1) if recipe.created - delta < last.created < recipe.created + delta: last.owner = publicuser last.slug = recipe.slug + '/history/' + str(last.key().id()) if not hasattr(last, 'color'): last.update_cache() entries.append({ 'recipe': last, 'edited': last.created, 'slug': last.slug, 'customtag': 'Original', 'first': True }) # Perform a second pass in reverse to check for large changes that # should show up as a snippet but were missed in the pairwise # checking above. entries[-1]['show_snippet'] = True for i in range(len(entries) - 1, 0, -1): # Check if the snippet is already showing if entries[i]['show_snippet']: last_snippet = entries[i]['recipe'] continue # Check if the name, description, color, ibu, or alcohol changed # and we should show a snippet for snippetItem in RecipeHistoryHandler.IGNORED_KEYS: if not hasattr(entries[i]['recipe'], snippetItem): continue attr = getattr(entries[i]['recipe'], snippetItem) if type(attr) != int and type(attr) != float: continue # See if the change was more than 10%, then show the # snippet, else show the orb try: change = float(attr) / getattr(last_snippet, snippetItem) except: change = 2 logging.info(snippetItem) logging.info(change) if change < 0.9 or change > 1.1: last_snippet = entries[i]['recipe'] entries[i]['show_snippet'] = True break # Stop the template from performing another query for the username # when it tries to render the recipe recipe.owner = publicuser self.render('recipe-history.html', { 'publicuser': publicuser, 'recipe': recipe, 'entries': entries })
def delete_all(self): Recipe.objects().delete() return None
}, { "name": "hltToMash", "prettyName": "HLT To Mash", "status": con.relay_status(con.settings.relays['hltToMash']) }, { "name": "rimsToMash", "prettyName": "RIMS To Mash", "status": con.relay_status(con.settings.relays["rimsToMash"]) }, { "name": "pump", "prettyName": "Pump", "status": con.relay_status(con.settings.relays["pump"]) } ] return json.dumps(relays) # PID API Resource @app.route("/pid", methods=["GET"]) def pid(): pid = con.pid_status() return json.dumps(pid) if __name__ == '__main__': Recipe.create_table(True) app.run('0.0.0.0', 8000, extra_files="static/main.js")