<file_sep>{% extends 'layouts/main.html' %}
{% block title %}MyFridge{% endblock %}
{% block content %}
<div class="row">
	<div class="col-sm-6">
		<h1>MyFridge</h1>
		<p class="lead">Eat Clean. Clean Earth</p>
		<h3>
			<a href="/recipes"><button class="btn btn-primary btn-lg">Find a Recipe</button></a>
		</h3>
		<h3>
			<a href="/users"><button class="btn btn-primary btn-lg">Find a User</button></a>
			<a href="/users/create"><button class="btn btn-default btn-lg">Add a User</button></a>
		</h3>
		<h3>
			<a href="/products"><button class="btn btn-primary btn-lg">Find a product</button></a>
			<a href="/products/create"><button class="btn btn-default btn-lg">Add a product</button></a>
		</h3>
	</div>
	<div class="col-sm-6 hidden-sm hidden-xs">
		<img id="front-splash" src="{{ url_for('static',filename='img/myfridge-splash.png') }}" alt="Front Photo of Productive App" />
	</div>
	<form class="form-upload" method=post enctype=multipart/form-data>
        <h1 class="h3 mb-3 font-weight-normal">Please Upload</h1>
        <input type="file" id="image" name=image class="form-control" required autofocus>
        <button class="btn btn-lg btn-primary btn-block" type="submit">Add Receipt</button>
        <br>
        {% if image_loc %}
          <img class="mb-4" src="static/{{ image_name }}" alt="" width="256" height="256">
          <h3 class="h3 mb-3 font-weight-normal">Prediction: {{Prediction}}</h3>
        {% endif %}
      </form>
</div>
{% endblock %}<file_sep>import os
from sqlalchemy import Column, String, Integer, DateTime, ForeignKey, \
  Table, create_engine
from flask_sqlalchemy import SQLAlchemy
import json
from flask_migrate import Migrate

database_name = "myfridge"
database_path = "postgresql://{}/{}".format('localhost:5432', database_name)

db = SQLAlchemy()
migrate = Migrate()

'''
setup_db(app)
    binds a flask application and a SQLAlchemy service
'''
def setup_db(app, database_path=database_path):
    app.config["SQLALCHEMY_DATABASE_URI"] = database_path
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
    db.app = app
    db.init_app(app)
    migrate.init_app(app, db)
    db.create_all()


"""
db_drop_and_create_all()
    drops the database tables and starts fresh
    can be used to initialize a clean database

    Keyword arguments: n/a
    argument -- n/a
    Return: return_description
"""
def db_drop_and_create_all():
    db.drop_all()
    db.create_all()


'''
User-Product association table
'''
user_products = Table('user_products', db.Model.metadata,    
      Column('user_id', Integer, ForeignKey('users.id',
        onupdate='CASCADE', ondelete='CASCADE'), primary_key=True),
      Column('product_id', Integer, ForeignKey('products.id',
        onupdate='CASCADE', ondelete='CASCADE'), primary_key=True))

'''
User
'''
class User(db.Model):  
  __tablename__ = 'users'

  id = Column(Integer, primary_key=True)
  first_name = Column(String, nullable=False)
  last_name = Column(String, nullable=False)
  age = Column(Integer)
  products = db.relationship('Product', secondary='user_products',
                            backref=db.backref('users', lazy=True))
  current_products = Column(String)
  past_products = Column(String)
  date_registered = Column(DateTime)

  def __init__(self, first_name, last_name, age):
    self.first_name = first_name
    self.last_name = last_name
    self.age = age
    self.current_products={}
    self.past_products={}


  def insert(self):
    db.session.add(self)
    db.session.commit()
  
  def update(self):
    db.session.commit()

  def delete(self):
    db.session.delete(self)
    db.session.commit()

  def format(self):
    return {
      'id': self.id,
      'first_name': self.first_name,
      'last_name': self.last_name,
      'current_products': self.current_products,
      'past_products': self.past_products,
      'date_registered': self.date_registered
    }

  def __repr__(self):
        return f'<User {self.id}: {self.last_name}, {self.first_name}>'


'''
Product

'''
class Product(db.Model):  
  __tablename__ = 'products'

  id = Column(Integer, primary_key=True)
  name = Column(String)
  weight = Column(String)
  quantity = Column(String)
  date_purchased = Column(Integer)
  image_link = Column(String)

  def __init__(self, name, weight, quantity, date_purchased, description=''):
    self.name = name
    self.description = description
    self.weight = weight
    self.quantity = quantity
    self.date_purchased = date_purchased

  def insert(self):
    db.session.add(self)
    db.session.commit()
  
  def update(self):
    db.session.commit()

  def delete(self):
    db.session.delete(self)
    db.session.commit()

  def format(self):
    return {
      'id': self.id,
      'name': self.name,
      'weight': self.weight,
      'quantity': self.quantity,
      'date_purchased': self.date_purchased
    }

  def __repr__(self):
        return f'<Product {self.id}: {self.last_name}, {self.first_name}>'

<file_sep>
import os
import babel
import dateutil.parser
from flask import Flask, request, abort, jsonify, redirect, flash
from flask import url_for, render_template
from flask import session
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
from flask_migrate import Migrate
from .database.models import *
from .auth.auth import AuthError, requires_auth
from datetime import datetime, date
import json
import logging
from six.moves.urllib.parse import urlencode
from google.cloud import vision
import io
from .forms import *
import sys



def create_app(test_config=None):
    
    app = Flask(__name__)
    setup_db(app)
    CORS(app)
    #app.secret_key = os.environ['SECRET']
    #os.environ["GOOGLE_APPLICATION_CREDENTIALS"]=r"C:\Users\shahd\OneDrive\Desktop\MediDate Application\MediDate_Credentials\steel-aileron-266916-d88c69f449c7.json"
    UPLOAD_FOLDER = '/home/Jared/Desktop/Hackathon/enactusHacks/App/app/static/img/Receipts/'
    #----------------------------------------------------------------------------#
    # Functions.
    #----------------------------------------------------------------------------#

    def format_datetime(value, format='medium'):
        date = dateutil.parser.parse(value)
        if format == 'full':
            format="EEEE MMMM, d, y 'at' h:mma"
        elif format == 'medium':
            format="EE MM, dd, y h:mma"
        return babel.dates.format_datetime(date, format)

    app.jinja_env.filters['datetime'] = format_datetime



    def detect_text(path):
        """Detects text in the receipt file."""
    
        client = vision.ImageAnnotatorClient()

        with io.open(path, 'rb') as image_file:
            content = image_file.read()

        image = vision.types.Image(content=content)

        response = client.text_detection(image=image)
        texts = response.text_annotations
        d = {"Name": 0, "Fill Date": 0, "RX": 0, "Qty": 90, "date-to-take": 0, "Red": 0, "Blue": 0,"Green": 0}
        count = 0
        for text in texts:
            if(text.description == "Rx" or text.description == "Rx#" or text.description == "#" or text.description == "Rx:" or text.description == "Rx:#" or text.description == "Rx: #" or text.description == ":"):
                count = 1
                continue
            if(text.description[0:2] == "Qty"):
                d["Qty"] = text.description[3:len(text.description)-1]
                
            if(count == 1):
                d["RX"] = text.description
                count = 0
            vertices = (['({},{})'.format(vertex.x, vertex.y)
                        for vertex in text.bounding_poly.vertices])

            print('bounds: {}'.format(','.join(vertices)))
        return d

        if response.error.message:
            raise Exception(
                '{}\nFor more info on error messages, check: '
                'https://cloud.google.com/apis/design/errors'.format(
                    response.error.message))
   
    #----------------------------------------------------------------------------#
    # Endpoints.
    #----------------------------------------------------------------------------#

    
    @app.after_request
    def after_request(response):
        response.headers.add('Access-Control-Allow-Headers',
                             'Authorization, Content-Type')
        response.headers.add('Access-Control-Allow-Methods',
                             'GET, POST, DELETE, PATCH')
        return response
    
    """Main Index Endpoint
    
        Return: returns home.html
    """
    
    @app.route('/')
    def home():
        return render_template('pages/home.html')

    def upload_predict():
        if request.method == "POST":
            image_file = request.files["image"]
            if image_file:
                image_location = os.path.join(
                    UPLOAD_FOLDER,
                    image_file.filename
                )
                image_file.save(image_location)
                pred = detect_text
                return render_template("pages/home.html", prediction=pred, image_name=image_file.filename)
        return render_template("pages/home.html", prediction=0, image_name=None)


    """GET /products
      Gets all products in the database

      Returns:
          JSON Object -- json of all products in the database
    """
    @app.route('/products')
    #@requires_auth('get:products')
    def get_products():

        data= Product.query.distinct().order_by(Product.name.desc()).all()
        
        return render_template('pages/products.html', products=data)

    """GET /users
      Gets all users in the database

      Returns:
          JSON Object -- json of all users in the database
    """
    @app.route('/users')
    #@requires_auth('get:user')
    def get_users():

        data= User.query.distinct().order_by(User.last_name.desc()).all()
  
        return render_template('pages/users.html', users=data)

    @app.route('/users/search', methods=['POST'])
    def search_artists():
        
        search_term = request.form.get('search_term',None)
        artists = User.query.filter(User.name.ilike("%{}%".format(search_term))).all()

        response={
            "count":len(users),
            "data": user
        }


    """GET /products/create
      Creates and adds a new product to the database

      Returns:
          JSON Object -- json of movie added if the entry is successful
    """

    @app.route('/products/create', methods=['GET'])
    def create_product_form():
        form = ProductForm()   
        return render_template('forms/new_product.html', form=form)

    """POST /products
      Creates and adds a new product to the database

      Returns:
          JSON Object -- json of movie added if the entry is successful
    """
    @app.route('/products', methods=['POST'])
    #@requires_auth('post:products')
    def new_product():

        form = ProductForm(request.form)
        print(form)
        error=False
        try:
            product = Product(
                name=form.name.data,
                description=form.description.data,
                weight=form.weight.data,
                quantity=form.quanitity.data,
                date_purchased=form.date_purchased.data
            )
            db.session.add(product)
            db.session.commit()
            # on successful db insert, flash success
            flash('Product ' + request.form['name'] +  
                ' was successfully listed!')
        except:
            error = True
            db.session.rollback()
            print(sys.exc_info())
            flash('An error occurred. Product ' + Product.name +
                ' could not be listed.')
        finally:
            db.session.close()
            
        return render_template('pages/home.html')
    
    """GET /users
      Creates and adds a new user to the database

      Returns:
          web page
    """
    @app.route('/users/create', methods=['GET'])
    def create_user_form():
        form = UserForm()   
        return render_template('forms/new_user.html', form=form)

    """POST /users
      Creates and adds a new user to the database

      Returns:
          web page
    """
    @app.route('/users', methods=['POST'])
    #@requires_auth('post:user')
    def new_user():

        form = UserForm(request.form)
        print(form)
        error=False
        try:
            user = User(
                first_name=form.first_name.data,
                last_name=form.last_name.data,
                age=form.age.data
            )
            db.session.add(user)
            db.session.commit()
            # on successful db insert, flash success
            flash('User ' + request.form['first_name'] + request.form['last_name'] + 
                ' was successfully listed!')
        except:
            error = True
            db.session.rollback()
            print(sys.exc_info())
            flash('An error occurred. User ' + User.first_name +
                User.last_name + ' could not be listed.')
        finally:
            db.session.close()
            
        return render_template('pages/home.html')

    """'DELETE /products/<int:product_id>
        Deletes a product from the database

      Inputs:
          int "product_id"

      Returns:
          JSON Object -- json message if deletion is successful
    """
    @app.route('/products/<int:product_id>', methods=['DELETE'])
    #@requires_auth('delete:product')
    def delete_product(product_id):

        # Delete product with submitted id from database
        try:
            # Find product with product_id
            product = Product.query.filter(Product.id == product_id).one_or_none()

            # if product is none throw 404  
            if product is None:
                abort(404)

            # Delete the product
            product.delete()

            result = {
                'success': True,
                'message': 'Deleted Product ID: ' + str(product_id)
            }

        except:
            abort(422)

        return jsonify(result)

    """'DELETE /users/<int:user_id>
      Deletes an user from the database

      Inputs:
          int "user_id"

      Returns:
          JSON Object -- json message if deletion is successful
    """
    @app.route('/users/<int:user_id>', methods=['DELETE'])
    #@requires_auth('delete:user')
    def delete_user(payload, user_id):

        # Delete user with submitted id from database
        try:

            # Find user with user_id
            user = User.query.filter(User.id == user_id).one_or_none()

            # If user is none throw 404
            if user is None:
                abort(404)

            # Delete the user
            user.delete()

            result = {
                'success': True,
                'message': 'Deleted User ID: ' + str(user_id)
            }

        except:
            abort(422)

        return jsonify(result)


    """GET /products/<int:product_id>
      Edits a recipe in the database

      Inputs:
          int "recipe_id"

      Returns:
          JSON Object -- json message if edit is successful
    """
    @app.route('/products/<int:product_id>', methods=['GET'])
    #@requires_auth('post:product')
    def edit_product(product_id):

        form = ProductForm()

        product_update=Product.query.filter_by(id=product_id).one_or_none()
        
        if product_update is None:
            abort(404)

        product={
            'id': product_update.id,
            'name' : product_update.name,
            'description' : product_update.description,
            'weight' : product_update.weight,
            'quantity' : product_update.date_purchased
        }

        form=ProductForm(data=product)
        
        return render_template('forms/edit_product.html', form=form, product=product)
    


    """GET /products/<int:product_id>
      Edits a recipe in the database

      Inputs:
          int "recipe_id"

      Returns:
          JSON Object -- json message if edit is successful
    """
    @app.route('/products/<int:product_id>/edit', methods=['POST'])
    #@requires_auth('post:product')
    def edit_product_submission(product_id):

        form = ProductForm(request.form)
        try:
            product = Product.query.filter_by(id=product_id).one()
            product.name=form.name.data
            product.description=form.description.data
            product.weight=form.weight.data
            product.quantity = form.quantity.data
            product.date_purchased = form.date_purchased.data

            db.session.commit()
            flash('Product ' + request.form['name'] + ' was updated successfully.')
        
        except:
            db.session.rollback()
            flash('An error occurred.  User ' + request.form['name'] + 
             ' failed to update.')

        return redirect(url_for('show_product', product_id=product_id))

    """GET /users/<int:user_id>/edit
      Edits an user in the database

      Inputs:
          int "user_id"

      Returns:
          JSON Object -- json message if edit is successful
    """
    @app.route('/users/<int:user_id>/edit', methods=['GET'])
    def edit_user(user_id):
        form = UserForm()
        user_update = User.query.filter_by(id=user_id).one_or_none()
        if user_update is None:
            abort(404)

        user={
            'id': user_update.id,
            'first_name' : user_update.first_name,
            'last_name' : user_update.last_name,
            'age' : user_update.age
        }

        form=UserForm(data=user)

        return render_template('forms/edit_artist.html', form=form, user=user)

    """POST /users/<int:user_id>/edit
      Edits an user in the database

      Inputs:
          int "user_id"

      Returns:
          JSON Object -- json message if edit is successful
    """
    @app.route('/users/<int:user_id>/edit', methods=['POST'])
    #@requires_auth('patch:user')
    def edit_user_submission(user_id):

        form = UserForm(request.form)
        try:
            user = User.query.filter_by(id=user_id).one()
            user.first_name=form.first_name.data
            user.last_name=form.last_name.data
            user.age=form.age.data

            db.session.commit()
            flash('User ' + request.form['first_name'] + 
                request.form['last_name'] + ' was updated successfully.')
        
        except:
            db.session.rollback()
            flash('An error occurred.  User ' + request.form['first_name'] + 
                request.form['last_name'] + ' failed to update.')

        return redirect(url_for('show_user', user_id=user_id))


    """
    Login Route

    The login route redirects to the Auth0 login page
    """
    '''
    @app.route('/login')
    def login():
        link = 'https://'
        link += os.environ['AUTH0_DOMAIN']
        link += '/authorize?'
        link += 'audience=' + os.environ['API_AUDIENCE'] + '&'
        link += 'response_type=token&'
        link += 'client_id=' + os.environ['CLIENT_ID'] + '&'
        link += 'redirect_uri=' + os.environ['CALLBACK_URL'] +\
            os.environ['CALLBACK_PATH']
        return redirect(link)

    """
    Logout Route

    The logout route logs out and redirects to the home page
    """
    @app.route('/logout')
    def logout():
        # Clear session stored data
        session.clear()
        # Redirect user to logout endpoint
        link = 'https://'
        link += os.environ['AUTH0_DOMAIN']
        link += '/v2/logout?'
        link += 'client_id=' + os.environ['CLIENT_ID'] + '&'
        link += 'returnTo=' + os.environ['CALLBACK_URL']

        return redirect(link)
    '''
# ---------------------------------------------------------------------------#
# Errors.
# ---------------------------------------------------------------------------#

    # ERROR - BAD REQUEST (400)
    @app.errorhandler(400)
    def bad_request(error):
        return jsonify({
            'success': False,
            'error': 400,
            'message': 'bad request'
        }), 400

    # ERROR - UNAUTHORIZED (401)
    @app.errorhandler(401)
    def forbidden(error):
        return jsonify({
            'success': False,
            'error': 401,
            'message': 'unauthorized'
        }), 401

    # ERROR - FORBIDDEN (403)
    @app.errorhandler(403)
    def forbidden(error):
        return jsonify({
            'success': False,
            'error': 403,
            'message': 'forbidden'
        }), 403

    # ERROR - NOT FOUND (404)
    @app.errorhandler(404)
    def resource_not_found(error):
        return jsonify({
            'success': False,
            'error': 404,
            'message': 'resource not found'
        }), 404

    # ERROR - METHOD NOT ALLOWED (405)
    @app.errorhandler(405)
    def method_not_allowed(error):
        return jsonify({
            'success': False,
            'error': 405,
            'message': 'method not allowed'
        }), 405

    # ERROR - UNPROCESSABLE (422)
    @app.errorhandler(422)
    def unprocessable(error):
        return jsonify({
            'success': False,
            'error': 422,
            'message': 'unprocessable'
        }), 422

    # ERROR - INTERNAL SERVER ERROR (500)
    @app.errorhandler(500)
    def server_error(error):
        return jsonify({
            'success': False,
            'error': 500,
            'message': 'internal server error'
        }), 500
    
    # ERROR - AUTHENTICATION ERROR
    @app.errorhandler(AuthError)
    def auth_error(error):
        return jsonify({
            "success": False,
            "error": error.status_code,
            "message": error.error
        }), error.status_code
    
    return app

# ----------------------------------------------------------------------------#
# Ceate and Launch App.
# ----------------------------------------------------------------------------#

# Create App
app = create_app()


# Run App
if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG)
    app.run(host='127.0.0.1', port=8080)
<file_sep>"""empty message

Revision ID: 88162422f489
Revises: 
Create Date: 2020-10-25 02:28:49.305303

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '88162422f489'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_constraint('user_products_product_id_fkey', 'user_products', type_='foreignkey')
    op.drop_constraint('user_products_user_id_fkey', 'user_products', type_='foreignkey')
    op.create_foreign_key(None, 'user_products', 'users', ['user_id'], ['id'], onupdate='CASCADE', ondelete='CASCADE')
    op.create_foreign_key(None, 'user_products', 'products', ['product_id'], ['id'], onupdate='CASCADE', ondelete='CASCADE')
    op.alter_column('users', 'first_name',
               existing_type=sa.VARCHAR(),
               nullable=False)
    op.alter_column('users', 'last_name',
               existing_type=sa.VARCHAR(),
               nullable=False)
    # ### end Alembic commands ###


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column('users', 'last_name',
               existing_type=sa.VARCHAR(),
               nullable=True)
    op.alter_column('users', 'first_name',
               existing_type=sa.VARCHAR(),
               nullable=True)
    op.drop_constraint(None, 'user_products', type_='foreignkey')
    op.drop_constraint(None, 'user_products', type_='foreignkey')
    op.create_foreign_key('user_products_user_id_fkey', 'user_products', 'users', ['user_id'], ['id'])
    op.create_foreign_key('user_products_product_id_fkey', 'user_products', 'products', ['product_id'], ['id'])
    # ### end Alembic commands ###
<file_sep>alembic==1.3.0
appnope==0.1.0
asn1crypto==1.3.0
astroid==2.4.1
attrs==19.3.0
Authlib==0.14.3
Babel==2.8.0
backcall==0.1.0
backports.functools-lru-cache==1.6.1
backports.tempfile==1.0
backports.weakref==1.0.post1
beautifulsoup4==4.9.0
bleach==3.1.4
certifi==2019.9.11
cffi==1.14.0
chardet==3.0.4
click==7.1.1
cryptography==2.8
decorator==4.4.2
defusedxml==0.6.0
ecdsa==0.15
entrypoints==0.3
filelock==3.0.12
Flask==1.1.1
Flask-Cors==3.0.8
Flask-Migrate==2.5.2
Flask-Moment==0.9.0
Flask-Script==2.0.6
Flask-SQLAlchemy==2.4.1
Flask-WTF==0.14.3
future==0.18.2
glob2==0.7
gunicorn==20.0.0
idna==2.9
importlib-metadata==1.5.0
ipykernel==5.1.4
ipython==7.13.0
ipython-genutils==0.2.0
ipywidgets==7.5.1
isort==4.3.21
itsdangerous==1.1.0
jedi==0.17.0
Jinja2==2.10.3
joblib==0.14.1
json5==0.9.4
jsonschema==3.2.0
jupyter-client==6.1.3
jupyter-core==4.6.3
jupyterlab==1.2.6
jupyterlab-server==1.1.1
lazy-object-proxy==1.4.3
libarchive-c==2.9
Mako==1.1.0
MarkupSafe==1.1.1
mccabe==0.6.1
mistune==0.8.4
nbconvert==5.6.1
nbformat==5.0.4
nltk==3.5
notebook==6.0.3
pandocfilters==1.4.2
parso==0.7.0
pexpect==4.8.0
phonenumbers==8.12.3
pickleshare==0.7.5
pkginfo==1.5.0.1
postgres==3.0.0
prometheus-client==0.7.1
prompt-toolkit==3.0.4
psutil==5.7.0
psycopg2-binary==2.8.4
psycopg2-pool==1.1
ptyprocess==0.6.0
pyasn1==0.4.8
pycosat==0.6.3
pycparser==2.20
pycryptodome==3.3.1
Pygments==2.6.1
PyJWT==1.7.1
pylint==2.5.2
pylint-flask==0.6
pylint-flask-sqlalchemy==0.2.0
pylint-plugin-utils==0.6
pyOpenSSL==19.1.0
pyrsistent==0.16.0
PySocks==1.7.1
python-dateutil==2.8.1
python-dotenv==0.13.0
python-editor==1.0.4
python-jose==3.1.0
python-jose-cryptodome==1.3.2
pytz==2020.1
PyYAML==5.3.1
pyzmq==18.1.1
regex==2020.4.4
requests==2.23.0
rsa==4.0
ruamel-yaml==0.15.87
Send2Trash==1.5.0
six==1.13.0
soupsieve==2.0
SQLAlchemy==1.3.10
terminado==0.8.3
testpath==0.4.4
toml==0.10.0
tornado==6.0.4
tqdm==4.46.0
traitlets==4.3.3
typed-ast==1.4.1
urllib3==1.25.8
wcwidth==0.1.9
webencodings==0.5.1
Werkzeug==0.16.0
widgetsnbextension==3.5.1
wrapt==1.12.1
WTForms==2.3.1
zipp==3.1.0
<file_sep>from datetime import datetime
from flask_wtf import Form
from wtforms import StringField, SelectField, SelectMultipleField, DateTimeField
from wtforms.validators import DataRequired, AnyOf, URL

class ProductForm(Form):
    name = StringField(
        'name', validators=[DataRequired()]
    )
    weight = StringField(
        'weight', validators=[DataRequired()]
    )
    quanitity = StringField(
        'quantity', validators=[DataRequired()]
    )
    date_purchased = DateTimeField(
        'date_purchased', validators=[DataRequired()]
    )
    image_link = StringField(
        'image_link'
    )


class UserForm(Form):
    first_name = StringField(
        'first_name', validators=[DataRequired()]
    )
    last_name = StringField(
        'last_name', validators=[DataRequired()]
    )
    age = StringField(
        'age', validators=[DataRequired()]
    )



