text: from flask import (Flask,
                     render_template,
                     request, redirect,
                     url_for,
                     jsonify,
                     flash)
  from sqlalchemy import create_engine
  from sqlalchemy.orm import sessionmaker
  from database_setup import Base, Category, MenuItem, User
  from flask import session as login_session
  import random
  import string
  from oauth2client.client import flow_from_clientsecrets
  from oauth2client.client import FlowExchangeError
  import httplib2
  import json
  from flask import make_response
  import requests
  
  
  app = Flask(__name__)
  
  CLIENT_ID = json.loads(
      open('client_secrets.json', 'r').read())['web']['client_id']
  APPLICATION_NAME = "Catalog Menu Application"
  
  
  # Connect to Database and create database session
  engine = create_engine('sqlite:///catalogwithusers.db')
  Base.metadata.bind = engine
  
  DBSession = sessionmaker(bind=engine)
  session = DBSession()
  
  
  # Create anti-forgery state token
  @app.route('/login')
  def showLogin():
      state = ''.join(random.choice(string.ascii_uppercase + string.digits)
                      for x in xrange(32))
      login_session['state'] = state
      # return "The current session state is %s" % login_session['state']
      return render_template('login.html', STATE=state)
  
  
  @app.route('/gconnect', methods=['POST'])
  def gconnect():
      # Validate state token
      if request.args.get('state') != login_session['state']:
          response = make_response(json.dumps('Invalid state parameter.'), 401)
          response.headers['Content-Type'] = 'application/json'
          return response
      # Obtain authorization code
      code = request.data
      # Obtain authorization code, now compatible with Python3
      # request.get_data()
      # code = request.data.decode('utf-8')
  
      try:
          # Upgrade the authorization code into a credentials object
          oauth_flow = flow_from_clientsecrets('client_secrets.json', scope='')
          oauth_flow.redirect_uri = 'postmessage'
          credentials = oauth_flow.step2_exchange(code)
      except FlowExchangeError:
          response = make_response(
              json.dumps('Failed to upgrade the authorization code.'), 401)
          response.headers['Content-Type'] = 'application/json'
          return response
  
      # Check that the access token is valid.
      access_token = credentials.access_token
      url = ('https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=%s'
             % access_token)
  
      h = httplib2.Http()
      result = json.loads(h.request(url, 'GET')[1])
      # Submit request, parse response - Python3 compatible
      # h = httplib2.Http()
      # response = h.request(url, 'GET')[1]
      # str_response = response.decode('utf-8')
      # result = json.loads(str_response)
  
      # If there was an error in the access token info, abort.
      if result.get('error') is not None:
          response = make_response(json.dumps(result.get('error')), 500)
          response.headers['Content-Type'] = 'application/json'
          return response
  
      # Verify that the access token is used for the intended user.
      gplus_id = credentials.id_token['sub']
      if result['user_id'] != gplus_id:
          response = make_response(
              json.dumps("Token's user ID doesn't match given user ID."), 401)
          response.headers['Content-Type'] = 'application/json'
          return response
  
      # Verify that the access token is valid for this app.
      if result['issued_to'] != CLIENT_ID:
          response = make_response(
              json.dumps("Token's client ID does not match app's."), 401)
          print "Token's client ID does not match app's."
          response.headers['Content-Type'] = 'application/json'
          return response
  
      stored_access_token = login_session.get('access_token')
      stored_gplus_id = login_session.get('gplus_id')
      if stored_access_token is not None and gplus_id == stored_gplus_id:
          response = make_response(json.dumps('Current user is already '
                                              'connected.'), 200)
          response.headers['Content-Type'] = 'application/json'
          return response
  
      # Store the access token in the session for later use.
      login_session['access_token'] = credentials.access_token
      login_session['gplus_id'] = gplus_id
  
      # Get user info
      userinfo_url = "https://www.googleapis.com/oauth2/v1/userinfo"
      params = {'access_token': credentials.access_token, 'alt': 'json'}
      answer = requests.get(userinfo_url, params=params)
  
      data = answer.json()
  
      login_session['username'] = data['name']
      login_session['picture'] = data['picture']
      login_session['email'] = data['email']
  
      # see if user exists, if it doesn't make a new one
      user_id = getUserID(login_session['email'])
      if not user_id:
          user_id = createUser(login_session)
      login_session['user_id'] = user_id
  
      output = ''
      output += '<h1>Welcome, '
      output += login_session['username']
      output += '!</h1>'
      output += '<img src="'
      output += login_session['picture']
      output += ' " style = "width: 300px; height: 300px;border-radius: "\
              "150px;-webkit-border-radius: 150px;-moz-border-radius: 150px;"> '
      flash("you are now logged in as %s" % login_session['username'])
      print "done!"
      return output
  
  
  # User Helper Functions
  def createUser(login_session):
      newUser = User(name=login_session['username'], email=login_session[
                     'email'], picture=login_session['picture'])
      session.add(newUser)
      session.commit()
      user = session.query(User).filter_by(email=login_session['email']).one()
      return user.id
  
  
  def getUserInfo(user_id):
      user = session.query(User).filter_by(id=user_id).one()
      return user
  
  
  def getUserID(email):
      try:
          user = session.query(User).filter_by(email=email).one()
          return user.id
      except:
          return None
  
  
  # DISCONNECT - Revoke a current user's token and reset their login_session
  @app.route('/gdisconnect')
  def gdisconnect():
      access_token = login_session.get('access_token')
      if access_token is None:
          print 'Access Token is None'
          response = make_response(json.dumps('Current user not connected.'),
                                   401)
          response.headers['Content-Type'] = 'application/json'
          return response
      print 'In gdisconnect access token is %s', access_token
      print 'User name is: '
      print login_session['username']
      url = 'https://accounts.google.com/o/oauth2/revoke?token=%s' \
            % login_session['access_token']
      h = httplib2.Http()
      result = h.request(url, 'GET')[0]
      print 'result is '
      print result
      if result['status'] == '200':
          del login_session['access_token']
          del login_session['gplus_id']
          del login_session['username']
          del login_session['email']
          del login_session['picture']
          response = make_response(json.dumps('Successfully disconnected.'), 200)
          response.headers['Content-Type'] = 'application/json'
          return response
      else:
          response = make_response(json.dumps('Failed to revoke token for given'
                                   ' user.', 400))
          response.headers['Content-Type'] = 'application/json'
          return response
  
  
  # JSON Endpoint for Category Menu
  @app.route('/category/<int:category_id>/menu/JSON')
  def CatalogJSON(category_id):
      category = session.query(Category).filter_by(id=category_id).one()
      items = session.query(MenuItem).filter_by(
          category_id=category_id).all()
      return jsonify(MenuItems=[i.serialize for i in items])
  
  
  # JSON Endpoint for Menu Item
  @app.route('/category/<int:category_id>/menu/<int:menu_id>/JSON')
  def menuItemJSON(category_id, menu_id):
      menuItem = session.query(MenuItem).filter_by(id=menu_id).one()
      return jsonify(MenuItem=menuItem.serialize)
  
  
  # Show all categories
  @app.route('/')
  def Catalog():
      category = session.query(Category).order_by(Category.name)
      if 'username' not in login_session:
          return render_template('publiccatalog.html', category=category)
      else:
          return render_template('catalog.html', category=category)
  
  
  # Category pages
  @app.route('/category/<int:category_id>/')
  @app.route('/category/<int:category_id>/menu')
  def CatalogMenu(category_id):
      category1 = session.query(Category).all()
      category = session.query(Category).filter_by(id=category_id).one()
      creator = getUserInfo(category.user_id)
      items = session.query(MenuItem).filter_by(category_id=category_id)
      if ('username' not in login_session or
          creator.id != login_session['user_id']):
          return render_template(
              'publicmenu.html', category1=category1, category=category,
              items=items, category_id=category_id)
      else:
          return (render_template('menu.html', category1=category1,
          category=category, items=items, category_id=category_id))
  
  
  # Create a new Category
  @app.route('/category/new/', methods=['GET', 'POST'])
  def newCategory():
      if 'username' not in login_session:
          return redirect('/login')
      if request.method == 'POST':
          newCategory = Category(name=request.form['name'],
                                 user_id=login_session['user_id'])
          session.add(newCategory)
          flash('New Category %s Successfully Created' % newCategory.name)
          session.commit()
          return redirect(url_for('Catalog'))
      else:
          return render_template('newCategory.html')
  
  
  # Edit a Category
  @app.route('/category/<int:category_id>/edit/', methods=['GET', 'POST'])
  def editCategory(category_id):
      if 'username' not in login_session:
          return redirect('/login')
      editedCategory = session.query(
          Category).filter_by(id=category_id).one()
      if editedCategory.user_id != login_session['user_id']:
          return "<script>function myFunction() {alert('You are not authorized"\
              " to edit this restaurant. Please create your own category in " \
              "order to edit.');}</script><body onload='myFunction()''>"
      if request.method == 'POST':
          if request.form['name']:
              editedCategory.name = request.form['name']
              flash('Successfully Edited Category: %s' % editedCategory.name)
              return redirect(url_for('CatalogMenu', category_id=category_id))
      else:
          return render_template('editcategory.html', category=editedCategory)
  
  
  # Delete a Category
  @app.route('/category/<int:category_id>/delete/', methods=['GET', 'POST'])
  def deleteCategory(category_id):
      if 'username' not in login_session:
          return redirect('/login')
      categoryToDelete = session.query(
          Category).filter_by(id=category_id).one()
      if categoryToDelete.user_id != login_session['user_id']:
          return "<script>function myFunction() {alert('You are not authorized"\
              " to delete this category. Please create your own category in " \
              "order to delete it.');}</script><body onload='myFunction()''>"
      if request.method == 'POST':
          session.delete(categoryToDelete)
          flash('%s Successfully Deleted' % categoryToDelete.name)
          session.commit()
          return redirect(url_for('Catalog', category=category_id))
      else:
          return render_template('deletecategory.html',
                                 category=categoryToDelete)
  
  
  # New menu item
  @app.route('/category/<int:category_id>/new', methods=['GET', 'POST'])
  def newMenuItem(category_id):
      if 'username' not in login_session:
          return redirect('/login')
      category = session.query(Category).filter_by(id=category_id).one()
      if login_session['user_id'] != category.user_id:
          return "<script>function myFunction() {alert('You are not "\
          "authorized to add menu items to this category. Please create "\
          "your own category in order to add items.');}"\
              "</script><body onload='myFunction()'>"
      if request.method == 'POST':
          newItem = MenuItem(name=request.form['name'], description=request.form[
                             'description'], price=request.form['price'],
                             category_id=category_id)
          session.add(newItem)
          session.commit()
          flash("new menu item created!")
          return redirect(url_for('CatalogMenu', category_id=category_id))
      else:
          return render_template('newmenuitem.html', category_id=category_id)
  
  
  # Edit a menu item
  @app.route('/category/<int:category_id>/<int:menu_id>/edit',
             methods=['GET', 'POST'])
  def editMenuItem(category_id, menu_id):
      if 'username' not in login_session:
          return redirect('/login')
      editedItem = session.query(MenuItem).filter_by(id=menu_id).one()
      category = session.query(Category).filter_by(id=category_id).one()
      if login_session['user_id'] != category.user_id:
          return "<script>function myFunction() {alert('You are not "\
          "authorized to edit menu items to this category. Please create "\
          "your own category in order to add items.');}"\
              "</script><body onload='myFunction()'>"
      if request.method == 'POST':
          if request.form['name']:
              editedItem.name = request.form['name']
          if request.form['description']:
              editedItem.description = request.form['description']
          if request.form['price']:
              editedItem.price = request.form['price']
          session.add(editedItem)
          session.commit()
          flash('Menu Item Successfully Edited')
          return redirect(url_for('CatalogMenu', category_id=category_id))
      else:
  
          return render_template(
              'editmenuitem.html', category_id=category_id, menu_id=menu_id,
              item=editedItem)
  
  
  # Delete a menu item
  @app.route('/category/<int:category_id>/<int:menu_id>/delete',
             methods=['GET', 'POST'])
  def deleteMenuItem(category_id, menu_id):
      if 'username' not in login_session:
          return redirect('/login')
      itemToDelete = session.query(MenuItem).filter_by(id=menu_id).one()
      category = session.query(Category).filter_by(id=category_id).one()
      if login_session['user_id'] != category.user_id:
          return "<script>function myFunction() {alert('You are not "\
          "authorized to delete menu items to this category. Please create "\
          "your own category in order to add items.');}"\
              "</script><body onload='myFunction()'>"
      if request.method == 'POST':
          session.delete(itemToDelete)
          session.commit()
          flash('Menu Item Successfully Deleted')
          return redirect(url_for('CatalogMenu', category_id=category_id))
      else:
          return render_template('deletemenuitem.html', item=itemToDelete)
  
  if __name__ == '__main__':
      app.secret_key = 'super_secret_key'
      app.debug = True
      app.run(host='0.0.0.0', port=5000)
  