parent
23aa5d8cee
commit
0f0f148418
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,16 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
# (FLASK) Sectret key wich will be used to secure some requests an connections
|
||||||
|
SECRET_KEY = os.environ.get('MINIBASE_SECRET_KEY')
|
||||||
|
|
||||||
|
# (SQLALCHEMY) COnfiguration
|
||||||
|
SQLALCHEMY_DATABASE_URI = os.environ.get('MINIBASE_SQLALCHEMY_DATABASE_URI')
|
||||||
|
|
||||||
|
# (MAIL AGENT) Configure mail Server to send EMails.
|
||||||
|
MAIL_SERVER = os.environ.get('MINIBASE_MAIL_SERVER')
|
||||||
|
MAIL_USERNAME = os.environ.get('MINIBASE_MAIL_USERNAME')
|
||||||
|
MAIL_PASSWORD = os.environ.get('MINIBASE_MAIL_PASSWORD')
|
||||||
|
MAIL_PORT = 465
|
||||||
|
MAIL_USE_TLS = False
|
||||||
|
MAIL_USE_SSL = True
|
Binary file not shown.
@ -0,0 +1,21 @@
|
|||||||
|
from flask import render_template, request, Blueprint
|
||||||
|
from minibase.models import Post
|
||||||
|
|
||||||
|
# Declaring a blueprint
|
||||||
|
main = Blueprint('main', __name__)
|
||||||
|
|
||||||
|
#Redirect from / and also /home routes to the /
|
||||||
|
@main.route("/")
|
||||||
|
@main.route("/home")
|
||||||
|
def home():
|
||||||
|
# (PAGINATION) Defines the page number that we will start with
|
||||||
|
page = request.args.get('page', 1, type=int)
|
||||||
|
# (POSTS) Query posts usin SQLAlchemy
|
||||||
|
posts = Post.query.order_by(Post.date_posted.asc()).paginate(per_page=2)
|
||||||
|
# (HTML) Renders the template for templates/home.html
|
||||||
|
return render_template('home.html', posts=posts)
|
||||||
|
|
||||||
|
|
||||||
|
@main.route("/about")
|
||||||
|
def about():
|
||||||
|
return render_template('about.html', title='About')
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,10 @@
|
|||||||
|
from flask_wtf import FlaskForm
|
||||||
|
from wtforms import StringField, SubmitField, TextAreaField
|
||||||
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
|
class postForm(FlaskForm):
|
||||||
|
title = StringField('Title',
|
||||||
|
validators=[DataRequired()])
|
||||||
|
content = TextAreaField('Content',
|
||||||
|
validators=[DataRequired()])
|
||||||
|
submit = SubmitField('Post')
|
@ -0,0 +1,55 @@
|
|||||||
|
from flask import (render_template, url_for, flash,
|
||||||
|
redirect, request, abort, Blueprint)
|
||||||
|
from flask_login import current_user, login_required
|
||||||
|
from minibase import db
|
||||||
|
from minibase.models import Post
|
||||||
|
from minibase.posts.forms import postForm
|
||||||
|
|
||||||
|
# Declaring a blueprint
|
||||||
|
posts = Blueprint('posts', __name__)
|
||||||
|
|
||||||
|
@posts.route("/post/new", methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
def new_post():
|
||||||
|
form = postForm()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
post = Post(title=form.title.data, content=form.content.data, author=current_user)
|
||||||
|
db.session.add(post)
|
||||||
|
db.session.commit()
|
||||||
|
flash('Your post has been created', 'success')
|
||||||
|
return redirect(url_for('main.home'))
|
||||||
|
return render_template('create_post.html', title='Create Post', legend='Create Post', form=form)
|
||||||
|
|
||||||
|
@posts.route("/post/<int:post_id>")
|
||||||
|
def post(post_id):
|
||||||
|
post = Post.query.get_or_404(post_id)
|
||||||
|
return render_template('post.html', title=post.title, post=post)
|
||||||
|
|
||||||
|
@posts.route("/post/<int:post_id>/update", methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
def post_update(post_id):
|
||||||
|
post = Post.query.get_or_404(post_id)
|
||||||
|
if post.author != current_user:
|
||||||
|
abort(403)
|
||||||
|
form = postForm()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
post.title = form.title.data
|
||||||
|
post.content = form.content.data
|
||||||
|
db.session.commit()
|
||||||
|
flash('Your post has been updated', 'success')
|
||||||
|
return redirect(url_for('posts.post', post_id=post.id))
|
||||||
|
elif request.method == 'GET':
|
||||||
|
form.title.data = post.title
|
||||||
|
form.content.data = post.content
|
||||||
|
return render_template('create_post.html', title='Update Post', legend='Update Post', form=form)
|
||||||
|
|
||||||
|
@posts.route("/post/<int:post_id>/delete", methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def post_delete(post_id):
|
||||||
|
post = Post.query.get_or_404(post_id)
|
||||||
|
if post.author != current_user:
|
||||||
|
abort(403)
|
||||||
|
db.session.delete(post)
|
||||||
|
db.session.commit()
|
||||||
|
flash('Your post has been deleted', 'success')
|
||||||
|
return redirect(url_for('main.home'))
|
@ -1,183 +0,0 @@
|
|||||||
import os
|
|
||||||
import secrets
|
|
||||||
from PIL import Image
|
|
||||||
from flask import render_template, url_for, flash, redirect, request, abort
|
|
||||||
from minibase import app, db, bcrypt, mail
|
|
||||||
from minibase.forms import registrationForm, loginForm, updateAccountForm, postForm, requestResetForm, resetPasswordForm
|
|
||||||
from minibase.models import User, Post
|
|
||||||
from flask_login import login_user, current_user, logout_user, login_required
|
|
||||||
from flask_mail import Message
|
|
||||||
|
|
||||||
#Redirect from / and also /home routes to the /
|
|
||||||
@app.route("/")
|
|
||||||
@app.route("/home")
|
|
||||||
def home():
|
|
||||||
page = request.args.get('page', 1, type=int)
|
|
||||||
posts = Post.query.order_by(Post.date_posted.asc()).paginate(per_page=2)
|
|
||||||
return render_template('home.html', posts=posts)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/about")
|
|
||||||
def about():
|
|
||||||
return render_template('about.html', title='About')
|
|
||||||
|
|
||||||
@app.route("/register", methods=['GET', 'POST'])
|
|
||||||
def register():
|
|
||||||
if current_user.is_authenticated:
|
|
||||||
return redirect(url_for('home'))
|
|
||||||
|
|
||||||
form = registrationForm()
|
|
||||||
if form.validate_on_submit():
|
|
||||||
hashed_pw = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
|
|
||||||
user = User(username=form.username.data, email=form.email.data, password=hashed_pw)
|
|
||||||
db.session.add(user)
|
|
||||||
db.session.commit()
|
|
||||||
flash(f'Your account has benn created you can now log in!','success')
|
|
||||||
return redirect(url_for('login'))
|
|
||||||
|
|
||||||
return render_template('register.html', title='Register', form=form)
|
|
||||||
|
|
||||||
@app.route("/login", methods=['GET', 'POST'])
|
|
||||||
def login():
|
|
||||||
if current_user.is_authenticated:
|
|
||||||
return redirect(url_for('home'))
|
|
||||||
form = loginForm()
|
|
||||||
if form.validate_on_submit():
|
|
||||||
user = User.query.filter_by(email=form.email.data).first()
|
|
||||||
if user and bcrypt.check_password_hash(user.password, form.password.data):
|
|
||||||
login_user(user,remember=form.remember.data)
|
|
||||||
next_page = request.args.get('next')
|
|
||||||
return redirect(next_page) if next_page else redirect(url_for('home'))
|
|
||||||
else:
|
|
||||||
flash('Login unsuccessful. Please chek your Email and Password!','danger')
|
|
||||||
return render_template('login.html', title='Login', form=form)
|
|
||||||
|
|
||||||
@app.route("/logout")
|
|
||||||
def logout():
|
|
||||||
logout_user()
|
|
||||||
return redirect(url_for('home'))
|
|
||||||
|
|
||||||
def save_picture(form_picture):
|
|
||||||
random_hex = secrets.token_hex(8)
|
|
||||||
_, f_ext =os.path.splitext(form_picture.filename)
|
|
||||||
picture_fn = random_hex + f_ext
|
|
||||||
picture_path = os.path.join(app.root_path, 'static/pics', picture_fn)
|
|
||||||
output_size = (125,125)
|
|
||||||
i = Image.open(form_picture)
|
|
||||||
i.thumbnail(output_size)
|
|
||||||
i.save(picture_path)
|
|
||||||
return picture_fn
|
|
||||||
|
|
||||||
@app.route("/account", methods=['GET', 'POST'])
|
|
||||||
@login_required
|
|
||||||
def account():
|
|
||||||
form = updateAccountForm()
|
|
||||||
if form.validate_on_submit():
|
|
||||||
if form.picture.data:
|
|
||||||
picture_file = save_picture(form.picture.data)
|
|
||||||
current_user.image_file = picture_file
|
|
||||||
current_user.username = form.username.data
|
|
||||||
current_user.email = form.email.data
|
|
||||||
db.session.commit()
|
|
||||||
flash('Your account has been updated!', 'success')
|
|
||||||
return redirect(url_for('account'))
|
|
||||||
elif request.method == 'GET':
|
|
||||||
form.username.data = current_user.username
|
|
||||||
form.email.data = current_user.email
|
|
||||||
image_file = url_for('static', filename='pics/'+ current_user.image_file)
|
|
||||||
return render_template('account.html', title='Account', image_file = image_file, form=form)
|
|
||||||
|
|
||||||
@app.route("/post/new", methods=['GET', 'POST'])
|
|
||||||
@login_required
|
|
||||||
def new_post():
|
|
||||||
form = postForm()
|
|
||||||
if form.validate_on_submit():
|
|
||||||
post = Post(title=form.title.data, content=form.content.data, author=current_user)
|
|
||||||
db.session.add(post)
|
|
||||||
db.session.commit()
|
|
||||||
flash('Your post has been created', 'success')
|
|
||||||
return redirect(url_for('home'))
|
|
||||||
return render_template('create_post.html', title='Create Post', legend='Create Post', form=form)
|
|
||||||
|
|
||||||
@app.route("/post/<int:post_id>")
|
|
||||||
def post(post_id):
|
|
||||||
post = Post.query.get_or_404(post_id)
|
|
||||||
return render_template('post.html', title=post.title, post=post)
|
|
||||||
|
|
||||||
@app.route("/post/<int:post_id>/update", methods=['GET', 'POST'])
|
|
||||||
@login_required
|
|
||||||
def post_update(post_id):
|
|
||||||
post = Post.query.get_or_404(post_id)
|
|
||||||
if post.author != current_user:
|
|
||||||
abort(403)
|
|
||||||
form = postForm()
|
|
||||||
if form.validate_on_submit():
|
|
||||||
post.title = form.title.data
|
|
||||||
post.content = form.content.data
|
|
||||||
db.session.commit()
|
|
||||||
flash('Your post has been updated', 'success')
|
|
||||||
return redirect(url_for('post', post_id=post.id))
|
|
||||||
elif request.method == 'GET':
|
|
||||||
form.title.data = post.title
|
|
||||||
form.content.data = post.content
|
|
||||||
return render_template('create_post.html', title='Update Post', legend='Update Post', form=form)
|
|
||||||
|
|
||||||
@app.route("/post/<int:post_id>/delete", methods=['POST'])
|
|
||||||
@login_required
|
|
||||||
def post_delete(post_id):
|
|
||||||
post = Post.query.get_or_404(post_id)
|
|
||||||
if post.author != current_user:
|
|
||||||
abort(403)
|
|
||||||
db.session.delete(post)
|
|
||||||
db.session.commit()
|
|
||||||
flash('Your post has been deleted', 'success')
|
|
||||||
return redirect(url_for('home'))
|
|
||||||
|
|
||||||
@app.route("/user/<string:username>")
|
|
||||||
def user_posts(username):
|
|
||||||
user = User.query.filter_by(username=username).first_or_404()
|
|
||||||
page = request.args.get('page', 1, type=int)
|
|
||||||
posts = Post.query.filter_by(author=user)\
|
|
||||||
.order_by(Post.date_posted.asc())\
|
|
||||||
.paginate(page=page, per_page=2)
|
|
||||||
return render_template('user_posts.html', posts=posts, user=user)
|
|
||||||
|
|
||||||
|
|
||||||
def send_reset_email(user):
|
|
||||||
token = user.get_reset_token()
|
|
||||||
msg = Message('Password Reset Request',
|
|
||||||
sender='noreply@demo.com',
|
|
||||||
recipients=[user.email])
|
|
||||||
msg.body = f'''To reset your password, visit the following link:
|
|
||||||
{url_for('reset_token', token=token, _external=True)}
|
|
||||||
If you didn't make this request, then simply ingnore this email and no chancges will be made.
|
|
||||||
'''
|
|
||||||
mail.send(msg)
|
|
||||||
|
|
||||||
@app.route("/reset_password", methods=['GET', 'POST'])
|
|
||||||
def reset_request():
|
|
||||||
if current_user.is_authenticated:
|
|
||||||
return redirect(url_for('home'))
|
|
||||||
form = requestResetForm()
|
|
||||||
if form.validate_on_submit():
|
|
||||||
user = User.query.filter_by(email=form.email.data).first()
|
|
||||||
send_reset_email(user)
|
|
||||||
flash('An Email has benn sent with instruction to reset your password', 'warning')
|
|
||||||
return render_template('reset_request.html', title='Reset Password', form=form)
|
|
||||||
|
|
||||||
@app.route("/reset_password/<token>", methods=['GET', 'POST'])
|
|
||||||
def reset_token(token):
|
|
||||||
if current_user.is_authenticated:
|
|
||||||
return redirect(url_for('home'))
|
|
||||||
user = User.verify_reset_token(token)
|
|
||||||
if user is None:
|
|
||||||
flash('That is an invalid or expired token', 'warning')
|
|
||||||
return redirect(url_for('reset_request'))
|
|
||||||
form = resetPasswordForm()
|
|
||||||
if form.validate_on_submit():
|
|
||||||
hashed_pw = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
|
|
||||||
user.password = hashed_pw
|
|
||||||
db.session.commit()
|
|
||||||
flash(f'Your password has benn udated','success')
|
|
||||||
return redirect(url_for('login'))
|
|
||||||
return render_template('reset_token.html', title='Reset Password', form=form)
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,106 @@
|
|||||||
|
from flask import render_template, url_for, flash, redirect, request, Blueprint
|
||||||
|
from flask_login import login_user, current_user, logout_user, login_required
|
||||||
|
from minibase import db, bcrypt
|
||||||
|
from minibase.models import User, Post
|
||||||
|
from minibase.users.forms import registrationForm, loginForm, updateAccountForm, requestResetForm, resetPasswordForm
|
||||||
|
from minibase.posts.forms import postForm
|
||||||
|
from minibase.users.utils import save_picture, send_reset_email
|
||||||
|
|
||||||
|
|
||||||
|
# Declaring a blueprint
|
||||||
|
users = Blueprint('users', __name__)
|
||||||
|
|
||||||
|
#Route is the file that is going to be generated
|
||||||
|
@users.route("/register", methods=['GET', 'POST'])
|
||||||
|
def register():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
return redirect(url_for('main.home'))
|
||||||
|
|
||||||
|
form = registrationForm()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
hashed_pw = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
|
||||||
|
user = User(username=form.username.data, email=form.email.data, password=hashed_pw)
|
||||||
|
db.session.add(user)
|
||||||
|
db.session.commit()
|
||||||
|
flash(f'Your account has benn created you can now log in!','success')
|
||||||
|
return redirect(url_for('users.login'))
|
||||||
|
|
||||||
|
return render_template('register.html', title='Register', form=form)
|
||||||
|
|
||||||
|
@users.route("/login", methods=['GET', 'POST'])
|
||||||
|
def login():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
return redirect(url_for('main.home'))
|
||||||
|
form = loginForm()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
user = User.query.filter_by(email=form.email.data).first()
|
||||||
|
if user and bcrypt.check_password_hash(user.password, form.password.data):
|
||||||
|
login_user(user,remember=form.remember.data)
|
||||||
|
next_page = request.args.get('next')
|
||||||
|
return redirect(next_page) if next_page else redirect(url_for('main.home'))
|
||||||
|
else:
|
||||||
|
flash('Login unsuccessful. Please chek your Email and Password!','danger')
|
||||||
|
return render_template('login.html', title='Login', form=form)
|
||||||
|
|
||||||
|
@users.route("/logout")
|
||||||
|
def logout():
|
||||||
|
logout_user()
|
||||||
|
return redirect(url_for('main.home'))
|
||||||
|
|
||||||
|
|
||||||
|
@users.route("/account", methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
def account():
|
||||||
|
form = updateAccountForm()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
if form.picture.data:
|
||||||
|
picture_file = save_picture(form.picture.data)
|
||||||
|
current_user.image_file = picture_file
|
||||||
|
current_user.username = form.username.data
|
||||||
|
current_user.email = form.email.data
|
||||||
|
db.session.commit()
|
||||||
|
flash('Your account has been updated!', 'success')
|
||||||
|
return redirect(url_for('users.account'))
|
||||||
|
elif request.method == 'GET':
|
||||||
|
form.username.data = current_user.username
|
||||||
|
form.email.data = current_user.email
|
||||||
|
image_file = url_for('static', filename='pics/'+ current_user.image_file)
|
||||||
|
return render_template('account.html', title='Account', image_file = image_file, form=form)
|
||||||
|
|
||||||
|
|
||||||
|
@users.route("/user/<string:username>")
|
||||||
|
def user_posts(username):
|
||||||
|
user = User.query.filter_by(username=username).first_or_404()
|
||||||
|
page = request.args.get('page', 1, type=int)
|
||||||
|
posts = Post.query.filter_by(author=user)\
|
||||||
|
.order_by(Post.date_posted.asc())\
|
||||||
|
.paginate(page=page, per_page=2)
|
||||||
|
return render_template('user_posts.html', posts=posts, user=user)
|
||||||
|
|
||||||
|
@users.route("/reset_password", methods=['GET', 'POST'])
|
||||||
|
def reset_request():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
return redirect(url_for('main.home'))
|
||||||
|
form = requestResetForm()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
user = User.query.filter_by(email=form.email.data).first()
|
||||||
|
send_reset_email(user)
|
||||||
|
flash('An Email has benn sent with instruction to reset your password', 'warning')
|
||||||
|
return render_template('reset_request.html', title='Reset Password', form=form)
|
||||||
|
|
||||||
|
@users.route("/reset_password/<token>", methods=['GET', 'POST'])
|
||||||
|
def reset_token(token):
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
return redirect(url_for('main.home'))
|
||||||
|
user = User.verify_reset_token(token)
|
||||||
|
if user is None:
|
||||||
|
flash('That is an invalid or expired token', 'warning')
|
||||||
|
return redirect(url_for('users.reset_request'))
|
||||||
|
form = resetPasswordForm()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
hashed_pw = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
|
||||||
|
user.password = hashed_pw
|
||||||
|
db.session.commit()
|
||||||
|
flash(f'Your password has benn udated','success')
|
||||||
|
return redirect(url_for('users.login'))
|
||||||
|
return render_template('reset_token.html', title='Reset Password', form=form)
|
@ -0,0 +1,28 @@
|
|||||||
|
import os
|
||||||
|
import secrets
|
||||||
|
from PIL import Image
|
||||||
|
from flask import url_for, current_app
|
||||||
|
from flask_mail import Message
|
||||||
|
from minibase import mail
|
||||||
|
|
||||||
|
def save_picture(form_picture):
|
||||||
|
random_hex = secrets.token_hex(8)
|
||||||
|
_, f_ext =os.path.splitext(form_picture.filename)
|
||||||
|
picture_fn = random_hex + f_ext
|
||||||
|
picture_path = os.path.join(current_app.root_path, 'static/pics', picture_fn)
|
||||||
|
output_size = (125,125)
|
||||||
|
i = Image.open(form_picture)
|
||||||
|
i.thumbnail(output_size)
|
||||||
|
i.save(picture_path)
|
||||||
|
return picture_fn
|
||||||
|
|
||||||
|
def send_reset_email(user):
|
||||||
|
token = user.get_reset_token()
|
||||||
|
msg = Message('Password Reset Request',
|
||||||
|
sender='noreply@demo.com',
|
||||||
|
recipients=[user.email])
|
||||||
|
msg.body = f'''To reset your password, visit the following link:
|
||||||
|
{url_for('reset_token', token=token, _external=True)}
|
||||||
|
If you didn't make this request, then simply ingnore this email and no chancges will be made.
|
||||||
|
'''
|
||||||
|
mail.send(msg)
|
Loading…
Reference in new issue