def testDeleteAllForProgram(self): """Tests if all proposal duplicates for a program are deleted. """ #Before deleting. q = GSoCProposalDuplicate.all() q.filter('program', self.program1) q_result = q.fetch(limit=10) actual = [entity.key() for entity in q_result] expected = [entity.key() for entity in self.proposal_duplicates] self.assertEqual(actual, expected) #Delete duplicate proposals for program. duplicate_logic.deleteAllForProgram(self.program1) q = GSoCProposalDuplicate.all() q.filter('program', self.program1) actual = q.fetch(limit=10) expected = [] self.assertEqual(actual, expected) #Test that duplicate proposals for other program were not deleted. expected = [entity.key() for entity in self.other_proposal_duplicates] q = GSoCProposalDuplicate.all() q.filter('program', self.program2) q_result = q.fetch(limit=10) actual = [entity.key() for entity in q_result] self.assertEqual(actual, expected)
def getListData(self): idx = lists.getListIndex(self.data.request) if idx != 0: return None program = self.data.program # Hold all the accepted projects for orgs where this user is a member of accepted = [] # Hold all duplicates for either the entire program or the orgs of the user. duplicates = [] dupQ = GSoCProposalDuplicate.all() dupQ.filter('is_duplicate', True) dupQ.filter('org', self.data.url_ndb_org.key.to_old_key()) dupQ.filter('program', program) accepted.extend( p.key() for p in getProposalsToBeAcceptedForOrg(self.data.url_ndb_org)) duplicate_entities = dupQ.fetch(1000) for dup in duplicate_entities: duplicates.extend(dup.duplicates) q = GSoCProposal.all() q.filter('org', self.data.url_ndb_org.key.to_old_key()) q.filter('program', program) starter = lists.keyStarter # TODO(daniel): enable prefetching from ndb models ('org', 'parent') # prefetcher = lists.ModelPrefetcher(GSoCProposal, [], parent=True) response_builder = lists.RawQueryContentResponseBuilder( self.data.request, self._list_config, q, starter, prefetcher=None) return response_builder.build(accepted, duplicates)
def getListData(self): idx = lists.getListIndex(self.request) if idx != 0: return None org = self.data.organization program = self.data.program # Hold all the accepted projects for orgs where this user is a member of accepted = [] # Hold all duplicates for either the entire program or the orgs of the user. duplicates = [] dupQ = GSoCProposalDuplicate.all() dupQ.filter('is_duplicate', True) dupQ.filter('org', org) dupQ.filter('program', program) accepted.extend([p.key() for p in getProposalsToBeAcceptedForOrg(org)]) duplicate_entities = dupQ.fetch(1000) for dup in duplicate_entities: duplicates.extend(dup.duplicates) q = GSoCProposal.all() q.filter('org', org) q.filter('program', program) starter = lists.keyStarter prefetcher = lists.modelPrefetcher(GSoCProposal, ['org'], parent=True) response_builder = lists.RawQueryContentResponseBuilder( self.request, self._list_config, q, starter, prefetcher=prefetcher) return response_builder.build(accepted, duplicates)
def testCalculateDuplicatesForSingleOrg(self): """Test that calculates properly creates GSoCProposalDuplicate entities for a single organization. """ # skip the initialization step status = duplicates_logic.getOrCreateStatusForProgram(self.gsoc) status.status = 'processing' status.put() post_data = {'program_key': self.gsoc.key().id_or_name()} response = self.post(self.CALCULATE_URL, post_data) # must have enqueued itself again successfully self.assertEqual(response.status_code, httplib.OK) self.assertTasksInQueue(n=1) self.assertTasksInQueue(n=1, url=self.CALCULATE_URL) # the new task should have a query cursor present params = self.get_tasks()[0]['params'] self.assertTrue(params.has_key('org_cursor')) self.assertEqual(params['program_key'], urllib.quote_plus(self.gsoc.key().id_or_name())) # 2 duplicates should have been created since there are 2 students duplicates = GSoCProposalDuplicate.all().fetch(1000) self.assertLength(duplicates, 2) for dup in duplicates: if dup.student.key() == self.student1.key(): self.assertTrue(dup.is_duplicate) else: self.assertFalse(dup.is_duplicate) status = duplicates_logic.getOrCreateStatusForProgram(self.gsoc) self.assertEqual(status.status, 'processing')
def testCalculateFailsWhenMissingProgram(self): """Tests that calculates fails when a Program is not present in the POST data. """ post_data = {} response = self.post(self.CALCULATE_URL, post_data) self.assertEqual(response.status_code, httplib.OK) self.assertTasksInQueue(n=0) self.assertEqual(GSoCProposalDuplicate.all().count(1), 0)
def testDeleteAllForProgramNonDupesOnlyIsTrue(self): """Tests if only those proposals are deleted which have is_duplicate set to false. """ #is_duplicate is set to False by default for all the GSoCProposalDuplicate #entities. So, test if all the entities in program1 are deleted. duplicate_logic.deleteAllForProgram(self.program1, non_dupes_only=True) q = GSoCProposalDuplicate.all() q.filter('program', self.program1) q.filter('is_duplicate', False) q_result = q.fetch(limit=10) expected = [] actual = [entity.key() for entity in q_result] self.assertEqual(actual, expected) #set is_duplicate = True for each of the first 3 students in #self.other_gsoc_students and test if these are not deleted for program2. for i in xrange(3): self.other_proposal_duplicates[i].is_duplicate = True self.other_proposal_duplicates[i].put() duplicate_logic.deleteAllForProgram(self.program2, non_dupes_only=True) q = GSoCProposalDuplicate.all() q.filter('program', self.program2) q.filter('is_duplicate', False) q_result = q.fetch(limit=10) expected = [] actual = [entity.key() for entity in q_result] self.assertEqual(actual, expected) #check if entities with is_duplicate=True are not deleted q = GSoCProposalDuplicate.all() q.filter('program', self.program2) q.filter('is_duplicate', True) q_result = q.fetch(limit=10) expected = [ entity.key() for entity in self.other_proposal_duplicates[:3] ] actual = [entity.key() for entity in q_result] self.assertEqual(actual, expected)
def testDeleteAllForProgramNonDupesOnlyIsTrue(self): """Tests if only those proposals are deleted which have is_duplicate set to false. """ #is_duplicate is set to False by default for all the GSoCProposalDuplicate #entities. So, test if all the entities in program1 are deleted. duplicate_logic.deleteAllForProgram(self.program1, non_dupes_only=True) q = GSoCProposalDuplicate.all() q.filter('program', self.program1) q.filter('is_duplicate', False) q_result = q.fetch(limit=10) expected = [] actual = [entity.key() for entity in q_result] self.assertEqual(actual, expected) #set is_duplicate = True for each of the first 3 students in #self.other_gsoc_students and test if these are not deleted for program2. for i in xrange(3): self.other_proposal_duplicates[i].is_duplicate = True self.other_proposal_duplicates[i].put() duplicate_logic.deleteAllForProgram(self.program2, non_dupes_only=True) q = GSoCProposalDuplicate.all() q.filter('program', self.program2) q.filter('is_duplicate', False) q_result = q.fetch(limit=10) expected = [] actual = [entity.key() for entity in q_result] self.assertEqual(actual, expected) #check if entities with is_duplicate=True are not deleted q = GSoCProposalDuplicate.all() q.filter('program', self.program2) q.filter('is_duplicate', True) q_result = q.fetch(limit=10) expected = [entity.key() for entity in self.other_proposal_duplicates[:3]] actual = [entity.key() for entity in q_result] self.assertEqual(actual, expected)
def testCalculateDuplicatesTerminates(self): """Test that calculates terminates properly after going through all orgs. """ # skip the initialization step status = duplicates_logic.getOrCreateStatusForProgram(self.gsoc) status.status = 'processing' status.put() post_data = {'program_key': self.gsoc.key().id_or_name()} response = self.post(self.CALCULATE_URL, post_data) # must have enqueued itself again successfully self.assertEqual(response.status_code, httplib.OK) self.assertTasksInQueue(n=1) self.assertTasksInQueue(n=1, url=self.CALCULATE_URL) # this data should be used for the second iteration params = self.get_tasks()[0]['params'] for key, value in params.iteritems(): params[key] = urllib.unquote_plus(value) # clean the queue self.clear_task_queue() response = self.post(self.CALCULATE_URL, params) # only 1 org in test data so task should terminate now self.assertEqual(response.status_code, httplib.OK) self.assertTasksInQueue(n=0) # 1 duplicate should be left after task termination duplicates = GSoCProposalDuplicate.all().fetch(1000) self.assertEqual(len(duplicates), 1) dup = duplicates[0] self.assertTrue(dup.is_duplicate) student_key = GSoCProposalDuplicate.student.get_value_for_datastore( dup) self.assertEqual(student_key, self.student1.key.to_old_key()) self.assertEqual(len(dup.duplicates), _FIRST_STUDENT_NUMBER_OF_DUPLICATES) status = duplicates_logic.getOrCreateStatusForProgram(self.program) self.assertEqual(status.status, 'idle')
def context(self, data, check, mutator): """Returns the context for this page.""" program = data.program q = GSoCProposalDuplicate.all() q.filter('program', program) q.filter('is_duplicate', True) duplicates = [Duplicate(data, duplicate) for duplicate in q.fetch(1000)] duplicates_status = duplicates_logic.getOrCreateStatusForProgram(program) context = { 'page_name': 'Duplicates for %s' %program.name, 'duplicates_status': duplicates_status, 'duplicates': duplicates, } return context
def testCalculateDuplicatesTerminates(self): """Test that calculates terminates properly after going through all orgs. """ # skip the initialization step status = duplicates_logic.getOrCreateStatusForProgram(self.gsoc) status.status = 'processing' status.put() post_data = {'program_key': self.gsoc.key().id_or_name()} response = self.post(self.CALCULATE_URL, post_data) # must have enqueued itself again successfully self.assertEqual(response.status_code, httplib.OK) self.assertTasksInQueue(n=1) self.assertTasksInQueue(n=1, url=self.CALCULATE_URL) # this data should be used for the second iteration params = self.get_tasks()[0]['params'] for key, value in params.iteritems(): params[key] = urllib.unquote_plus(value) # clean the queue self.clear_task_queue() response = self.post(self.CALCULATE_URL, params) # only 1 org in test data so task should terminate now self.assertEqual(response.status_code, httplib.OK) self.assertTasksInQueue(n=0) # 1 duplicate should be left after task termination duplicates = GSoCProposalDuplicate.all().fetch(1000) self.assertEqual(len(duplicates), 1) dup = duplicates[0] self.assertTrue(dup.is_duplicate) student_key = GSoCProposalDuplicate.student.get_value_for_datastore(dup) self.assertEqual(student_key, self.student1.key.to_old_key()) self.assertEqual(len(dup.duplicates), _FIRST_STUDENT_NUMBER_OF_DUPLICATES) status = duplicates_logic.getOrCreateStatusForProgram(self.program) self.assertEqual(status.status, 'idle')
def deleteAllForProgram(program_entity, non_dupes_only=False): """Deletes all ProposalDuplicates for a given program. Args: program_entity: Program to delete the ProposalDuplicatesFor non_dupes_only: Iff True removes only the ones which have is_duplicate set to False. False by default. """ q = GSoCProposalDuplicate.all() q.filter('program', program_entity) if non_dupes_only: q.filter('is_duplicate', False) # can not delete more then 500 entities in one call proposal_duplicates = q.fetch(500) while proposal_duplicates: db.delete(proposal_duplicates) proposal_duplicates = q.fetch(500)
def deleteAllForProgram(program_entity, non_dupes_only=False): """Deletes all ProposalDuplicates for a given program. Args: program_entity: Program to delete the ProposalDuplicatesFor non_dupes_only: Iff True removes only the ones which have is_duplicate set to False. False by default. """ q = GSoCProposalDuplicate.all() q.filter("program", program_entity) if non_dupes_only: q.filter("is_duplicate", False) # can not delete more then 500 entities in one call proposal_duplicates = q.fetch(500) while proposal_duplicates: db.delete(proposal_duplicates) proposal_duplicates = q.fetch(500)
def context(self, data, check, mutator): """Returns the context for this page.""" program = data.program q = GSoCProposalDuplicate.all() q.filter('program', program) q.filter('is_duplicate', True) duplicates = [ Duplicate(data, duplicate) for duplicate in q.fetch(1000) ] duplicates_status = duplicates_logic.getOrCreateStatusForProgram( program) context = { 'page_name': 'Duplicates for %s' % program.name, 'duplicates_status': duplicates_status, 'duplicates': duplicates, } return context
def context(self, data, check, mutator): context = {} user_role = None scores = self.getScores(data) # TODO: check if the scoring is not disabled score_action = reverse('score_gsoc_proposal', kwargs=data.kwargs) # get all the comments for the the proposal public_comments, private_comments = self.getComments(data) # TODO: check if it is possible to post a comment comment_action = reverse('comment_gsoc_proposal', kwargs=data.kwargs) if _getApplyingCommentType(data) == PRIVATE_COMMENTS: # only mentors and org admins can see that the proposal is ignored # TODO(daniel): replace status literals with constants context['proposal_ignored'] = data.url_proposal.status == 'ignored' form = PrivateCommentForm(data=data.POST or None) org_key = proposal_model.GSoCProposal.org.get_value_for_datastore( data.url_proposal) if data.orgAdminFor(org_key): user_role = 'org_admin' else: user_role = 'mentor' else: form = CommentForm(data=data.POST or None) comment_box = { 'action': comment_action, 'form': form, } # to keep the blocks as simple as possible, the if branches have # been broken down into several if blocks user_is_proposer = ( data.user and (data.ndb_user.key == data.url_ndb_user.key())) if user_is_proposer: user_role = 'proposer' # we will check if the student is allowed to modify the proposal # after the student proposal deadline is_editable = data.timeline.afterStudentSignupEnd() and \ data.url_proposal.is_editable_post_deadline if data.timeline.studentSignup() or is_editable: context['update_link'] = links.LINKER.userId( data.url_ndb_profile.key(), data.url_proposal.key().id(), 'update_gsoc_proposal') possible_mentors = ndb.get_multi( map(ndb.Key.from_old_key, data.url_proposal.possible_mentors)) possible_mentors = self.sanitizePossibleMentors(data, possible_mentors) possible_mentors_names = ', '.join([ m.public_name for m in possible_mentors]) org_key = proposal_model.GSoCProposal.org.get_value_for_datastore( data.url_proposal) org = ndb.Key.from_old_key(org_key).get() scoring_visible = _getApplyingCommentType(data) == PRIVATE_COMMENTS and ( org.scoring_enabled) if data.orgAdminFor(org_key): scoring_visible = True duplicate = None if (data.program.duplicates_visible and data.orgAdminFor(org_key)): q = GSoCProposalDuplicate.all() q.filter('duplicates', data.url_proposal) q.filter('is_duplicate', True) dup_entity = q.get() duplicate = Duplicate(data, dup_entity) if dup_entity else None additional_info = data.url_proposal.additional_info if user_role: context['user_actions'] = UserActions(data, user_role) mentor_key = proposal_model.GSoCProposal.mentor.get_value_for_datastore( data.url_proposal) mentor = ndb.Key.from_old_key(mentor_key).get() if mentor_key else None context.update({ 'additional_info': url_helper.trim_url_to(additional_info, 50), 'additional_info_link': additional_info, 'comment_box': comment_box, 'duplicate': duplicate, 'max_score': org.max_score, 'mentor': mentor, 'page_name': data.url_proposal.title, 'possible_mentors': possible_mentors_names, 'private_comments': private_comments, 'private_comments_visible': _getApplyingCommentType(data) == PRIVATE_COMMENTS, 'proposal': data.url_proposal, 'public_comments': public_comments, 'public_comments_visible': _getApplyingCommentType(data) == PRIVATE_COMMENTS or _getApplyingCommentType(data) == PUBLIC_COMMENTS, 'score_action': score_action, 'scores': scores, 'scoring_visible': scoring_visible, 'student_email': data.url_ndb_profile.contact.email, 'student_name': data.url_ndb_profile.public_name, 'user_role': user_role, }) return context
def context(self): assert isSet(self.data.public_comments_visible) assert isSet(self.data.private_comments_visible) assert isSet(self.data.url_profile) assert isSet(self.data.url_user) assert isSet(self.data.proposal) context = {} user_role = None scores = self.getScores() # TODO: check if the scoring is not disabled score_action = reverse("score_gsoc_proposal", kwargs=self.data.kwargs) # get all the comments for the the proposal public_comments, private_comments = self.getComments() # TODO: check if it is possible to post a comment comment_action = reverse("comment_gsoc_proposal", kwargs=self.data.kwargs) if self.data.private_comments_visible: form = PrivateCommentForm(self.data.POST or None) if self.data.orgAdminFor(self.data.proposal.org): user_role = "org_admin" else: user_role = "mentor" else: form = CommentForm(self.data.POST or None) comment_box = {"action": comment_action, "form": form} # to keep the blocks as simple as possible, the if branches have # been broken down into several if blocks user_is_proposer = self.data.user and (self.data.user.key() == self.data.url_user.key()) if user_is_proposer: user_role = "proposer" # we will check if the student is allowed to modify the proposal # after the student proposal deadline is_editable = self.data.timeline.afterStudentSignupEnd() and self.data.proposal.is_editable_post_deadline if self.data.timeline.studentSignup() or is_editable: context["update_link"] = self.data.redirect.id().urlOf("update_gsoc_proposal") possible_mentors = db.get(self.data.proposal.possible_mentors) possible_mentors = self.sanitizePossibleMentors(possible_mentors) possible_mentors_names = ", ".join([m.name() for m in possible_mentors]) scoring_visible = self.data.private_comments_visible and (not self.data.proposal_org.scoring_disabled) if self.data.orgAdminFor(self.data.proposal_org): scoring_visible = True duplicate = None if self.data.program.duplicates_visible and self.data.orgAdminFor(self.data.proposal_org): q = GSoCProposalDuplicate.all() q.filter("duplicates", self.data.proposal) q.filter("is_duplicate", True) dup_entity = q.get() duplicate = Duplicate(self.data, dup_entity) if dup_entity else None additional_info = self.data.proposal.additional_info if user_role: context["user_actions"] = UserActions(self.data, user_role) context.update( { "additional_info": url_helper.trim_url_to(additional_info, 50), "additional_info_link": additional_info, "comment_box": comment_box, "duplicate": duplicate, "max_score": self.data.proposal_org.max_score, "mentor": self.data.proposal.mentor, "page_name": self.data.proposal.title, "possible_mentors": possible_mentors_names, "private_comments": private_comments, "private_comments_visible": self.data.private_comments_visible, "proposal": self.data.proposal, "public_comments": public_comments, "public_comments_visible": self.data.public_comments_visible, "score_action": score_action, "scores": scores, "scoring_visible": scoring_visible, "student_email": self.data.url_profile.email, "student_name": self.data.url_profile.name(), "proposal_ignored": self.data.proposal.status == "ignored", "user_role": user_role, } ) return context
def calculate(self, request, *args, **kwargs): """Calculates the duplicate proposals in a given program for a student on a per Organization basis. Expects the following to be present in the POST dict: program_key: Specifies the program key name for which to find the duplicate proposals org_cursor: Specifies the organization datastore cursor from which to start the processing of finding the duplicate proposals Args: request: Django Request object """ post_dict = request.POST program_key = post_dict.get('program_key') if not program_key: # invalid task data, log and return OK return error_handler.logErrorAndReturnOK( 'Invalid program key: %s' % post_dict) program_entity = GSoCProgram.get_by_key_name(program_key) if not program_entity: # invalid program specified, log and return OK return error_handler.logErrorAndReturnOK( 'Invalid program specified: %s' % program_key) # get the organization and update the cursor if possible q = GSoCOrganization.all() q.filter('status', 'active') q.filter('scope', program_entity) q.filter('slots >', 0) # retrieve the org_cursor from POST data org_cursor = post_dict.get('org_cursor') if org_cursor: org_cursor = str(org_cursor) q.with_cursor(org_cursor) org_entity = q.get() # update the cursor org_cursor = q.cursor() if org_entity: # get all the proposals likely to be accepted in the program accepted_proposals = proposal_logic.getProposalsToBeAcceptedForOrg(org_entity) for ap in accepted_proposals: student_entity = ap.parent() q = GSoCProposalDuplicate.all() q.filter('student', student_entity) proposal_duplicate = q.get() if proposal_duplicate and ap.key() not in proposal_duplicate.duplicates: # non-counted (to-be) accepted proposal found proposal_duplicate.duplicates = proposal_duplicate.duplicates + \ [ap.key()] proposal_duplicate.is_duplicate = \ len(proposal_duplicate.duplicates) >= 2 if org_entity.key() not in proposal_duplicate.orgs: proposal_duplicate.orgs = proposal_duplicate.orgs + [org_entity.key()] else: pd_fields = { 'program': program_entity, 'student': student_entity, 'orgs':[org_entity.key()], 'duplicates': [ap.key()], 'is_duplicate': False } proposal_duplicate = GSoCProposalDuplicate(**pd_fields) proposal_duplicate.put() # Adds a new task that performs duplicate calculation for # the next organization. task_params = {'program_key': program_key, 'org_cursor': unicode(org_cursor)} task_url = '/tasks/gsoc/proposal_duplicates/calculate' new_task = taskqueue.Task(params=task_params, url=task_url) new_task.add() else: # There aren't any more organizations to process. So delete # all the proposals for which there are not more than one # proposal for duplicates property. duplicates_logic.deleteAllForProgram(program_entity, non_dupes_only=True) # update the proposal duplicate status and its timestamp pds_entity = duplicates_logic.getOrCreateStatusForProgram(program_entity) pds_entity.status = 'idle' pds_entity.calculated_on = datetime.datetime.now() pds_entity.put() # return OK return http.HttpResponse()
def calculate(self, request, *args, **kwargs): """Calculates the duplicate proposals in a given program for a student on a per Organization basis. Expects the following to be present in the POST dict: program_key: Specifies the program key name for which to find the duplicate proposals org_cursor: Specifies the organization datastore cursor from which to start the processing of finding the duplicate proposals Args: request: Django Request object """ post_dict = request.POST program_key = post_dict.get('program_key') if not program_key: # invalid task data, log and return OK return error_handler.logErrorAndReturnOK( 'Invalid program key: %s' % post_dict) program_entity = GSoCProgram.get_by_key_name(program_key) if not program_entity: # invalid program specified, log and return OK return error_handler.logErrorAndReturnOK( 'Invalid program specified: %s' % program_key) # get the organization and update the cursor if possible query = soc_org_model.SOCOrganization.query( soc_org_model.SOCOrganization.status == org_model.Status.ACCEPTED, soc_org_model.SOCOrganization.program == ndb.Key.from_old_key( program_entity.key()), soc_org_model.SOCOrganization.slot_allocation > 0) # retrieve the org_cursor from POST data org_cursor = post_dict.get('org_cursor') start_cursor = (datastore_query.Cursor( urlsafe=org_cursor) if org_cursor else None) organizations, next_cursor, _ = query.fetch_page( 1, start_cursor=start_cursor) if organizations: organization = organizations[0] # get all the proposals likely to be accepted in the program accepted_proposals = ( proposal_logic.getProposalsToBeAcceptedForOrg(organization)) for accepted_proposal in accepted_proposals: q = GSoCProposalDuplicate.all() q.filter('student', accepted_proposal.parent_key()) proposal_duplicate = q.get() if (proposal_duplicate and accepted_proposal.key() not in proposal_duplicate.duplicates): # non-counted (to-be) accepted proposal found proposal_duplicate.duplicates = proposal_duplicate.duplicates + \ [accepted_proposal.key()] proposal_duplicate.is_duplicate = \ len(proposal_duplicate.duplicates) >= 2 if organization.key.to_old_key( ) not in proposal_duplicate.orgs: proposal_duplicate.orgs = ( proposal_duplicate.orgs + [organization.key.to_old_key()]) else: pd_fields = { 'program': program_entity, 'student': accepted_proposal.parent_key(), 'orgs': [organization.key.to_old_key()], 'duplicates': [accepted_proposal.key()], 'is_duplicate': False } proposal_duplicate = GSoCProposalDuplicate(**pd_fields) proposal_duplicate.put() # Adds a new task that performs duplicate calculation for # the next organization. task_params = { 'program_key': program_key, 'org_cursor': next_cursor.urlsafe() } task_url = '/tasks/gsoc/proposal_duplicates/calculate' new_task = taskqueue.Task(params=task_params, url=task_url) new_task.add() else: # There aren't any more organizations to process. So delete # all the proposals for which there are not more than one # proposal for duplicates property. duplicates_logic.deleteAllForProgram(program_entity, non_dupes_only=True) # update the proposal duplicate status and its timestamp pds_entity = duplicates_logic.getOrCreateStatusForProgram( program_entity) pds_entity.status = 'idle' pds_entity.calculated_on = datetime.datetime.now() pds_entity.put() # return OK return http.HttpResponse()
def calculate(self, request, *args, **kwargs): """Calculates the duplicate proposals in a given program for a student on a per Organization basis. Expects the following to be present in the POST dict: program_key: Specifies the program key name for which to find the duplicate proposals org_cursor: Specifies the organization datastore cursor from which to start the processing of finding the duplicate proposals Args: request: Django Request object """ post_dict = request.POST program_key = post_dict.get('program_key') if not program_key: # invalid task data, log and return OK return error_handler.logErrorAndReturnOK( 'Invalid program key: %s' % post_dict) program_entity = GSoCProgram.get_by_key_name(program_key) if not program_entity: # invalid program specified, log and return OK return error_handler.logErrorAndReturnOK( 'Invalid program specified: %s' % program_key) # get the organization and update the cursor if possible query = soc_org_model.SOCOrganization.query( soc_org_model.SOCOrganization.status == org_model.Status.ACCEPTED, soc_org_model.SOCOrganization.program == ndb.Key.from_old_key(program_entity.key()), soc_org_model.SOCOrganization.slot_allocation > 0) # retrieve the org_cursor from POST data org_cursor = post_dict.get('org_cursor') start_cursor = ( datastore_query.Cursor(urlsafe=org_cursor) if org_cursor else None) organizations, next_cursor, _ = query.fetch_page( 1, start_cursor=start_cursor) if organizations: organization = organizations[0] # get all the proposals likely to be accepted in the program accepted_proposals = ( proposal_logic.getProposalsToBeAcceptedForOrg(organization)) for accepted_proposal in accepted_proposals: q = GSoCProposalDuplicate.all() q.filter('student', accepted_proposal.parent_key()) proposal_duplicate = q.get() if (proposal_duplicate and accepted_proposal.key() not in proposal_duplicate.duplicates): # non-counted (to-be) accepted proposal found proposal_duplicate.duplicates = proposal_duplicate.duplicates + \ [accepted_proposal.key()] proposal_duplicate.is_duplicate = \ len(proposal_duplicate.duplicates) >= 2 if organization.key.to_old_key() not in proposal_duplicate.orgs: proposal_duplicate.orgs = ( proposal_duplicate.orgs + [organization.key.to_old_key()]) else: pd_fields = { 'program': program_entity, 'student': accepted_proposal.parent_key(), 'orgs':[organization.key.to_old_key()], 'duplicates': [accepted_proposal.key()], 'is_duplicate': False } proposal_duplicate = GSoCProposalDuplicate(**pd_fields) proposal_duplicate.put() # Adds a new task that performs duplicate calculation for # the next organization. task_params = { 'program_key': program_key, 'org_cursor': next_cursor.urlsafe() } task_url = '/tasks/gsoc/proposal_duplicates/calculate' new_task = taskqueue.Task(params=task_params, url=task_url) new_task.add() else: # There aren't any more organizations to process. So delete # all the proposals for which there are not more than one # proposal for duplicates property. duplicates_logic.deleteAllForProgram(program_entity, non_dupes_only=True) # update the proposal duplicate status and its timestamp pds_entity = duplicates_logic.getOrCreateStatusForProgram(program_entity) pds_entity.status = 'idle' pds_entity.calculated_on = datetime.datetime.now() pds_entity.put() # return OK return http.HttpResponse()
def context(self, data, check, mutator): context = {} user_role = None scores = self.getScores(data) # TODO: check if the scoring is not disabled score_action = reverse('score_gsoc_proposal', kwargs=data.kwargs) # get all the comments for the the proposal public_comments, private_comments = self.getComments(data) # TODO: check if it is possible to post a comment comment_action = reverse('comment_gsoc_proposal', kwargs=data.kwargs) if _getApplyingCommentType(data) == PRIVATE_COMMENTS: # only mentors and org admins can see that the proposal is ignored # TODO(daniel): replace status literals with constants context['proposal_ignored'] = data.url_proposal.status == 'ignored' form = PrivateCommentForm(data=data.POST or None) org_key = proposal_model.GSoCProposal.org.get_value_for_datastore( data.url_proposal) if data.orgAdminFor(org_key): user_role = 'org_admin' else: user_role = 'mentor' else: form = CommentForm(data=data.POST or None) comment_box = { 'action': comment_action, 'form': form, } # to keep the blocks as simple as possible, the if branches have # been broken down into several if blocks user_is_proposer = (data.user and (data.ndb_user.key == data.url_ndb_user.key())) if user_is_proposer: user_role = 'proposer' # we will check if the student is allowed to modify the proposal # after the student proposal deadline is_editable = data.timeline.afterStudentSignupEnd() and \ data.url_proposal.is_editable_post_deadline if data.timeline.studentSignup() or is_editable: context['update_link'] = links.LINKER.userId( data.url_ndb_profile.key(), data.url_proposal.key().id(), 'update_gsoc_proposal') possible_mentors = ndb.get_multi( map(ndb.Key.from_old_key, data.url_proposal.possible_mentors)) possible_mentors = self.sanitizePossibleMentors(data, possible_mentors) possible_mentors_names = ', '.join( [m.public_name for m in possible_mentors]) org_key = proposal_model.GSoCProposal.org.get_value_for_datastore( data.url_proposal) org = ndb.Key.from_old_key(org_key).get() scoring_visible = _getApplyingCommentType( data) == PRIVATE_COMMENTS and (org.scoring_enabled) if data.orgAdminFor(org_key): scoring_visible = True duplicate = None if (data.program.duplicates_visible and data.orgAdminFor(org_key)): q = GSoCProposalDuplicate.all() q.filter('duplicates', data.url_proposal) q.filter('is_duplicate', True) dup_entity = q.get() duplicate = Duplicate(data, dup_entity) if dup_entity else None additional_info = data.url_proposal.additional_info if user_role: context['user_actions'] = UserActions(data, user_role) mentor_key = proposal_model.GSoCProposal.mentor.get_value_for_datastore( data.url_proposal) mentor = ndb.Key.from_old_key(mentor_key).get() if mentor_key else None context.update({ 'additional_info': url_helper.trim_url_to(additional_info, 50), 'additional_info_link': additional_info, 'comment_box': comment_box, 'duplicate': duplicate, 'max_score': org.max_score, 'mentor': mentor, 'page_name': data.url_proposal.title, 'possible_mentors': possible_mentors_names, 'private_comments': private_comments, 'private_comments_visible': _getApplyingCommentType(data) == PRIVATE_COMMENTS, 'proposal': data.url_proposal, 'public_comments': public_comments, 'public_comments_visible': _getApplyingCommentType(data) == PRIVATE_COMMENTS or _getApplyingCommentType(data) == PUBLIC_COMMENTS, 'score_action': score_action, 'scores': scores, 'scoring_visible': scoring_visible, 'student_email': data.url_ndb_profile.contact.email, 'student_name': data.url_ndb_profile.public_name, 'user_role': user_role, }) return context