diff --git a/app.py b/app.py index 4347b45..a1190e6 100644 --- a/app.py +++ b/app.py @@ -2,9 +2,11 @@ from flask.ext.sqlalchemy import SQLAlchemy app = Flask(__name__) +app.secret_key = 'thisisasecret' #To "log in" a user, first make sure you have imported the session - you'll also need to set up an app secret key. -# Set up the SQLAlchemy Database to be a local file 'desserts.db' -app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///desserts.db' + +# Set up the SQLAlchemy Database to be a local file 'users.db' +app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db' db = SQLAlchemy(app) diff --git a/desserts.db b/desserts.db new file mode 100644 index 0000000..7c69d21 Binary files /dev/null and b/desserts.db differ diff --git a/models.py b/models.py index 65eaf43..2020588 100644 --- a/models.py +++ b/models.py @@ -1,4 +1,5 @@ from app import db +from users import get_user_by_username class Dessert(db.Model): @@ -12,20 +13,23 @@ class Dessert(db.Model): name = db.Column(db.String(100)) price = db.Column(db.Float) calories = db.Column(db.Integer) - + origin = db.Column(db.String(100)) + image_url = db.Column(db.String(100)) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) user = db.relationship("User", backref="desserts") - def __init__(self, name, price, calories): + def __init__(self, name, price, calories, origin,image_url,user_id): self.name = name self.price = price self.calories = calories + self.origin = origin + self.image_url = image_url + self.user_id = user_id def calories_per_dollar(self): if self.calories: return self.calories / self.price - class Menu(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -35,23 +39,36 @@ def __init__(self, name): self.name = name -class User(db.Model): - id = db.Column(db.Integer, primary_key=True) - username = db.Column(db.String(100)) - password = db.Column(db.String(100)) - email = db.Column(db.String(250)) - name = db.Column(db.String(100)) - avatar = db.Column(db.String(250)) - - def __init__(self, username, password, email, name, avatar): - self.username = username - self.password = password - self.email = email - self.name = name - self.avatar = avatar - - -def create_dessert(new_name, new_price, new_calories): +# class User(db.Model): +# id = db.Column(db.Integer, primary_key=True) +# username = db.Column(db.String(100)) +# password = db.Column(db.String(100)) +# email = db.Column(db.String(250)) +# name = db.Column(db.String(100)) +# avatar = db.Column(db.String(250)) +# +# def __init__(self, username, password, email, name, avatar): +# self.username = username +# self.password = password +# self.email = email +# self.name = name +# self.avatar = avatar + +def get_desserts(user_id): + desserts = Dessert.query.filter_by(user_id=user_id).all() + return desserts + +def get_all_desserts(): + desserts = Dessert.query.all() + return desserts + + +def get_user_id(username): + user = get_user_by_username(username) + user_id = user.id + return user_id + +def create_dessert(new_name, new_price, new_calories, new_origin, new_image_url,new_user_id): # Create a dessert with the provided input. # We need every piece of input to be provided. @@ -64,8 +81,22 @@ def create_dessert(new_name, new_price, new_calories): if new_name == '' or new_price == '' or new_calories == '': raise Exception("Need name, price and calories!") + # Check for price + if int(new_price) > 50: + raise Exception("A bit too pricey!") + + # Check for calories + if int(new_calories) > 1000: + raise Exception("No one should eat that") + + #Check duplicates + if Dessert.query.filter_by(name=new_name).first(): + raise Exception("Already in the database") + + # This line maps to line 16 above (the Dessert.__init__ method) - dessert = Dessert(new_name, new_price, new_calories) + + dessert = Dessert(new_name, new_price, new_calories, new_origin, new_image_url,new_user_id) # Actually add this dessert to the database db.session.add(dessert) @@ -80,25 +111,68 @@ def create_dessert(new_name, new_price, new_calories): db.session.rollback() -def delete_dessert(id): +def edit_dessert(dessert, new_name, new_price, new_calories, new_origin, new_image_url): + # Edit a dessert with the provided input. - dessert = Dessert.query.get(id) - if dessert: - # We store the name before deleting it, because we can't access it - # afterwards. - dessert_name = dessert.name - db.session.delete(dessert) - - try: - db.session.commit() - return "Dessert {} deleted".format(dessert_name) - except: - # If something went wrong, explicitly roll back the database - db.session.rollback() - return "Something went wrong" + # Can you think of other ways to write this following check? + if new_name is None or new_price is None or new_calories is None: + raise Exception("Need name, price and calories!") + + # They can also be empty strings if submitted from a form + if new_name == '' or new_price == '' or new_calories == '': + raise Exception("Need name, price and calories!") + + # Check for price + if int(new_price) > 50: + raise Exception("A bit too pricey!") + + # Check for calories + if int(new_calories) > 1000: + raise Exception("No one should eat that") + + # This line maps to line 16 above (the Dessert.__init__ method) + dessert.name = new_name + dessert.price = new_price + dessert.calories = new_calories + dessert.origin = new_origin + dessert.image_url = new_image_url + + # Save all pending changes to the database + + try: + db.session.commit() + return dessert + except: + # If something went wrong, explicitly roll back the database + db.session.rollback() + +def delete_dessert(id,user_id): + + dessert = Dessert.query.get(id) + print dessert.user_id + print user_id + if dessert.user_id == user_id: + + if dessert: + # We store the name before deleting it, because we can't access it + # afterwards. + dessert_name = dessert.name + db.session.delete(dessert) + + try: + db.session.commit() + return "Dessert {} deleted".format(dessert_name) + except: + # If something went wrong, explicitly roll back the database + db.session.rollback() + return "Something went wrong" + else: + return "Dessert not found" else: - return "Dessert not found" + return "You can't delete this dessert" + + if __name__ == "__main__": diff --git a/static/starter-template.css b/static/starter-template.css new file mode 100755 index 0000000..eab5c58 --- /dev/null +++ b/static/starter-template.css @@ -0,0 +1,10 @@ +body { + padding-top: 50px; +} +.starter-template { + padding: 40px 15px; + text-align: center; +} +.search { + align-items: baseline; +} diff --git a/templates/add.html b/templates/add.html index d3ad60c..e9781d8 100644 --- a/templates/add.html +++ b/templates/add.html @@ -1,6 +1,5 @@ {% include 'header.html' %} -
Price: ${{ dessert.price }}
+ +Calories: {{ dessert.calories }}
+ +Calories per dollar: {{ dessert.calories_per_dollar() }}
-Price: ${{ dessert.price }}
+Origin: {{ dessert.origin }}
-Calories: {{ dessert.calories }}
+Image:
+
Calories per dollar: {{ dessert.calories_per_dollar() }}
+ Edit {{ dessert.name }} Delete {{ dessert.name }} + {% endif %} - Delete {{ dessert.name }} + {% if error %} +| Name | +Price | +Calories | +Image | +
| {{dessert.name}} | +$ {{dessert.price}} | +{{dessert.calories}} | +
diff --git a/templates/details.html b/templates/details.html index 23f0356..cc4d219 100644 --- a/templates/details.html +++ b/templates/details.html @@ -1,23 +1,42 @@ {% include 'header.html' %} -
\ No newline at end of file + diff --git a/templates/edit.html b/templates/edit.html new file mode 100644 index 0000000..db6683a --- /dev/null +++ b/templates/edit.html @@ -0,0 +1,87 @@ +{% include 'header.html' %} + + +
{{dessert.name}} successfully edited!
+ + ++ + diff --git a/templates/header.html b/templates/header.html index afbc019..11287ee 100644 --- a/templates/header.html +++ b/templates/header.html @@ -1,6 +1,6 @@
-
+
@@ -13,6 +13,55 @@ + + + + + + + + +
diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..a28bd4e --- /dev/null +++ b/templates/login.html @@ -0,0 +1,44 @@ +{% include 'header.html' %} + + +
+ + diff --git a/templates/signup.html b/templates/signup.html new file mode 100644 index 0000000..61e9ec2 --- /dev/null +++ b/templates/signup.html @@ -0,0 +1,67 @@ +{% include 'header.html' %} + + +
+
+
diff --git a/test_users.py b/test_users.py
new file mode 100644
index 0000000..fb627fe
--- /dev/null
+++ b/test_users.py
@@ -0,0 +1,80 @@
+""" Test file for models.py.
+
+ When models.py is complete, this file should completely pass.
+
+ NOTE:
+ To make these tests accurate, this file DELETES all content in the
+ database first.
+"""
+import traceback
+
+from users import *
+
+
+def check_test(func):
+ """ This is a decorator that simply prints out whether the function
+ it calls succeeded or not. You don't need to edit this.
+ """
+ def func_wrapper(*args, **kwargs):
+ try:
+ func(*args, **kwargs)
+ print ":) {} passed".format(func.__name__)
+ except AssertionError:
+ traceback.print_exc()
+ print ":( {} failed".format(func.__name__)
+ return func_wrapper
+
+
+@check_test
+def test_connection():
+ # No longer needed, but let's update this to delete everything so we can
+ # test
+ User.query.delete()
+ db.session.commit()
+
+
+@check_test
+def test_create():
+ # Test that the create user function finishes cleanly
+ result = create_user('test', 'test', 'test', 'test', 'test')
+ # assert is a special Python keyword that throws an error if the thing it
+ # is testing turns out not to be True. Our check_test decorator looks for
+ # errors and tells us the test failed if it found any errors like this.
+ assert result is not None
+ assert isinstance(result, User)
+ assert result.username == 'test'
+
+
+@check_test
+def test_create_worked():
+ result = get_user_by_username('test')
+ assert result is not None
+
+
+@check_test
+def test_get_user_by_id():
+ result = get_user(1)
+ assert result is not None
+
+
+@check_test
+def test_list_users():
+ result = list_users()
+ assert isinstance(result, list) # isinstance says "is it of this type"
+ assert len(result) > 0
+
+
+@check_test
+def test_update_user():
+ result = update_user(1, password='newpass')
+ assert result is not None
+ assert isinstance(result, User)
+ assert result.password == 'newpass'
+
+
+for item in dir():
+ """ Loop through all the defined items we know about (functions, etc).
+ If the name starts with test_, assume it's a test function and run it!
+ """
+ if item.startswith('test_'):
+ globals()[item]()
diff --git a/users.db b/users.db
new file mode 100644
index 0000000..cbba394
Binary files /dev/null and b/users.db differ
diff --git a/users.py b/users.py
new file mode 100644
index 0000000..015cce7
--- /dev/null
+++ b/users.py
@@ -0,0 +1,71 @@
+from app import db
+
+
+class User(db.Model):
+
+ id = db.Column(db.Integer, primary_key=True)
+
+ username = db.Column(db.String(100))
+ password = db.Column(db.String(100))
+ email = db.Column(db.String(250))
+ name = db.Column(db.String(100))
+ avatar = db.Column(db.String(250))
+
+ def __init__(self, username, password, email, name, avatar):
+ self.username = username
+ self.password = password
+ self.email = email
+ self.name = name
+ self.avatar = avatar
+
+
+def list_users():
+ return User.query.all()
+
+
+def get_user(id):
+ return User.query.get(id)
+
+
+def get_user_by_username(username):
+ return User.query.filter_by(username=username).first()
+
+def get_user_by_email(email):
+ return User.query.filter_by(email=email).first()
+
+
+def create_user(username, email, password, realname, avatar):
+ user = User(username, email, password, realname, avatar)
+ db.session.add(user)
+ db.session.commit()
+ return user
+
+
+def update_user(id, username=None, email=None, password=None, realname=None,
+ avatar=None):
+ # This one is harder with the object syntax actually! So we changed the
+ # function definition.
+
+ user = User.query.get(id)
+
+ if username:
+ user.username = username
+
+ if email:
+ user.email = email
+
+ if password:
+ user.password = password
+
+ if realname:
+ user.realname = realname
+
+ if avatar:
+ user.avatar = avatar
+
+ db.session.commit()
+ return user
+
+
+if __name__ == "__main__":
+ db.create_all()
diff --git a/views.py b/views.py
index 679621a..fabe50c 100644
--- a/views.py
+++ b/views.py
@@ -1,60 +1,295 @@
-from flask import render_template, request
+from flask import render_template, request, redirect, session, jsonify
-from models import Dessert, create_dessert, delete_dessert
+from models import *
+from users import *
from app import app
@app.route('/')
def index():
+ if session.get('username'): # this will be executed if 'username' is present in the session
+ print "Logged-in: Found session"
+ username = session['username']
- desserts = Dessert.query.all()
+ user_id = get_user_id(username)
- return render_template('index.html', desserts=desserts)
+ desserts = get_desserts(user_id)
+
+ return render_template('index.html', desserts=desserts, username=username)
+ else:
+ print "Logged-in: No session"
+ return render_template('login.html', error="Please login.")
+
+
+@app.route('/login')
+def login():
+ return render_template('login.html')
+
+@app.route('/submit-login', methods=['POST'])
+def submit_login():
+ #get form info
+ user_username = request.form.get('username_field')
+ user_password = request.form.get('password_field')
+
+ print user_username
+
+ # check for username
+ user_login = get_user_by_username(user_username)
+ if user_login:
+ # check for password
+ print "username is ok"
+ print user_login.password
+ print user_password
+ if user_login.password == user_password:
+ print "password is ok"
+ session['username'] = user_username
+ return redirect('/')
+ else:
+ print "password does not match"
+ return render_template('login.html', error="Login credentials don't not work")
+ else:
+ print "password does not match"
+ return render_template('login.html', error="Login credentials don't not work")
+
+
+@app.route('/signup')
+def signup_():
+ return render_template('signup.html')
+
+@app.route('/submit-signup', methods=['POST'])
+def submit_signup():
+ #get form info
+ user_username = request.form.get('username_field')
+ user_password = request.form.get('password_field')
+ user_email = request.form.get('email_field')
+ user_name = request.form.get('name_field')
+ user_avatar = request.form.get('avatar_field')
+
+ print user_username
+
+ # check for duplicated username
+ if get_user_by_username(user_username):
+ return render_template('signup.html',error="Username already exists")
+
+ # check for duplicated email
+ elif get_user_by_email(user_email):
+ return render_template('signup.html',error="Email already exists")
+
+ # if no duplicates, create user
+ else:
+ try:
+ user = create_user(user_username, user_email, user_password, user_name, user_avatar)
+ session['username'] = user_username
+ return redirect('/')
+ except Exception as e:
+ # Oh no, something went wrong!
+ # We can access the error message via e.message:
+ return render_template('signup.html', error=e.message)
@app.route('/add', methods=['GET', 'POST'])
def add():
+ if session.get('username'): # this will be executed if 'username' is present in the session
+ print "Logged-in: Found session"
+ username = session['username']
+
+ if request.method == 'GET':
+ return render_template('add.html')
+
+ # Because we 'returned' for a 'GET', if we get to this next bit, we must
+ # have received a POST
+
+ # Get the incoming data from the request.form dictionary.
+ # The values on the right, inside get(), correspond to the 'name'
+ # values in the HTML form that was submitted.
+
+ dessert_name = request.form.get('name_field')
+ dessert_price = request.form.get('price_field')
+ dessert_cals = request.form.get('cals_field')
+ dessert_origin = request.form.get('origin_field')
+ dessert_image_url = request.form.get('image_url_field')
+
+ user_id = get_user_id(username)
+
+ # Now we are checking the input in create_dessert, we need to handle
+ # the Exception that might happen here.
+
+ # Wrap the thing we're trying to do in a 'try' block:
+ try:
+ dessert = create_dessert(dessert_name, dessert_price, dessert_cals, dessert_origin, dessert_image_url, user_id)
+ return render_template('add.html', dessert=dessert, username=username)
+ except Exception as e:
+ # Oh no, something went wrong!
+ # We can access the error message via e.message:
+ return render_template('add.html', error=e.message, username=username)
+
+ else:
+ print "Logged-in: No session"
+ return render_template('login.html', error="Please login.")
+
+
- if request.method == 'GET':
- return render_template('add.html')
+@app.route('/edit/