diff --git a/SE_API/Email_Utils.py b/SE_API/Email_Utils.py index 2939cc7..90f2ec4 100644 --- a/SE_API/Email_Utils.py +++ b/SE_API/Email_Utils.py @@ -125,3 +125,61 @@ def notify_se_hub_campus_request(campus, campus_name): """ message.send() + + +def send_task_reminder( email, name, task_name, course_name): + message = mail.EmailMessage(sender="SE-Hub Support ", + subject="Hey! Due Date for task " + task_name + " is TOMORROW!") + + message.to = email + + message.body = """ + Dear """+name+""": + + You Have A Task that Due tomorrow! don't forget to submit the task. + + Task name: """ + task_name + """ \n + In Course: """ + course_name + """ \n\n + + + http://se-hub.appspot.com + + + Please let us know if you have any questions. + + SE-Hub (c) 2015 niptop Team. + """ + + message.html = """ + +
+
+ + +
+
+
+

Dear """+name+""":

+ +
+ +
+
+ + You Have A Task that Due tomorrow! don't forget to submit the task.
+ + Task name: """ + task_name + """
+ In Course: """ + course_name + """
+
+ SE - Hub + +
+

+ Please let us know if you have any questions. +
+ SE-Hub (c) 2015 niptop Team. + + + """ + + message.send() diff --git a/SE_API/ProjectRoutes.py b/SE_API/ProjectRoutes.py index a2d1383..998039d 100644 --- a/SE_API/ProjectRoutes.py +++ b/SE_API/ProjectRoutes.py @@ -377,10 +377,10 @@ def deleteProject(token,projectId): #remove all users related to project for uId in p.membersId: - user = User.get_by_id(uId) + user = User.get_by_id(int(uId)) if user is None: return bad_request("trying to remove a user from project failed") - user.projects_id_list.remove(p.key().id()) + user.projects_id_list.remove(str(p.key().id())) db.put(user) diff --git a/SE_API/TaskRoutes.py b/SE_API/TaskRoutes.py index 38f10bd..e7c6c54 100644 --- a/SE_API/TaskRoutes.py +++ b/SE_API/TaskRoutes.py @@ -20,10 +20,12 @@ 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__) @@ -200,13 +202,25 @@ def submitTask(token, taskId, ownerId): 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['components']: + for c in payload: try: - component = TaskComponent(taskId=task.key().id(), userId=(int(ownerId)), type=c['type'], label=c['label'], isMandatory=c['isMandatory'], order=c['order']) + 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") @@ -678,6 +692,12 @@ def getTaskById(token, taskId, ownerId): 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'] = [] @@ -847,6 +867,38 @@ 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() + + + diff --git a/cron.yaml b/cron.yaml index 67b8d7e..d1ffbd4 100644 --- a/cron.yaml +++ b/cron.yaml @@ -1,4 +1,7 @@ cron: - description: update project data url: /api/projects/updateProjectsInfo - schedule: every 1 hours \ No newline at end of file + schedule: every 1 hours + - description: send task notification mail + url: /api/tasks/sendTaskReminder + schedule: every day 03:00 \ No newline at end of file diff --git a/models/TaskComponent.py b/models/TaskComponent.py index 161cfcc..f220b97 100644 --- a/models/TaskComponent.py +++ b/models/TaskComponent.py @@ -10,6 +10,7 @@ class TaskComponent(db.Model): userId = db.IntegerProperty(required=True, default = -1) type = db.StringProperty(required=True,default=" ") label = db.StringProperty(required=True,default=" ") + value = db.StringProperty(required=True, default=" ") isMandatory = db.BooleanProperty(required=True, default=True) order = db.IntegerProperty(required=True) @@ -18,6 +19,7 @@ class TaskComponent(db.Model): 'userId' : self.userId, 'type' : self.type, 'label' : self.label, + 'value' : self.value, 'isMandatory' : self.isMandatory, 'order' : self.order, 'id' : self.key().id() diff --git a/templates/android-icon-144x144.png b/templates/android-icon-144x144.png new file mode 100644 index 0000000..8c4aac7 Binary files /dev/null and b/templates/android-icon-144x144.png differ diff --git a/templates/android-icon-192x192.png b/templates/android-icon-192x192.png new file mode 100644 index 0000000..da41e19 Binary files /dev/null and b/templates/android-icon-192x192.png differ diff --git a/templates/android-icon-36x36.png b/templates/android-icon-36x36.png new file mode 100644 index 0000000..18dfb0f Binary files /dev/null and b/templates/android-icon-36x36.png differ diff --git a/templates/android-icon-48x48.png b/templates/android-icon-48x48.png new file mode 100644 index 0000000..a2ef791 Binary files /dev/null and b/templates/android-icon-48x48.png differ diff --git a/templates/android-icon-72x72.png b/templates/android-icon-72x72.png new file mode 100644 index 0000000..f552d73 Binary files /dev/null and b/templates/android-icon-72x72.png differ diff --git a/templates/android-icon-96x96.png b/templates/android-icon-96x96.png new file mode 100644 index 0000000..3e27476 Binary files /dev/null and b/templates/android-icon-96x96.png differ diff --git a/templates/apple-icon-114x114.png b/templates/apple-icon-114x114.png new file mode 100644 index 0000000..cf6a615 Binary files /dev/null and b/templates/apple-icon-114x114.png differ diff --git a/templates/apple-icon-120x120.png b/templates/apple-icon-120x120.png new file mode 100644 index 0000000..a6e44f7 Binary files /dev/null and b/templates/apple-icon-120x120.png differ diff --git a/templates/apple-icon-144x144.png b/templates/apple-icon-144x144.png new file mode 100644 index 0000000..8c4aac7 Binary files /dev/null and b/templates/apple-icon-144x144.png differ diff --git a/templates/apple-icon-152x152.png b/templates/apple-icon-152x152.png new file mode 100644 index 0000000..e669026 Binary files /dev/null and b/templates/apple-icon-152x152.png differ diff --git a/templates/apple-icon-180x180.png b/templates/apple-icon-180x180.png new file mode 100644 index 0000000..60a2a32 Binary files /dev/null and b/templates/apple-icon-180x180.png differ diff --git a/templates/apple-icon-57x57.png b/templates/apple-icon-57x57.png new file mode 100644 index 0000000..582780f Binary files /dev/null and b/templates/apple-icon-57x57.png differ diff --git a/templates/apple-icon-60x60.png b/templates/apple-icon-60x60.png new file mode 100644 index 0000000..561ea02 Binary files /dev/null and b/templates/apple-icon-60x60.png differ diff --git a/templates/apple-icon-72x72.png b/templates/apple-icon-72x72.png new file mode 100644 index 0000000..f552d73 Binary files /dev/null and b/templates/apple-icon-72x72.png differ diff --git a/templates/apple-icon-76x76.png b/templates/apple-icon-76x76.png new file mode 100644 index 0000000..ae249c9 Binary files /dev/null and b/templates/apple-icon-76x76.png differ diff --git a/templates/apple-icon-precomposed.png b/templates/apple-icon-precomposed.png new file mode 100644 index 0000000..02bbc41 Binary files /dev/null and b/templates/apple-icon-precomposed.png differ diff --git a/templates/apple-icon.png b/templates/apple-icon.png new file mode 100644 index 0000000..02bbc41 Binary files /dev/null and b/templates/apple-icon.png differ diff --git a/templates/browserconfig.xml b/templates/browserconfig.xml new file mode 100644 index 0000000..f6c2328 --- /dev/null +++ b/templates/browserconfig.xml @@ -0,0 +1,2 @@ + +#ffffff \ No newline at end of file diff --git a/templates/css/theme.css b/templates/css/theme.css index ab99672..11ef815 100644 --- a/templates/css/theme.css +++ b/templates/css/theme.css @@ -127,6 +127,10 @@ body.noscroll margin-bottom: auto; } +.center_all{ + margin:auto; +} + .mail_suffix { margin-top: auto; diff --git a/templates/favicon-16x16.png b/templates/favicon-16x16.png new file mode 100644 index 0000000..7d08289 Binary files /dev/null and b/templates/favicon-16x16.png differ diff --git a/templates/favicon-32x32.png b/templates/favicon-32x32.png new file mode 100644 index 0000000..1f63b13 Binary files /dev/null and b/templates/favicon-32x32.png differ diff --git a/templates/favicon-96x96.png b/templates/favicon-96x96.png new file mode 100644 index 0000000..3e27476 Binary files /dev/null and b/templates/favicon-96x96.png differ diff --git a/templates/favicon.ico b/templates/favicon.ico new file mode 100644 index 0000000..ff1fc7f Binary files /dev/null and b/templates/favicon.ico differ diff --git a/templates/index.html b/templates/index.html index a94ff2e..3dce025 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,6 +1,23 @@ + + + + + + + + + + + + + + + + + diff --git a/templates/js/controllers/newTasksController.js b/templates/js/controllers/newTasksController.js index c348a31..8a029df 100644 --- a/templates/js/controllers/newTasksController.js +++ b/templates/js/controllers/newTasksController.js @@ -133,7 +133,7 @@ angular.module('SeHub').controller('newTasksController', ['$scope', 'apiService' $scope.compDetails = [{ detail: "Label" }, { - detail: "URL Path" + detail: "URL Path (You Need To Include 'http://'" }]; if (type === 'radiobuttons') diff --git a/templates/js/controllers/taskController.js b/templates/js/controllers/taskController.js index 979bfe2..e29a493 100644 --- a/templates/js/controllers/taskController.js +++ b/templates/js/controllers/taskController.js @@ -8,12 +8,14 @@ angular.module('SeHub') var submitterId = $routeParams.submitterId; var token = $cookies['com.sehub.www']; var groupId = $routeParams.gId; + $scope.loading = true; - apiService.getTaskById(token, taskId, groupId).success(function(data){ + apiService.getTaskById(token, taskId, groupId).success(function(data) { $scope.task = data; $scope.dateInit($scope.task.dueDate); - }).error(function(err){ - console.error('Error: ', err); + $scope.loading = false; + }).error(function(err) { + $location.path('/tasks'); }) if (submitterId) { //In This Case we Only Want to show The Content of the Submitter @@ -71,8 +73,23 @@ angular.module('SeHub') $scope.submitTask = function(event) { //Dialog will pop-up if not all mandatory fields are filled if (validateComponents()) { - alert('All Shit Are Filled'); - return; + apiService.submitTask(token, taskId, groupId, $scope.task.components).success(function(data) { + $mdDialog.show( + $mdDialog.alert() + .title('Submitted!') + .content('Your Task Was Successfully Submitted!') + .ariaLabel('ddd') + .ok('GoTo My Submitted Task') + .then(function(dd){ + if($scope.task.isPersonal) + $location.path('/tasks/overview/'+taskId+'/'+groupId+'/'+groupId); + else + $location.path('/tasks/overview/'+taskId+'/'+groupId+'/'+groupId); + }) + .targetEvent(event) + ); + }) + } $mdDialog.show( $mdDialog.alert() @@ -119,7 +136,7 @@ angular.module('SeHub') // }] // }; - + $scope.dueTime = function() { if (!$scope.task.date || $scope.task.date === '') diff --git a/templates/js/services/apiService.js b/templates/js/services/apiService.js index cd8b0df..2460da0 100644 --- a/templates/js/services/apiService.js +++ b/templates/js/services/apiService.js @@ -262,6 +262,15 @@ service.factory('apiService', ['$http', function($http) { }; return $http(req); + }, + submitTask: function(token, taskId, ownerId, payload){ + var url = (DEBUG ? "http://localhost:8080" : "http://se-hub.appspot.com") + "/api/tasks/submitTask/" + token + '/' + taskId + '/' + ownerId; + req = { + method: 'POST', + data: payload, + url: url + }; + return $http(req); } }; }]); \ No newline at end of file diff --git a/templates/manifest.json b/templates/manifest.json new file mode 100644 index 0000000..013d4a6 --- /dev/null +++ b/templates/manifest.json @@ -0,0 +1,41 @@ +{ + "name": "App", + "icons": [ + { + "src": "\/android-icon-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": "0.75" + }, + { + "src": "\/android-icon-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": "1.0" + }, + { + "src": "\/android-icon-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": "1.5" + }, + { + "src": "\/android-icon-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": "2.0" + }, + { + "src": "\/android-icon-144x144.png", + "sizes": "144x144", + "type": "image\/png", + "density": "3.0" + }, + { + "src": "\/android-icon-192x192.png", + "sizes": "192x192", + "type": "image\/png", + "density": "4.0" + } + ] +} \ No newline at end of file diff --git a/templates/ms-icon-144x144.png b/templates/ms-icon-144x144.png new file mode 100644 index 0000000..8c4aac7 Binary files /dev/null and b/templates/ms-icon-144x144.png differ diff --git a/templates/ms-icon-150x150.png b/templates/ms-icon-150x150.png new file mode 100644 index 0000000..dcf672a Binary files /dev/null and b/templates/ms-icon-150x150.png differ diff --git a/templates/ms-icon-310x310.png b/templates/ms-icon-310x310.png new file mode 100644 index 0000000..cb0da26 Binary files /dev/null and b/templates/ms-icon-310x310.png differ diff --git a/templates/ms-icon-70x70.png b/templates/ms-icon-70x70.png new file mode 100644 index 0000000..e3a3de7 Binary files /dev/null and b/templates/ms-icon-70x70.png differ diff --git a/templates/views/task.html b/templates/views/task.html index 760a2fb..b682860 100644 --- a/templates/views/task.html +++ b/templates/views/task.html @@ -1,4 +1,7 @@ -
+
+ +
+