diff --git a/week-0/day-3/my_todo_app/run.sh b/week-0/day-3/my_todo_app/run.sh new file mode 100755 index 00000000..df743747 --- /dev/null +++ b/week-0/day-3/my_todo_app/run.sh @@ -0,0 +1,4 @@ +export FLASK_APP=todo_app +export FLASK_ENV=development +flask init-db +flask run diff --git a/week-0/day-3/my_todo_app/todo_app/__init__.py b/week-0/day-3/my_todo_app/todo_app/__init__.py index c1833cb0..9751f819 100644 --- a/week-0/day-3/my_todo_app/todo_app/__init__.py +++ b/week-0/day-3/my_todo_app/todo_app/__init__.py @@ -1,52 +1,43 @@ import os - from flask import Flask -from flask import request - - def create_app(test_config=None): # create and configure the app app = Flask(__name__, instance_relative_config=True) - # ensure the instance folder exists + app.config.from_mapping( + SECRET_KEY='dev', + DATABASE=os.path.join(app.instance_path,'todo_app.sqlite') + ) + + + if test_config is None: + # load the instance config, if it exists, when not testing + app.config.from_pyfile('config.py', silent=True) + else: + # load the test config if passed in + app.config.from_mapping(test_config) + + try: os.makedirs(app.instance_path) except OSError: pass + # a simple page that list my todos + @app.route('/shivang') + def shivang(): + return ('Wake Up' + '
' + + 'Drink Coffee' + '
' + + 'Read Non-fiction Novel' + '
' + ) - def todo_view(todos): - the_view = 'List of my todos:' + '
' - for todo in todos: - the_view += ( todo + '
' ) - - the_view += '---- LIST ENDS HERE ---' - return the_view - - def get_todos_by_name(name): - if name == 'depo': - return ['Go for run', 'Listen Rock Music'] - elif name == 'shivang': - return ['Read book', 'Play Fifa', 'Drink Coffee'] - elif name == 'raj': - return ['Study', 'Brush'] - elif name == 'sanket': - return ['Sleep', 'Code'] - elif name == 'aagam': - return ['play cricket', 'have tea'] - else: - return [] + from . import db + db.init_app(app) + from . import auth + app.register_blueprint(auth.bp) - # http://127.0.0.1:5000/todos?name=duster - @app.route('/todos') - def todos(): - name = request.args.get('name') - print('---------') - print(name) - print('---------') - - person_todo_list = get_todos_by_name(name) - return todo_view(person_todo_list) + from . import post + app.register_blueprint(post.bp) + app.add_url_rule('/', endpoint='index') return app - diff --git a/week-0/day-3/my_todo_app/todo_app/__init__.pyc b/week-0/day-3/my_todo_app/todo_app/__init__.pyc deleted file mode 100644 index 45e35a62..00000000 Binary files a/week-0/day-3/my_todo_app/todo_app/__init__.pyc and /dev/null differ diff --git a/week-0/day-3/my_todo_app/todo_app/auth.py b/week-0/day-3/my_todo_app/todo_app/auth.py new file mode 100644 index 00000000..e26da5fd --- /dev/null +++ b/week-0/day-3/my_todo_app/todo_app/auth.py @@ -0,0 +1,92 @@ +import functools + +from flask import ( + Blueprint, flash, g, redirect, render_template, request, session, url_for +) +from werkzeug.security import check_password_hash, generate_password_hash + +from todo_app.db import get_db +from flask import current_app + +bp = Blueprint('auth', __name__, url_prefix='/auth') + +@bp.route('/register',methods=('GET','POST')) +def register(): + if request.method=='POST': + username=request.form['username'] + password=request.form['password'] + db=get_db() + error=None + + if not username: + error='Username is required' + elif not password: + error='Password is required' + elif db.execute( + 'SELECT id FROM user WHERE username=?',(username,) + ).fetchone() is not None: + error='User {} is already registered'.format(username) + + if error is None: + db.execute( + 'INSERT INTO user(username,password) VALUES (?,?)', + (username,generate_password_hash(password)) + ) + db.commit() + return redirect(url_for('auth.login')) + + flash(error) + return render_template('auth/register.html') + +@bp.route('/login',methods=('GET','POST')) +def login(): + if request.method=='POST': + username=request.form['username'] + password=request.form['password'] + db=get_db() + error=None + user=db.execute( + 'SELECT * FROM user WHERE username=?',(username,) + ).fetchone() + + if user is None: + error='Incorrect Username' + elif not check_password_hash(user['password'],password): + error='Incorrect password' + + if error is None: + session.clear() + session['user_id']=user['id'] + return redirect(url_for('index')) + + flash(error) + return render_template('auth/login.html') + +@bp.route('/logout') +def logout(): + session.clear() + return redirect(url_for('auth.login')) + +def login_required(view): + @functools.wraps(view) + def wrapped_view(**kwargs): + if g.user is None: + return redirect(url_for('auth.login')) + + return view(**kwargs) + + return wrapped_view + +@bp.before_app_request +def load_logged_in_user(): + user_id=session.get('user_id') + + if user_id is None: + g.user=None + else: + g.user=get_db().execute( + 'SELECT * FROM user WHERE id=?',(user_id,) + ).fetchone() + + + diff --git a/week-0/day-3/my_todo_app/todo_app/db.py b/week-0/day-3/my_todo_app/todo_app/db.py new file mode 100644 index 00000000..c83d0adf --- /dev/null +++ b/week-0/day-3/my_todo_app/todo_app/db.py @@ -0,0 +1,38 @@ +import sqlite3 + +import click +from flask import current_app,g +from flask.cli import with_appcontext + +def get_db(): + if 'db' not in g: + g.db=sqlite3.connect( + current_app.config['DATABASE'], + detect_types=sqlite3.PARSE_DECLTYPES + ) + g.db.row_factory=sqlite3.Row + return g.db; + +def init_app(app): + app.teardown_appcontext(close_db) + app.cli.add_command(init_db_command) + +def init_db(): + db = get_db() + + with current_app.open_resource('schema.sql') as f: + db.executescript(f.read().decode('utf8')) + + +@click.command('init-db') +@with_appcontext +def init_db_command(): + """Clear the existing data and create new tables.""" + init_db() + click.echo('Initialized the database.') + +def close_db(e=None): + db=g.pop('db',None) + + if db is not None: + db.close() \ No newline at end of file diff --git a/week-0/day-3/my_todo_app/todo_app/post.py b/week-0/day-3/my_todo_app/todo_app/post.py new file mode 100644 index 00000000..a03b1720 --- /dev/null +++ b/week-0/day-3/my_todo_app/todo_app/post.py @@ -0,0 +1,102 @@ +from flask import( + Blueprint, flash, g, redirect, render_template,request,url_for,session +) +from werkzeug.exceptions import abort + +from todo_app.auth import login_required +from todo_app.db import get_db +from flask import session + +bp=Blueprint('post',__name__) + +@bp.route('/') +def index(): + user_id=session.get('user_id') + print(user_id) + if user_id is None: + return redirect('auth/login') + + db=get_db() + posts = db.execute( + 'SELECT * FROM post WHERE author_id=?',(user_id,) + + # 'SELECT p.id, title, body, created, author_id' + # 'FROM post p WHERE p.author_id=?', (user_id,) + ).fetchall() + return render_template('posts/index.html',posts=posts) + + +@bp.route('/create',methods=('GET','POST')) +@login_required +def create(): + if request.method=='POST': + title=request.form['title'] + body=request.form['body'] + error=None + + if not title: + error='Title required' + if error is not None: + flash(error) + else: + db=get_db() + db.execute( + 'INSERT INTO post (title, body, author_id)' + ' VALUES (?, ?, ?)', + (title, body, g.user['id']) + ) + db.commit() + return redirect(url_for('post.index')) + return render_template('posts/create.html') + +def get_post(id,check_author=True): + post=get_db().execute( + 'SELECT p.id, title, body, created, author_id, username' + ' FROM post p JOIN user u ON p.author_id = u.id' + ' WHERE p.id = ?', + (id,) + ).fetchone() + + if post is None: + abort(404,"Post id {0} doesn't exist.".format(id)) + + if check_author and post['author_id']!=g.user['id']: + abort(403) + + return post + +@bp.route('//update',methods=('GET','POST')) +@login_required +def update(id): + post=get_post(id) + + if request.method=='POST': + title=request.form['title'] + body=request.form['body'] + error=None + + if not title: + error='Title is required' + + if error is not None: + flash(error) + else: + db=get_db() + db.execute( + 'UPDATE post SET title=?,body=?' + 'WHERE id=?' + (title,body,id) + ) + db.commit() + return redirect(url_for('post.index')) + + return render_template('posts/update.html',post=post) + +@bp.route('//delete',methods=('POST',)) +@login_required +def delete(id): + get_post(id) + db=get_db() + db.execute('DELETE FROM post WHERE id=?',(id,)) + db.commit() + return redirect(url_for('post.index')) diff --git a/week-0/day-3/my_todo_app/todo_app/schema.sql b/week-0/day-3/my_todo_app/todo_app/schema.sql new file mode 100644 index 00000000..113a7438 --- /dev/null +++ b/week-0/day-3/my_todo_app/todo_app/schema.sql @@ -0,0 +1,18 @@ +DROP TABLE IF EXISTS user; +DROP TABLE IF EXISTS post; + +CREATE TABLE user( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + password TEXT NOT NULL +); + +CREATE TABLE post( + id INTEGER PRIMARY KEY AUTOINCREMENT, + author_id INTEGER NOT NULL, + created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + title TEXT NOT NULL, + body TEXT NOT NULL, + FOREIGN KEY(author_id) REFERENCES user (id) +); + diff --git a/week-0/day-3/my_todo_app/todo_app/templates/auth/login.html b/week-0/day-3/my_todo_app/todo_app/templates/auth/login.html new file mode 100644 index 00000000..b7dd5dc1 --- /dev/null +++ b/week-0/day-3/my_todo_app/todo_app/templates/auth/login.html @@ -0,0 +1,15 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Log In{% endblock %}

+{% endblock %} + +{% block content %} +
+ + + + + +
+{% endblock %} \ No newline at end of file diff --git a/week-0/day-3/my_todo_app/todo_app/templates/auth/register.html b/week-0/day-3/my_todo_app/todo_app/templates/auth/register.html new file mode 100644 index 00000000..a3c73cc9 --- /dev/null +++ b/week-0/day-3/my_todo_app/todo_app/templates/auth/register.html @@ -0,0 +1,15 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Register{% endblock %}

+{% endblock %} + +{% block content %} +
+ + + + + +
+{% endblock %} \ No newline at end of file diff --git a/week-0/day-3/my_todo_app/todo_app/templates/base.html b/week-0/day-3/my_todo_app/todo_app/templates/base.html new file mode 100644 index 00000000..d5a5d370 --- /dev/null +++ b/week-0/day-3/my_todo_app/todo_app/templates/base.html @@ -0,0 +1,24 @@ + +{% block title %}{% endblock %} - TodoApp + + +
+
+ {% block header %}{% endblock %} +
+ {% for message in get_flashed_messages() %} +
{{ message }}
+ {% endfor %} + {% block content %}{% endblock %} +
\ No newline at end of file diff --git a/week-0/day-3/my_todo_app/todo_app/templates/posts/create.html b/week-0/day-3/my_todo_app/todo_app/templates/posts/create.html new file mode 100644 index 00000000..90d5c379 --- /dev/null +++ b/week-0/day-3/my_todo_app/todo_app/templates/posts/create.html @@ -0,0 +1,15 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Add NewTodo{% endblock %}

+{% endblock %} + +{% block content %} +
+ + + + + +
+{% endblock %} \ No newline at end of file diff --git a/week-0/day-3/my_todo_app/todo_app/templates/posts/index.html b/week-0/day-3/my_todo_app/todo_app/templates/posts/index.html new file mode 100644 index 00000000..b4364ed9 --- /dev/null +++ b/week-0/day-3/my_todo_app/todo_app/templates/posts/index.html @@ -0,0 +1,28 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Todos{% endblock %}

+ {% if g.user %} + New + {% endif %} +{% endblock %} + +{% block content %} + {% for post in posts %} +
+
+
+

{{ post['title'] }}

+
on {{ post['created'].strftime('%Y-%m-%d') }}
+
+ {% if g.user['id'] == post['author_id'] %} + Edit + {% endif %} +
+

{{ post['body'] }}

+
+ {% if not loop.last %} +
+ {% endif %} + {% endfor %} +{% endblock %} \ No newline at end of file diff --git a/week-0/day-3/my_todo_app/todo_app/templates/posts/update.html b/week-0/day-3/my_todo_app/todo_app/templates/posts/update.html new file mode 100644 index 00000000..a24a8d4f --- /dev/null +++ b/week-0/day-3/my_todo_app/todo_app/templates/posts/update.html @@ -0,0 +1,20 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Edit "{{ post['title'] }}"{% endblock %}

+{% endblock %} + +{% block content %} +
+ + + + + +
+
+
+ +
+{% endblock %} \ No newline at end of file