|
@@ -0,0 +1,113 @@
|
|
|
+#!/bin/env python
|
|
|
+
|
|
|
+from flask import Flask
|
|
|
+from flask_restful import reqparse, abort, Api, Resource
|
|
|
+from flask_httpauth import HTTPBasicAuth
|
|
|
+from flask_sqlalchemy import SQLAlchemy
|
|
|
+import json
|
|
|
+
|
|
|
+# This "protects" paths with @auth.login_required
|
|
|
+auth = HTTPBasicAuth()
|
|
|
+
|
|
|
+# This is a very basic (and dumb) security model
|
|
|
+# We'll actually want the @auth.verify_password model,
|
|
|
+# which will let us use hashed passwords, etc.
|
|
|
+
|
|
|
[email protected]_password
|
|
|
+def get_password(username):
|
|
|
+ if username == 'admin':
|
|
|
+ return '12345'
|
|
|
+ return None
|
|
|
+
|
|
|
[email protected]_handler
|
|
|
+def unauthorized():
|
|
|
+ return abort(401, message='Unauthorized access')
|
|
|
+
|
|
|
+
|
|
|
+app = Flask(__name__)
|
|
|
+app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
|
|
|
+db = SQLAlchemy(app)
|
|
|
+api = Api(app)
|
|
|
+
|
|
|
+class Todo(db.Model):
|
|
|
+ id = db.Column(db.Integer, primary_key=True)
|
|
|
+ name = db.Column(db.String(20), unique=True, nullable=False)
|
|
|
+ detail = db.Column(db.String(200), unique=False, nullable=False)
|
|
|
+
|
|
|
+ def __repr__(self):
|
|
|
+ return '<Todo {0}: {1}'.format(self.id, self.name)
|
|
|
+
|
|
|
+ def serialize(self):
|
|
|
+ return {'id': self.id, 'name': self.name, 'detail': self.detail}
|
|
|
+
|
|
|
+TODOS = {
|
|
|
+ 'todo1': {'task': 'build an API'},
|
|
|
+ 'todo2': {'task': '?????'},
|
|
|
+ 'todo3': {'task': 'profit!'},
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+def abort_if_todo_doesnt_exist(todo_id):
|
|
|
+ task = Todo.query.filter_by(id=todo_id).first()
|
|
|
+ if task is None:
|
|
|
+ abort(404, message="Todo {} doesn't exist".format(todo_id))
|
|
|
+ return task
|
|
|
+
|
|
|
+ # if todo_id not in TODOS:
|
|
|
+ # abort(404, message="Todo {} doesn't exist".format(todo_id))
|
|
|
+
|
|
|
+parser = reqparse.RequestParser()
|
|
|
+parser.add_argument('task')
|
|
|
+
|
|
|
+
|
|
|
+# Todo
|
|
|
+# shows a single todo item and lets you delete a todo item
|
|
|
+
|
|
|
+# Yes! You can add the @auth.login_required to methods of the class. ! \o/ !
|
|
|
+
|
|
|
+class TodoPath(Resource):
|
|
|
+ def get(self, todo_id):
|
|
|
+ t = abort_if_todo_doesnt_exist(todo_id)
|
|
|
+ return { 'id': t.id, 'name': t.name, 'detail': t.detail }
|
|
|
+
|
|
|
+ def delete(self, todo_id):
|
|
|
+ abort_if_todo_doesnt_exist(todo_id)
|
|
|
+ del TODOS[todo_id]
|
|
|
+ return '', 204
|
|
|
+
|
|
|
+ # @auth.login_required
|
|
|
+ def put(self, todo_id):
|
|
|
+ args = parser.parse_args()
|
|
|
+ t = args['task']
|
|
|
+ if t is None:
|
|
|
+ abort(400, message="I need text for the task. task=...")
|
|
|
+ task = Todo(name=todo_id, detail=t)
|
|
|
+ db.session.add(task)
|
|
|
+ db.session.commit()
|
|
|
+ return task.id, 201
|
|
|
+
|
|
|
+
|
|
|
+# TodoList
|
|
|
+# shows a list of all todos, and lets you POST to add new tasks
|
|
|
+class TodoList(Resource):
|
|
|
+ def get(self):
|
|
|
+ tasks = Todo.query.all()
|
|
|
+ return [t.serialize() for t in tasks]
|
|
|
+ # return TODOS
|
|
|
+
|
|
|
+ def post(self):
|
|
|
+ args = parser.parse_args()
|
|
|
+ todo_id = int(max(TODOS.keys()).lstrip('todo')) + 1
|
|
|
+ todo_id = 'todo%i' % todo_id
|
|
|
+ TODOS[todo_id] = {'task': args['task']}
|
|
|
+ return TODOS[todo_id], 201
|
|
|
+
|
|
|
+##
|
|
|
+## Actually setup the Api resource routing here
|
|
|
+##
|
|
|
+api.add_resource(TodoList, '/todos')
|
|
|
+api.add_resource(TodoPath, '/todos/<todo_id>')
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ app.run(port=11022, debug=True)
|