Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Branch: master
Fetching contributors…

Cannot retrieve contributors at this time

566 lines (527 sloc) 17.18 kB
import os
import re
import datetime
import traceback
import urllib
from google.appengine.dist import use_library
use_library('django', '1.2')
from django.conf import settings
settings.configure(
DEBUG=True,
TEMPLATE_DEBUG=True,
TEMPLATE_DIRS=(os.path.join(os.path.dirname(__file__), 'templates'),),
INSTALLED_APPS=('django.contrib.humanize',))
from django.template.loader import render_to_string
from google.appengine.api import users
from google.appengine.api import images
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from models import *
class ImageHandler(webapp.RequestHandler):
def get(self, tail=''):
image_type, key = tail[:-4].split('/')
key = urllib.unquote(key)
self.response.headers['Content-Type'] = 'image/png'
if image_type == 'user':
user = User.all().filter('who =', users.User(key)).get()
if not user:
# TODO(calebegg): Hook this into NotFoundError somehow?
self.error(404)
return
self.response.out.write(user.image)
print user.image
elif image_type == 'recipe':
pass
elif image_type == 'instruction':
pass
else:
self.error(404)
pass
# Pages
class Page(webapp.RequestHandler):
def __init__(self):
self.out = out = {}
self.account = users.get_current_user()
if not self.account:
out['account'] = None
out['user'] = None
return
# Populate 'out'
out['account'] = self.account
user = self.user = User.all().filter('who =', self.account).get()
if not user:
return
out['user_first_name'] = user.first_name
out['user_last_name'] = user.last_name
if user.image:
out['user_image_url'] = '/image/user/' + str(self.account) + '.png'
out['user_name'] = '%s %s' % (user.first_name or '',
user.last_name or '')
out['logout_url'] = users.create_logout_url('/')
# Populate notifications
notifications = Notification.all().filter('receiver =', self.account)
if notifications.count() >= 1:
out['notifications'] = notifications
# Populate recipe box values
box = user.box
recipes = []
for key in box.contents:
recipe = Recipe.get(key)
recipe.is_starred = recipe.key() in user.starred
recipes.append(recipe)
out['recipes'] = recipes
out['color'] = box.color
def users_only(self):
if not self.account:
self.redirect(users.create_login_url(self.request.uri))
return True
if not self.user:
self.redirect('/welcome')
return True
return False
def get(self):
pass
def handle_exception(self, exception, debug_mode):
self.response.clear()
self.response.set_status(500)
# TODO(calebegg): Use traceback.extract_tb(sys.exc_info()[2])
# http://docs.python.org/library/traceback.html
out = {'stack_trace': traceback.format_exc()}
self.response.out.write(render_to_string('server_error.html', out))
class Home(Page):
def get(self):
if self.account:
self.response.out.write(render_to_string('index.html', self.out))
else:
self.response.out.write(render_to_string('landing.html',
{'login_url': users.create_login_url('/welcome')}))
class Welcome(Page):
def get(self):
if self.user:
self.redirect('/')
return
box = RecipeBox()
box.color = 'brown'
box.put()
user = User()
user.box = box
user.put()
self.response.out.write(render_to_string('welcome.html', self.out))
class ViewRecipe(Page):
def get(self, tail=''):
if not self.account:
self.out['logged_out'] = True
recipe = Recipe.get(tail)
if recipe:
self.out['recipe'] = recipe
ingredients = map(lambda i: Ingredient.get(i), recipe.ingredients)
self.out['ingredients'] = ingredients
instructions = map(lambda i: Instruction.get(i), recipe.instructions)
self.out['instructions'] = instructions
owner_db = User.all().filter('who =', recipe.owner).get()
if self.account and self.user:
self.out['is_in_box'] = recipe.key() in self.user.box.contents
self.out['is_starred'] = recipe.key() in self.user.starred
self.out['owner_name'] = '%s %s' % (owner_db.first_name or '',
owner_db.last_name or '')
self.response.out.write(render_to_string('recipe.html', self.out))
else:
self.redirect('/')
class ViewItem(Page):
def get(self, tail=''):
item = Item.get(tail)
if item:
self.out['item'] = item
self.response.out.write(render_to_string('item.html', self.out))
else:
self.redirect('/')
class ViewRecipeBox(Page):
def get(self):
if self.users_only():
return
self.response.out.write(render_to_string('recipebox.html', self.out))
class ShoppingList(Page):
def get(self):
if self.users_only():
return
self.out['title'] = 'Shopping list'
self.response.out.write(render_to_string('placeholder.html', self.out))
class Friends(Page):
def get(self):
if self.users_only():
return
friends = []
for friend_email in self.user.friends:
friend = User.all().filter('who =', friend_email).get()
friends.append(friend)
if len(friends) >= 1:
self.out['friends'] = friends
self.response.out.write(render_to_string('friends.html', self.out))
class ViewCalendar(Page):
def get(self):
if self.users_only():
return
self.out['title'] = 'Calendar'
self.response.out.write(render_to_string('calendar.html', self.out))
class SearchResults(Page):
def get(self):
if self.users_only():
return
self.out['title'] = 'Search results'
self.response.out.write(render_to_string('placeholder.html', self.out))
class EditRecipe(Page):
def get(self):
if self.users_only():
return
self.out['categories'] = ['Appetizers', 'Beverages', 'Breads',
'Cakes and Cookies', 'Desserts', 'Entrées', 'Salads', 'Soups and'
'Stews', 'Vegetables']
self.out['units'] = ['tsp', 'tbsp', 'cup', 'lb', 'oz', 'pinch',
'clove', '']
which = self.request.get('recipe')
if which:
self.out['recipe_key'] = which
recipe = Recipe.get(which)
self.out['recipe'] = recipe
self.response.out.write(render_to_string('edit.html', self.out))
class EditItem(Page):
def get(self):
if self.users_only():
return
which = self.request.get('item')
if which:
item = Item.get(item)
self.response.out.write(render_to_string('edit_item.html', self.out))
class EditAccount(Page):
def get(self):
if self.users_only():
return
self.out['colors'] = ['brown', 'red', 'orange', 'yellow', 'green', 'blue',
'purple', 'black']
self.response.out.write(render_to_string('account.html', self.out))
class NotFoundError(Page):
def get(self):
self.response.set_status(404)
self.response.out.write(render_to_string('not_found_error.html', self.out))
# Form submits
class PostPage(Page):
def handle_exception(self, exception, debug_mode):
self.response.clear()
self.response.set_status(500)
out = {'stack_trace': traceback.format_exc()}
self.response.out.write(render_to_string('post_error.html', out))
class SaveAccount(PostPage):
def get(self):
self.redirect('/')
def post(self):
if self.users_only():
return
user = self.user
user.first_name = self.request.get('first_name')
user.last_name = self.request.get('last_name')
image = self.request.get('image')
if image:
user.image_original = db.Blob(str(image))
user.image = images.resize(image, 100, 100)
box = user.box
box.color = self.request.get('color')
user.put()
box.put()
self.redirect('/')
class SaveItem(PostPage):
def get(self):
self.redirect('/')
def post(self):
if self.users_only():
return
item = None
item_id = self.request.get('item')
if item_id:
item = Recipe.get(recipe_id)
else:
item = Item()
class SaveRecipe(PostPage):
def get(self):
self.redirect('/')
def post(self):
if self.users_only():
return
recipe = None
recipe_id = self.request.get('recipe')
if recipe_id:
recipe = Recipe.get(recipe_id)
else:
recipe = Recipe()
recipe.name = self.request.get('title')
amounts = self.request.get_all('amounts')
units = self.request.get_all('units')
items = self.request.get_all('items')
ingredients = []
while amounts and units and items:
ingredient = Ingredient()
ingredient.amount = int(amounts.pop())
ingredient.unit = units.pop()
item_name = items.pop()
item = Item.all().filter('name =', item_name).get()
if not item:
item = Item()
item.name = item_name
item.put()
ingredient.item = item
ingredient.put()
ingredients.append(ingredient.key())
recipe.ingredients = ingredients
for i in range(1):
instruction = Instruction(body=self.request.get('directions'))
instruction.put()
recipe.instructions.append(instruction.key())
recipe.category = self.request.get('category')
recipe.source = self.request.get('source')
makesserves = (self.request.get('makesserves') == 'Makes')
recipe.makesserves = makesserves
recipe.number = int(self.request.get('makes_num'))
if makesserves:
recipe.what = self.request.get('makes_what')
recipe.stars = 0
recipe.put()
self.user.box.contents.append(recipe.key())
self.user.box.put()
self.redirect('/')
class Json(webapp.RequestHandler):
def __init__(self):
self.account = users.get_current_user()
self.user = User.all().filter('who =', self.account).get()
pass
def error(self, message):
self.response.out.write('{"error": "%s"}' % message)
def warning(self, message):
self.response.out.write('{"warning": "%s"}' % message)
def info(self, message):
self.response.out.write('{"info": "%s"}' % message)
def json(self, obj):
self.response.out.write('{"info": %s}' % demjson.encode(obj))
def users_only(self):
if not self.user:
self.error('You are not logged in')
return True
return False
@staticmethod
def simplify(model):
simple_model = {}
simple_model['key'] = str(model.key())
for prop in model.__class__.properties().keys():
value = model.__getattribute__(prop)
# TODO(calebegg): Expand values if they are model keys.
simple_model[prop] = str(value)
return simple_model
class AddToBox(Json):
def post(self):
if self.users_only():
return
recipe_key = Recipe.get(self.request.get('id')).key()
if recipe_key in self.user.box.contents:
self.warning('This recipe is already in your box.')
else:
self.user.box.contents.append(recipe_key)
self.user.box.put()
self.info('Success')
class RemoveFromBox(Json):
def post(self):
if self.users_only():
return
recipe = Recipe.get(self.request.get('id'))
if not recipe.key() in self.user.box.contents:
self.warning('This recipe is not in your box.')
else:
self.user.box.contents.remove(recipe.key())
if recipe.key() in self.user.starred:
self.user.starred.remove(recipe.key())
recipe.stars -= 1
recipe.put()
self.user.put()
self.info('Success')
class AddStar(Json):
def post(self):
recipe = Recipe.get(self.request.get('id'))
if self.users_only():
return
if recipe.key() in self.user.starred:
self.warning('This recipe is already starred.')
else:
self.user.starred.append(recipe.key())
self.user.put()
recipe.stars += 1
recipe.put()
self.info('Success')
class RemoveStar(Json):
def post(self):
if self.users_only():
return
recipe = Recipe.get(self.request.get('id'))
if not recipe.key() in self.user.starred:
self.warning('This recipe has not been starred.')
else:
self.user.starred.remove(recipe.key())
self.user.put()
recipe.stars -= 1
recipe.put()
self.info('Success')
class UserSearch(Json):
def get(self):
if self.users_only():
return
query = self.request.get('query')
results = User.all().filter('who =', users.User(query)).fetch(10)
result_list = []
for result in results:
result_list.append({'name': '%s %s' % (result.first_name,
result.last_name),
'email': str(result.who),
'key': str(result.key()),
'is_current_user': result.who == self.account,
'is_already_friend': result.who in self.user.friends
})
self.json({'query': query, 'results': result_list})
class RequestFriend(Json):
def post(self):
if self.users_only():
return
receiver = db.get(self.request.get('id'))
notification = Notification()
notification.receiver = receiver.who
notification.sender = self.account
notification.type = 'friend_request'
notification.sender_name = '%s %s' % (self.user.first_name,
self.user.last_name)
notification.put()
self.info('Success')
class NotificationAction(Json):
def post(self):
if self.users_only():
return
notification = db.get(self.request.get('id'))
if self.request.get('action') == 'close':
notification.delete()
self.info('Success')
elif self.request.get('action') == 'accept_friend_request':
if notification.type != 'friend_request':
self.warning('This action is not allowed for this notification type.')
else:
if not notification.sender in self.user.friends:
self.user.friends.append(notification.sender)
self.user.put()
friend = User.all().filter('who =', notification.sender).get()
friend.friends.append(self.account)
friend.put()
response = Notification()
response.sender = self.account
response.receiver = notification.sender
response.sender_name = ('%s %s' %
(self.user.first_name, self.user.last_name))
response.type = 'friend_request_accept'
response.put()
notification.delete()
self.info('Success')
else:
self.warning('Unrecognized notification type.')
class Menus(Json):
def get(self):
if self.users_only():
return
start = datetime.date(* map(int, self.request.get('start').split('-')))
end = datetime.date(* map(int, self.request.get('end').split('-')))
results = Menu.all().filter('when >', start).filter('when <', end)
simple_results = []
for menu in results:
simple_menu = {
'when': str(menu.when),
'meal': menu.meal,
'what': [],
}
for key in menu.what:
recipe = Recipe.get(key)
simple_menu['what'].append({
'key': str(key),
'name': recipe.name,
})
simple_results.append(simple_menu)
self.json({'results': simple_results})
class ParseIngredient(Json):
def get(self):
def is_numeric(token):
return re.match(r'^\d+$|^\d+[./]\d+$', token)
def parse_num(token):
ret = 0
try:
ret = float(token)
except ValueError:
num, denom = token.split('/')
ret = float(num) / float(denom)
return ret
query = self.request.get('query')
tokens = query.split(' ')
tokens = filter(lambda s: s != '', tokens)
tokens.reverse()
# Number
number = 0
token = tokens.pop()
if is_numeric(token):
number += parse_num(token)
token = tokens.pop()
if token == 'and':
token = tokens.pop()
if is_numeric(token):
number += parse_num(token)
# Unit
token = tokens.pop()
unit = token
if token in UNITS.keys():
pass
else:
pass
token = tokens.pop()
if token == 'of':
token = tokens.pop()
# Item
item = ''
while True:
if token[-1] == ',':
item += token[:-1] + ' '
break
item += token + ' '
if token == []:
break
token = tokens.pop()
item = item and item[:-1]
# Instructions
instructions = ' '.join(tokens)
self.json({'number': number, 'unit': unit, 'item': item, 'instructions':
instructions})
application = webapp.WSGIApplication([
('/image/(.*)', ImageHandler),
# Pages
('/', Home),
('/edit_recipe', EditRecipe),
('/add', EditRecipe),
('/welcome', Welcome),
('/edit_item', EditItem),
('/recipe/(.*)', ViewRecipe),
('/item/(.*)', ViewItem),
('/account', EditAccount),
('/recipebox', ViewRecipeBox),
('/list', ShoppingList),
('/calendar', ViewCalendar),
('/friends', Friends),
('/search', SearchResults),
# Post
('/save_recipe', SaveRecipe),
('/save_item', SaveItem),
('/save_account', SaveAccount),
# 404 handler
('/.*', NotFoundError), # NB: Must be last
], debug=True)
def main():
run_wsgi_app(application)
if __name__ == '__main__':
main()
Jump to Line
Something went wrong with that request. Please try again.