diff --git a/schema.sql b/schema.sql new file mode 100644 index 0000000..e4638ae --- /dev/null +++ b/schema.sql @@ -0,0 +1,5 @@ +drop table if exists entries; +create table entries ( + id integer primary key autoincrement, + todo text not null +); diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..671e9df --- /dev/null +++ b/static/style.css @@ -0,0 +1,18 @@ +body { font-family: sans-serif; background: #eee; } +a, h1, h2 { color: #377ba8; } +h1, h2 { font-family: 'Georgia', serif; margin: 0; } +h1 { border-bottom: 2px solid #eee; } +h2 { font-size: 1.2em; } + +.page { margin: 2em auto; width: 35em; border: 5px solid #ccc; + padding: 0.8em; background: white; } +.entries { list-style: none; margin: 0; padding: 0; } +.entries li { margin: 0.8em 1.2em; } +.entries li h2 { margin-left: -1em; } +.add-entry { font-size: 0.9em; border-bottom: 1px solid #ccc; } +.add-entry dl { font-weight: bold; } +.metanav { text-align: right; font-size: 0.8em; padding: 0.3em; + margin-bottom: 1em; background: #fafafa; } +.flash { background: #cee5F5; padding: 0.5em; + border: 1px solid #aacbe2; } +.error { background: #f0d6d6; padding: 0.5em; } diff --git a/templates/completed.html b/templates/completed.html new file mode 100644 index 0000000..2c9e335 --- /dev/null +++ b/templates/completed.html @@ -0,0 +1,15 @@ +{% extends "layout.html" %} +{% block body %} + {% if session.logged_in %} + + +

Completed To Do's

+ + {% endif %} +{% endblock %} diff --git a/templates/layout.html b/templates/layout.html new file mode 100644 index 0000000..3bef6ff --- /dev/null +++ b/templates/layout.html @@ -0,0 +1,17 @@ + +To Do App + +
+

To Dos

+
+ {% if not session.logged_in %} + log in + {% else %} + log out + {% endif %} +
+ {% for message in get_flashed_messages() %} +
{{ message }}
+ {% endfor %} + {% block body %}{% endblock %} +
diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..6f70bb7 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,14 @@ +{% extends "layout.html" %} +{% block body %} +

Login

+ {% if error %}

Error: {{ error }}{% endif %} +

+
+
Username: +
+
Password: +
+
+
+
+{% endblock %} diff --git a/templates/show_entries.html b/templates/show_entries.html new file mode 100644 index 0000000..63d1f50 --- /dev/null +++ b/templates/show_entries.html @@ -0,0 +1,37 @@ +{% extends "layout.html" %} +{% block body %} + {% if session.logged_in %} +
+
+
Create a new to do: +
+ +
+
+ +
+
+
+ +
+ +
+ + + +

All To Do's

+

To Do          Due Date

+
+ {% for todo in entries %} + {% if todo in pastdue %}{% endif %} + +
+ {% if todo in pastdue %}
{% endif %} + {% else %} +
  • Clean State + {% endfor %} +
    + + + {% endif %} +{% endblock %} diff --git a/to_do.py b/to_do.py new file mode 100644 index 0000000..793f981 --- /dev/null +++ b/to_do.py @@ -0,0 +1,106 @@ +from datetime import datetime +from flask import Flask, request, session, g, redirect, url_for, \ + abort, render_template, flash +from contextlib import closing + +from flask.ext.sqlalchemy import SQLAlchemy +from flask.ext.script import Manager +from flask.ext.migrate import Migrate, MigrateCommand +from flask.ext.script.commands import ShowUrls, Clean + + +DATABASE = '/tmp/todo.db' +DEBUG = True +SECRET_KEY = 'this is hard' +SQLALCHEMY_DATABASE_URI = "sqlite:///" + DATABASE + +app = Flask(__name__) +app.config.from_object(__name__) +db = SQLAlchemy(app) +migrate = Migrate(app,db) +manager = Manager(app) +manager.add_command('db',MigrateCommand) + + + +class Todo(db.Model): + id = db.Column(db.Integer, primary_key=True) + todo = db.Column(db.String(255), nullable=False) + completed_at = db.Column(db.DateTime) + due_date = db.Column(db.DateTime) + + def __init__(self, text,due_date): + self.todo = text + self.due_date = due_date + + def __repr__(self): + return "".format(self.text) + +@app.route('/') +def show_entries(): + current_todo_list = Todo.query.filter(Todo.completed_at==None).order_by(Todo.due_date.desc()).all() + past_due_list = [elem for elem in current_todo_list if elem.due_date < datetime.utcnow()] + return render_template('show_entries.html', + entries=current_todo_list, + pastdue = past_due_list) + + +@app.route('/add', methods=['POST']) +def add_entry(): + if not session.get('logged_in'): + abort(401) + text = request.form['todo'] + duedate = request.form['due_date'] + todo = Todo(text, datetime.strptime(duedate, '%Y-%m-%d')) + db.session.add(todo) + db.session.commit() + flash('New to-do was successfully posted') + return redirect(url_for('show_entries')) + + +@app.route('/mark_completed', methods=['POST']) +def complete_entry(): + if not session.get('logged_in'): + abort(401) + ids = request.form.getlist('entry') + for id in ids: + todo = Todo.query.get(id) + todo.completed_at = datetime.utcnow() + db.session.add(todo) + db.session.commit() + flash('To-dos have been updated') + return redirect(url_for('show_entries')) + +@app.route('/completed', methods=['GET','POST']) +def show_completed(): + if not session.get('logged_in'): + abort(401) + completed_todo_list = Todo.query.filter(Todo.completed_at!=None).order_by(Todo.completed_at.desc()).all() + return render_template('completed.html', + completed=completed_todo_list) + +# Login management +@app.route('/login', methods=['GET', 'POST']) +def login(): + error = None + if request.method == 'POST': + if request.form['username'] != app.config['USERNAME']: + error = 'Invalid username' + elif request.form['password'] != app.config['PASSWORD']: + error = 'Invalid password' + else: + session['logged_in'] = True + flash('You were logged in') + return redirect(url_for('show_entries')) + return render_template('login.html', error=error) + +# Logout. using pop removes the user entry. No need to check if user loggedin +@app.route('/logout') +def logout(): + session.pop('logged_in', None) + flash('You were logged out') + return redirect(url_for('show_entries')) + +# to start the application +if __name__ == '__main__': + manager.run()