__author__ = 'Aran' from flask import Blueprint import json from GithubAPI.GithubAPI import GitHubAPI_Keys from google.appengine.ext import db import requests import datetime from operator import itemgetter from flask import Flask, request, render_template, redirect, abort, Response from flask.ext.github import GitHub from flask.ext.cors import CORS, cross_origin from flask.ext.autodoc import Autodoc # DB Models from models.Task import Task from models.Course import Course from models.TaskComponent import TaskComponent from models.TaskGrade import TaskGrade from models.Project import Project #Validation Utils Libs from SE_API.Validation_Utils import * from SE_API.Respones_Utils import * from Email_Utils import * task_routes = Blueprint("task_routes", __name__) auto = Autodoc() #---------------------------------------------------------- # POST #---------------------------------------------------------- @task_routes.route('/api/tasks/create/', methods=['POST']) @auto.doc() def create_task(token): """ This call will create a new Task in the DB
Route Parameters
- seToken: 'seToken'

Payload
- JSON Object, Example:
{
"title":"task1",
"courseId":1234567890,
"description":"pls fddfsdfdsk",
"dueDate":{"year":2010,
"month":2,
"day":4
}, "isPersonal":true,
"components":[
{
"type" : "should be type1",
"label" : "should be label1",
"isMandatory" : true,
"order" : 1
},
{
"type" : "should be type2",
"label" : "should be label2",
"isMandatory" : true,
"order" : 2
},
{
"type" : "should be type3",
"label" : "should be label3",
"isMandatory" : false,
"order" : 3
}
]
}

Response
201 - Created
400 - Bad Request
403 - Invalid token or not a lecturer """ if not request.data: return bad_request("no payload") payload = json.loads(request.data) if not is_lecturer(token): #todo: change to lecturer id return forbidden("Invalid token or not a lecturer!") user = get_user_by_token(token) #check lecturer is owner of course try: courseId = payload['courseId'] except Exception as e: print e return bad_request("invalid courseId format") course = Course.get_by_id(int(courseId)) if course is None: return bad_request("No such Course") if course.master_id != user.key().id(): return forbidden("Lecturer is not owner of Course") #parse dueDate try: date = datetime.date(payload['dueDate']['year'],payload['dueDate']['month'],payload['dueDate']['day']) except Exception: return bad_request("invalid dueDate format") #create Task object try: task = Task(title=payload['title'], courseId=payload['courseId'], description=payload['description'], dueDate=date) except Exception as e: print e return bad_request("bad") try: task.isPersonal = payload['isPersonal'] except Exception: pass db.put(task) db.save #create components for c in payload['components']: try: component = TaskComponent(taskId=task.key().id(), userId=-1, type=c['type'], label=c['label'], isMandatory=c['isMandatory'], order=c['order']) except Exception as e: print e return bad_request("Bad component") db.put(component) db.save return Response(response=task.to_JSON(), status=200, mimetype="application/json") @task_routes.route('/api/tasks/submitTask///', methods=['POST']) @auto.doc() def submitTask(token, taskId, ownerId): """ This call will create a new Task in the DB
Route Parameters
- seToken: 'seToken'

Payload
- JSON Object, Example:
{
"title":"task1",
"courseId":1234567890,
"description":"pls fddfsdfdsk",
"dueDate":{"year":2010,
"month":2,
"day":4
}, "isPersonal":true,
"components":[
{
"type" : "should be type1",
"label" : "should be label1",
"isMandatory" : true,
"order" : 1
},
{
"type" : "should be type2",
"label" : "should be label2",
"isMandatory" : true,
"order" : 2
},
{
"type" : "should be type3",
"label" : "should be label3",
"isMandatory" : false,
"order" : 3
}
]
}

Response
201 - Created
400 - Bad Request
403 - Invalid token or not a lecturer """ if not request.data: return bad_request("no payload") payload = json.loads(request.data) user = get_user_by_token(token) if user is None: bad_request("bad user Token") task = Task.get_by_id(int(taskId)) if task is None: bad_request("bad Task id") if task.isPersonal: if User.get_by_id(int(ownerId)) is None: return bad_request("no such user") else: if Project.get_by_id(int(ownerId)) is None: return bad_request("no such project") #create components for c in payload: try: component = TaskComponent(taskId=task.key().id(), userId=(int(ownerId)), type=c['type'], label=c['label'], value=c['value'], isMandatory=c['isMandatory'], order=c['order']) except Exception as e: print e return bad_request("Bad component") db.put(component) db.save return Response(response=task.to_JSON(), status=200, mimetype="application/json") #---------------------------------------------------------- # PUT #---------------------------------------------------------- #---------------------------------------------------------- # GET #---------------------------------------------------------- @task_routes.route('/api/tasks/getAllTasksByCourse//', methods=["GET"]) @auto.doc() def getAllTasksByCourse(token, courseId): """ >This Call will return an array of all Tasks in a course ordered by date
Route Parameters
- SeToken: token
- courseId: 1234567890

Payload
- NONE

Response
200 - JSON Example:
{
'title' : 'Task1',
'courseId' : 12345678,
'description' : 'prepare by sunday',
'dueDate' : { 'year' : 2015, 'month' : 12, 'day' : 23 }
'isPersonal' : true,
'task_id' : 589689456894
}

""" if get_user_by_token(token) is None: return bad_request("Bad User Token") arr = [] query = Task.all() try: query.filter("courseId = ", int(courseId)) except Exception as e: return bad_request("Bad id format") for t in query.run(): taskDic =dict(json.loads(t.to_JSON())) #add a key 'forSortDate' for sorting dates taskTime = datetime.datetime(taskDic['dueDate']['year'], taskDic['dueDate']['month'], taskDic['dueDate']['day']) taskDic['forSortDate'] = taskTime arr.append(taskDic) #sort array by date, and remove added key arr = sorted(arr, key=itemgetter('forSortDate'), reverse=False) for i in arr: del i['forSortDate'] if len(arr) != 0: return Response(response=json.dumps(arr), status=200, mimetype="application/json") else: return no_content() @task_routes.route('/api/tasks/getAllFutureCampusTasks//', methods=["GET"]) @auto.doc() def getAllFutureCampusTasks(token, courseId): """ >This Call will return an array of all Future Tasks in a course, ordered by date
Route Parameters
- SeToken: token
- courseId: 1234567890

Payload
- NONE

Response
200 - JSON Example:
{
'title' : 'Task1',
'courseName' : 'advance Math',
'description' : 'prepare by sunday',
'dueDate' : { 'year' : 2015, 'month' : 12, 'day' : 23 }
'isPersonal' : true,
'task_id' : 589689456894
}

""" if get_user_by_token(token) is None: return bad_request("Bad User Token") arr = [] query = Task.all() try: query.filter("courseId = ", int(courseId)) except Exception as e: return bad_request("Bad id format") for t in query.run(): taskDic =dict(json.loads(t.to_JSON())) #add a key 'forSortDate' for sorting dates taskTime = datetime.date(taskDic['dueDate']['year'], taskDic['dueDate']['month'], taskDic['dueDate']['day']) if taskTime >= datetime.date.today(): taskDic['forSortDate'] = taskTime arr.append(taskDic) #sort array by date, and remove added key arr = sorted(arr, key=itemgetter('forSortDate'), reverse=False) for i in arr: del i['forSortDate'] if len(arr) != 0: return Response(response=json.dumps(arr), status=200, mimetype="application/json") else: return no_content() @task_routes.route('/api/tasks/getAllFutureTasks/', methods=["GET"]) @auto.doc() def getAllFutureTasks(token): """ >This Call will return an array of all Future Tasks ordered by date
Route Parameters
- SeToken: token


Payload
- NONE

Response
200 - JSON Example:
{
'title' : 'Task1',
'courseName' : 'advance Math',
'description' : 'prepare by sunday',
'dueDate' : { 'year' : 2015, 'month' : 12, 'day' : 23 }
'isPersonal' : true,
'task_id' : 589689456894
}

""" user = get_user_by_token(token) if user is None: return bad_request("Bad User Token") arr = [] for courseId in user.courses_id_list: query = Task.all() try: query.filter("courseId = ", int(courseId)) except Exception as e: return bad_request("Bad id format") for t in query.run(): taskDic =dict(json.loads(t.to_JSON())) #add a key 'forSortDate' for sorting dates taskTime = datetime.date(taskDic['dueDate']['year'], taskDic['dueDate']['month'], taskDic['dueDate']['day']) if taskTime >= datetime.date.today(): taskDic['forSortDate'] = taskTime arr.append(taskDic) #sort array by date, and remove added key arr = sorted(arr, key=itemgetter('forSortDate'), reverse=False) for i in arr: del i['forSortDate'] if len(arr) != 0: return Response(response=json.dumps(arr), status=200, mimetype="application/json") else: return no_content() @task_routes.route('/api/tasks/getTaskComponents//', methods=["GET"]) @auto.doc() def getTaskComponents(token, taskId): """ >This Call will return an array of all components for a given task
Route Parameters
- SeToken: token
- taskId: 1234567890

Payload
- NONE

Response
200 - JSON Example:
[ {
'taskId' : 7589454894, 'userId' : -1, 'type' : 'kindOfType', 'label' : 'kindOfLabel', 'isMandatory' : true, 'order' : 2 }
{
'taskId' : 7589454894, 'userId' : yossi, 'type' : 'otherKindOfType', 'label' : 'otherKindOfLabel', 'isMandatory' : false, 'order' : 4 }
]

""" if get_user_by_token(token) is None: return bad_request("Bad User Token") arr = [] query = TaskComponent.all() try: query.filter("taskId = ", int(taskId)) except Exception as e: return bad_request("Bad id format") for tc in query.run(): arr.append(dict(json.loads(tc.to_JSON()))) #sort array by order, and remove added key arr = sorted(arr, key=itemgetter('order'), reverse=False) if len(arr) != 0: return Response(response=json.dumps(arr), status=200, mimetype="application/json") else: return no_content() @task_routes.route('/api/tasks/getAllUserTasks/', methods=["GET"]) @auto.doc() def getAllUserTasks(token): """ >This Call will return an array of all of the User's Tasks
Route Parameters
- SeToken: token


Payload
- NONE

Response
200 - JSON Example:
[
{
"courseName": "Advance Math",
"courseId": 4762397176758272,
"PersonalTasks": [
{
"grade": 12,
"isPersonal": true,
"dueDate": {
"year": 2010,
"day": 4,
"month": 2
},
"courseId": 4762397176758272,
"title": "task1",
"description": "pls fddfsdfdsk",
"id": 5888297083600896
}
],
"projectTasks": []
},
{
"courseName": "Bad Math",
"courseId": 5659598665023488,
"PersonalTasks": [
{
"grade": 12,
"isPersonal": true,
"dueDate": {
"year": 2010,
"day": 4,
"month": 2
},
"courseId": 5659598665023488,
"title": "new task1",
"description": "pls fddfsdfdsk",
"id": 5096648711602176
},
{
"grade": 12,
"isPersonal": true,
"dueDate": {
"year": 2010,
"day": 4,
"month": 2
},
"courseId": 5659598665023488,
"title": "new task4",
"description": "pls fddfsdfdsk",
"id": 5167017455779840
}
],
"projectTasks": [
{
"grade": 12,
"isPersonal": false,
"dueDate": {
"year": 2010,
"day": 4,
"month": 2
},
"courseId": 5659598665023488,
"title": "new task3",
"description": "pls fddfsdfdsk",
"id": 5237386199957504
}
]
}
]

""" user = get_user_by_token(token) if user is None: return bad_request("Bad User Token") arr = [] for c in user.courses_id_list: dic = {} course = Course.get_by_id(int(c)) dic['courseName'] = course.courseName dic['courseId'] = course.key().id() courseTasks = Task.all().filter("courseId = ", course.key().id()) taskArr = [] for t in courseTasks.run(): taskDic =dict(json.loads(t.to_JSON())) #add a key 'forSortDate' for sorting dates taskTime = datetime.datetime(taskDic['dueDate']['year'], taskDic['dueDate']['month'], taskDic['dueDate']['day']) taskDic['forSortDate'] = taskTime grade = TaskGrade.all().filter("taskId = ", t.key().id()).filter("userId = ", user.key().id()) for g in grade.run(): taskDic['grade'] = g.grade if grade.count() == 0: taskDic['grade'] = 0 taskArr.append(taskDic) taskArr = sorted(taskArr, key=itemgetter('forSortDate'), reverse=False) for i in taskArr: del i['forSortDate'] userTaskArr = [] projectTaskArr = [] for t in taskArr: if t['isPersonal']: userTaskArr.append(t) else: projectTaskArr.append(t) dic['PersonalTasks'] = userTaskArr dic['projectTasks'] = projectTaskArr arr.append(dic) #sort array by date, and remove added key return Response(response=json.dumps(arr), status=200, mimetype="application/json") @task_routes.route('/api/tasks/getTaskById///', methods=["GET"]) @auto.doc() def getTaskById(token, taskId, ownerId): """ >This Call will return an array of all components for a given task
Route Parameters
- SeToken: token
- taskId: 1234567890 - ownerId: 123456789

Payload
- NONE

Response
200 - JSON Example:
[ {
'taskId' : 7589454894, 'userId' : -1, 'type' : 'kindOfType', 'label' : 'kindOfLabel', 'isMandatory' : true, 'order' : 2 }
{
'taskId' : 7589454894, 'userId' : yossi, 'type' : 'otherKindOfType', 'label' : 'otherKindOfLabel', 'isMandatory' : false, 'order' : 4 }
]

""" user = get_user_by_token(token) if user is None: return bad_request("Bad User Token") task = Task.get_by_id(int(taskId)) if task is None: return bad_request("Bad Task id") if task.isPersonal: if User.get_by_id(int(ownerId)) is None: return bad_request("no such user") else: if Project.get_by_id(int(ownerId)) is None: return bad_request("no such project") task = json.loads(task.to_JSON()) task['components'] = [] task['grade'] = {} taskCompQuery = TaskComponent.all() taskCompQuery.filter("taskId = ", taskId) taskCompQuery.filter("userId = ", ownerId) # if task.isPersonal: # taskCompQuery.filter("userId = ", user.key().id()) # else: # taskCompQuery.filter("userId = ", user.key().id())#TODO: fix to project #check if never created a personalized task and if so, create it if taskCompQuery.count() == 0: print "here" taskCompQuery = TaskComponent.all().filter("taskId =", int(taskId)).filter("userId =", -1) print "query count is: ", taskCompQuery.count() for tc in taskCompQuery.run(): task['components'].append(dict(json.loads(tc.to_JSON()))) # for tc in taskCompQuery.run(): # tcNew = TaskComponent(taskId=tc.taskId, userId=user.key().id(), type=tc.type, label=tc.label, isMandatory=tc.isMandatory, order=tc.order) # db.put(tcNew) # grade = TaskGrade(grade=0, taskId=task.key().id(), userId=user.key().id()) # db.put(grade) grade = TaskGrade.all().filter("taskId = ", taskId).filter("userId = ", ownerId) gradeFound = False for g in grade.run(): task['grade'] = g gradeFound = True if not gradeFound: task['grade'] = {'taskId': taskId, 'userId': ownerId, 'grade': None} return Response(response=json.dumps(task), status=200, mimetype="application/json") #---------------------------------------------------------- # DELETE #---------------------------------------------------------- @task_routes.route('/api/tasks/deleteTask//', methods=['DELETE']) @auto.doc() def deleteTask(token, taskId): """ This Call will delete a specific Task
Route Parameters
- seToken: 'seToken' - taskId: 'taskid'

Payload
- NONE


Response
202 - Deleted Course
....
{
...
}req
]
400 - no such Course
403 - Invalid token or not a lecturer or lecturer is not owner of Course!
""" if not is_lecturer(token): return forbidden("Invalid token or not a lecturer!") #todo: check if lecturer is owner of course #return forbidden("lecturer is not owner of course") user = get_user_by_token(token) try: c = Task.get_by_id(int(taskId)) except Exception as e: return bad_request("Bad id format") if c is None: return bad_request("no such Task") db.delete(c) db.save return accepted("Task deleted") @task_routes.route('/api/tasks/deleteTaskComponents//', methods=['DELETE']) @auto.doc() def deleteTaskComponents(token,taskId): """ This Call will delete a specific Task's components
Route Parameters
- seToken: 'seToken' - taskId: 'taskid'

Payload
- NONE


Response
202 - Deleted Course
....
{
...
}req
]
400 - no such Task
403 - Invalid token or not a lecturer or lecturer is not owner of Task!
""" if not is_lecturer(token): return forbidden("Invalid token or not a lecturer!") #todo: check if lecturer is owner of course #return forbidden("lecturer is not owner of course") user = get_user_by_token(token) try: t = Task.get_by_id(int(taskId)) except Exception as e: return bad_request("Bad id format") if t is None: return bad_request("no such Task") query = TaskComponent.all() query.filter('taskId = ', t.key().id()) for tc in query.run(): db.delete(tc) db.save return accepted("Task deleted") #---------------------------------------------------------- # DOCUMENTATION #---------------------------------------------------------- @task_routes.route('/api/tasks/help') def documentation(): return auto.html() @task_routes.route('/api/tasks/sendTaskReminder', methods=['GET']) def sendTaskReminder(): tasks = Task.all() try: for t in tasks.run(): if t.dueDate == datetime.date.today() + datetime.timedelta(days=1): course = Course.get_by_id(int(t.courseId)) if t.isPersonal: for uId in course.membersId: tc = TaskComponent.all().filter("taskId = ", t.key().id()).filter("userId = ", int(uId)) if tc.count() == 0: user = User.get_by_id(int(uId)) send_task_reminder(user.email, user.name, t.title, course.courseName) print "" else: projects = Project.all().filter("courseId = ", course.key().id()) for p in projects.run(): tc = TaskComponent.all().filter("taskId = ", t.key().id()).filter("userId = ", p.key().id()) if tc.count() == 0: for uId in p.membersId: user = User.get_by_id(int(uId)) send_task_reminder(user.email, user.name, t.title, course.courseName) return accepted() except: return bad_request() # @task_routes.route('/api/tasks/getClosestTask/', methods=["GET"]) # @auto.doc() # def getClosestTask(courseName): # """ # >This Call will return an array of all projects in a given course #
# Route Parameters
# - name: 'course name' #
#
# Payload
# - NONE #
#
# Response #
# 200 - JSON Example:
# # {
# 'projectName': 'Advance Math',
# 'courseName': 'JCE',
# 'grade': 98,
# 'logo_url': 'http://location.domain.com/image.jpg',
# 'gitRepository': 'http://location.git.com/somthing',
# 'membersId': ['bob', 'dylan', 'quentin', 'terentino']
# } #
#
# """ # #get all tasks for a specific course # arr = [] # query = Task.all() # query.filter("courseName =", courseName) # for t in query.run(): # count+=1 # if t.dueDate < closestDate: # closestDate = t.dueDate # index = count # arr.append(dict(json.loads(t.to_JSON()))) # # print arr # if len(arr) != 0: # return Response(response=json.dumps(arr[index]), # status=200, # mimetype="application/json") # else: # return no_content("no Tasks") #