Compare commits

...

2 Commits

Author SHA1 Message Date
Malar Kannan 0f8c70a38e completed attendance get/update 2017-09-01 00:37:59 +05:30
Malar Kannan fe97494629 1. code clean up
2. get_attendance wip
2017-08-31 22:07:58 +05:30
3 changed files with 122 additions and 51 deletions

View File

@ -6,4 +6,15 @@ start the server by running
`$http --session=./session.json -f POST http://127.0.0.1:5000/api/login username=user@example.com password=password` `$http --session=./session.json -f POST http://127.0.0.1:5000/api/login username=user@example.com password=password`
### Update Attendance ### Update Attendance
Student :
`$http --session=./session.json -f POST http://127.0.0.1:5000/api/attendance/student presence=absent identifier=2 time=now` `$http --session=./session.json -f POST http://127.0.0.1:5000/api/attendance/student presence=absent identifier=2 time=now`
Class :
`http --session=./session.json -f POST http://127.0.0.1:5000/api/attendance/class presence=present identifier=1 time=now`
### Get Attendance
Student:
`http --session=./session.json GET "http://127.0.0.1:5000/api/attendance/student?identifier=2&start_time=now&end_time=now"`
`http --session=./session.json GET "http://127.0.0.1:5000/api/attendance/student?identifier=3&start_time=now&end_time=now"`
Class:
`http --session=./session.json GET "http://127.0.0.1:5000/api/attendance/class?identifier=1&start_time=now&end_time=now"`

View File

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

129
server.py
View File

@ -1,8 +1,10 @@
from flask import Flask, Blueprint, request, Response from flask import Flask, Blueprint, request
from flask_security import SQLAlchemyUserDatastore, login_required, current_user, Security from flask_security import (SQLAlchemyUserDatastore, login_required,
from flask_security.utils import verify_and_update_password,login_user 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 models import db, User, Role, Gradeclass, Student, AttendanceUpdate, Presence from models import (db, User, Role, Gradeclass, Student, AttendanceUpdate,
Presence)
from sqlalchemy import func from sqlalchemy import func
import json import json
from datetime import datetime, date from datetime import datetime, date
@ -31,22 +33,33 @@ def auth_func(*args, **kwargs):
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=[ manager.create_api(
'GET', 'PUT'], results_per_page=5, preprocessors=verify_logged_id) Student,
manager.create_api(Gradeclass, methods=[ methods=['GET', 'PUT'],
'GET', 'PUT'], results_per_page=5, preprocessors=verify_logged_id) results_per_page=5,
preprocessors=verify_logged_id)
manager.create_api(
Gradeclass,
methods=['GET', 'PUT'],
results_per_page=5,
preprocessors=verify_logged_id)
json_cont = {'Content-Type': 'application/json'}
resp = lambda val,code: (json.dumps({'status': val}), code, json_cont)
presense_map = {i:str(i).replace('Presence.', '').upper() for i in Presence}
@app.before_first_request @app.before_first_request
def create_test_data(): def create_test_data():
try: try:
db.drop_all() db.drop_all()
db.create_all() db.create_all()
for i in range(12): for i in range(3):
g_cls = Gradeclass("Class {}".format(i)) g_cls = Gradeclass("Class {}".format(i))
db.session.add(g_cls) db.session.add(g_cls)
for s in range(10): db.session.commit()
stu = Student("TestStudent#{}-Class{}".format(s,i), g_cls.id) for s in range(5):
stu = Student("TestStudent#{}-Class{}".format(s,g_cls.id), g_cls.id)
db.session.add(stu) db.session.add(stu)
user_datastore.create_user( user_datastore.create_user(
email='user@example.com', password='password') email='user@example.com', password='password')
@ -55,11 +68,6 @@ def create_test_data():
pass pass
def api_resp(data, code=200):
return Response(response=data,
status=code,
mimetype="application/json")
def parse_time(time_str): def parse_time(time_str):
utc_now = (time_str and time_str == 'now') or not time_str utc_now = (time_str and time_str == 'now') or not time_str
time = datetime.utcnow() if utc_now else None time = datetime.utcnow() if utc_now else None
@ -69,64 +77,105 @@ def parse_time(time_str):
pass pass
return time return time
def compute_attendance(request_type,object_id, start_time, end_time):
def get_record(req_type,obj_id):
attend = AttendanceUpdate.query.filter(
AttendanceUpdate.update_type == req_type
).filter(
AttendanceUpdate.value_identifier == obj_id
).filter(
func.date(AttendanceUpdate.time) >= start_time.date()
).filter(
func.date(AttendanceUpdate.time) >= end_time.date()
).first()
return attend
pres_rec = None
if request_type == 'student':
stud_rec = get_record('student',object_id)
stud = Student.query.get(object_id)
pres_rec = stud_rec if stud_rec else get_record('class',stud.gradeclass_id)
if request_type == 'class':
pres_rec = get_record(request_type,object_id)
return presense_map[pres_rec.presence].lower() if pres_rec else 'no_records'
def upsert_attendance(update_type, object_id, attend_time, pres_enum): def upsert_attendance(update_type, object_id, attend_time, pres_enum):
existing = AttendanceUpdate.query.filter( existing = AttendanceUpdate.query.filter(
AttendanceUpdate.update_type == update_type AttendanceUpdate.update_type == update_type).filter(
).filter( AttendanceUpdate.value_identifier == object_id).filter(
AttendanceUpdate.value_identifier == object_id func.date(
).filter( AttendanceUpdate.time) == attend_time.date()).first()
func.date(AttendanceUpdate.time) == attend_time.date()
).first()
if existing: if existing:
existing.presence = pres_enum existing.presence = pres_enum
else: else:
new_entry = AttendanceUpdate( new_entry = AttendanceUpdate(update_type, object_id, attend_time,
update_type, object_id, attend_time, pres_enum) pres_enum)
db.session.add(new_entry) db.session.add(new_entry)
db.session.commit() db.session.commit()
def validate_attend(update_type, object_id): def validate_attend(update_type, object_id):
return True # return True
if update_type in ['class', 'student'] and object_id: if update_type in ['class', 'student'] and object_id:
g_cls_found = update_type == 'class' and Gradeclass.query.get(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) stud_found = update_type == 'student' and Student.query.get(object_id)
return g_cls_found or stud_found return g_cls_found or stud_found
else: else:
return False return False
presense_keys = [str(i).replace('Presence.', '').upper() for i in Presence] def get_attendance(update_type, request):
object_id = request.args.get('identifier', None)
start_timestr = request.args.get('start_time', None)
end_timestr = request.args.get('end_time', None)
start_time, end_time = parse_time(start_timestr), parse_time(end_timestr)
ret_data = resp('invalid',400)
if validate_attend(update_type, object_id) and start_time and end_time:
pres = compute_attendance(update_type,object_id,start_time,end_time)
ret_data = resp(pres,200)
return ret_data
@app.route('/api/attendance/<update_type>', methods=['POST']) def update_attendance(update_type, request):
# @login_required
def update_attendance(update_type):
object_id = request.form.get('identifier', None) object_id = request.form.get('identifier', None)
presence = request.form.get('presence', None) presence = request.form.get('presence', None)
attend_str = request.form.get('time', None) attend_str = request.form.get('time', None)
attend_time = parse_time(attend_str) attend_time = parse_time(attend_str)
ret_data = (json.dumps({'status': 'invalid'}),400) ret_data = resp('invalid',400)
if validate_attend(update_type, object_id) and presence and attend_time and presence.upper() in presense_keys: if validate_attend(
update_type, object_id
) and presence and attend_time and presence.upper() in presense_map.values():
pres_enum = Presence[presence.upper()] pres_enum = Presence[presence.upper()]
upsert_attendance(update_type, object_id, attend_time, pres_enum) upsert_attendance(update_type, object_id, attend_time, pres_enum)
ret_data = (json.dumps({'status': 'updated'}),200) ret_data = resp('updated',200)
return api_resp(*ret_data) return ret_data
@app.route('/api/login',methods=['POST'])
@app.route('/api/attendance/<update_type>', methods=['GET', 'POST'])
@login_required
def attendance(update_type):
if request.method == 'GET':
return get_attendance(update_type, request)
elif request.method == 'POST':
return update_attendance(update_type, request)
@app.route('/api/login', methods=['POST'])
def login(): def login():
username = request.form.get('username', None) username = request.form.get('username', None)
password = request.form.get('password', None) password = request.form.get('password', None)
print(username,password) ret_data = (json.dumps({'status': 'failed'}), 401, json_cont)
ret_data = (json.dumps({'status': 'failed'}),401)
if username and password: if username and password:
user = User.query.filter(User.email == username).first() user = User.query.filter(User.email == username).first()
if not user: if not user:
ret_data = (json.dumps({'status': 'notfound'}),401) ret_data = resp('notfound',401)
elif verify_and_update_password(password,user): elif verify_and_update_password(password, user):
login_user(user) login_user(user)
ret_data = (json.dumps({'status': 'success'}),200) ret_data = resp('success',200)
return ret_data return ret_data
@app.route('/') @app.route('/')
def home(): def home():
return 'hello' return 'hello'