def getListData(self): """Returns the list data as requested by the current request. If the lists as requested is not supported by this component None is returned. """ if lists.getListIndex(self.data.request) != 1: return None q = GCITask.all() q.filter('program', self.data.program) q.filter( 'org IN', map(lambda org_key: org_key.to_old_key(), self.data.ndb_profile.mentor_for)) starter = lists.keyStarter # TODO(daniel): enable prefetching #prefetcher = lists.ListModelPrefetcher( # GCITask, ['org', 'student', 'created_by', 'modified_by'], ['mentors']) response_builder = lists.RawQueryContentResponseBuilder( self.data.request, self._list_config, q, starter, prefetcher=None) return response_builder.build()
def _processStudentEntity(self, entity, properties): query = GCITask.all() query.filter('student', entity) query.filter('status', 'Closed') no_of_tasks = query.count() properties['number_of_tasks_completed'] = no_of_tasks
def testPostButtonExtendDeadline(self): """Tests the extend deadline button. """ self.data.createMentor(self.org) profile_helper = GCIProfileHelper(self.gci, self.dev_test) profile_helper.createOtherUser('*****@*****.**').createStudent() student = profile_helper.profile # set it in the future so that the auto state transfer doesn't trigger deadline = datetime.datetime.utcnow() + datetime.timedelta(hours=24) self.task.status = 'Claimed' self.task.student = student self.task.deadline = deadline self.task.put() url = self._taskPageUrl(self.task) response = self.buttonPost( url, 'button_extend_deadline', {'hours': 1}) task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) delta = task.deadline - deadline self.assertTrue(delta.seconds == 3600) # check if a comment has been created comments = self.task.comments() self.assertLength(comments, 1) self.assertMailSentToSubscribers(comments[0])
def testPostButtonNeedsWork(self): """Tests the needs more work for task button. """ self.data.createMentor(self.org) profile_helper = GCIProfileHelper(self.gci, self.dev_test) profile_helper.createOtherUser("*****@*****.**").createStudent() student = profile_helper.profile self.task.status = "NeedsReview" self.task.student = student self.task.put() url = self._taskPageUrl(self.task) response = self.buttonPost(url, "button_needs_work") # check if the task is properly closed task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task.status, "NeedsWork") self.assertEqual(task.student.key(), student.key()) self.assertEqual(task.deadline, None) # check if a comment has been created comments = self.task.comments() self.assertLength(comments, 1) self.assertMailSentToSubscribers(comments[0])
def testPostButtonUnassign(self): """Tests the unassign button. """ self.data.createMentor(self.org) profile_helper = GCIProfileHelper(self.gci, self.dev_test) profile_helper.createOtherUser("*****@*****.**").createStudent() student = profile_helper.profile self.task.status = "Claimed" self.task.student = student self.task.put() url = self._taskPageUrl(self.task) response = self.buttonPost(url, "button_unassign") # check if the task is properly unassigned task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task.status, "Reopened") self.assertEqual(task.student, None) self.assertEqual(task.deadline, None) # check if a comment has been created comments = self.task.comments() self.assertLength(comments, 1) self.assertMailSentToSubscribers(comments[0])
def testPostButtonExtendDeadline(self): """Tests the extend deadline button. """ self.data.createMentor(self.org) profile_helper = GCIProfileHelper(self.gci, self.dev_test) profile_helper.createOtherUser("*****@*****.**").createStudent() student = profile_helper.profile # set it in the future so that the auto state transfer doesn't trigger deadline = datetime.datetime.utcnow() + datetime.timedelta(hours=24) self.task.status = "Claimed" self.task.student = student self.task.deadline = deadline self.task.put() url = self._taskPageUrl(self.task) response = self.buttonPost(url, "button_extend_deadline", {"hours": 1}) task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) delta = task.deadline - deadline self.assertTrue(delta.seconds == 3600) # check if a comment has been created comments = self.task.comments() self.assertLength(comments, 1) self.assertMailSentToSubscribers(comments[0])
def testPostButtonAssign(self): """Tests the assign button. """ self.data.createMentor(self.org) profile_helper = GCIProfileHelper(self.gci, self.dev_test) profile_helper.createOtherUser("*****@*****.**").createStudent() student = profile_helper.profile self.task.status = "ClaimRequested" self.task.student = student self.task.put() url = self._taskPageUrl(self.task) response = self.buttonPost(url, "button_assign") # check if the task is properly assigned and a deadline has been set task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task.status, "Claimed") self.assertEqual(task.student.key(), student.key()) self.assertTrue(task.deadline) # check if a comment has been created comments = self.task.comments() self.assertLength(comments, 1) self.assertMailSentToSubscribers(comments[0]) # check if the update task has been enqueued self.assertTasksInQueue(n=1, url=self._taskUpdateUrl(task))
def testPostButtonAssign(self): """Tests the assign button. """ self.data.createMentor(self.org) profile_helper = GCIProfileHelper(self.gci, self.dev_test) profile_helper.createOtherUser('*****@*****.**').createStudent() student = profile_helper.profile self.task.status = 'ClaimRequested' self.task.student = student self.task.put() url = self._taskPageUrl(self.task) response = self.buttonPost(url, 'button_assign') # check if the task is properly assigned and a deadline has been set task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task.status, 'Claimed') self.assertEqual(task.student.key(), student.key()) self.assertTrue(task.deadline) # check if a comment has been created comments = self.task.comments() self.assertLength(comments, 1) self.assertMailSentToSubscribers(comments[0]) # check if the update task has been enqueued self.assertTasksInQueue(n=1, url=self._taskUpdateUrl(task))
def testPostButtonUnassign(self): """Tests the unassign button. """ self.data.createMentor(self.org) profile_helper = GCIProfileHelper(self.gci, self.dev_test) profile_helper.createOtherUser('*****@*****.**').createStudent() student = profile_helper.profile self.task.status = 'Claimed' self.task.student = student self.task.put() url = self._taskPageUrl(self.task) response = self.buttonPost(url, 'button_unassign') # check if the task is properly unassigned task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task.status, 'Reopened') self.assertEqual(task.student, None) self.assertEqual(task.deadline, None) # check if a comment has been created comments = self.task.comments() self.assertLength(comments, 1) self.assertMailSentToSubscribers(comments[0])
def testPostButtonNeedsWork(self): """Tests the needs more work for task button. """ self.data.createMentor(self.org) profile_helper = GCIProfileHelper(self.gci, self.dev_test) profile_helper.createOtherUser('*****@*****.**').createStudent() student = profile_helper.profile self.task.status = 'NeedsReview' self.task.student = student self.task.put() url = self._taskPageUrl(self.task) response = self.buttonPost(url, 'button_needs_work') # check if the task is properly closed task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task.status, 'NeedsWork') self.assertEqual(task.student.key(), student.key()) self.assertEqual(task.deadline, None) # check if a comment has been created comments = self.task.comments() self.assertLength(comments, 1) self.assertMailSentToSubscribers(comments[0])
def taskFromKwargs(self, comments=False, work_submissions=True): """Sets the GCITask entity in RequestData object. The entity that is set will always be in a valid state and for the program that is set in the RequestData. Args: comments: If true the comments on this task are added to RequestData work_submissions: If true the work submissions on this task are added to RequestData """ id = long(self.data.kwargs['id']) task = GCITask.get_by_id(id) if not task or (task.program.key() != self.data.program.key()) or \ task.status == 'invalid': error_msg = access_checker.DEF_ID_BASED_ENTITY_NOT_EXISTS % { 'model': 'GCITask', 'id': id, } raise NotFound(error_msg) self.data.task = task if comments: self.data.comments = task.comments() if work_submissions: self.data.work_submissions = task.workSubmissions()
def publish_task_txn(profile_key): """Publishes or unpublishes a task in a transaction. profile_key: profile key of the user who takes this action. """ task = GCITask.get_by_id(int(task_key)) profile = profile_key.get() if not task: logging.warning("Task with task_id '%s' does not exist", task_key) return org_key = ndb.Key.from_old_key( GCITask.org.get_value_for_datastore(task)) if not org_key in profile.admin_for: logging.warning('Not an org admin') return if publish: if task.status in task_model.UNAVAILABLE: task.status = task_model.OPEN task.put() else: logging.warning( 'Trying to publish task with %s status.', task.status) else: if task.status == task_model.OPEN: task.status = task_model.UNPUBLISHED task.put() else: logging.warning( 'Trying to unpublish task with %s status.', task.status)
def context(self): context = { 'user_email': accounts.denormalizeAccount(self.data.user.account).email(), 'link_id': self.data.user.link_id, 'logout_link': links.LINKER.logout(self.data.request), 'dashboard_link': links.LINKER.program(self.data.program, 'gci_dashboard') } # TODO(daniel): simplify this if statement if self.data.ndb_profile: if (self.data.ndb_profile.is_student and self.data.ndb_profile.status == profile_model.Status.ACTIVE): q = GCITask.all() q.filter('student', self.data.ndb_profile.key.to_old_key()) q.filter('status IN', ACTIVE_CLAIMED_TASK) task = q.get() if task: context['task'] = task context['time_left'] = self.getTimeLeftForTask(task) task_url = self.data.redirect.id( task.key().id()).urlOf('gci_view_task') context['task_url'] = task_url return context
def recalculateForStudent(self, request, *args, **kwargs): """Recalculates GCI Student Ranking for the specified student. Args in POST: key: The string version of the key for the GCIProfile entity representing the student. """ post_dict = request.POST key = db.Key(post_dict['key']) student = GCIProfile.get(key) if not student: logging.warning('Enqueued task to recalculate ranking for ' 'non-existent student %s' %(key)) return responses.terminateTask() # get all the tasks that the student has completed q = GCITask.all() q.filter('student', student) q.filter('status', 'Closed') tasks = q.fetch(1000) ranking_logic.calculateRankingForStudent(student, tasks) return responses.terminateTask()
def getRemainingTaskQuota(org): """Returns the number of remaining tasks that the organization can publish. While calculating the remaining quota we consider all the tasks that were published including the closed tasks but not the deleted tasks. Args: org: The organization entity for which the quota must be calculated Returns: An integer which is the number of tasks the organization can publish yet """ # TODO(Madhu): Refactor to create Open Tasks and Closed tasks variables # count all the tasks the organization has published till now. # This excludes tasks in Unapproved, Unpublished and Invalid states. valid_status = [ "Open", "Reopened", "ClaimRequested", "Claimed", "ActionNeeded", "Closed", "AwaitingRegistration", "NeedsWork", "NeedsReview", ] q = GCITask.all() q.filter("org", org) q.filter("status IN", valid_status) return org.task_quota_limit - q.count()
def recalculateForStudent(self, request, *args, **kwargs): """Recalculates GCI Student Ranking for the specified student. Args in POST: key: The string version of the key for the GCIProfile entity representing the student. """ post_dict = request.POST key = db.Key(post_dict['key']) student = GCIProfile.get(key) if not student: logging.warning( 'Enqueued task to recalculate ranking for ' 'non-existent student %s', key) return responses.terminateTask() # get all the tasks that the student has completed q = GCITask.all() q.filter('student', student) q.filter('status', 'Closed') tasks = q.fetch(1000) score_logic.calculateRankingForStudent(student, tasks) return responses.terminateTask()
def queryAllTasksClosedByStudent(profile, keys_only=False): """Returns a query for all the tasks that have been closed by the specified profile. """ if not profile.student_info: raise ValueError('Only students can be queried for closed tasks.') return GCITask.all(keys_only=keys_only).filter( 'student', profile).filter('status', 'Closed')
def process_task(task): """Conversion to make GCI Tasks ID based and getting rid of unnecessary properties. """ if task.key().name(): # Get the values for all the properties in the GCITask model from the # old entity to create the new entity. new_task_properties = {} for prop in TASK_PROPERTIES: new_task_properties[prop] = getattr(task, prop) new_task_properties['org'] = task.scope new_task = GCITask(**new_task_properties) new_task_key = new_task.put() if new_task_key: # Update all the comments with the new task as the parent comments = GCIComment.all().ancestor(task).fetch(1000) for c in comments: new_comm_properties = {} for c_prop in COMMENT_PROPERTIES: new_comm_properties[c_prop] = getattr(c, c_prop) new_comment = GCIComment(parent=new_task_key, **new_comm_properties) # set these fields to behave like last_modified_on/by new_comment.modified_on = new_comment.created_on new_comment.modified_by = new_comment.created_by yield operation.db.Put(new_comment) yield operation.counters.Increment("comment_updated") # Update all the work submission entities with the new task as the parent work_submissions = GCIWorkSubmission.all().ancestor(task).fetch(1000) for ws in work_submissions: new_ws_properties = {} for ws_prop in WORK_SUBMISSION_PROPERTIES: new_ws_properties[ws_prop] = getattr(ws, ws_prop) new_ws = GCIWorkSubmission(parent=new_task_key, **new_ws_properties) yield operation.db.Put(new_ws) yield operation.counters.Increment("work_submission_updated") yield operation.counters.Increment("task_updated")
def testPostButtonDelete(self): """Tests the delete button. """ self.data.createOrgAdmin(self.org) url = self._taskPageUrl(self.task) response = self.buttonPost(url, "button_delete") task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task, None)
def testPostButtonUnpublish(self): """Tests the unpublish button. """ self.data.createOrgAdmin(self.org) url = self._taskPageUrl(self.task) response = self.buttonPost(url, 'button_unpublish') task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task.status, 'Unpublished')
def testPostButtonDelete(self): """Tests the delete button. """ self.data.createOrgAdmin(self.org) url = self._taskPageUrl(self.task) response = self.buttonPost(url, 'button_delete') task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task, None)
def testPostButtonUnpublish(self): """Tests the unpublish button. """ self.data.createOrgAdmin(self.org) url = self._taskPageUrl(self.task) response = self.buttonPost(url, "button_unpublish") task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task.status, "Unpublished")
def getListData(self): if lists.getListIndex(self.data.request) != 1: return None q = GCITask.all() q.filter('org', self.data.organization) q.filter('status', 'Closed') starter = lists.keyStarter response_builder = lists.RawQueryContentResponseBuilder( self.data.request, self.list_config, q, starter) return response_builder.build()
def getListData(self): if lists.getListIndex(self.request) != 0: return None q = GCITask.all() q.filter('org', self.data.organization) q.filter('status IN', CLAIMABLE) starter = lists.keyStarter response_builder = lists.RawQueryContentResponseBuilder( self.request, self.list_config, q, starter) return response_builder.build()
def getListData(self): idx = lists.getListIndex(self.data.request) if idx == 0: q = GCITask.all() q.filter('program', self.data.program) q.filter('status', 'Closed') response_builder = lists.RawQueryContentResponseBuilder( self.data.request, self._list_config, q, lists.keyStarter) return response_builder.build() else: return None
def recalculateGCIRanking(self, request, *args, **kwargs): """Recalculates student ranking for the entire program. Args in POST dict: cursor: Query cursor to figure out where we need to start processing """ key_name = '%s/%s' % (kwargs['sponsor'], kwargs['program']) cursor = request.POST.get('cursor') program = GCIProgram.get_by_key_name(key_name) if not program: logging.warning( 'Enqueued recalculate ranking task for non-existing program: %s', key_name) return responses.terminateTask() # Retrieve the students for the program q = GCIProfile.all() q.filter('program', program) q.filter('is_student', True) if cursor: q.with_cursor(cursor) students = q.fetch(25) for student in students: # get all the tasks that the student has completed task_q = GCITask.all() task_q.filter('student', student) task_q.filter('status', 'Closed') tasks = task_q.fetch(1000) # calculate score with all the tasks score_logic.calculateScore(student, tasks, program) # calculate org score with all the tasks db.run_in_transaction(org_score_logic.updateOrgScoresTxn(tasks)) if students: # schedule task to do the rest of the students params = { 'cursor': q.cursor(), } taskqueue.add(queue_name='gci-update', url=request.path, params=params) return responses.terminateTask()
def convertGCITask(task_key): """Converts the specified task by changing values of its profile related properties to the new NDB based profile entities. Args: task_key: Task key. """ task = GCITask.get(task_key) task.created_by = _convertReferenceProperty(GCITask.created_by, task) task.modified_by = _convertReferenceProperty(GCITask.modified_by, task) task.student = _convertReferenceProperty(GCITask.student, task) task.mentors = _convertListProperty(GCITask.mentors, task) task.subscribers = _convertListProperty(GCITask.subscribers, task) task.put()
def testPostButtonSubscribe(self): """Tests the subscribe button. """ self.data.createMentor(self.org) profile = self.data.profile self.assertFalse(profile.key() in self.task.subscribers) url = self._taskPageUrl(self.task) response = self.buttonPost(url, "button_subscribe") task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertTrue(profile.key() in task.subscribers)
def testPostButtonSubscribe(self): """Tests the subscribe button. """ self.data.createMentor(self.org) profile = self.data.profile self.assertFalse(profile.key() in self.task.subscribers) url = self._taskPageUrl(self.task) response = self.buttonPost(url, 'button_subscribe') task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertTrue(profile.key() in task.subscribers)
def testPostButtonUnsubscribe(self): """Tests the unsubscribe button. """ self.data.createMentor(self.org) # subscribe to the task manually profile = self.data.profile self.task.subscribers.append(profile.key()) self.task.put() url = self._taskPageUrl(self.task) response = self.buttonPost(url, 'button_unsubscribe') task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertFalse(profile.key() in task.subscribers)
def testPostButtonUnsubscribe(self): """Tests the unsubscribe button. """ self.data.createMentor(self.org) # subscribe to the task manually profile = self.data.profile self.task.subscribers.append(profile.key()) self.task.put() url = self._taskPageUrl(self.task) response = self.buttonPost(url, "button_unsubscribe") task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertFalse(profile.key() in task.subscribers)
def recalculateGCIRanking(self, request, *args, **kwargs): """Recalculates student ranking for the entire program. Args in POST dict: cursor: Query cursor to figure out where we need to start processing """ key_name = '%s/%s' % (kwargs['sponsor'], kwargs['program']) cursor = request.POST.get('cursor') program = GCIProgram.get_by_key_name(key_name) if not program: logging.warning( 'Enqueued recalculate ranking task for non-existing ' 'program: %s' %key_name) return responses.terminateTask() # Retrieve the students for the program q = GCIProfile.all() q.filter('scope', program) q.filter('is_student', True) if cursor: q.with_cursor(cursor) students = q.fetch(25) for student in students: # get all the tasks that the student has completed task_q = GCITask.all() task_q.filter('student', student) task_q.filter('status', 'Closed') tasks = task_q.fetch(1000) # calculate ranking with all the tasks # ranking_logic.calculateRankingForStudent(student, tasks) ranking_logic.calculateScore(student, tasks, program) if students: # schedule task to do the rest of the students params = { 'cursor': q.cursor(), } taskqueue.add(queue_name='gci-update', url=request.path, params=params) return responses.terminateTask()
def clear(*args, **kwargs): """Removes all entities from the datastore. """ # TODO(dbentley): If there are more than 1000 instances of any model, # this method will not clear all instances. Instead, it should continually # call .all(), delete all those, and loop until .all() is empty. entities = itertools.chain(*[ Survey.all(), SurveyRecord.all(), GCIOrganization.all(), GSoCTimeline.all(), GCITimeline.all(), GSoCProgram.all(), GSoCProject.all(), GSoCProposal.all(), GCIProgram.all(), GCIScore.all(), GSoCStudentInfo.all(), GCIStudentInfo.all(), GCITask.all(), Sponsor.all(), Site.all(), Document.all(), # The below models are all subclasses of ndb.Model and therefore must # use .query() to return all instances instead of .all(). soc_org_model.SOCOrganization.query(), profile_model.Profile.query(), soc_profile.SOCStudentData.query(), user.User.query(), address.Address.query(), contact.Contact.query() ]) try: for entity in entities: if isinstance(entity, ndb.Model): entity.key.delete() else: entity.delete() except db.Timeout: return http.HttpResponseRedirect('#') memcache.flush_all() return http.HttpResponse('Done')
def recalculateGCIRanking(self, request, *args, **kwargs): """Recalculates student ranking for the entire program. Args in POST dict: cursor: Query cursor to figure out where we need to start processing """ key_name = "%s/%s" % (kwargs["sponsor"], kwargs["program"]) cursor = request.POST.get("cursor") program = GCIProgram.get_by_key_name(key_name) if not program: logging.warning("Enqueued recalculate ranking task for non-existing program: %s", key_name) return responses.terminateTask() # Retrieve the students for the program q = GCIProfile.all() q.filter("program", program) q.filter("is_student", True) if cursor: q.with_cursor(cursor) students = q.fetch(25) for student in students: # get all the tasks that the student has completed task_q = GCITask.all() task_q.filter("student", student) task_q.filter("status", "Closed") tasks = task_q.fetch(1000) # calculate score with all the tasks score_logic.calculateScore(student, tasks, program) # calculate org score with all the tasks db.run_in_transaction(org_score_logic.updateOrgScoresTxn(tasks)) if students: # schedule task to do the rest of the students params = {"cursor": q.cursor()} taskqueue.add(queue_name="gci-update", url=request.path, params=params) return responses.terminateTask()
def testPostButtonClaim(self): """Tests the claim task button. """ self.data.createStudent() url = self._taskPageUrl(self.task) response = self.buttonPost(url, 'button_claim') # check if the task is properly claimed task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task.status, 'ClaimRequested') self.assertEqual(task.student.key(), self.data.profile.key()) # check if a comment has been created comments = self.task.comments() self.assertLength(comments, 1) self.assertMailSentToSubscribers(comments[0])
def updateGCITask(self, request, id, *args, **kwargs): """Method executed by Task Queue API to update a GCI Task to relevant state. Args: request: the standard Django HTTP request object """ id = int(id) task = GCITask.get_by_id(id) if not task: # invalid task data, log and return OK return error_handler.logErrorAndReturnOK("No GCITask found for id: %s" % id) task_logic.updateTaskStatus(task) return http.HttpResponse()
def process_tag(tag): """Replace all the references to the list of old tasks to the new tasks. """ new_tagged_keys = [] for t in tag.tagged: try: task = GCITask.get(t) new_tagged = new_task_for_old(task) if task else None except db.KindError: new_tagged = t if new_tagged: new_tagged_keys.append(new_tagged) tag.tagged = new_tagged_keys yield operation.db.Put(tag) yield operation.counters.Increment("tag_updated")
def testPostButtonClaim(self): """Tests the claim task button. """ self.data.createStudent() url = self._taskPageUrl(self.task) response = self.buttonPost(url, "button_claim") # check if the task is properly claimed task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task.status, "ClaimRequested") self.assertEqual(task.student.key(), self.data.profile.key()) # check if a comment has been created comments = self.task.comments() self.assertLength(comments, 1) self.assertMailSentToSubscribers(comments[0])
def updateRankingWithTask(self, request, *args, **kwargs): """Updates student ranking based on the task passed as post argument. Args in POST dict: id: The (numeric) id of the task to update the ranking for """ post_dict = request.POST id = int(post_dict.get('id')) task = GCITask.get_by_id(id) if not task: logging.warning('Ranking update queued for non-existing task: %s' %id) responses.terminateTask() ranking_logic.updateScore(task) logging.info("ranking_update updateRankingWithTask ends") return responses.terminateTask()
def updateGCITask(self, request, id, *args, **kwargs): """Method executed by Task Queue API to update a GCI Task to relevant state. Args: request: the standard Django HTTP request object """ id = int(id) task = GCITask.get_by_id(id) if not task: # invalid task data, log and return OK return error_handler.logErrorAndReturnOK( 'No GCITask found for id: %s' % id) task_logic.updateTaskStatus(task) return http.HttpResponse()
def testPostSendForReview(self): """Tests for submitting work. """ self.data.createStudent() self.task.status = "Claimed" self.task.student = self.data.profile # set deadline to far future self.task.deadline = datetime.datetime.utcnow() + datetime.timedelta(days=1) self.task.put() GCITaskHelper(self.program).createWorkSubmission(self.task, self.data.profile) url = "%s?send_for_review" % self._taskPageUrl(self.task) response = self.post(url) task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task.status, "NeedsReview")
def clear(*args, **kwargs): """Removes all entities from the datastore. """ # TODO(dbentley): If there are more than 1000 instances of any model, # this method will not clear all instances. Instead, it should continually # call .all(), delete all those, and loop until .all() is empty. entities = itertools.chain(*[ Notification.all(), GCIStudent.all(), Survey.all(), SurveyRecord.all(), StudentProposal.all(), GSoCOrganization.all(), GCIOrganization.all(), GSoCTimeline.all(), GCITimeline.all(), GSoCProgram.all(), GSoCProfile.all(), GCIProfile.all(), GSoCProposal.all(), GCIProgram.all(), GCIScore.all(), GSoCStudentInfo.all(), GCIStudentInfo.all(), GCITask.all(), Host.all(), Sponsor.all(), User.all(), Site.all(), Document.all(), ]) try: for entity in entities: entity.delete() except db.Timeout: return http.HttpResponseRedirect('#') # pylint: disable=E1101 memcache.flush_all() return http.HttpResponse('Done')
def testPostSendForReview(self): """Tests for submitting work. """ self.data.createStudent() self.task.status = 'Claimed' self.task.student = self.data.profile # set deadline to far future self.task.deadline = datetime.datetime.utcnow() + datetime.timedelta(days=1) self.task.put() GCITaskHelper(self.program).createWorkSubmission( self.task, self.data.profile) url = '%s?send_for_review' %self._taskPageUrl(self.task) response = self.post(url) task = GCITask.get(self.task.key()) self.assertResponseRedirect(response) self.assertEqual(task.status, 'NeedsReview')
def updateRankingWithTask(self, request, *args, **kwargs): """Updates student ranking based on the task passed as post argument. Args in POST dict: id: The (numeric) id of the task to update the ranking for """ post_dict = request.POST id = int(post_dict.get('id')) task = GCITask.get_by_id(id) if not task: logging.warning('Ranking update queued for non-existing task: %s', id) responses.terminateTask() score_logic.updateScore(task) logging.info("ranking_update updateRankingWithTask ends") return responses.terminateTask()
def context(self): context = { 'user_email': accounts.denormalizeAccount(self.data.user.account).email(), 'link_id': self.data.user.link_id, 'logout_link': self.data.redirect.logout().url(), 'dashboard_link': self.data.redirect.dashboard().url() } if self.data.profile: if self.data.is_student and self.data.profile.status == 'active': q = GCITask.all() q.filter('student', self.data.profile) q.filter('status IN', ACTIVE_CLAIMED_TASK) task = q.get() if task: context['task'] = task context['time_left'] = self.getTimeLeftForTask(task) task_url = self.data.redirect.id( task.key().id()).urlOf('gci_view_task') context['task_url'] = task_url return context
def getListData(self): """Returns the list data as requested by the current request. If the lists as requested is not supported by this component None is returned. """ if lists.getListIndex(self.request) != 1: return None q = GCITask.all() q.filter("program", self.data.program) q.filter("org IN", self.data.mentor_for) starter = lists.keyStarter prefetcher = lists.listModelPrefetcher(GCITask, ["org", "student", "created_by", "modified_by"], ["mentors"]) response_builder = lists.RawQueryContentResponseBuilder( self.request, self._list_config, q, starter, prefetcher=prefetcher ) return response_builder.build()
def subscribe_to_task_txn(task_key, subscribe): task = GCITask.get(task_key) task.subscribers = list(set(task.subscribers + subscribe)) task.put() return task
def bulkCreateTasks(self, request, *args, **kwargs): """Task that creates GCI Tasks from bulk data specified in the POST dict. The POST dict should have the following information present: bulk_create_key: the key of the bulk_create entity """ import settings # keep track of our own timelimit (20 seconds) timelimit = 20000 timekeeper = Timekeeper(timelimit) post_dict = request.POST bulk_create_key = post_dict.get('bulk_create_key') if not bulk_create_key: return error_handler.logErrorAndReturnOK( 'Not all POST data specified in: %s' % post_dict) bulk_data = GCIBulkCreateData.get(bulk_create_key) if not bulk_data: return error_handler.logErrorAndReturnOK( 'No valid data found for key: %s' % bulk_create_key) # note that we only query for the quota once org_admin = ndb.Key.from_old_key( GCIBulkCreateData.created_by.get_value_for_datastore( bulk_data)).get() org = bulk_data.org task_quota = getRemainingTaskQuota(org) # TODO(ljvderijk): Add transactions tasks = bulk_data.tasks while len(tasks) > 0: try: # check if we have time timekeeper.ping() if settings.GCI_TASK_QUOTA_LIMIT_ENABLED and task_quota <= 0: return error_handler.logErrorAndReturnOK( 'Task quota reached for %s' % (org.name)) # remove the first task task_as_string = tasks.pop(0) loaded_task = json.loads(task_as_string) task = {} for key, value in loaded_task.iteritems(): # If we don't do this python will complain about kwargs not being # strings when we try to save the new task. task[key.encode('UTF-8')] = value logging.info('Uncleaned task: %s', task) # clean the data errors = self._cleanTask(task, org) if errors: logging.warning( 'Invalid task data uploaded, the following errors occurred: %s', errors) bulk_data.errors.append(db.Text( 'The task in row %i contains the following errors.\n %s' \ %(bulk_data.tasksRemoved(), '\n'.join(errors)))) # at-most-once semantics for creating tasks bulk_data.put() if errors: # do the next task continue # set other properties task['org'] = org # TODO(daniel): access program in more efficient way task['program'] = org_admin.program.to_old_key() task['status'] = task_model.UNPUBLISHED task['created_by'] = org_admin.to_old_key() task['modified_by'] = org_admin.to_old_key() # TODO(ljv): Remove difficulty level completely if needed. # Difficulty is hardcoded to easy since GCI2012 has no difficulty. task['difficulty_level'] = DifficultyLevel.EASY subscribers_entities = task['mentor_entities'] + [org_admin] task['subscribers'] = list( set([ ent.key() for ent in subscribers_entities if ent.automatic_task_subscription ])) # create the new task logging.info('Creating new task with fields: %s', task) task_entity = GCITask(**task) task_entity.put() task_quota = task_quota - 1 except DeadlineExceededError: # time to bail out break if len(tasks) == 0: # send out a message notifications.sendBulkCreationCompleted(bulk_data) bulk_data.delete() else: # there is still work to be done, do a non 500 response and requeue task_params = {'bulk_create_key': bulk_data.key()} new_task = taskqueue.Task(params=task_params, url=BULK_CREATE_URL) # add to the gci queue new_task.add(queue_name='gci-update') # we're done here return http.HttpResponse('OK')
def seed(request, *args, **kwargs): """Seeds the datastore with some default values. """ site_properties = { 'key_name': 'site', 'latest_gsoc': 'google/gsoc2014', 'latest_gci': 'google/gci2013', } site = Site(**site_properties) site.put() account = accounts.getCurrentAccount() if not account: account = users.User(email='*****@*****.**') user_properties = { 'id': 'test', 'account_id': account.user_id(), 'account': account, } current_user = user.User(**user_properties) current_user.put() group_properties = { 'key_name': 'google', 'link_id': 'google', 'name': 'Google Inc.', 'short_name': 'Google', 'home_page': 'http://www.google.com', 'email': '*****@*****.**', 'description': 'This is the profile for Google.', 'contact_street': 'Some Street', 'contact_city': 'Some City', 'contact_country': 'United States', 'contact_postalcode': '12345', 'phone': '15551110000', 'status': 'active', } google = Sponsor(**group_properties) google.put() now = datetime.datetime.now() before = now - datetime.timedelta(365) after = now + datetime.timedelta(365) past_before = before - datetime.timedelta(2 * 365) past_after = after - datetime.timedelta(2 * 365) timeline_properties = { 'key_name': 'google/gsoc2014', 'link_id': 'gsoc2014', 'scope': google, 'program_start': before, 'program_end': after, 'accepted_organization_announced_deadline': before, 'accepted_students_announced_deadline': after, 'student_signup_start': before, 'student_signup_end': after, 'application_review_deadline': after, 'student_application_matched_deadline': after, 'accepted_students_announced_deadline': after, 'form_submission_start': before, } gsoc2014_timeline = GSoCTimeline(**timeline_properties) gsoc2014_timeline.put() program_properties = { 'key_name': 'google/gsoc2014', 'link_id': 'gsoc2014', 'program_id': 'gsoc2014', 'sponsor': google, 'scope': google, 'name': 'Google Summer of Code 2014', 'short_name': 'GSoC 2014', 'description': 'This is the program for GSoC 2014.', 'apps_tasks_limit': 42, 'slots': 42, 'timeline': gsoc2014_timeline, 'status': program_model.STATUS_VISIBLE, } gsoc2014 = GSoCProgram(**program_properties) gsoc2014.put() timeline_properties.update({ 'key_name': 'google/gsoc2010', 'link_id': 'gsoc2010', 'program_start': past_before, 'program_end': past_after, 'accepted_organization_announced_deadline': past_before, 'accepted_students_announced_deadline': past_after, 'student_signup_start': past_before, 'student_signup_end': past_after, 'application_review_deadline': past_after, 'student_application_matched_deadline': past_after, 'accepted_students_announced_deadline': past_after, 'form_submission_start': past_before, }) gsoc2010_timeline = GSoCTimeline(**timeline_properties) gsoc2010_timeline.put() program_properties.update({ 'key_name': 'google/gsoc2010', 'link_id': 'gsoc2010', 'program_id': 'gsoc2010', 'name': 'Google Summer of Code 2010', 'description': 'This is the program for GSoC 2010.', 'short_name': 'GSoC 2010', 'timeline': gsoc2010_timeline, }) gsoc2010 = GSoCProgram(**program_properties) gsoc2010.put() # TODO(drew): Replace gsoc2014.prefix with whatever its replacement becomes # once prefix is removed from program and no longer used in the query for # OrgAppSurvey in soc.views.helper.RequestData._getProgramWideFields(). org_app_survey_properties = { 'key_name': '%s/%s/orgapp' % (gsoc2014.prefix, gsoc2014.key().name()), 'program': gsoc2014, 'title': 'Org App Survey', 'content': 'Here is some content.', 'modified_by': current_user.key.to_old_key(), 'survey_start': before, 'survey_end': after } org_app_survey_model.OrgAppSurvey(**org_app_survey_properties).put() org_app_survey_properties['key_name'] = ( '%s/%s/orgapp' % (gsoc2010.prefix, gsoc2010.key().name())) org_app_survey_properties['program'] = gsoc2010 org_app_survey_properties['survey_start'] = past_before org_app_survey_properties['survey_end'] = past_after org_app_survey_model.OrgAppSurvey(**org_app_survey_properties).put() timeline_properties = { 'key_name': 'google/gci2013', 'link_id': 'gci2013', 'scope': google, 'program_start': before, 'program_end': after, 'accepted_organization_announced_deadline': before, 'student_signup_start': before, 'student_signup_end': after, 'tasks_publicly_visible': before, 'task_claim_deadline': after, 'stop_all_work_deadline': after, } gci2013_timeline = GCITimeline(**timeline_properties) gci2013_timeline.put() program_properties.update({ 'key_name': 'google/gci2013', 'link_id': 'gci2013', 'program_id': 'gci2013', 'name': 'Google Code In Contest 2013', 'short_name': 'GCI 2009', 'description': 'This is the program for GCI 2013.', 'timeline': gci2013_timeline, }) gci2013 = GCIProgram(**program_properties) gci2013.put() site.active_program = gci2013 site.put() current_user.host_for = [ ndb.Key.from_old_key(gsoc2010.key()), ndb.Key.from_old_key(gsoc2014.key()), ndb.Key.from_old_key(gci2013.key()) ] current_user.put() group_properties.update({ 'key_name': 'google/gci2013/melange', 'link_id': 'melange', 'name': 'Melange Development Team', 'short_name': 'Melange', 'scope': gci2013, 'program': gci2013, 'sponsor': google, 'home_page': 'http://code.google.com/p/soc', 'description': 'Melange, share the love!', 'license_name': 'Apache License', 'ideas': 'http://code.google.com/p/soc/issues', }) melange = GCIOrganization(**group_properties) melange.put() group_properties.update({ 'scope': gsoc2014, 'program': gsoc2014, }) address_properties = address.Address(street='1 Test St.', city='Some City', country='United States', postal_code='12345') address_properties.put() contact_info = contact.Contact(email='*****@*****.**') contact_info.put() gsoc_delta = datetime.timedelta(days=(365 * 18)) profile_properties = { 'id': gsoc2014.key().name() + '/' + current_user.key.id(), 'parent': current_user.key, 'public_name': 'test', 'program': ndb.Key.from_old_key(gsoc2014.key()), 'first_name': 'Test', 'last_name': 'Example', 'contact': contact_info, 'residential_address': address_properties, 'shipping_address': address_properties, 'birth_date': datetime.date.today() - gsoc_delta, 'program_knowledge': 'Friend referral', } profile = profile_model.Profile(**profile_properties) ndb_orgs = [] for i in range(15): group_properties.update({ 'key_name': 'google/gsoc2014/org_%d' % i, 'link_id': 'org_%d' % i, 'name': 'Organization %d' % i, 'short_name': 'Org %d' % i, 'description': 'Organization %d!' % i, }) org_properties = { 'name': 'Organization %d' % i, 'org_id': 'org_%d' % i, 'program': ndb.Key.from_old_key(gsoc2014.key()), 'description': 'Organization %d!' % i, } org = soc_org_model.SOCOrganization(id='google/gsoc2014/org_%d' % i, **org_properties) org.put() ndb_orgs.append(org) # Admin (and thus mentor) for the first org if i == 0: profile.admin_for.append(org.key) profile.mentor_for.append(org.key) profile.put() # Mentor for the second org if i == 1: profile.mentor_for.append(org.key) profile.put() profile_properties.update({ 'id': gci2013.key().name() + '/' + current_user.key.id(), 'parent': current_user.key, 'program': ndb.Key.from_old_key(gci2013.key()), 'admin_for': [ndb.Key.from_old_key(melange.key())], 'mentor_for': [ndb.Key.from_old_key(melange.key())], }) melange_admin = profile_model.Profile(**profile_properties) # TODO: add GCI orgs melange_admin.put() task_properties = { 'status': 'Open', 'modified_by': melange_admin.key.to_old_key(), 'subscribers': [melange_admin.key.to_old_key()], 'title': 'Awesomeness', 'created_by': melange_admin.key.to_old_key(), 'created_on': now, 'program': gci2013, 'time_to_complete': 1337, 'modified_on': now, 'org': melange.key(), 'description': '<p>AWESOME</p>', 'difficulty_level': DifficultyLevel.MEDIUM, 'types': ['Code'] } gci_task = GCITask(**task_properties) gci_task.put() user_properties = { 'id': 'student', 'account_id': '12345', 'account': users.User(email='*****@*****.**'), } student_user = user.User(**user_properties) student_user.put() gci_delta = datetime.timedelta(days=(365 * 14)) contact_properties = contact.Contact(email='*****@*****.**', web_page='http://www.homepage.com/', blog='http://www.blog.com/', phone='1650253000') contact_properties.put() graduation_year = datetime.date.today() + datetime.timedelta(days=365) student_data = soc_profile.SOCStudentData(education=education.Education( school_id="123", school_country="United States", expected_graduation=int(graduation_year.strftime('%Y')), major='Some Major', degree=education.Degree.UNDERGRADUATE)) student_data.put() student_id = 'student' student_properties = { 'id': gsoc2014.key().name() + "/" + student_id, 'parent': student_user.key, 'program': ndb.Key.from_old_key(gsoc2014.key()), 'public_name': 'Student', 'first_name': 'Student', 'last_name': 'Student', 'contact': contact_properties, 'residential_address': address_properties, 'shipping_address': address_properties, 'birth_date': datetime.date.today() - gci_delta, 'tee_size': profile_model.TeeSize.L, 'tee_style': profile_model.TeeStyle.MALE, 'gender': profile_model.Gender.MALE, 'program_knowledge': 'Friend referral.', 'student_data': student_data, } melange_student = profile_model.Profile(**student_properties) melange_student.put() student_id = 'student2' user_properties = { 'id': student_id, 'account_id': 'student2', 'account': users.User(email='*****@*****.**'), } student_user2 = user.User(**user_properties) student_user2.put() student_properties.update({ 'id': gsoc2014.key().name() + "/" + student_id, 'parent': student_user2.key, 'first_name': 'Student 2', 'last_name': 'Example' }) melange_student2 = profile_model.Profile(**student_properties) melange_student2.put() proposal_properties = { 'parent': melange_student.key.to_old_key(), 'program': gsoc2014, 'title': 'test proposal', 'abstract': 'test abstract', 'content': 'test content', 'mentor': profile.key.to_old_key(), 'status': 'accepted', 'has_mentor': True, 'org': ndb_orgs[0].key.to_old_key(), 'possible_mentors': [profile.key.to_old_key()] } melange_proposal = GSoCProposal(**proposal_properties) melange_proposal.put() project_properties = { 'title': 'test project', 'abstract': 'test abstract', 'status': 'accepted', 'parent': melange_student.key.to_old_key(), 'mentors': [profile.key.to_old_key()], 'program': gsoc2014, 'org': ndb_orgs[0].key.to_old_key(), 'proposal': melange_proposal.key(), } melange_project = GSoCProject(**project_properties) melange_project.put() ndb_orgs[1].slot_allocation = 1 ndb_orgs[1].put() student_data.number_of_projects = 1 student_data.number_of_proposals = 1 student_data.project_for_orgs = [ndb_orgs[1].key] melange_student.put() melange_student2.put() project_properties.update({ 'student': melange_student2, 'title': 'test project2' }) melange_project2 = GSoCProject(**project_properties) melange_project2.put() ndb_orgs[1].slot_allocation += 1 ndb_orgs[1].put() student_id = 'student' student_properties.update({ 'id': gci2013.key().name() + '/' + student_id, 'parent': student_user.key, 'program': ndb.Key.from_old_key(gci2013.key()), }) gci_student = profile_model.Profile(**student_properties) gci_student.put() score_properties = { 'parent': gci_student.key.to_old_key(), 'program': gci2013, 'points': 5, 'tasks': [gci_task.key()] } score = GCIScore(**score_properties) score.put() document_properties = { 'key_name': 'site/site/home', 'link_id': 'home', 'scope': site, 'prefix': 'site', 'author': current_user.key.to_old_key(), 'title': 'Home Page', 'content': 'This is the Home Page', 'modified_by': current_user.key.to_old_key(), } home_document = Document(**document_properties) home_document.put() document_properties = { 'key_name': 'user/test/notes', 'link_id': 'notes', 'scope': current_user.key.to_old_key(), 'prefix': 'user', 'author': current_user.key.to_old_key(), 'title': 'My Notes', 'content': 'These are my notes', 'modified_by': current_user.key.to_old_key(), } notes_document = Document(**document_properties) notes_document.put() site.home = home_document site.put() memcache.flush_all() return http.HttpResponse('Done')