def start(request, *args, **kwargs):
    """Starts the task to find all duplicate proposals which are about to be
  accepted for a single GSoCProgram.

  Expects the following to be present in the POST dict:
    program_key: Specifies the program key name for which to find the
                 duplicate proposals
    repeat: Specifies if a new task that must be performed again an hour
            later, with the same POST data

  Args:
    request: Django Request object
  """

    from soc.logic.helper import timeline as timeline_helper

    post_dict = request.POST

    # retrieve the program_key and survey_key from POST data
    program_key = post_dict.get('program_key')
    repeat = post_dict.get('repeat')

    if not (program_key and repeat):
        # invalid task data, log and return OK
        return error_handler.logErrorAndReturnOK('Invalid task data: %s' %
                                                 post_dict)

    # get the program for the given keyname
    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)

    # obtain the proposal duplicate status
    pds_entity = pds_logic.getOrCreateForProgram(program_entity)

    if pds_entity.status == 'idle':
        # delete all old duplicates
        prop_duplicates = pd_logic.deleteAllForProgram(program_entity)

        # pass these data along params as POST to the new task
        task_params = {'program_key': program_key}
        task_url = '/tasks/gsoc/proposal_duplicates/calculate'

        new_task = taskqueue.Task(params=task_params, url=task_url)
        # add a new task that performs duplicate calculation per
        # organization
        new_task.add()

        # update the status of the PDS entity to processing
        fields = {'status': 'processing'}
        pds_logic.updateEntityProperties(pds_entity, fields)

    # Add a new clone of this task that must be performed an hour later because
    # the current task is part of the task that repeatedly runs but repeat
    # it before accepted students are announced only.
    if repeat == 'yes' and timeline_helper.isBeforeEvent(
            program_entity.timeline, 'accepted_students_announced_deadline'):
        # pass along these params as POST to the new task
        task_params = {'program_key': program_key, 'repeat': 'yes'}
        task_url = '/tasks/gsoc/proposal_duplicates/start'

        new_task = taskqueue.Task(params=task_params,
                                  url=task_url,
                                  countdown=3600)
        new_task.add()

    # return OK
    return http.HttpResponse()
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()