forked from bradtraversy/myflaskapp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Brad Traversy
committed
Apr 25, 2017
0 parents
commit 872871e
Showing
17 changed files
with
539 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# FlaskApp | ||
|
||
Simple application with authentication and CRUD functionality using the Python Flask micro-framework | ||
|
||
## Installation | ||
|
||
To use this template, your computer needs: | ||
|
||
- [Python 2 or 3](https://python.org) | ||
- [Pip Package Manager](https://pypi.python.org/pypi) | ||
|
||
### Running the app | ||
|
||
Install the Foundation CLI with this command: | ||
|
||
```bash | ||
python app.py | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,279 @@ | ||
from flask import Flask, render_template, flash, redirect, url_for, session, request, logging | ||
#from data import Articles | ||
from flask_mysqldb import MySQL | ||
from wtforms import Form, StringField, TextAreaField, PasswordField, validators | ||
from passlib.hash import sha256_crypt | ||
from functools import wraps | ||
|
||
app = Flask(__name__) | ||
|
||
# Config MySQL | ||
app.config['MYSQL_HOST'] = 'localhost' | ||
app.config['MYSQL_USER'] = 'root' | ||
app.config['MYSQL_PASSWORD'] = '123456' | ||
app.config['MYSQL_DB'] = 'myflaskapp' | ||
app.config['MYSQL_CURSORCLASS'] = 'DictCursor' | ||
# init MYSQL | ||
mysql = MySQL(app) | ||
|
||
#Articles = Articles() | ||
|
||
# Index | ||
@app.route('/') | ||
def index(): | ||
return render_template('home.html') | ||
|
||
|
||
# About | ||
@app.route('/about') | ||
def about(): | ||
return render_template('about.html') | ||
|
||
|
||
# Articles | ||
@app.route('/articles') | ||
def articles(): | ||
# Create cursor | ||
cur = mysql.connection.cursor() | ||
|
||
# Get articles | ||
result = cur.execute("SELECT * FROM articles") | ||
|
||
articles = cur.fetchall() | ||
|
||
if result > 0: | ||
return render_template('articles.html', articles=articles) | ||
else: | ||
msg = 'No Articles Found' | ||
return render_template('articles.html', msg=msg) | ||
# Close connection | ||
cur.close() | ||
|
||
|
||
#Single Article | ||
@app.route('/article/<string:id>/') | ||
def article(id): | ||
# Create cursor | ||
cur = mysql.connection.cursor() | ||
|
||
# Get article | ||
result = cur.execute("SELECT * FROM articles WHERE id = %s", [id]) | ||
|
||
article = cur.fetchone() | ||
|
||
return render_template('article.html', article=article) | ||
|
||
|
||
# Register Form Class | ||
class RegisterForm(Form): | ||
name = StringField('Name', [validators.Length(min=1, max=50)]) | ||
username = StringField('Username', [validators.Length(min=4, max=25)]) | ||
email = StringField('Email', [validators.Length(min=6, max=50)]) | ||
password = PasswordField('Password', [ | ||
validators.DataRequired(), | ||
validators.EqualTo('confirm', message='Passwords do not match') | ||
]) | ||
confirm = PasswordField('Confirm Password') | ||
|
||
|
||
# User Register | ||
@app.route('/register', methods=['GET', 'POST']) | ||
def register(): | ||
form = RegisterForm(request.form) | ||
if request.method == 'POST' and form.validate(): | ||
name = form.name.data | ||
email = form.email.data | ||
username = form.username.data | ||
password = sha256_crypt.encrypt(str(form.password.data)) | ||
|
||
# Create cursor | ||
cur = mysql.connection.cursor() | ||
|
||
# Execute query | ||
cur.execute("INSERT INTO users(name, email, username, password) VALUES(%s, %s, %s, %s)", (name, email, username, password)) | ||
|
||
# Commit to DB | ||
mysql.connection.commit() | ||
|
||
# Close connection | ||
cur.close() | ||
|
||
flash('You are now registered and can log in', 'success') | ||
|
||
return redirect(url_for('login')) | ||
return render_template('register.html', form=form) | ||
|
||
|
||
# User login | ||
@app.route('/login', methods=['GET', 'POST']) | ||
def login(): | ||
if request.method == 'POST': | ||
# Get Form Fields | ||
username = request.form['username'] | ||
password_candidate = request.form['password'] | ||
|
||
# Create cursor | ||
cur = mysql.connection.cursor() | ||
|
||
# Get user by username | ||
result = cur.execute("SELECT * FROM users WHERE username = %s", [username]) | ||
|
||
if result > 0: | ||
# Get stored hash | ||
data = cur.fetchone() | ||
password = data['password'] | ||
|
||
# Compare Passwords | ||
if sha256_crypt.verify(password_candidate, password): | ||
# Passed | ||
session['logged_in'] = True | ||
session['username'] = username | ||
|
||
flash('You are now logged in', 'success') | ||
return redirect(url_for('dashboard')) | ||
else: | ||
error = 'Invalid login' | ||
return render_template('login.html', error=error) | ||
# Close connection | ||
cur.close() | ||
else: | ||
error = 'Username not found' | ||
return render_template('login.html', error=error) | ||
|
||
return render_template('login.html') | ||
|
||
# Check if user logged in | ||
def is_logged_in(f): | ||
@wraps(f) | ||
def wrap(*args, **kwargs): | ||
if 'logged_in' in session: | ||
return f(*args, **kwargs) | ||
else: | ||
flash('Unauthorized, Please login', 'danger') | ||
return redirect(url_for('login')) | ||
return wrap | ||
|
||
# Logout | ||
@app.route('/logout') | ||
@is_logged_in | ||
def logout(): | ||
session.clear() | ||
flash('You are now logged out', 'success') | ||
return redirect(url_for('login')) | ||
|
||
# Dashboard | ||
@app.route('/dashboard') | ||
@is_logged_in | ||
def dashboard(): | ||
# Create cursor | ||
cur = mysql.connection.cursor() | ||
|
||
# Get articles | ||
result = cur.execute("SELECT * FROM articles") | ||
|
||
articles = cur.fetchall() | ||
|
||
if result > 0: | ||
return render_template('dashboard.html', articles=articles) | ||
else: | ||
msg = 'No Articles Found' | ||
return render_template('dashboard.html', msg=msg) | ||
# Close connection | ||
cur.close() | ||
|
||
# Article Form Class | ||
class ArticleForm(Form): | ||
title = StringField('Title', [validators.Length(min=1, max=200)]) | ||
body = TextAreaField('Body', [validators.Length(min=30)]) | ||
|
||
# Add Article | ||
@app.route('/add_article', methods=['GET', 'POST']) | ||
@is_logged_in | ||
def add_article(): | ||
form = ArticleForm(request.form) | ||
if request.method == 'POST' and form.validate(): | ||
title = form.title.data | ||
body = form.body.data | ||
|
||
# Create Cursor | ||
cur = mysql.connection.cursor() | ||
|
||
# Execute | ||
cur.execute("INSERT INTO articles(title, body, author) VALUES(%s, %s, %s)",(title, body, session['username'])) | ||
|
||
# Commit to DB | ||
mysql.connection.commit() | ||
|
||
#Close connection | ||
cur.close() | ||
|
||
flash('Article Created', 'success') | ||
|
||
return redirect(url_for('dashboard')) | ||
|
||
return render_template('add_article.html', form=form) | ||
|
||
|
||
# Edit Article | ||
@app.route('/edit_article/<string:id>', methods=['GET', 'POST']) | ||
@is_logged_in | ||
def edit_article(id): | ||
# Create cursor | ||
cur = mysql.connection.cursor() | ||
|
||
# Get article by id | ||
result = cur.execute("SELECT * FROM articles WHERE id = %s", [id]) | ||
|
||
article = cur.fetchone() | ||
cur.close() | ||
# Get form | ||
form = ArticleForm(request.form) | ||
|
||
# Populate article form fields | ||
form.title.data = article['title'] | ||
form.body.data = article['body'] | ||
|
||
if request.method == 'POST' and form.validate(): | ||
title = request.form['title'] | ||
body = request.form['body'] | ||
|
||
# Create Cursor | ||
cur = mysql.connection.cursor() | ||
app.logger.info(title) | ||
# Execute | ||
cur.execute ("UPDATE articles SET title=%s, body=%s WHERE id=%s",(title, body, id)) | ||
# Commit to DB | ||
mysql.connection.commit() | ||
|
||
#Close connection | ||
cur.close() | ||
|
||
flash('Article Updated', 'success') | ||
|
||
return redirect(url_for('dashboard')) | ||
|
||
return render_template('edit_article.html', form=form) | ||
|
||
# Delete Article | ||
@app.route('/delete_article/<string:id>', methods=['POST']) | ||
@is_logged_in | ||
def delete_article(id): | ||
# Create cursor | ||
cur = mysql.connection.cursor() | ||
|
||
# Execute | ||
cur.execute("DELETE FROM articles WHERE id = %s", [id]) | ||
|
||
# Commit to DB | ||
mysql.connection.commit() | ||
|
||
#Close connection | ||
cur.close() | ||
|
||
flash('Article Deleted', 'success') | ||
|
||
return redirect(url_for('dashboard')) | ||
|
||
if __name__ == '__main__': | ||
app.secret_key='secret123' | ||
app.run(debug=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
def Articles(): | ||
articles = [ | ||
{ | ||
'id': 1, | ||
'title':'Article One', | ||
'body':'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', | ||
'author':'Brad Traversy', | ||
'create_date':'04-25-2017' | ||
}, | ||
{ | ||
'id': 2, | ||
'title':'Article Two', | ||
'body':'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', | ||
'author':'John Doe', | ||
'create_date':'04-25-2017' | ||
}, | ||
{ | ||
'id': 3, | ||
'title':'Article Three', | ||
'body':'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', | ||
'author':'Brad Traversy', | ||
'create_date':'04-25-2017' | ||
} | ||
] | ||
return articles |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{% extends 'layout.html' %} | ||
|
||
{% block body %} | ||
<h1>About Us</h1> | ||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{% extends 'layout.html' %} | ||
|
||
{% block body %} | ||
<h1>Add Article</h1> | ||
{% from "includes/_formhelpers.html" import render_field %} | ||
<form method="POST" action=""> | ||
<div class="form-group"> | ||
{{ render_field(form.title, class_="form-control") }} | ||
</div> | ||
<div class="form-group"> | ||
{{ render_field(form.body, class_="form-control", id="editor") }} | ||
</div> | ||
<p><input class="btn btn-primary" type="submit" value="Submit"> | ||
</form> | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{% extends 'layout.html' %} | ||
|
||
{% block body %} | ||
<h1>{{article.title}}</h1> | ||
<small>Written by {{article.author}} on {{article.create_date}}</small> | ||
<hr> | ||
<div> | ||
{{article.body | safe}} | ||
</div> | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{% extends 'layout.html' %} | ||
|
||
{% block body %} | ||
<h1>Articles</h1> | ||
<ul class="list-group"> | ||
{% for article in articles %} | ||
<li class="list-group-item"><a href="article/{{article.id}}">{{article.title}}</a></li> | ||
{% endfor %} | ||
</ul> | ||
{% endblock %} |
Oops, something went wrong.