1. implemented new api endpoints

master
Malar Kannan 2017-08-31 19:44:54 +05:30
parent c7dded9409
commit 6c3a6c28d1
4 changed files with 164 additions and 72 deletions

2
.gitignore vendored
View File

@ -102,3 +102,5 @@ ENV/
/site /site
# End of https://www.gitignore.io/api/python # End of https://www.gitignore.io/api/python
session.json

9
README.md Normal file
View File

@ -0,0 +1,9 @@
## Worflow
start the server by running
`$python server.py`
### Login
`$http --session=./session.json -f POST http://127.0.0.1:5000/api/login username=user@example.com password=password`
### Update Attendance
`$http --session=./session.json -f POST http://127.0.0.1:5000/api/attendance/student presence=absent identifier=2 time=now`

59
models.py Normal file
View File

@ -0,0 +1,59 @@
from flask_sqlalchemy import SQLAlchemy
from flask_security import UserMixin,RoleMixin
from enum import Enum,unique
from datetime import datetime
db = SQLAlchemy()
roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
active = db.Column(db.Boolean())
confirmed_at = db.Column(db.DateTime())
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
@unique
class Presence(Enum):
"""docstring for ResultType."""
PRESENT,ABSENT,SICK,VACATION = range(4)
class Gradeclass(db.Model):
id = db.Column(db.Integer, primary_key=True)
class_name = db.Column(db.String(255))
def __init__(self, class_name):
self.class_name = class_name
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
student_name = db.Column(db.String(255))
gradeclass_id = db.Column(db.Integer, db.ForeignKey('gradeclass.id'))
gradeclass = db.relationship('Gradeclass',backref=db.backref('gradeclass', lazy='dynamic'))
def __init__(self, student_name,gradeclass_id):
self.student_name = student_name
self.gradeclass_id = gradeclass_id
class AttendanceUpdate(db.Model):
id = db.Column(db.Integer, primary_key=True)
time = db.Column(db.DateTime())
presence = db.Column(db.Enum(Presence))
update_type = db.Column(db.String(10))
value_identifier = db.Column(db.Integer)
def __init__(self, update_type, value_identifier,time,presence):
self.update_type = update_type
self.value_identifier = value_identifier
self.presence = presence
self.time = time

166
server.py
View File

@ -1,114 +1,136 @@
from flask import Flask,Blueprint,request,Response from flask import Flask, Blueprint, request, Response
from flask_sqlalchemy import SQLAlchemy from flask_security import SQLAlchemyUserDatastore, login_required, current_user, Security
from flask_security import SQLAlchemyUserDatastore,UserMixin,RoleMixin,login_required,current_user,Security from flask_security.utils import verify_and_update_password,login_user
from flask_restless import APIManager,ProcessingException from flask_restless import APIManager, ProcessingException
from enum import Enum,unique from models import db, User, Role, Gradeclass, Student, AttendanceUpdate, Presence
from sqlalchemy import func
import json import json
from datetime import datetime, date
from dateutil import parser
app = Flask(__name__) app = Flask(__name__)
app.config['DEBUG'] = True app.config['DEBUG'] = True
app.config['PORT'] = 5001
app.config['SECRET_KEY'] = 'super-secret' app.config['SECRET_KEY'] = 'super-secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/db.sqlite' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/db.sqlite'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['DEFAULT_MAIL_SENDER'] = 'info@example.com' app.config['DEFAULT_MAIL_SENDER'] = 'info@example.com'
app.config['SECURITY_PASSWORD_SALT'] = 'uaisfyasiduyaisiuf' app.config['SECURITY_PASSWORD_SALT'] = 'uaisfyasiduyaisiuf'
db.init_app(app)
db = SQLAlchemy(app)
roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
active = db.Column(db.Boolean())
confirmed_at = db.Column(db.DateTime())
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
# class ClassSession(db.Model):
# id = db.Column(db.Integer, primary_key=True)
# name = db.Column(db.String(255), unique=True)
# confirmed_at = db.Column(db.DateTime())
@unique
class Presence(Enum):
"""docstring for ResultType."""
PRESENT,ABSENT,SICK,VACATION = range(4)
class Gradeclass(db.Model):
id = db.Column(db.Integer, primary_key=True)
class_name = db.Column(db.String(255))
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
student_name = db.Column(db.String(255))
gradeclass_id = db.Column(db.Integer, db.ForeignKey('gradeclass.id'))
gradeclass = db.relationship('Gradeclass',backref=db.backref('gradeclass', lazy='dynamic'))
class StudentAttendance(db.Model):
id = db.Column(db.BigInteger, primary_key=True)
student_id = db.Column(db.Integer, db.ForeignKey('student.id'))
gradeclass_id = db.Column(db.Integer, db.ForeignKey('gradeclass.id'))
time = db.Column(db.DateTime())
presence = db.Column(db.Enum(Presence))
student = db.relationship('Student',backref=db.backref('student', lazy='dynamic'))
gradeclass = db.relationship('Gradeclass',backref=db.backref('gradeclass', lazy='dynamic'))
user_datastore = SQLAlchemyUserDatastore(db, User, Role) user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore) security = Security(app, user_datastore)
def auth_func(*args, **kwargs): def auth_func(*args, **kwargs):
# if not current_user.is_authenticated: # if not current_user.is_authenticated:
# raise ProcessingException(description='Not authenticated', code=401) # raise ProcessingException(description='Not authenticated', code=401)
return True return True
verify_logged_id = dict(GET_SINGLE=[auth_func],GET_MANY=[auth_func])
verify_logged_id = dict(GET_SINGLE=[auth_func], GET_MANY=[auth_func])
manager = APIManager(app, flask_sqlalchemy_db=db) manager = APIManager(app, flask_sqlalchemy_db=db)
manager.create_api(Student, methods=['GET','PUT'],results_per_page=5,preprocessors=verify_logged_id) manager.create_api(Student, methods=[
manager.create_api(Gradeclass, methods=['GET','PUT'],results_per_page=5,preprocessors=verify_logged_id) 'GET', 'PUT'], results_per_page=5, preprocessors=verify_logged_id)
manager.create_api(Gradeclass, methods=[
'GET', 'PUT'], results_per_page=5, preprocessors=verify_logged_id)
@app.before_first_request @app.before_first_request
def create_user(): def create_test_data():
try: try:
db.drop_all() db.drop_all()
db.create_all() db.create_all()
user_datastore.create_user(email='user@example.com', password='password') for i in range(12):
g_cls = Gradeclass("Class {}".format(i))
db.session.add(g_cls)
for s in range(10):
stu = Student("TestStudent#{}-Class{}".format(s,i), g_cls.id)
db.session.add(stu)
user_datastore.create_user(
email='user@example.com', password='password')
db.session.commit() db.session.commit()
except: except:
pass pass
def api_resp(data,code=200): def api_resp(data, code=200):
return Response(response=data, return Response(response=data,
status=code, status=code,
mimetype="application/json") mimetype="application/json")
@app.route('/api/attendance/<update_type>',methods=['GET']) def parse_time(time_str):
utc_now = (time_str and time_str == 'now') or not time_str
time = datetime.utcnow() if utc_now else None
try:
time = parser.parse(attend_date)
except:
pass
return time
def upsert_attendance(update_type, object_id, attend_time, pres_enum):
existing = AttendanceUpdate.query.filter(
AttendanceUpdate.update_type == update_type
).filter(
AttendanceUpdate.value_identifier == object_id
).filter(
func.date(AttendanceUpdate.time) == attend_time.date()
).first()
if existing:
existing.presence = pres_enum
else:
new_entry = AttendanceUpdate(
update_type, object_id, attend_time, pres_enum)
db.session.add(new_entry)
db.session.commit()
def validate_attend(update_type, object_id):
return True
if update_type in ['class', 'student'] and object_id:
g_cls_found = update_type == 'class' and Gradeclass.query.get(object_id)
stud_found = update_type == 'student' and Student.query.get(object_id)
return g_cls_found or stud_found
else:
return False
presense_keys = [str(i).replace('Presence.', '').upper() for i in Presence]
@app.route('/api/attendance/<update_type>', methods=['POST'])
# @login_required # @login_required
def update_attendance(update_type): def update_attendance(update_type):
value = request.args.get('presence',None) object_id = request.form.get('identifier', None)
object_id = request.args.get('identifier',None) presence = request.form.get('presence', None)
if update_type == 'class': attend_str = request.form.get('time', None)
attend_time = parse_time(attend_str)
ret_data = (json.dumps({'status': 'invalid'}),400)
if validate_attend(update_type, object_id) and presence and attend_time and presence.upper() in presense_keys:
pres_enum = Presence[presence.upper()]
upsert_attendance(update_type, object_id, attend_time, pres_enum)
ret_data = (json.dumps({'status': 'updated'}),200)
return api_resp(*ret_data)
elif update_type == 'student': @app.route('/api/login',methods=['POST'])
data= json.dumps({'status':'updated'}) def login():
return api_resp(data) username = request.form.get('username', None)
password = request.form.get('password', None)
print(username,password)
ret_data = (json.dumps({'status': 'failed'}),401)
if username and password:
user = User.query.filter(User.email == username).first()
if not user:
ret_data = (json.dumps({'status': 'notfound'}),401)
elif verify_and_update_password(password,user):
login_user(user)
ret_data = (json.dumps({'status': 'success'}),200)
return ret_data
@app.route('/') @app.route('/')
def home(): def home():
return 'hello' return 'hello'
if __name__ == '__main__': if __name__ == '__main__':
app.run() app.run()