Skip to content

Commit

Permalink
first commit. finished up to part 5
Browse files Browse the repository at this point in the history
  • Loading branch information
Victor Marks authored and Victor Marks committed Oct 10, 2018
0 parents commit e904ca7
Show file tree
Hide file tree
Showing 39 changed files with 8,210 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
venv/
Binary file added __pycache__/app.cpython-37.pyc
Binary file not shown.
Binary file added __pycache__/forms.cpython-37.pyc
Binary file not shown.
Binary file added __pycache__/models.cpython-37.pyc
Binary file not shown.
357 changes: 357 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,357 @@
import os

from flask import Flask, render_template, request, flash, redirect, session, g
from flask_debugtoolbar import DebugToolbarExtension
from sqlalchemy.exc import IntegrityError

from forms import UserAddForm, EditAddForm, LoginForm, MessageForm
from models import db, connect_db, User, Message

CURR_USER_KEY = "curr_user"

app = Flask(__name__)

# Get DB_URI from environ variable (useful for production/testing) or,
# if not set there, use development local db.
app.config['SQLALCHEMY_DATABASE_URI'] = (
os.environ.get('DATABASE_URL', 'postgres:///warbler'))

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = False
app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = True
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', "it's a secret")
toolbar = DebugToolbarExtension(app)

connect_db(app)


##############################################################################
# User signup/login/logout


@app.before_request
def add_user_to_g():
"""If we're logged in, add curr user to Flask global."""

if CURR_USER_KEY in session:
g.user = User.query.get(session[CURR_USER_KEY])

else:
g.user = None


def do_login(user):
"""Log in user."""

session[CURR_USER_KEY] = user.id


def do_logout():
"""Logout user."""

if CURR_USER_KEY in session:
del session[CURR_USER_KEY]


@app.route('/signup', methods=["GET", "POST"])
def signup():
"""Handle user signup.
Create new user and add to DB. Redirect to home page.
If form not valid, present form.
If the there already is a user with that username: flash message
and re-present form.
"""

form = UserAddForm()

if form.validate_on_submit():
try:
user = User.signup(
username=form.data['username'],
password=form.data['password'],
email=form.data['email'],
image_url=form.data['image_url'] or 'https://t3.ftcdn.net/jpg/00/64/67/52/240_F_64675209_7ve2XQANuzuHjMZXP3aIYIpsDKEbF5dD.jpg',
)
db.session.commit()

except IntegrityError as e:
flash("Username already taken", 'danger')
return render_template('users/signup.html', form=form)

do_login(user)

return redirect("/")

else:
return render_template('users/signup.html', form=form)


@app.route('/login', methods=["GET", "POST"])
def login():
"""Handle user login."""

form = LoginForm()

if form.validate_on_submit():
user = User.authenticate(username=form.data['username'],
password=form.data['password'])

if user:
do_login(user)
flash(f"Hello, {user.username}!", "success")
return redirect("/")

flash("Invalid credentials.", 'danger')

return render_template('users/login.html', form=form)


@app.route('/logout')
def logout():
"""Handle logout of user."""

do_logout()

# No flash message

return redirect("/login")

##############################################################################
# General user routes:

@app.route('/users')
def list_users():
"""Page with listing of users.
Can take a 'q' param in querystring to search by that username.
"""

search = request.args.get('q')

if not search:
users = User.query.all()
else:
users = User.query.filter(User.username.like(f"%{search}%")).all()

return render_template('users/index.html', users=users)


@app.route('/users/<int:user_id>')
def users_show(user_id):
"""Show user profile."""

user = User.query.get_or_404(user_id)
return render_template('users/show.html', user=user)


@app.route('/users/<int:user_id>/following')
def show_following(user_id):
"""Show list of people this user is following."""

if not g.user:
flash("Access unauthorized.", "danger")
return redirect("/")

user = User.query.get_or_404(user_id)
return render_template('users/following.html', user=user)


@app.route('/users/<int:user_id>/followers')
def users_followers(user_id):
"""Show list of followers of this user."""

if not g.user:
flash("Access unauthorized.", "danger")
return redirect("/")

user = User.query.get_or_404(user_id)
return render_template('users/followers.html', user=user)


@app.route('/users/follow/<int:follow_id>', methods=['POST'])
def add_follow(follow_id):
"""Add a follow for the currently-logged-in user."""

if not g.user:
flash("Access unauthorized.", "danger")
return redirect("/")

followee = User.query.get_or_404(follow_id)
g.user.following.append(followee)
db.session.commit()

return redirect(f"/users/{g.user.id}/following")


@app.route('/users/stop-following/<int:follow_id>', methods=['POST'])
def stop_following(follow_id):
"""Have currently-logged-in-user stop following this user."""

if not g.user:
flash("Access unauthorized.", "danger")
return redirect("/")

followee = User.query.get(follow_id)
g.user.following.remove(followee)
db.session.commit()

return redirect(f"/users/{g.user.id}/following")


@app.route('/users/profile', methods=["GET", "POST"])
def profile():
"""Update profile for current user."""

user = User.query.get(session[CURR_USER_KEY])

form = EditAddForm(obj=user)

if form.validate_on_submit():

# FIX THIS!
user_auth = User.authenticate(username=g.user.username, password=form.data['password'])

# import pdb; pdb.set_trace()

if user_auth:

user.username = request.form.get('username')
user.email = request.form.get('email')
user.image_url = request.form.get('image_url')
user.header_image_url = request.form.get('header_image_url')
user.bio = request.form.get('bio')

db.session.commit()

return redirect(f"/users/{user.id}")

return render_template('users/edit.html',user=user, form=form)

@app.route('/users/delete', methods=["POST"])
def delete_user():
"""Delete user."""

if not g.user:
flash("Access unauthorized.", "danger")
return redirect("/")

do_logout()

db.session.delete(g.user)
db.session.commit()

return redirect("/signup")


##############################################################################
# Messages routes:

@app.route('/messages/new', methods=["GET", "POST"])
def messages_add():
"""Add a message:
Show form if GET. If valid, update message and redirect to user page.
"""

if not g.user:
flash("Access unauthorized.", "danger")
return redirect("/")

form = MessageForm()

if form.validate_on_submit():
msg = Message(text=form.data['text'])
g.user.messages.append(msg)
db.session.commit()

return redirect(f"/users/{g.user.id}")

return render_template('messages/new.html', form=form)


@app.route('/messages/<int:message_id>', methods=["GET"])
def messages_show(message_id):
"""Show a message."""

msg = Message.query.get(message_id)
return render_template('messages/show.html', message=msg)


@app.route('/messages/<int:message_id>/delete', methods=["POST"])
def messages_destroy(message_id):
"""Delete a message."""

if not g.user:
flash("Access unauthorized.", "danger")
return redirect("/")

msg = Message.query.get(message_id)
db.session.delete(msg)
db.session.commit()

return redirect(f"/users/{g.user.id}")


##############################################################################
# Homepage and error pages


@app.route('/')
def homepage():
"""Show homepage:
- anon users: no messages
- logged in: 100 most recent messages of followees
"""

if g.user:

user = User.query.get(session[CURR_USER_KEY])

following_ids = [f.id for f in user.following] + [g.user.id]
# turn into string?

# print('\n\n\n\n Follower ids: ' , g.user.following)

print('\n\n\n\n Following ids: ' , following_ids)

messages = (Message
.query
.order_by(Message.timestamp.desc())
.filter(Message.user_id.in_(following_ids))
.limit(100))

import pdb; pdb.set_trace()

return render_template('home.html', messages=messages)

else:
return render_template('home-anon.html')


@app.errorhandler(404)
def page_not_found(e):
"""404 NOT FOUND page."""

return render_template('404.html'), 404


##############################################################################
# Turn off all caching in Flask
# (useful for dev; in production, this kind of stuff is typically
# handled elsewhere)
#
# https://stackoverflow.com/questions/34066804/disabling-caching-in-flask

@app.after_request
def add_header(req):
"""Add non-caching headers on every request."""

req.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
req.headers["Pragma"] = "no-cache"
req.headers["Expires"] = "0"
req.headers['Cache-Control'] = 'public, max-age=0'
return req
37 changes: 37 additions & 0 deletions forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, TextAreaField
from wtforms.validators import DataRequired, Email, Length


class MessageForm(FlaskForm):
"""Form for adding/editing messages."""

text = TextAreaField('text', validators=[DataRequired()])


class UserAddForm(FlaskForm):
"""Form for adding users."""

username = StringField('Username', validators=[DataRequired()])
email = StringField('E-mail', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[Length(min=6)])
image_url = StringField('(Optional) Image URL')



class EditAddForm(FlaskForm):
"""Form for editing users."""

username = StringField('Username', validators=[DataRequired()])
email = StringField('E-mail', validators=[DataRequired(), Email()])
bio = StringField('Bio', validators=[DataRequired()])
image_url = StringField('(Optional) Image URL')
header_image_url = StringField('(Optional) Header Image URL')
password = PasswordField('Password', validators=[Length(min=6)])


class LoginForm(FlaskForm):
"""Login form."""

username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[Length(min=6)])
Loading

0 comments on commit e904ca7

Please sign in to comment.