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=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=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 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 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 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 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 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 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 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) 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._ingredients = history._ingredients cloned_from = None try: cloned_from = recipe.cloned_from except Exception, e: pass
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 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 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 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 get(self): """ Render the index page. Currently this renders a 'Coming soon' landing page that will eventually be replaced with a proper home page. """ user = self.user if 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('-likes_count')\ .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']]) # 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 recipe id -> recipe for easy lookups recipe_map = {} for r in 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, 'top_recipes': top_recipes, 'interesting_events': interesting_events }), 60) else: # Try to get rendered output from memcache rendered = memcache.get('index') if rendered and not settings.DEBUG: return self.response.out.write(rendered) recipes = Recipe.all()\ .order('-likes_count')\ .run(limit=15) # Render and cache for 15 minutes memcache.set('index', self.render('index.html', { 'recipes': recipes }), 900)
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 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 get(self): """ Render the index page. Currently this renders a 'Coming soon' landing page that will eventually be replaced with a proper home page. """ user = self.user if 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('-likes_count')\ .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']]) # 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 recipe id -> recipe for easy lookups recipe_map = {} for r in 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, 'top_recipes': top_recipes, 'interesting_events': interesting_events }), 60) else: # Try to get rendered output from memcache rendered = memcache.get('index') if rendered and not settings.DEBUG: return self.response.out.write(rendered) recipes = Recipe.all()\ .order('-likes_count')\ .run(limit=15) # Render and cache for 15 minutes memcache.set('index', self.render('index.html', {'recipes': recipes}), 900)
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 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(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)
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 # Ensure you own this recipe if not recipe or recipe.owner.name != user.name: self.render_json({ 'status': 'error', 'error': 'Permission denied: you are not the recipe owner!' })
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)
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 # Ensure you own this recipe if not recipe or recipe.owner.name != user.name: self.render_json({ 'status': 'error', 'error':