From be2feb1b6986ca7b06e55c1988a9b993e31d6fc2 Mon Sep 17 00:00:00 2001
From: michellecarey
Date: Fri, 1 Dec 2017 00:52:47 -0800
Subject: [PATCH 1/4] updates
---
.../users-messages-forms/app.py | 120 ++++++++++++++++++
.../users-messages-forms/forms.py | 9 ++
.../users-messages-forms/manage.py | 12 ++
.../users-messages-forms/migrations/README | 1 +
.../migrations/alembic.ini | 45 +++++++
.../users-messages-forms/migrations/env.py | 87 +++++++++++++
.../migrations/script.py.mako | 24 ++++
.../10ea5e18414a_adding_users_table.py | 33 +++++
.../bcb5d2e5decd_adding_messages_table.py | 34 +++++
.../users-messages-forms/templates/base.html | 11 ++
.../templates/messages/edit.html | 9 ++
.../templates/messages/index.html | 16 +++
.../templates/messages/new.html | 9 ++
.../templates/messages/show.html | 0
.../templates/users/edit.html | 12 ++
.../templates/users/index.html | 17 +++
.../templates/users/new.html | 18 +++
.../templates/users/show.html | 0
18 files changed, 457 insertions(+)
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/app.py
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/forms.py
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/manage.py
create mode 100755 Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/README
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/alembic.ini
create mode 100755 Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/env.py
create mode 100755 Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/script.py.mako
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/versions/10ea5e18414a_adding_users_table.py
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/versions/bcb5d2e5decd_adding_messages_table.py
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/templates/base.html
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/edit.html
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/index.html
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/new.html
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/show.html
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/edit.html
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/index.html
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/new.html
create mode 100644 Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/show.html
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/app.py b/Unit-01/07-sql-alchemy-2/users-messages-forms/app.py
new file mode 100644
index 0000000..f2f16a1
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/app.py
@@ -0,0 +1,120 @@
+from flask import Flask, request, redirect, render_template, url_for
+from flask_sqlalchemy import SQLAlchemy
+from flask_modus import Modus
+from forms import UserForm, MessageForm
+import os
+
+app = Flask(__name__)
+app.config['SQLALCHEMY_DATABASE_URI'] = "postgres://localhost/users-messages"
+app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
+app.config['SECRET KEY'] = os.environ.get('SECRET_KEY')
+modus = Modus(app)
+db = SQLAlchemy(app)
+
+class User(db.Model):
+
+ __tablename__ = "users"
+
+ id = db.Column(db.Integer, primary_key=True)
+ first_name = db.Column(db.Text)
+ last_name = db.Column(db.Text)
+ messages = db.relationship('Message', backref="user", lazy="dynamic")
+
+ def __init__(self, first_name, last_name):
+ self.first_name = first_name
+ self.last_name = last_name
+
+class Message(db.Model):
+
+ __tablename__ = "messages"
+
+ id = db.Column(db.Integer, primary_key=True)
+ content = db.Column(db.Text)
+ user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
+
+ def __init__(self, content, user_id):
+ self.content = content
+ self.user_id = user_id
+
+@app.route('/')
+def root():
+ return redirect(url_for('index'))
+
+@app.route('/users', methods=["GET", "POST"])
+def index():
+ if request.method == "POST":
+ form = UserForm(request.form)
+ if form.validate():
+ new_user = User(request.form['first_name'], request.form['last_name'])
+ db.session.add(new_user)
+ db.session.commit()
+ return redirect(url_for('index'))
+ else:
+ return render_template('users/new.html', form=form)
+ return render_template('users/index.html', users=User.query.all())
+
+@app.route('/users/new')
+def new():
+ found_user = UserForm()
+ return render_template('users/new.html', form=user_form)
+
+@app.route('/users//edit')
+def edit(id):
+ found_user = User.query.get(id)
+ return render_template('users/edit.html', user=found_user)
+
+@app.route('/users/', methods=["GET", "PATCH", "DELETE"])
+def show(id):
+ found_user = User.query.get(id)
+ if request.method == b"PATCH":
+ found_user.first_name = request.form['first_name']
+ found_user.last_name = request.form['last_name']
+ db.session.add(found_user)
+ db.session.commit()
+ return redirect(url_for('index'))
+ if request.method == b"DELETE":
+ db.session.delete(found_user)
+ db.session.commit()
+ return redirect(url_for('index'))
+ return render_template('users/show.html', user=found_user)
+
+@app.route('/users//messages', methods=["GET", "POST"])
+def messages_index(user_id):
+ if request.method == "POST":
+ new_message = Message(request.form['content'], user_id)
+ db.session.add(new_message)
+ db.session.commit()
+ return redirect(url_for('messages_index', user_id=user_id))
+ return render_template('messages/index.html', user=User.query.get(user_id))
+
+@app.route('/users//messages/new', methods=["GET", "POST"])
+def messages_new(user_id):
+ return render_template('messages/new.html', user=User.query.get(user_id))
+
+@app.route('/users//messages//edit', methods=["GET", "POST"])
+def messages_edit(user_id, id):
+ found_message = Message.query.get(id)
+ return render_template('messages/edit.html', message=found_message)
+
+
+@app.route('/users//messages/', methods=["GET", "PATCH", "DELETE"])
+def messages_show(user_id, id):
+ found_message = Message.query.get(id)
+ if request.method == b"PATCH":
+ found_message.content = request.form['content']
+ db.session.add(found_message)
+ db.session.commit()
+ return redirect(url_for('messages_index', user_id=user_id))
+ if request.method == b"DELETE":
+ db.session.delete(found_message)
+ db.session.commit()
+ return redirect(url_for('messages_index', user_id=user_id))
+ return render_template('messages/show.html', message=found_message)
+
+
+
+if __name__ == '__main__':
+ app.run(debug=True, port=3000)
+
+
+
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/forms.py b/Unit-01/07-sql-alchemy-2/users-messages-forms/forms.py
new file mode 100644
index 0000000..89d7b30
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/forms.py
@@ -0,0 +1,9 @@
+from flask_wtf import FLaskForm
+from wtforms import StringField, validators
+
+class UserForm(FlaskForm):
+ first_name = StringField('First Name', [validators.DataRequired()])
+ last_name = StringField('Last Name', [validators.DataRequired()])
+
+ class MessageForm(FlaskForm):
+ content = StringField('Content', [validators.DataRequired])
\ No newline at end of file
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/manage.py b/Unit-01/07-sql-alchemy-2/users-messages-forms/manage.py
new file mode 100644
index 0000000..23ae47a
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/manage.py
@@ -0,0 +1,12 @@
+from app import app, db
+
+from flask_script import Manager
+from flask_migrate import Migrate, MigrateCommand
+
+migrate = Migrate(app, db)
+manager = Manager(app)
+
+manager.add_command('db', MigrateCommand)
+
+if __name__ == '__main__':
+ manager.run()
\ No newline at end of file
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/README b/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/README
new file mode 100755
index 0000000..98e4f9c
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/README
@@ -0,0 +1 @@
+Generic single-database configuration.
\ No newline at end of file
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/alembic.ini b/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/alembic.ini
new file mode 100644
index 0000000..f8ed480
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/alembic.ini
@@ -0,0 +1,45 @@
+# A generic, single database configuration.
+
+[alembic]
+# template used to generate migration files
+# file_template = %%(rev)s_%%(slug)s
+
+# set to 'true' to run the environment during
+# the 'revision' command, regardless of autogenerate
+# revision_environment = false
+
+
+# Logging configuration
+[loggers]
+keys = root,sqlalchemy,alembic
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = WARN
+handlers = console
+qualname =
+
+[logger_sqlalchemy]
+level = WARN
+handlers =
+qualname = sqlalchemy.engine
+
+[logger_alembic]
+level = INFO
+handlers =
+qualname = alembic
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(levelname)-5.5s [%(name)s] %(message)s
+datefmt = %H:%M:%S
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/env.py b/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/env.py
new file mode 100755
index 0000000..23663ff
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/env.py
@@ -0,0 +1,87 @@
+from __future__ import with_statement
+from alembic import context
+from sqlalchemy import engine_from_config, pool
+from logging.config import fileConfig
+import logging
+
+# this is the Alembic Config object, which provides
+# access to the values within the .ini file in use.
+config = context.config
+
+# Interpret the config file for Python logging.
+# This line sets up loggers basically.
+fileConfig(config.config_file_name)
+logger = logging.getLogger('alembic.env')
+
+# add your model's MetaData object here
+# for 'autogenerate' support
+# from myapp import mymodel
+# target_metadata = mymodel.Base.metadata
+from flask import current_app
+config.set_main_option('sqlalchemy.url',
+ current_app.config.get('SQLALCHEMY_DATABASE_URI'))
+target_metadata = current_app.extensions['migrate'].db.metadata
+
+# other values from the config, defined by the needs of env.py,
+# can be acquired:
+# my_important_option = config.get_main_option("my_important_option")
+# ... etc.
+
+
+def run_migrations_offline():
+ """Run migrations in 'offline' mode.
+
+ This configures the context with just a URL
+ and not an Engine, though an Engine is acceptable
+ here as well. By skipping the Engine creation
+ we don't even need a DBAPI to be available.
+
+ Calls to context.execute() here emit the given string to the
+ script output.
+
+ """
+ url = config.get_main_option("sqlalchemy.url")
+ context.configure(url=url)
+
+ with context.begin_transaction():
+ context.run_migrations()
+
+
+def run_migrations_online():
+ """Run migrations in 'online' mode.
+
+ In this scenario we need to create an Engine
+ and associate a connection with the context.
+
+ """
+
+ # this callback is used to prevent an auto-migration from being generated
+ # when there are no changes to the schema
+ # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
+ def process_revision_directives(context, revision, directives):
+ if getattr(config.cmd_opts, 'autogenerate', False):
+ script = directives[0]
+ if script.upgrade_ops.is_empty():
+ directives[:] = []
+ logger.info('No changes in schema detected.')
+
+ engine = engine_from_config(config.get_section(config.config_ini_section),
+ prefix='sqlalchemy.',
+ poolclass=pool.NullPool)
+
+ connection = engine.connect()
+ context.configure(connection=connection,
+ target_metadata=target_metadata,
+ process_revision_directives=process_revision_directives,
+ **current_app.extensions['migrate'].configure_args)
+
+ try:
+ with context.begin_transaction():
+ context.run_migrations()
+ finally:
+ connection.close()
+
+if context.is_offline_mode():
+ run_migrations_offline()
+else:
+ run_migrations_online()
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/script.py.mako b/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/script.py.mako
new file mode 100755
index 0000000..2c01563
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/script.py.mako
@@ -0,0 +1,24 @@
+"""${message}
+
+Revision ID: ${up_revision}
+Revises: ${down_revision | comma,n}
+Create Date: ${create_date}
+
+"""
+from alembic import op
+import sqlalchemy as sa
+${imports if imports else ""}
+
+# revision identifiers, used by Alembic.
+revision = ${repr(up_revision)}
+down_revision = ${repr(down_revision)}
+branch_labels = ${repr(branch_labels)}
+depends_on = ${repr(depends_on)}
+
+
+def upgrade():
+ ${upgrades if upgrades else "pass"}
+
+
+def downgrade():
+ ${downgrades if downgrades else "pass"}
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/versions/10ea5e18414a_adding_users_table.py b/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/versions/10ea5e18414a_adding_users_table.py
new file mode 100644
index 0000000..d29cb68
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/versions/10ea5e18414a_adding_users_table.py
@@ -0,0 +1,33 @@
+"""adding users table
+
+Revision ID: 10ea5e18414a
+Revises:
+Create Date: 2017-11-30 14:09:26.373494
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = '10ea5e18414a'
+down_revision = None
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('users',
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('first_name', sa.Text(), nullable=True),
+ sa.Column('last_name', sa.Text(), nullable=True),
+ sa.PrimaryKeyConstraint('id')
+ )
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_table('users')
+ # ### end Alembic commands ###
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/versions/bcb5d2e5decd_adding_messages_table.py b/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/versions/bcb5d2e5decd_adding_messages_table.py
new file mode 100644
index 0000000..0a3cec5
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/migrations/versions/bcb5d2e5decd_adding_messages_table.py
@@ -0,0 +1,34 @@
+"""adding messages table
+
+Revision ID: bcb5d2e5decd
+Revises: 10ea5e18414a
+Create Date: 2017-11-30 18:07:25.906299
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = 'bcb5d2e5decd'
+down_revision = '10ea5e18414a'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('messages',
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('content', sa.Text(), nullable=True),
+ sa.Column('user_id', sa.Integer(), nullable=True),
+ sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_table('messages')
+ # ### end Alembic commands ###
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/base.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/base.html
new file mode 100644
index 0000000..397f3c7
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/base.html
@@ -0,0 +1,11 @@
+
+
+
+
+ Document
+
+
+ {% block content %}
+ {% endblock %}
+
+
\ No newline at end of file
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/edit.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/edit.html
new file mode 100644
index 0000000..3d0d8e9
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/edit.html
@@ -0,0 +1,9 @@
+{% extends 'base.html' %}
+
+{% block content %}
+ Edit a new message
+
+{% endblock %}
\ No newline at end of file
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/index.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/index.html
new file mode 100644
index 0000000..48454b3
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/index.html
@@ -0,0 +1,16 @@
+{% extends 'base.html' %}
+
+{% block content %}
+Add a new message!
+ See all the messages for {{user.first_name}}
+ {% for message in user.mesaages %}
+
+ {{message.content}}
+
+ Edit a message
+
+
+ {% endfor %}
+{% endblock %}
\ No newline at end of file
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/new.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/new.html
new file mode 100644
index 0000000..483d2d6
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/new.html
@@ -0,0 +1,9 @@
+{% extends 'base.html' %}
+
+{% block content %}
+ Add a new message
+
+{% endblock %}
\ No newline at end of file
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/show.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/show.html
new file mode 100644
index 0000000..e69de29
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/edit.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/edit.html
new file mode 100644
index 0000000..342bae8
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/edit.html
@@ -0,0 +1,12 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+Add a new user!
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/index.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/index.html
new file mode 100644
index 0000000..a8f1c70
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/index.html
@@ -0,0 +1,17 @@
+{% extends 'base.html' %}
+
+{% block content %}
+Add a new user!
+See all the users!
+{% for user in users %}
+
+ {{user.first_name}} {{user.last_name}}
+
+ See all messages for {{user.first_name}}!
+ Edit a user!
+
+
+ {% endfor %}
+{% endblock %}
\ No newline at end of file
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/new.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/new.html
new file mode 100644
index 0000000..c935c32
--- /dev/null
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/new.html
@@ -0,0 +1,18 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+Add a new user!
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/show.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/show.html
new file mode 100644
index 0000000..e69de29
From f1ed1ed3a80626629a8ff0c0125561fee10caccf Mon Sep 17 00:00:00 2001
From: michellecarey
Date: Sun, 3 Dec 2017 18:57:53 -0800
Subject: [PATCH 2/4] updates
---
.../users-messages-forms/app.py | 37 +++++++++++--------
.../users-messages-forms/forms.py | 9 +++--
.../templates/messages/index.html | 4 +-
.../templates/messages/new.html | 30 +++++++++++----
.../templates/users/index.html | 2 +
.../templates/users/new.html | 23 ++++--------
6 files changed, 63 insertions(+), 42 deletions(-)
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/app.py b/Unit-01/07-sql-alchemy-2/users-messages-forms/app.py
index f2f16a1..2ba8559 100644
--- a/Unit-01/07-sql-alchemy-2/users-messages-forms/app.py
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/app.py
@@ -1,7 +1,7 @@
from flask import Flask, request, redirect, render_template, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_modus import Modus
-from forms import UserForm, MessageForm
+from forms import UserForm, MessageForm, DeleteForm
import os
app = Flask(__name__)
@@ -42,6 +42,7 @@ def root():
@app.route('/users', methods=["GET", "POST"])
def index():
+ delete_form = DeleteForm()
if request.method == "POST":
form = UserForm(request.form)
if form.validate():
@@ -51,31 +52,37 @@ def index():
return redirect(url_for('index'))
else:
return render_template('users/new.html', form=form)
- return render_template('users/index.html', users=User.query.all())
+ return render_template('users/index.html', users=User.query.all(), delete_form=delete_form)
@app.route('/users/new')
def new():
- found_user = UserForm()
+ user_form = UserForm()
return render_template('users/new.html', form=user_form)
@app.route('/users//edit')
def edit(id):
found_user = User.query.get(id)
- return render_template('users/edit.html', user=found_user)
+ user_form = UserForm(obj=found_user)
+ return render_template('users/edit.html', user=found_user, form=user_form)
@app.route('/users/', methods=["GET", "PATCH", "DELETE"])
def show(id):
- found_user = User.query.get(id)
- if request.method == b"PATCH":
- found_user.first_name = request.form['first_name']
- found_user.last_name = request.form['last_name']
- db.session.add(found_user)
- db.session.commit()
- return redirect(url_for('index'))
- if request.method == b"DELETE":
- db.session.delete(found_user)
- db.session.commit()
- return redirect(url_for('index'))
+ found_user = User.query.get(id)
+ if request.method == b"PATCH":
+ form = UserForm(request.form)
+ if form.validate():
+ found_user.first_name = form.first_name.data
+ found_user.last_name = form.last_name.data
+ db.session.add(found_user)
+ db.session.commit()
+ return redirect(url_for('index'))
+ return render_template('users/edit.html', user=found_user, form=form)
+ if request.method == b"DELETE":
+ delete_form = DeleteForm(request.form)
+ if delete_form.validate():
+ db.session.delete(found_user)
+ db.session.commit()
+ return redirect(url_for('index'))
return render_template('users/show.html', user=found_user)
@app.route('/users//messages', methods=["GET", "POST"])
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/forms.py b/Unit-01/07-sql-alchemy-2/users-messages-forms/forms.py
index 89d7b30..328a13a 100644
--- a/Unit-01/07-sql-alchemy-2/users-messages-forms/forms.py
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/forms.py
@@ -1,9 +1,12 @@
-from flask_wtf import FLaskForm
+from flask_wtf import FlaskForm
from wtforms import StringField, validators
class UserForm(FlaskForm):
first_name = StringField('First Name', [validators.DataRequired()])
last_name = StringField('Last Name', [validators.DataRequired()])
- class MessageForm(FlaskForm):
- content = StringField('Content', [validators.DataRequired])
\ No newline at end of file
+class MessageForm(FlaskForm):
+ content = StringField('Content', [validators.DataRequired])
+
+class DeleteForm(FlaskForm):
+ pass
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/index.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/index.html
index 48454b3..c1606c8 100644
--- a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/index.html
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/index.html
@@ -3,12 +3,12 @@
{% block content %}
Add a new message!
See all the messages for {{user.first_name}}
- {% for message in user.mesaages %}
+ {% for message in user.messages %}
{{message.content}}
Edit a message
-
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/new.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/new.html
index 483d2d6..f7c3e46 100644
--- a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/new.html
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/messages/new.html
@@ -1,9 +1,25 @@
-{% extends 'base.html' %}
+% extends 'base.html' %}
{% block content %}
- Add a new message
-
-{% endblock %}
\ No newline at end of file
+
+Add a new user!
+
+{% endblock %}
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/index.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/index.html
index a8f1c70..b5423c3 100644
--- a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/index.html
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/index.html
@@ -10,7 +10,9 @@ See all the users!
See all messages for {{user.first_name}}!
Edit a user!
{% endfor %}
diff --git a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/new.html b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/new.html
index c935c32..0155bbf 100644
--- a/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/new.html
+++ b/Unit-01/07-sql-alchemy-2/users-messages-forms/templates/users/new.html
@@ -1,18 +1,11 @@
-{% extends 'base.html' %}
+{
+{% endblock %}
+% extends 'base.html' %}
{% block content %}
-
-Add a new user!
-
-
+ Add a new message
+
{% endblock %}
\ No newline at end of file
From 44141a43b89f8d7f21417ecd58704fb45df83672 Mon Sep 17 00:00:00 2001
From: michellecarey
Date: Sun, 10 Dec 2017 18:04:23 -0800
Subject: [PATCH 3/4] updates
---
Unit-02/02-many-to-many/app.py | 4 +
Unit-02/02-many-to-many/manage.py | 11 +++
Unit-02/02-many-to-many/migrations/README | 1 +
.../02-many-to-many/migrations/alembic.ini | 45 ++++++++++
Unit-02/02-many-to-many/migrations/env.py | 87 +++++++++++++++++++
.../02-many-to-many/migrations/script.py.mako | 24 +++++
...3_create_employee_and_department_tables.py | 48 ++++++++++
Unit-02/02-many-to-many/project/__init__.py | 24 +++++
.../project/departments/forms.py | 21 +++++
.../templates/departments/index.html | 9 ++
.../templates/departments/show.html | 18 ++++
.../project/departments/views.py | 10 +++
.../project/employees/forms.py | 21 +++++
.../employees/templates/employees/edit.html | 26 ++++++
.../employees/templates/employees/index.html | 16 ++++
.../employees/templates/employees/new.html | 19 ++++
.../employees/templates/employees/show.html | 0
.../project/employees/views.py | 66 ++++++++++++++
Unit-02/02-many-to-many/project/models.py | 35 ++++++++
.../project/templates/base.html | 40 +++++++++
Unit-02/02-many-to-many/requirements.txt | 33 +++++++
21 files changed, 558 insertions(+)
create mode 100644 Unit-02/02-many-to-many/app.py
create mode 100644 Unit-02/02-many-to-many/manage.py
create mode 100755 Unit-02/02-many-to-many/migrations/README
create mode 100644 Unit-02/02-many-to-many/migrations/alembic.ini
create mode 100755 Unit-02/02-many-to-many/migrations/env.py
create mode 100755 Unit-02/02-many-to-many/migrations/script.py.mako
create mode 100644 Unit-02/02-many-to-many/migrations/versions/a4746f2299f3_create_employee_and_department_tables.py
create mode 100644 Unit-02/02-many-to-many/project/__init__.py
create mode 100644 Unit-02/02-many-to-many/project/departments/forms.py
create mode 100644 Unit-02/02-many-to-many/project/departments/templates/departments/index.html
create mode 100644 Unit-02/02-many-to-many/project/departments/templates/departments/show.html
create mode 100644 Unit-02/02-many-to-many/project/departments/views.py
create mode 100644 Unit-02/02-many-to-many/project/employees/forms.py
create mode 100644 Unit-02/02-many-to-many/project/employees/templates/employees/edit.html
create mode 100644 Unit-02/02-many-to-many/project/employees/templates/employees/index.html
create mode 100644 Unit-02/02-many-to-many/project/employees/templates/employees/new.html
create mode 100644 Unit-02/02-many-to-many/project/employees/templates/employees/show.html
create mode 100644 Unit-02/02-many-to-many/project/employees/views.py
create mode 100644 Unit-02/02-many-to-many/project/models.py
create mode 100644 Unit-02/02-many-to-many/project/templates/base.html
create mode 100644 Unit-02/02-many-to-many/requirements.txt
diff --git a/Unit-02/02-many-to-many/app.py b/Unit-02/02-many-to-many/app.py
new file mode 100644
index 0000000..1fb8c5f
--- /dev/null
+++ b/Unit-02/02-many-to-many/app.py
@@ -0,0 +1,4 @@
+from project import app
+
+if __name__ == '__main__':
+ app.run(debug=True,port=3000)
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/manage.py b/Unit-02/02-many-to-many/manage.py
new file mode 100644
index 0000000..21f84b0
--- /dev/null
+++ b/Unit-02/02-many-to-many/manage.py
@@ -0,0 +1,11 @@
+from project import app,db
+from flask_script import Manager
+from flask_migrate import Migrate,MigrateCommand
+
+migrate = Migrate(app, db)
+
+manager = Manager(app)
+manager.add_command('db', MigrateCommand)
+
+if __name__ == '__main__':
+ manager.run()
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/migrations/README b/Unit-02/02-many-to-many/migrations/README
new file mode 100755
index 0000000..98e4f9c
--- /dev/null
+++ b/Unit-02/02-many-to-many/migrations/README
@@ -0,0 +1 @@
+Generic single-database configuration.
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/migrations/alembic.ini b/Unit-02/02-many-to-many/migrations/alembic.ini
new file mode 100644
index 0000000..f8ed480
--- /dev/null
+++ b/Unit-02/02-many-to-many/migrations/alembic.ini
@@ -0,0 +1,45 @@
+# A generic, single database configuration.
+
+[alembic]
+# template used to generate migration files
+# file_template = %%(rev)s_%%(slug)s
+
+# set to 'true' to run the environment during
+# the 'revision' command, regardless of autogenerate
+# revision_environment = false
+
+
+# Logging configuration
+[loggers]
+keys = root,sqlalchemy,alembic
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = WARN
+handlers = console
+qualname =
+
+[logger_sqlalchemy]
+level = WARN
+handlers =
+qualname = sqlalchemy.engine
+
+[logger_alembic]
+level = INFO
+handlers =
+qualname = alembic
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(levelname)-5.5s [%(name)s] %(message)s
+datefmt = %H:%M:%S
diff --git a/Unit-02/02-many-to-many/migrations/env.py b/Unit-02/02-many-to-many/migrations/env.py
new file mode 100755
index 0000000..23663ff
--- /dev/null
+++ b/Unit-02/02-many-to-many/migrations/env.py
@@ -0,0 +1,87 @@
+from __future__ import with_statement
+from alembic import context
+from sqlalchemy import engine_from_config, pool
+from logging.config import fileConfig
+import logging
+
+# this is the Alembic Config object, which provides
+# access to the values within the .ini file in use.
+config = context.config
+
+# Interpret the config file for Python logging.
+# This line sets up loggers basically.
+fileConfig(config.config_file_name)
+logger = logging.getLogger('alembic.env')
+
+# add your model's MetaData object here
+# for 'autogenerate' support
+# from myapp import mymodel
+# target_metadata = mymodel.Base.metadata
+from flask import current_app
+config.set_main_option('sqlalchemy.url',
+ current_app.config.get('SQLALCHEMY_DATABASE_URI'))
+target_metadata = current_app.extensions['migrate'].db.metadata
+
+# other values from the config, defined by the needs of env.py,
+# can be acquired:
+# my_important_option = config.get_main_option("my_important_option")
+# ... etc.
+
+
+def run_migrations_offline():
+ """Run migrations in 'offline' mode.
+
+ This configures the context with just a URL
+ and not an Engine, though an Engine is acceptable
+ here as well. By skipping the Engine creation
+ we don't even need a DBAPI to be available.
+
+ Calls to context.execute() here emit the given string to the
+ script output.
+
+ """
+ url = config.get_main_option("sqlalchemy.url")
+ context.configure(url=url)
+
+ with context.begin_transaction():
+ context.run_migrations()
+
+
+def run_migrations_online():
+ """Run migrations in 'online' mode.
+
+ In this scenario we need to create an Engine
+ and associate a connection with the context.
+
+ """
+
+ # this callback is used to prevent an auto-migration from being generated
+ # when there are no changes to the schema
+ # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
+ def process_revision_directives(context, revision, directives):
+ if getattr(config.cmd_opts, 'autogenerate', False):
+ script = directives[0]
+ if script.upgrade_ops.is_empty():
+ directives[:] = []
+ logger.info('No changes in schema detected.')
+
+ engine = engine_from_config(config.get_section(config.config_ini_section),
+ prefix='sqlalchemy.',
+ poolclass=pool.NullPool)
+
+ connection = engine.connect()
+ context.configure(connection=connection,
+ target_metadata=target_metadata,
+ process_revision_directives=process_revision_directives,
+ **current_app.extensions['migrate'].configure_args)
+
+ try:
+ with context.begin_transaction():
+ context.run_migrations()
+ finally:
+ connection.close()
+
+if context.is_offline_mode():
+ run_migrations_offline()
+else:
+ run_migrations_online()
diff --git a/Unit-02/02-many-to-many/migrations/script.py.mako b/Unit-02/02-many-to-many/migrations/script.py.mako
new file mode 100755
index 0000000..2c01563
--- /dev/null
+++ b/Unit-02/02-many-to-many/migrations/script.py.mako
@@ -0,0 +1,24 @@
+"""${message}
+
+Revision ID: ${up_revision}
+Revises: ${down_revision | comma,n}
+Create Date: ${create_date}
+
+"""
+from alembic import op
+import sqlalchemy as sa
+${imports if imports else ""}
+
+# revision identifiers, used by Alembic.
+revision = ${repr(up_revision)}
+down_revision = ${repr(down_revision)}
+branch_labels = ${repr(branch_labels)}
+depends_on = ${repr(depends_on)}
+
+
+def upgrade():
+ ${upgrades if upgrades else "pass"}
+
+
+def downgrade():
+ ${downgrades if downgrades else "pass"}
diff --git a/Unit-02/02-many-to-many/migrations/versions/a4746f2299f3_create_employee_and_department_tables.py b/Unit-02/02-many-to-many/migrations/versions/a4746f2299f3_create_employee_and_department_tables.py
new file mode 100644
index 0000000..111bf5e
--- /dev/null
+++ b/Unit-02/02-many-to-many/migrations/versions/a4746f2299f3_create_employee_and_department_tables.py
@@ -0,0 +1,48 @@
+"""create employee and department tables
+
+Revision ID: a4746f2299f3
+Revises:
+Create Date: 2017-12-05 12:07:15.813866
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = 'a4746f2299f3'
+down_revision = None
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('departments',
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('name', sa.Text(), nullable=True),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_table('employees',
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('name', sa.Text(), nullable=True),
+ sa.Column('years_at_company', sa.Integer(), nullable=True),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_table('employee_departments',
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('employee_id', sa.Integer(), nullable=True),
+ sa.Column('department_id', sa.Integer(), nullable=True),
+ sa.ForeignKeyConstraint(['department_id'], ['departments.id'], ondelete='cascade'),
+ sa.ForeignKeyConstraint(['employee_id'], ['employees.id'], ondelete='cascade'),
+ sa.PrimaryKeyConstraint('id')
+ )
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_table('employee_departments')
+ op.drop_table('employees')
+ op.drop_table('departments')
+ # ### end Alembic commands ###
diff --git a/Unit-02/02-many-to-many/project/__init__.py b/Unit-02/02-many-to-many/project/__init__.py
new file mode 100644
index 0000000..bda9f61
--- /dev/null
+++ b/Unit-02/02-many-to-many/project/__init__.py
@@ -0,0 +1,24 @@
+from flask import Flask, redirect
+from flask_sqlalchemy import SQLAlchemy
+from flask_modus import Modus
+import os
+
+app = Flask(__name__)
+modus = Modus(app)
+
+app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://localhost/manymany'
+app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
+app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
+db = SQLAlchemy(app)
+
+# import a blueprint that we will create
+from project.employees.views import employees_blueprint
+from project.departments.views import departments_blueprint
+
+# register our blueprints with the application
+app.register_blueprint(employees_blueprint, url_prefix='/employees')
+app.register_blueprint(departments_blueprint, url_prefix='/departments')
+
+@app.route('/')
+def root():
+ return redirect('/employees')
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/project/departments/forms.py b/Unit-02/02-many-to-many/project/departments/forms.py
new file mode 100644
index 0000000..28b1993
--- /dev/null
+++ b/Unit-02/02-many-to-many/project/departments/forms.py
@@ -0,0 +1,21 @@
+from flask_wtf import FlaskForm
+from wtforms import TextField, IntegerField, SelectMultipleField, widgets
+from wtforms.validators import DataRequired
+from project.models import Employee
+
+
+class NewDepartmentForm(FlaskForm):
+ name = TextField('Name', validators=[DataRequired()])
+
+ employees = SelectMultipleField(
+ 'Employees',
+ coerce=int,
+ widget=widgets.ListWidget(prefix_label=True),
+ option_widget=widgets.CheckboxInput())
+
+ def set_choices(self):
+ self.employees.choices = [(employee.id, employee.name) for employee in Employee.query.all()]
+
+
+class DeleteForm(FlaskForm):
+ pass
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/project/departments/templates/departments/index.html b/Unit-02/02-many-to-many/project/departments/templates/departments/index.html
new file mode 100644
index 0000000..4d8a354
--- /dev/null
+++ b/Unit-02/02-many-to-many/project/departments/templates/departments/index.html
@@ -0,0 +1,9 @@
+{% extends 'base.html' %}
+{% block content %}
+ All Departments
+ {% for department in departments %}
+
+ {{department.name}} | See More
+
+ {% endfor %}
+{% endblock %}
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/project/departments/templates/departments/show.html b/Unit-02/02-many-to-many/project/departments/templates/departments/show.html
new file mode 100644
index 0000000..4c32aea
--- /dev/null
+++ b/Unit-02/02-many-to-many/project/departments/templates/departments/show.html
@@ -0,0 +1,18 @@
+{% extends 'base.html' %}
+
+{% block content %}
+Employees in {{department.name}} Department
+{% if department.employees|length == 0 %}
+ No employees yet
+{% else %}
+ {% for e in department.employees %}
+
+ {{e.name}}
+
+ {% endfor %}
+{% endif %}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/project/departments/views.py b/Unit-02/02-many-to-many/project/departments/views.py
new file mode 100644
index 0000000..dc301f7
--- /dev/null
+++ b/Unit-02/02-many-to-many/project/departments/views.py
@@ -0,0 +1,10 @@
+from flask import redirect, url_for, render_template, Blueprint, request
+from project.models import Department, Employee
+from project.departments.forms import NewDepartmentForm, DeleteForm
+from project import db
+
+departments_blueprint = Blueprint(
+ 'departments',
+ __name__,
+ template_folder = 'templates'
+)
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/project/employees/forms.py b/Unit-02/02-many-to-many/project/employees/forms.py
new file mode 100644
index 0000000..8d97f7c
--- /dev/null
+++ b/Unit-02/02-many-to-many/project/employees/forms.py
@@ -0,0 +1,21 @@
+from flask_wtf import FlaskForm
+from wtforms import TextField, IntegerField, SelectMultipleField, widgets
+from wtforms.validators import DataRequired
+from project.models import Department
+
+class NewEmployeeForm(FlaskForm):
+ name = TextField('Name', validators=[DataRequired()])
+ years_at_company = IntegerField('Years At Company',
+ validators=[DataRequired()])
+
+ departments = SelectMultipleField(
+ 'Departments',
+ coerce=int,
+ widget=widgets.ListWidget(prefix_label=True),
+ option_widget=widgets.CheckboxInput())
+
+ def set_choices(self):
+ self.departments.choices = [(d.id, d.name) for d in Department.query.all()]
+
+class DeleteForm(FlaskForm):
+ pass
diff --git a/Unit-02/02-many-to-many/project/employees/templates/employees/edit.html b/Unit-02/02-many-to-many/project/employees/templates/employees/edit.html
new file mode 100644
index 0000000..f3efa91
--- /dev/null
+++ b/Unit-02/02-many-to-many/project/employees/templates/employees/edit.html
@@ -0,0 +1,26 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/project/employees/templates/employees/index.html b/Unit-02/02-many-to-many/project/employees/templates/employees/index.html
new file mode 100644
index 0000000..3468d6b
--- /dev/null
+++ b/Unit-02/02-many-to-many/project/employees/templates/employees/index.html
@@ -0,0 +1,16 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+Employee Directory
+
+{% for employee in employees %}
+
+ {{employee.name}} - {{employee.years_at_company}} years of service
+ Edit
+
+
+
+{% endfor %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/project/employees/templates/employees/new.html b/Unit-02/02-many-to-many/project/employees/templates/employees/new.html
new file mode 100644
index 0000000..0a50ebf
--- /dev/null
+++ b/Unit-02/02-many-to-many/project/employees/templates/employees/new.html
@@ -0,0 +1,19 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/project/employees/templates/employees/show.html b/Unit-02/02-many-to-many/project/employees/templates/employees/show.html
new file mode 100644
index 0000000..e69de29
diff --git a/Unit-02/02-many-to-many/project/employees/views.py b/Unit-02/02-many-to-many/project/employees/views.py
new file mode 100644
index 0000000..27b6390
--- /dev/null
+++ b/Unit-02/02-many-to-many/project/employees/views.py
@@ -0,0 +1,66 @@
+from flask import Blueprint, render_template, redirect, request, url_for
+from project.employees.forms import NewEmployeeForm
+from project.models import Employee, Department
+from project import db
+
+
+employees_blueprint = Blueprint(
+ 'employees',
+ __name__,
+ template_folder='templates'
+)
+
+@employees_blueprint.route('/', methods=["POST", "GET"])
+def index():
+ if request.method == 'POST':
+ form = NewEmployeeForm(request.form)
+ form.set_choices()
+ if form.validate_on_submit():
+ new_employee = Employee(form.name.data, form.years_at_company.data)
+ for department in form.departments.data:
+ new_employee.departments.append(Department.query.get(department))
+ db.session.add(new_employee)
+ db.session.commit()
+ else:
+ return render_template('employees/new.html', form=form)
+ return render_template('employees/index.html', employees=Employee.query.all())
+
+
+@employees_blueprint.route('/new', methods=["GET"])
+def new():
+ form = NewEmployeeForm()
+ form.set_choices()
+ return render_template('employees/new.html', form=form)
+
+
+@employees_blueprint.route('//edit', methods=["GET"])
+def edit(id):
+ employee = Employee.query.get(id)
+ departments = [department.id for department in employee.departments]
+ form = NewEmployeeForm(departments=departments)
+ form.set_choices()
+ return render_template('employees/edit.html', employee=employee, form=form)
+
+
+@employees_blueprint.route('/', methods=["GET", "PATCH", "DELETE"])
+def show(id):
+ found_employee=Employee.query.get(id)
+ if request.method == b"DELETE":
+ db.session.delete(found_employee)
+ db.session.commit()
+ return redirect(url_for('employees.index'))
+ if request.method == b"PATCH":
+ form = NewEmployeeForm(request.form)
+ form.set_choices()
+ if form.validate():
+ found_employee.name = form.name.data
+ found_employee.years_at_company = form.years_at_company.data
+ found_employee.departments = []
+ for department in form.departments.data:
+ found_employee.departments.append(Department.query.get(department))
+ db.session.add(found_employee)
+ db.session.commit()
+ return redirect(url_for('employees.index'))
+ else:
+ return render_template('employees/edit.html', form=form)
+ return render_template('employees/show.html', employee=found_employee)
diff --git a/Unit-02/02-many-to-many/project/models.py b/Unit-02/02-many-to-many/project/models.py
new file mode 100644
index 0000000..aa216c8
--- /dev/null
+++ b/Unit-02/02-many-to-many/project/models.py
@@ -0,0 +1,35 @@
+from project import db
+
+EmployeeDepartment = db.Table('employee_departments',
+ db.Column('id',
+ db.Integer,
+ primary_key=True),
+ db.Column('employee_id',
+ db.Integer,
+ db.ForeignKey('employees.id', ondelete="cascade")),
+ db.Column('department_id',
+ db.Integer,
+ db.ForeignKey('departments.id', ondelete="cascade")))
+
+class Employee(db.Model):
+ __tablename__ = 'employees'
+
+ id = db.Column(db.Integer, primary_key=True)
+ name = db.Column(db.Text)
+ years_at_company = db.Column(db.Integer)
+ departments = db.relationship("Department",
+ secondary=EmployeeDepartment,
+ backref=db.backref('employees'))
+
+ def __init__(self, name, years_at_company):
+ self.name = name
+ self.years_at_company = years_at_company
+
+class Department(db.Model):
+ __tablename__ = 'departments'
+
+ id = db.Column(db.Integer, primary_key=True)
+ name = db.Column(db.Text)
+
+ def __init__(self, name):
+ self.name = name
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/project/templates/base.html b/Unit-02/02-many-to-many/project/templates/base.html
new file mode 100644
index 0000000..b7651d4
--- /dev/null
+++ b/Unit-02/02-many-to-many/project/templates/base.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+ Blueprints Many to Many
+
+
+
+
+
+
+
+ {% block content %}
+
+ {% endblock %}
+
+
+
+
\ No newline at end of file
diff --git a/Unit-02/02-many-to-many/requirements.txt b/Unit-02/02-many-to-many/requirements.txt
new file mode 100644
index 0000000..85561bc
--- /dev/null
+++ b/Unit-02/02-many-to-many/requirements.txt
@@ -0,0 +1,33 @@
+alembic==0.9.6
+appnope==0.1.0
+click==6.7
+decorator==4.1.2
+Flask==0.12.2
+Flask-Migrate==2.1.1
+Flask-Modus==0.0.1
+Flask-Script==2.0.6
+Flask-SQLAlchemy==2.3.2
+Flask-WTF==0.14.2
+ipython==6.2.1
+ipython-genutils==0.2.0
+itsdangerous==0.24
+jedi==0.11.0
+Jinja2==2.10
+Mako==1.0.7
+MarkupSafe==1.0
+parso==0.1.0
+pexpect==4.3.0
+pickleshare==0.7.4
+prompt-toolkit==1.0.15
+psycopg2==2.7.3.2
+ptyprocess==0.5.2
+Pygments==2.2.0
+python-dateutil==2.6.1
+python-editor==1.0.3
+simplegeneric==0.8.1
+six==1.11.0
+SQLAlchemy==1.1.15
+traitlets==4.3.2
+wcwidth==0.1.7
+Werkzeug==0.12.2
+WTForms==2.1
From 4e2998bb101dfe01642d07b2fffd46e91db9ef96 Mon Sep 17 00:00:00 2001
From: michellecarey
Date: Sun, 10 Dec 2017 18:13:06 -0800
Subject: [PATCH 4/4] updates
---
.../03-hashing-sessions/project/__init__.py | 24 ++++
.../project/decorators/__init__.py | 41 +++++++
.../project/messages/views.py | 64 +++++++++++
Unit-02/03-hashing-sessions/project/models.py | 41 +++++++
.../project/users/views.py | 105 ++++++++++++++++++
5 files changed, 275 insertions(+)
create mode 100644 Unit-02/03-hashing-sessions/project/__init__.py
create mode 100644 Unit-02/03-hashing-sessions/project/decorators/__init__.py
create mode 100644 Unit-02/03-hashing-sessions/project/messages/views.py
create mode 100644 Unit-02/03-hashing-sessions/project/models.py
create mode 100644 Unit-02/03-hashing-sessions/project/users/views.py
diff --git a/Unit-02/03-hashing-sessions/project/__init__.py b/Unit-02/03-hashing-sessions/project/__init__.py
new file mode 100644
index 0000000..c5a9f24
--- /dev/null
+++ b/Unit-02/03-hashing-sessions/project/__init__.py
@@ -0,0 +1,24 @@
+from flask import Flask, redirect, url_for
+from flask_modus import Modus
+from flask_sqlalchemy import SQLAlchemy
+from os import environ
+from flask_bcrypt import Bcrypt
+
+app = Flask(__name__)
+app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://localhost/03_hashing'
+app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
+#app.config['SQLALCHEMY_ECHO'] = True
+app.config['SECRET_KEY'] = environ.get('SECRET_KEY')
+modus = Modus(app)
+db = SQLAlchemy(app)
+bcrypt = Bcrypt(app)
+
+from project.users.views import users_blueprint
+from project.messages.views import messages_blueprint
+
+app.register_blueprint(users_blueprint, url_prefix="/users")
+app.register_blueprint(messages_blueprint, url_prefix="/users//messages")
+
+@app.route("/")
+def root():
+ return redirect(url_for('users.index'))
\ No newline at end of file
diff --git a/Unit-02/03-hashing-sessions/project/decorators/__init__.py b/Unit-02/03-hashing-sessions/project/decorators/__init__.py
new file mode 100644
index 0000000..bcbe410
--- /dev/null
+++ b/Unit-02/03-hashing-sessions/project/decorators/__init__.py
@@ -0,0 +1,41 @@
+from functools import wraps
+from flask import redirect, url_for, session, flash
+
+def ensure_authenticated(fn):
+ @wraps(fn)
+ def wrapper(*args, **kwargs):
+ if session.get('user_id') is None:
+ flash('Please log in first!')
+ return redirect(url_for('users.login'))
+ return fn(*args, **kwargs)
+ return wrapper
+
+def prevent_loginsignup(fn):
+ @wraps(fn)
+ def wrapper(*args, **kwargs):
+ if session.get('user_id'):
+ flash('You are logged in already!')
+ return redirect(url_for('users.index'))
+ return fn(*args, **kwargs)
+ return wrapper
+
+def ensure_correct_user(fn):
+ @wraps(fn)
+ def wrapper(*args, **kwargs):
+ correct_id = kwargs.get('id')
+ if correct_id != session.get('user_id'):
+ flash('Not Authorized')
+ return redirect(url_for('users.index'))
+ return fn(*args, **kwargs)
+ return wrapper
+
+def ensure_correct_user_message(fn):
+ @wraps(fn)
+ def wrapper(*args, ** kwargs):
+ correct_id = kwargs.get('id')
+ if correct_id != session.get('id'):
+ flash('Not Authortized')
+ return redirect(url_for('users.index'))
+ return fn(*args, **kwargs)
+ return wrapper
+
diff --git a/Unit-02/03-hashing-sessions/project/messages/views.py b/Unit-02/03-hashing-sessions/project/messages/views.py
new file mode 100644
index 0000000..bbbdedb
--- /dev/null
+++ b/Unit-02/03-hashing-sessions/project/messages/views.py
@@ -0,0 +1,64 @@
+from flask import Blueprint, url_for, redirect, render_template, request, flash
+from project.models import Message, User
+from project.forms import MessageForm, DeleteForm
+from project import db
+from project.decorators import ensure_correct_user_message
+from flask_login import login_required
+
+messages_blueprint = Blueprint(
+ 'messages',
+ __name__,
+ template_folder='templates'
+)
+
+@messages_blueprint.route("/", methods=["GET", "POST"])
+@login_required
+@ensure_correct_user_message
+def index(user_id):
+ if request.method == "POST":
+ message = Message(request.form.get("text"), request.form.get("img"), user_id)
+ db.session.add(message)
+ db.session.commit()
+ flash('Message Created')
+ return redirect(url_for('messages.index', user_id=user_id))
+ user = User.query.get(user_id)
+ return render_template('messages/index.html', user=user)
+
+@messages_blueprint.route("/new")
+@login_required
+def new(user_id):
+ form = MessageForm()
+ user = User.query.get(user_id)
+ return render_template('messages/new.html', user=user, form=form)
+
+@messages_blueprint.route("/", methods = ["GET", "PATCH", "DELETE"])
+@login_required
+def show(user_id, id):
+ message = Message.query.get(id)
+ if request.method == b"PATCH":
+ form = MessageForm(request.form)
+ if form.validate():
+ message.text = form.text.data
+ message.img = form.img.data
+ db.session.add(message)
+ db.session.commit()
+ flash('Message Updated')
+ return redirect(url_for('messages.index', user_id=user_id))
+ return render_template('messages/edit.html', message=message, form=form)
+ if request.method == b"DELETE":
+ delete_form = DeleteForm(request.form)
+ if delete_form.validate():
+ db.session.delete(message)
+ db.session.commit()
+ flash('Message Deleted')
+ return redirect(url_for('messages.index', user_id=user_id))
+ delete_form = DeleteForm()
+ return render_template('messages/show.html', message=message, delete_form=delete_form)
+
+@messages_blueprint.route("//edit")
+@ensure_correct_user_message
+@ensure_authenticated
+def edit(user_id, id):
+ message = Message.query.get(id)
+ form = MessageForm(obj=message)
+ return render_template('messages/edit.html', message=message, form=form)
\ No newline at end of file
diff --git a/Unit-02/03-hashing-sessions/project/models.py b/Unit-02/03-hashing-sessions/project/models.py
new file mode 100644
index 0000000..dc1129e
--- /dev/null
+++ b/Unit-02/03-hashing-sessions/project/models.py
@@ -0,0 +1,41 @@
+from project import db, bcrypt
+
+class User(db.Model):
+
+ __tablename__ = "users"
+
+ id = db.Column(db.Integer, primary_key = True)
+ first_name = db.Column(db.Text)
+ last_name = db.Column(db.Text)
+ username = db.Column(db.Text, unique=True)
+ password = db.Column(db.Text)
+ messages = db.relationship("Message", backref="user", lazy="dynamic", cascade="all, delete")
+
+ def __init__(self, first_name, last_name, username, password):
+ self.first_name = first_name
+ self.last_name = last_name
+ self.username = username
+ self.password = bcrypt.generate_password_hash(password).decode('UTF-8')
+
+ @classmethod
+ def authenticate(cls, username, password):
+ found_user = cls.query.filter_by(username = username).first()
+ if found_user:
+ is_authenticated = bcrypt.check_password_hash(found_user.password,password)
+ if is_authenticated:
+ return found_user
+ return False
+
+class Message(db.Model):
+
+ __tablename__ = "messages"
+
+ id = db.Column(db.Integer, primary_key = True)
+ text = db.Column(db.Text)
+ img = db.Column(db.Text)
+ user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
+
+ def __init__(self, text, img, user_id):
+ self.text = text
+ self.img = img
+ self.user_id = user_id
diff --git a/Unit-02/03-hashing-sessions/project/users/views.py b/Unit-02/03-hashing-sessions/project/users/views.py
new file mode 100644
index 0000000..e8a1435
--- /dev/null
+++ b/Unit-02/03-hashing-sessions/project/users/views.py
@@ -0,0 +1,105 @@
+from flask import Blueprint, url_for, redirect, render_template, request, flash, session, g
+from project.models import User
+from project.forms import UserForm, DeleteForm, LoginForm
+from project import db, bcrypt
+from sqlalchemy.exc import IntegrityError
+from project.decorators import ensure_authenticated, ensure_correct_user, prevent_loginsignup
+
+users_blueprint = Blueprint(
+ 'users',
+ __name__,
+ template_folder='templates'
+)
+@users_blueprint.before_request
+def current_user():
+ if session.get('user_id'):
+ g.current_user = User.query.get(session['user_id'])
+ else:
+ g.current_user = None
+
+@users_blueprint.route('/')
+@ensure_authenticated
+def index():
+ delete_form = DeleteForm()
+ return render_template('users/index.html', users=User.query.all(), delete_form=delete_form)
+
+@users_blueprint.route("/", methods = ["POST"])
+def signup():
+ form = UserForm(request.form)
+ if request.method == "POST" and form.validate():
+ try:
+ user = User(form.first_name.data, form.last_name.data, form.username.data, form.password.data)
+ db.session.add(user)
+ db.session.commit()
+ flash('User Created')
+ return redirect(url_for('users.index'))
+ except IntegrityError as e:
+ return render_template('users/new.html', form=form)
+ return render_template('users/new.html', form=form)
+
+
+@users_blueprint.route("/new")
+@prevent_loginsignup
+def new():
+ form = UserForm(request.form)
+ return render_template('users/new.html', form=form)
+
+@users_blueprint.route('/login', methods = ["GET", "POST"])
+@prevent_loginsignup
+def login():
+ form = LoginForm(request.form)
+ if request.method == "POST" and form.validate():
+ authenticated_user = User.authenticate(form.username.data, form.password.data)
+ if authenticated_user:
+ session['user_id'] = authenticated_user.id
+ flash('You are logged in!')
+ return redirect(url_for('users.index'))
+ else:
+ flash("invalid credentials")
+ return redirect(url_for('users.login'))
+ return render_template('users/login.html', form=form)
+
+@users_blueprint.route('/welcome')
+def welcome():
+ return "Welcome"
+
+@users_blueprint.route("/", methods = ["GET", "PATCH", "DELETE"])
+@ensure_authenticated
+@ensure_correct_user
+def show(id):
+ user = User.query.get(id)
+ if request.method == b"PATCH":
+ form = UserForm(request.form)
+ if form.validate():
+ user.first_name = form.first_name.data
+ user.last_name = form.last_name.data
+ db.session.add(user)
+ db.session.commit()
+ flash('User Updated')
+ return redirect(url_for('users.index'))
+ return render_template('users/edit.html', user=user, form=form)
+ if request.method == b"DELETE":
+ delete_form = DeleteForm(request.form)
+ if delete_form.validate():
+ db.session.delete(user)
+ db.session.commit()
+ flash('User Deleted')
+ return redirect(url_for('users.index'))
+ delete_form = DeleteForm()
+ return render_template('users/show.html', user=user, delete_form=delete_form)
+
+@users_blueprint.route("//edit")
+@ensure_authenticated
+@ensure_correct_user
+def edit(id):
+ user = User.query.get(id)
+ form = UserForm(obj=user)
+ return render_template('users/edit.html', user=user, form=form)
+
+
+@users_blueprint.route('/logout')
+@ensure_authenticated
+def logout():
+ session.pop('user_id')
+ flash('Logged out!')
+ return redirect('users.login')