def testCalculateThroughPostWithCorrectXsrfToken(self):
    """Tests that duplicate proposals can be calculated with correct XSRF token.

    Through HTTP POST with correct XSRF token, the duplicate
    proposals in a given program for a student can be calculated on a per
    organization basis and a new taskqueue is spawned if there are more than
    one organization after the org_cursor.
    """
    pds = pd_logic.getForFields({'program': self.program})
    self.assertEqual(len(pds), 0)
    fields = {'scope': self.program,
              'slots >': 0,
              'status': 'active'}
    # Get an organization and save the cursor
    q = gsoc_organization_logic.getQueryForFields(fields)
    orgs = q.fetch(1)
    org_cursor = q.cursor()
    url = '/tasks/gsoc/proposal_duplicates/calculate'
    postdata = {'program_key': self.program.key().name(),
        'org_cursor': unicode(org_cursor)}
    xsrf_token = self.getXsrfToken(url, data=postdata)
    postdata.update(xsrf_token=xsrf_token)
    response = self.client.post(url, postdata)
    self.assertEqual(response.status_code, httplib.OK)
    pds = pd_logic.getForFields({'program': self.program})
    self.assertEqual(len(pds), 1)
    self.assertTrue(pds[0].is_duplicate)
    task_url = '/tasks/gsoc/proposal_duplicates/calculate'
    self.assertTasksInQueue(n=1, url=task_url)
  def testCalculateFinishedThroughPostWithCorrectXsrfToken(self):
    """Tests the result after calculating duplicate proposals is finished.

    Through HTTP POST with correct XSRF token, when finished
    (there is no org to calculate), all pb records with no duplicate proposals
    are deleted and there is no taskqueue spawned.
    """
    pd_fields  = {
        'program': self.program,
        'student': self.student,
        'orgs':[self.organization.key()],
        'duplicates': [self.student_proposal.key()],
        'is_duplicate': False
        }
    pd_logic.updateOrCreateFromFields(pd_fields)
    pds = pd_logic.getForFields({'program': self.program})
    self.assertEqual(len(pds), 1)
    fields = {'scope': self.program,
              'slots >': 0,
              'status': 'active'}
    # Get all organizations and save the cursor
    q = gsoc_organization_logic.getQueryForFields(fields)
    q.fetch(3)
    org_cursor = q.cursor()
    url = '/tasks/gsoc/proposal_duplicates/calculate'
    postdata = {'program_key': self.program.key().name(),
        'org_cursor': unicode(org_cursor)}
    xsrf_token = self.getXsrfToken(url, data=postdata)
    postdata.update(xsrf_token=xsrf_token)
    response = self.client.post(url, postdata)
    self.assertEqual(response.status_code, httplib.OK)
    pds = pd_logic.getForFields({'program': self.program})
    self.assertEqual(len(pds), 0)
    task_url = '/tasks/gsoc/proposal_duplicates/calculate'
    self.assertTasksInQueue(n=0, url=task_url)
Пример #3
0
    def testCalculateFinishedThroughPostWithCorrectXsrfToken(self):
        """Tests the result after calculating duplicate proposals is finished.

    Through HTTP POST with correct XSRF token, when finished
    (there is no org to calculate), all pb records with no duplicate proposals
    are deleted and there is no taskqueue spawned.
    """
        pd_fields = {
            'program': self.program,
            'student': self.student,
            'orgs': [self.organization.key()],
            'duplicates': [self.student_proposal.key()],
            'is_duplicate': False
        }
        pd_logic.updateOrCreateFromFields(pd_fields)
        pds = pd_logic.getForFields({'program': self.program})
        self.assertEqual(len(pds), 1)
        fields = {'scope': self.program, 'slots >': 0, 'status': 'active'}
        # Get all organizations and save the cursor
        q = gsoc_organization_logic.getQueryForFields(fields)
        q.fetch(3)
        org_cursor = q.cursor()
        url = '/tasks/gsoc/proposal_duplicates/calculate'
        postdata = {
            'program_key': self.program.key().name(),
            'org_cursor': unicode(org_cursor)
        }
        xsrf_token = self.getXsrfToken(url, data=postdata)
        postdata.update(xsrf_token=xsrf_token)
        response = self.client.post(url, postdata)
        self.assertEqual(response.status_code, httplib.OK)
        pds = pd_logic.getForFields({'program': self.program})
        self.assertEqual(len(pds), 0)
        task_url = '/tasks/gsoc/proposal_duplicates/calculate'
        self.assertTasksInQueue(n=0, url=task_url)
Пример #4
0
    def testCalculateThroughPostWithCorrectXsrfToken(self):
        """Tests that duplicate proposals can be calculated with correct XSRF token.

    Through HTTP POST with correct XSRF token, the duplicate
    proposals in a given program for a student can be calculated on a per
    organization basis and a new taskqueue is spawned if there are more than
    one organization after the org_cursor.
    """
        pds = pd_logic.getForFields({'program': self.program})
        self.assertEqual(len(pds), 0)
        fields = {'scope': self.program, 'slots >': 0, 'status': 'active'}
        # Get an organization and save the cursor
        q = gsoc_organization_logic.getQueryForFields(fields)
        orgs = q.fetch(1)
        org_cursor = q.cursor()
        url = '/tasks/gsoc/proposal_duplicates/calculate'
        postdata = {
            'program_key': self.program.key().name(),
            'org_cursor': unicode(org_cursor)
        }
        xsrf_token = self.getXsrfToken(url, data=postdata)
        postdata.update(xsrf_token=xsrf_token)
        response = self.client.post(url, postdata)
        self.assertEqual(response.status_code, httplib.OK)
        pds = pd_logic.getForFields({'program': self.program})
        self.assertEqual(len(pds), 1)
        self.assertTrue(pds[0].is_duplicate)
        task_url = '/tasks/gsoc/proposal_duplicates/calculate'
        self.assertTasksInQueue(n=1, url=task_url)
Пример #5
0
    def showDuplicates(self,
                       request,
                       access_type,
                       page_name=None,
                       params=None,
                       **kwargs):
        """View in which a host can see which students have been assigned
       multiple slots.

    For params see base.view.Public().
    """

        from google.appengine.api import taskqueue

        from soc.modules.gsoc.logic.models.proposal_duplicates import logic \
            as duplicates_logic
        from soc.modules.gsoc.logic.models.proposal_duplicates_status import \
            logic as ds_logic

        program_entity = program_logic.getFromKeyFieldsOr404(kwargs)

        context = helper.responses.getUniversalContext(request)
        helper.responses.useJavaScript(context, params['js_uses_all'])
        context['page_name'] = page_name

        fields = {'program': program_entity, 'is_duplicate': True}

        template = 'modules/gsoc/program/show_duplicates.html'

        context['duplicates'] = duplicates_logic.getForFields(fields)
        duplicates_status = ds_logic.getOrCreateForProgram(program_entity)
        context['duplicates_status'] = duplicates_status

        if request.POST:
            post_data = request.POST

            # pass along these params as POST to the new task
            task_params = {'program_key': program_entity.key().id_or_name()}
            task_url = '/tasks/gsoc/proposal_duplicates/start'

            # checks if the task newly added is the first task
            # and must be performed repeatedly every hour or
            # just be performed once right away
            if 'calculate' in post_data:
                task_params['repeat'] = 'yes'
            elif 'recalculate' in post_data:
                task_params['repeat'] = 'no'

            # adds a new task
            new_task = taskqueue.Task(params=task_params, url=task_url)
            new_task.add()

        return helper.responses.respond(request,
                                        template=template,
                                        context=context)
Пример #6
0
  def showDuplicates(self, request, access_type, page_name=None,
                     params=None, **kwargs):
    """View in which a host can see which students have been assigned
       multiple slots.

    For params see base.view.Public().
    """

    from google.appengine.api import taskqueue

    from soc.modules.gsoc.logic.models.proposal_duplicates import logic \
        as duplicates_logic
    from soc.modules.gsoc.logic.models.proposal_duplicates_status import \
        logic as ds_logic

    program_entity = program_logic.getFromKeyFieldsOr404(kwargs)

    context = helper.responses.getUniversalContext(request)
    helper.responses.useJavaScript(context, params['js_uses_all'])
    context['page_name'] = page_name

    fields = {'program': program_entity,
              'is_duplicate': True}

    template = 'modules/gsoc/program/show_duplicates.html'

    context['duplicates'] = duplicates_logic.getForFields(fields)
    duplicates_status = ds_logic.getOrCreateForProgram(program_entity)
    context['duplicates_status'] = duplicates_status

    if request.POST:
      post_data = request.POST

      # pass along these params as POST to the new task
      task_params = {'program_key': program_entity.key().id_or_name()}
      task_url = '/tasks/gsoc/proposal_duplicates/start'

      # checks if the task newly added is the first task
      # and must be performed repeatedly every hour or
      # just be performed once right away
      if 'calculate' in post_data:
        task_params['repeat'] = 'yes'
      elif 'recalculate' in post_data:
        task_params['repeat'] = 'no'

      # adds a new task
      new_task = taskqueue.Task(params=task_params, url=task_url)
      new_task.add()

    return helper.responses.respond(request, template=template,
                                    context=context)
Пример #7
0
  def _getDefaultReviewContext(self, entity, org_admin,
                               mentor):
    """Returns the default context for the review page.

    Args:
      entity: Student Proposal entity
      org_admin: org admin entity for the current user/proposal (iff available)
      mentor: mentor entity for the current user/proposal (iff available)
    """

    from soc.modules.gsoc.logic.models.proposal_duplicates import logic \
        as duplicates_logic
    from soc.modules.gsoc.logic.models.review_follower import logic as \
        review_follower_logic

    context = {}

    context['student'] = entity.scope
    context['student_name'] = entity.scope.name()

    if entity.mentor:
      context['mentor_name'] = entity.mentor.name()
    else:
      context['mentor_name'] = "No mentor assigned"

    # set the possible mentors in the context
    possible_mentors = entity.possible_mentors

    if not possible_mentors:
      context['possible_mentors'] = "None"
    else:
      mentor_names = []

      for mentor_key in possible_mentors:
        possible_mentor = mentor_logic.logic.getFromKeyName(
            mentor_key.id_or_name())
        mentor_names.append(possible_mentor.name())

      context['possible_mentors'] = ', '.join(mentor_names)

    # update the reviews context
    self._updateReviewsContext(context, entity)

    # update the scores context
    self._updateScoresContext(context, entity)

    if mentor:
      context['is_mentor'] = True
      if not entity.mentor or entity.mentor.key() != mentor.key():
        # which button to (un)propose yourself as mentor should we show
        if mentor.key() in possible_mentors:
          # show "No longer willing to mentor"
          context['remove_me_as_mentor'] = True
        else:
          # show "I am willing to mentor"
          context['add_me_as_mentor'] = True

    if org_admin:
      context['is_org_admin'] = True

      # when the duplicates can be visible obtain the
      # duplicates for this proposal
      if entity.program.duplicates_visible:
        fields = {'student': entity.scope,
                      'is_duplicate': True}

        duplicate_entity = duplicates_logic.getForFields(fields, unique=True)

        if duplicate_entity:
          # this list also contains the current proposal
          # entity, so remove it
          duplicate_keys = duplicate_entity.duplicates
          duplicate_keys.remove(entity.key())
          context['sp_duplicates'] = db.get(duplicate_keys)

    user_entity = user_logic.logic.getCurrentUser()

    # check if the current user is subscribed to public or private reviews
    fields = {'scope': entity,
              'user': user_entity,}
    follower_entity = review_follower_logic.getForFields(fields, unique=True)

    if follower_entity:
      # pylint: disable=E1103
      context['is_subscribed'] =  follower_entity.subscribed_public

    return context
Пример #8
0
def calculate(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
  """

    from soc.modules.gsoc.logic.models.student_proposal import logic \
        as sp_logic

    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 = program_logic.getFromKeyName(program_key)
    if not program_entity:
        # invalid program specified, log and return OK
        return error_handler.logErrorAndReturnOK(
            'Invalid program specified: %s' % program_key)

    fields = {'scope': program_entity, 'slots >': 0, 'status': 'active'}

    # get the organization and update the cursor if possible
    q = org_logic.getQueryForFields(fields)

    # 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)

    result = q.fetch(1)
    # update the cursor
    org_cursor = q.cursor()

    if result:
        org_entity = result[0]

        # get all the proposals likely to be accepted in the program
        accepted_proposals = sp_logic.getProposalsToBeAcceptedForOrg(
            org_entity)

        for ap in accepted_proposals:
            student_entity = ap.scope
            proposal_duplicate = pd_logic.getForFields(
                {'student': student_entity}, unique=True)
            if proposal_duplicate and ap.key(
            ) not in proposal_duplicate.duplicates:
                # non-counted (to-be) accepted proposal found
                pd_fields = {
                    'duplicates': proposal_duplicate.duplicates + [ap.key()],
                }
                pd_fields['is_duplicate'] = len(pd_fields['duplicates']) >= 2
                if org_entity.key() not in proposal_duplicate.orgs:
                    pd_fields['orgs'] = proposal_duplicate.orgs + [
                        org_entity.key()
                    ]

                proposal_duplicate = pd_logic.updateEntityProperties(
                    proposal_duplicate, pd_fields)
            else:
                pd_fields = {
                    'program': program_entity,
                    'student': student_entity,
                    'orgs': [org_entity.key()],
                    'duplicates': [ap.key()],
                    'is_duplicate': False
                }
                proposal_duplicate = pd_logic.updateOrCreateFromFields(
                    pd_fields)

        # 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.
        pd_logic.deleteAllForProgram(program_entity, non_dupes_only=True)

        # update the proposal duplicate status and its timestamp
        pds_entity = pds_logic.getOrCreateForProgram(program_entity)
        new_fields = {
            'status': 'idle',
            'calculated_on': datetime.datetime.now()
        }
        pds_logic.updateEntityProperties(pds_entity, new_fields)

    # return OK
    return http.HttpResponse()
Пример #9
0
    def getListProposalsData(self, request, params_collection, org_entity):
        """Returns the list data for listProposals.

    Args:
      request: HTTPRequest object
      params_collection: List of list Params indexed with the idx of the list
      org_entity: GSoCOrganization entity for which the lists are generated
    """

        from soc.modules.gsoc.logic.models.proposal_duplicates import logic \
            as pd_logic
        from soc.modules.gsoc.logic.models.ranker_root import logic \
            as ranker_root_logic

        idx = lists.getListIndex(request)

        # default list settings
        args = []
        visibility = None

        if idx == 0:
            filter = {'org': org_entity, 'status': 'new'}
        elif idx == 1:
            # retrieve the ranker
            fields = {
                'link_id': student_proposal.DEF_RANKER_NAME,
                'scope': org_entity
            }

            ranker_root = ranker_root_logic.getForFields(fields, unique=True)
            ranker = ranker_root_logic.getRootFromEntity(ranker_root)

            status = {}

            program_entity = org_entity.scope

            # only when the program allows allocations
            # we show that proposals are likely to be
            # accepted or rejected
            if program_entity.allocations_visible:
                proposals = sp_logic.getProposalsToBeAcceptedForOrg(org_entity)

                duplicate_proposals = []

                # get all the duplicate entities if duplicates can be shown
                # to the organizations and make a list of all such proposals.
                if program_entity.duplicates_visible:
                    duplicate_properties = {
                        'orgs': org_entity,
                        'is_duplicate': True
                    }
                    duplicates = pd_logic.getForFields(duplicate_properties)

                    for duplicate in duplicates:
                        duplicate_proposals.extend(duplicate.duplicates)

                for proposal in proposals:
                    proposal_key = proposal.key()
                    if proposal.status == 'pending' and proposal_key in duplicate_proposals:
                        status[proposal_key] = """<strong><font color="red">
                Duplicate</font></strong>"""
                    else:
                        status[proposal_key] = """<strong><font color="green">
                Pending acceptance</font><strong>"""

            filter = {
                'org': org_entity,
                'status': ['accepted', 'pending', 'rejected']
            }

            # some extras for the list
            args = [ranker, status]
            visibility = 'review'
        elif idx == 2:
            # check if the current user is a mentor
            user_entity = user_logic.getCurrentUser()

            fields = {
                'user': user_entity,
                'scope': org_entity,
                'status': ['active', 'inactive']
            }
            mentor_entity = mentor_logic.getForFields(fields, unique=True)

            filter = {
                'org': org_entity,
                'mentor': mentor_entity,
                'status': ['pending', 'accepted', 'rejected']
            }
        elif idx == 3:
            filter = {'org': org_entity, 'status': 'invalid'}
        else:
            return lists.getErrorResponse(request, "idx not valid")

        params = params_collection[idx]
        contents = helper.lists.getListData(request,
                                            params,
                                            filter,
                                            visibility=visibility,
                                            args=args)

        return lists.getResponse(request, contents)
Пример #10
0
  def getListProposalsData(self, request, params_collection, org_entity):
    """Returns the list data for listProposals.

    Args:
      request: HTTPRequest object
      params_collection: List of list Params indexed with the idx of the list
      org_entity: GSoCOrganization entity for which the lists are generated
    """

    from soc.modules.gsoc.logic.models.proposal_duplicates import logic \
        as pd_logic
    from soc.modules.gsoc.logic.models.ranker_root import logic \
        as ranker_root_logic

    idx = lists.getListIndex(request)

    # default list settings
    args = []
    visibility = None

    if idx == 0:
      filter = {'org': org_entity,
                'status': 'new'}
    elif idx == 1:
      # retrieve the ranker
      fields = {'link_id': student_proposal.DEF_RANKER_NAME,
                'scope': org_entity}

      ranker_root = ranker_root_logic.getForFields(fields, unique=True)
      ranker = ranker_root_logic.getRootFromEntity(ranker_root)

      status = {}

      program_entity = org_entity.scope

      # only when the program allows allocations
      # we show that proposals are likely to be
      # accepted or rejected
      if program_entity.allocations_visible:
        proposals = sp_logic.getProposalsToBeAcceptedForOrg(org_entity)

        duplicate_proposals = []

        # get all the duplicate entities if duplicates can be shown
        # to the organizations and make a list of all such proposals.
        if program_entity.duplicates_visible:
          duplicate_properties = {
              'orgs': org_entity,
              'is_duplicate': True
              }
          duplicates = pd_logic.getForFields(duplicate_properties)

          for duplicate in duplicates:
            duplicate_proposals.extend(duplicate.duplicates)

        for proposal in proposals:
          proposal_key =  proposal.key()
          if proposal.status == 'pending' and proposal_key in duplicate_proposals:
            status[proposal_key] = """<strong><font color="red">
                Duplicate</font></strong>"""
          else:
            status[proposal_key] = """<strong><font color="green">
                Pending acceptance</font><strong>"""

      filter = {'org': org_entity,
                'status': ['accepted','pending','rejected']}

      # some extras for the list
      args = [ranker, status]
      visibility = 'review'
    elif idx == 2:
      # check if the current user is a mentor
      user_entity = user_logic.getCurrentUser()

      fields = {'user': user_entity,
                'scope': org_entity,
                'status': ['active', 'inactive']}
      mentor_entity = mentor_logic.getForFields(fields, unique=True)

      filter = {'org': org_entity,
                'mentor': mentor_entity,
                'status': ['pending', 'accepted', 'rejected']}
    elif idx == 3:
      filter = {'org': org_entity,
                'status': 'invalid'}
    else:
      return lists.getErrorResponse(request, "idx not valid")

    params = params_collection[idx]
    contents = helper.lists.getListData(request, params, filter,
                                        visibility=visibility, args=args)

    return lists.getResponse(request, contents)
Пример #11
0
    def showDuplicates(self,
                       request,
                       access_type,
                       page_name=None,
                       params=None,
                       **kwargs):
        """View in which a host can see which students have been assigned
       multiple slots.

    For params see base.view.Public().
    """

        from django.utils import simplejson

        from soc.modules.gsoc.logic.models.proposal_duplicates import logic as duplicates_logic

        program_entity = program_logic.getFromKeyFieldsOr404(kwargs)

        if request.POST and request.POST.get('result'):
            # store result in the datastore
            fields = {
                'link_id': program_entity.link_id,
                'scope': program_entity,
                'scope_path': program_entity.key().id_or_name(),
                'json_representation': request.POST['result']
            }
            key_name = duplicates_logic.getKeyNameFromFields(fields)
            duplicates_logic.updateOrCreateFromKeyName(fields, key_name)

            response = simplejson.dumps({'status': 'done'})
            return http.HttpResponse(response)

        context = helper.responses.getUniversalContext(request)
        helper.responses.useJavaScript(context, params['js_uses_all'])
        context['uses_duplicates'] = True
        context['uses_json'] = True
        context['page_name'] = page_name

        # get all orgs for this program who are active and have slots assigned
        fields = {'scope': program_entity, 'slots >': 0, 'status': 'active'}

        query = org_logic.logic.getQueryForFields(fields)

        to_json = {
            'nr_of_orgs': query.count(),
            'program_key': program_entity.key().id_or_name()
        }
        json = simplejson.dumps(to_json)
        context['info'] = json
        context['offset_length'] = 10

        fields = {'link_id': program_entity.link_id, 'scope': program_entity}
        duplicates = duplicates_logic.getForFields(fields, unique=True)

        if duplicates:
            # we have stored information
            # pylint: disable-msg=E1103
            context['duplicate_cache_content'] = duplicates.json_representation
            context['date_of_calculation'] = duplicates.calculated_on
        else:
            # no information stored
            context['duplicate_cache_content'] = simplejson.dumps({})

        template = 'soc/program/show_duplicates.html'

        return helper.responses.respond(request,
                                        template=template,
                                        context=context)
Пример #12
0
def calculate(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
  """

  from soc.modules.gsoc.logic.models.student_proposal import logic \
      as sp_logic

  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 = program_logic.getFromKeyName(program_key)
  if not program_entity:
    # invalid program specified, log and return OK
    return error_handler.logErrorAndReturnOK(
        'Invalid program specified: %s' % program_key)

  fields = {'scope': program_entity,
            'slots >': 0,
            'status': 'active'}

  # get the organization and update the cursor if possible
  q = org_logic.getQueryForFields(fields)

  # 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)

  result = q.fetch(1)
  # update the cursor
  org_cursor = q.cursor()

  if result:
    org_entity = result[0]

    # get all the proposals likely to be accepted in the program
    accepted_proposals = sp_logic.getProposalsToBeAcceptedForOrg(org_entity)

    for ap in accepted_proposals:
      student_entity = ap.scope
      proposal_duplicate = pd_logic.getForFields({'student': student_entity},
                                                 unique=True)
      if proposal_duplicate and ap.key() not in proposal_duplicate.duplicates:
        # non-counted (to-be) accepted proposal found
        pd_fields = {
            'duplicates': proposal_duplicate.duplicates + [ap.key()],
            }
        pd_fields['is_duplicate'] = len(pd_fields['duplicates']) >= 2
        if org_entity.key() not in proposal_duplicate.orgs:
          pd_fields['orgs'] = proposal_duplicate.orgs + [org_entity.key()]

        proposal_duplicate = pd_logic.updateEntityProperties(
            proposal_duplicate, pd_fields)
      else:
        pd_fields  = {
            'program': program_entity,
            'student': student_entity,
            'orgs':[org_entity.key()],
            'duplicates': [ap.key()],
            'is_duplicate': False
            }
        proposal_duplicate = pd_logic.updateOrCreateFromFields(pd_fields)

    # 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.
    pd_logic.deleteAllForProgram(program_entity, non_dupes_only=True)

    # update the proposal duplicate status and its timestamp
    pds_entity = pds_logic.getOrCreateForProgram(program_entity)
    new_fields = {'status': 'idle',
                  'calculated_on': datetime.datetime.now()}
    pds_logic.updateEntityProperties(pds_entity, new_fields)

  # return OK
  return http.HttpResponse()