Ejemplo n.º 1
0
  def pickSuggestedTags(self, request, access_type,
                        page_name=None, params=None, **kwargs):
    """Returns a JSON representation of a list of organization tags
     that are suggested for a given GSoCProgram in scope.
    """

    if 'scope_path' not in request.GET:
      data = []
    else:
      program = program_logic.getFromKeyName(request.GET.get('scope_path'))
      if not program:
        data = []
      else:
        fun = soc.cache.logic.cache(OrgTag.get_for_custom_query)
        suggested_tags = fun(OrgTag, filter={'scope': program}, order=None)
        # TODO: this should be refactored after the issue with autocompletion
        #       is resolved
        data = simplejson.dumps({
            'data': [{'link_id': item['tag']} for item in [dicts.toDict(tag, ['tag']) for tag in suggested_tags]],
            'autocomplete_options': {
               'multiple': True,
               'selectFirst': False
            }
        })

    return self.json(request, data, False)
Ejemplo n.º 2
0
def runOrgConversionUpdate(request, entities, context, *args, **kwargs):
  """AppEngine Task that converts Organizations into GSoCOrganizations.

  Also updates the RankerRoots that are associated with the Organization.

  Args:
    request: Django Request object
    entities: list of Organization entities to convert
    context: the context of this task
  """

  from soc.modules.gsoc.logic.models.program import logic as gsoc_program_logic
  from soc.modules.gsoc.logic.models.ranker_root import logic as \
      ranker_root_logic
  from soc.modules.gsoc.models.organization import GSoCOrganization

  # get all the properties that are part of each Organization
  org_model = org_logic.getModel()
  org_properties = org_model.properties().keys()

  # use this to store all the new GSoCOrganization
  gsoc_orgs = []
  gsoc_rankers = []

  for entity in entities:
    gsoc_properties = {}

    for org_property in org_properties:
      # copy over all the information from the Organization entity
      gsoc_properties[org_property] = getattr(entity, org_property)

    # get the Program key belonging to the old Organization
    program_key = entity.scope.key().id_or_name()
    # get the new GSoCProgram and set it as scope for the GSoCOrganzation
    gsoc_program = gsoc_program_logic.getFromKeyName(program_key)
    gsoc_properties['scope'] = gsoc_program

    # create the new GSoCOrganization entity and prepare it to be stored
    gsoc_org_entity = GSoCOrganization(key_name=entity.key().name(),
                                       **gsoc_properties)
    gsoc_orgs.append(gsoc_org_entity)

    # retrieve the RankerRoots belonging to the Organization
    fields = {'scope': entity}
    rankers = ranker_root_logic.getForFields(fields)

    for ranker in rankers:
      ranker.scope = gsoc_org_entity
      # append the adjusted ranker
      gsoc_rankers.append(ranker)

  # store all the new GSoCOrganizations
  db.put(gsoc_orgs)
  # store all the new rankers
  db.put(gsoc_rankers)

  # task completed, return
  return
Ejemplo n.º 3
0
def assignSlots(request, *args, **kwargs):
  """Sets the slots attribute for each organization entity

  POST Args:
    slots: an org_key:num_slots JSON dictionary
  """

  # Setup an artifical request deadline
  timelimit = int(request.REQUEST.get("timelimit", 20000))
  timekeeper = Timekeeper(timelimit)

  program_key = request.REQUEST.get("programkey")
  last_key = request.REQUEST.get("lastkey", "")
  program = program_logic.getFromKeyName(program_key)

  # Copy for modification below
  params = request.POST.copy()
  params["timelimit"] = timelimit

  # Parse the JSON org:slots dictionary
  slots = simplejson.loads(program.slots_allocation)
  org_keys = [i for i in sorted(slots.keys()) if i > last_key]
  logging.info(org_keys)

  # Assign slots for each organization
  try:
    for clock, org_key in timekeeper.iterate(org_keys):
      logging.info("%s %s %s", request.path, clock, org_key)

      org_slots = slots[org_key]
      # Get the organization entity
      org = org_logic.getFromKeyFields({
          'link_id': org_key,
          'scope_path': program_key,
      })

      if not org:
        logging.error("no such org '%s'/'%s'" % (program_key, org_key))
        continue

      # Count proposals and mentors
      org.slots = int(org_slots['slots'])
      org.nr_applications, org.nr_mentors = countProposals(org)

      # Update the organization entity
      org.put()

      # Mark the organization as done
      last_key = org_key

  # Requeue this task for continuation
  except DeadlineExceededError:
    params["lastkey"] = last_key
    taskqueue.add(url=request.path, params=params)

  # Exit this task successfully
  return responses.terminateTask()
Ejemplo n.º 4
0
def _getCommonProperties():
  """Returns properties that are common for all statistic entities.
  """

  program = program_logic.getFromKeyName(program_keyname)

  properties = {
      'access_for_other_programs': 'invisible',
      'scope': program,
      'scope_path': program_keyname,
      }

  return properties
Ejemplo n.º 5
0
def _runOrgRoleConversionUpdate(entities, from_role_logic, to_role_model):
  """AppEngine Task that converts a normal Organization Role into a
  GSoCOrganization Role.

  Args:
    entities: Role entities to convert
    from_role_logic: the Role Logic instance where to convert from
    to_role_model: the role Model class where to convert to
  """

  from soc.modules.gsoc.logic.models.organization import logic as \
      gsoc_org_logic
  from soc.modules.gsoc.logic.models.program import logic as gsoc_program_logic

  # get all the properties that are part of each Organization's Role
  role_model = from_role_logic.getModel()
  role_properties = role_model.properties().keys()

  # use this to store all the new Roles
  gsoc_roles = []

  for entity in entities:
    gsoc_properties = {}

    for role_property in role_properties:
      # copy over all the information from the Role entity
      gsoc_properties[role_property] = getattr(entity, role_property)

    # get the Program key belonging to the old Role
    program_key = entity.program.key().id_or_name()
    # get the new GSoCProgram and set it for the Role
    gsoc_program = gsoc_program_logic.getFromKeyName(program_key)
    gsoc_properties['program'] = gsoc_program

    # get the Organization key belonging to the old Role
    org_key = entity.scope.key().id_or_name()
    # get the new GSoCOrganization and set it as scope for the Role
    gsoc_org = gsoc_org_logic.getFromKeyName(org_key)
    gsoc_properties['scope'] = gsoc_org

    # create the new GSoC Role entity and prepare it to be stored
    gsoc_role_entity = to_role_model(key_name=entity.key().name(),
                                        **gsoc_properties)
    gsoc_roles.append(gsoc_role_entity)

  # store all the new GSoC Roles
  db.put(gsoc_roles)

  # task completed, return
  return
Ejemplo n.º 6
0
def runStudentConversionUpdate(request, entities, context, *args, **kwargs):
  """AppEngine Task that converts Students into GSoCStudents.

  Args:
    request: Django Request object
    entities: list of Student entities to convert
    context: the context of this task
  """

  from soc.modules.gsoc.logic.models.program import logic as gsoc_program_logic
  from soc.modules.gsoc.models.student import GSoCStudent

  # get all the properties that are part of each Student
  student_model = student_logic.getModel()
  student_properties = student_model.properties().keys()

  # use this to store all the new GSoCStudents
  gsoc_students = []

  for entity in entities:
    gsoc_properties = {}

    for student_property in student_properties:
      # copy over all the information from the Student entity
      gsoc_properties[student_property] = getattr(entity, student_property)

    # get the Program key belonging to the old Student
    program_key = entity.scope.key().id_or_name()
    # get the new GSoCProgram and set it as scope for the GSoCStudent
    gsoc_program = gsoc_program_logic.getFromKeyName(program_key)
    gsoc_properties['scope'] = gsoc_program

    # create the new GSoCStudent entity and prepare it to be stored
    gsoc_student_entity = GSoCStudent(key_name=entity.key().name(),
                                      **gsoc_properties)
    gsoc_students.append(gsoc_student_entity)

  # store all the new GSoCStudents
  db.put(gsoc_students)

  # task completed, return
  return
Ejemplo n.º 7
0
def assignProgramSlots(request, *args, **kwargs):
  """Assign slots for organizations within a program

  Gets the slot assignment data as a JSON string from the program
  and enqueues a task to process the slot assignments

  POST Args:
    programkey: the key of the program to operate upon
  """

  program = None
  params = request.REQUEST

  # Query the program entity
  try:
    program = program_logic.getFromKeyName(params["programkey"])
  except KeyError:
    logging.error("programkey not in params")
    return responses.terminateTask()

  if not program:
    logging.error("no such program '%s'" % params["programkey"])
    return responses.terminateTask()

  if not program.slots_allocation:
    logging.error("empty slots_allocation")
    return responses.terminateTask()

  # Enqueue a task to assign the slots
  taskqueue.add(
    url = "/gsoc/tasks/assignslots/assign",
    params = {
        'programkey': params["programkey"],
    })

  # Return successful
  return responses.terminateTask()
Ejemplo n.º 8
0
    def pickSuggestedTags(self,
                          request,
                          access_type,
                          page_name=None,
                          params=None,
                          **kwargs):
        """Returns a JSON representation of a list of organization tags
     that are suggested for a given GSoCProgram in scope.
    """

        if 'scope_path' not in request.GET:
            data = []
        else:
            program = program_logic.getFromKeyName(
                request.GET.get('scope_path'))
            if not program:
                data = []
            else:
                fun = soc.cache.logic.cache(OrgTag.get_for_custom_query)
                suggested_tags = fun(OrgTag,
                                     filter={'scope': program},
                                     order=None)
                # TODO: this should be refactored after the issue with autocompletion
                #       is resolved
                data = simplejson.dumps({
                    'data':
                    [{
                        'link_id': item['tag']
                    } for item in
                     [dicts.toDict(tag, ['tag']) for tag in suggested_tags]],
                    'autocomplete_options': {
                        'multiple': True,
                        'selectFirst': False
                    }
                })

        return self.json(request, data, False)
Ejemplo n.º 9
0
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()
Ejemplo n.º 10
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()
Ejemplo n.º 11
0
def convert_proposals(request, *args, **kwargs):
  """Convert proposals for all organizations.

  POST Args:
    programkey: the key of the program whose proposals should be converted
    orgkey: the organization key to start at
  """

  # Setup an artifical request deadline
  timelimit = 20000
  timekeeper = Timekeeper(timelimit)

  # Copy for modification below
  params = dicts.merge(request.POST, request.GET)

  if "programkey" not in params:
    logging.error("missing programkey in params: '%s'" % params)
    return responses.terminateTask()

  program = program_logic.getFromKeyName(params["programkey"])

  if not program:
    logging.error("invalid programkey in params: '%s'" % params)
    return responses.terminateTask()

  fields = {
      "scope": program,
      "status": "active",
  }

  # Continue from the next organization
  if "orgkey" in params:
    org = org_logic.getFromKeyName(params["orgkey"])

    if not org:
      logging.error("invalid orgkey in params: '%s'" % params)
      return responses.terminateTask()

    fields["__key__ >="] = org

  # Add a task for each organization
  org = None
  try:
    orgs = org_logic.getQueryForFields(filter=fields)

    for remain, org in timekeeper.iterate(orgs):
      logging.info("convert %s %s", remain, org.key())

      # Compound accept/reject taskflow
      taskqueue.add(
        url = "/tasks/accept_proposals/accept",
        params = {
          "orgkey": org.key().id_or_name(),
          "timelimit": timelimit,
          "nextpath": "/tasks/accept_proposals/reject"
        })

  # Requeue this task for continuation
  except DeadlineExceededError:
    if org:
      params["orgkey"] = org.key().id_or_name()

    taskqueue.add(url=request.path, params=params)

  # Exit this task successfully
  return responses.terminateTask()
Ejemplo n.º 12
0
def convert_proposals(request, *args, **kwargs):
    """Convert proposals for all organizations.

  POST Args:
    programkey: the key of the program whose proposals should be converted
    orgkey: the organization key to start at
  """

    # Setup an artifical request deadline
    timelimit = 20000
    timekeeper = Timekeeper(timelimit)

    # Copy for modification below
    params = dicts.merge(request.POST, request.GET)

    if "programkey" not in params:
        logging.error("missing programkey in params: '%s'" % params)
        return responses.terminateTask()

    program = program_logic.getFromKeyName(params["programkey"])

    if not program:
        logging.error("invalid programkey in params: '%s'" % params)
        return responses.terminateTask()

    fields = {
        "scope": program,
        "status": "active",
    }

    # Continue from the next organization
    if "orgkey" in params:
        org = org_logic.getFromKeyName(params["orgkey"])

        if not org:
            logging.error("invalid orgkey in params: '%s'" % params)
            return responses.terminateTask()

        fields["__key__ >="] = org

    # Add a task for each organization
    org = None
    try:
        orgs = org_logic.getQueryForFields(filter=fields)

        for remain, org in timekeeper.iterate(orgs):
            logging.info("convert %s %s", remain, org.key())

            # Compound accept/reject taskflow
            taskqueue.add(url="/tasks/accept_proposals/accept",
                          params={
                              "orgkey": org.key().id_or_name(),
                              "timelimit": timelimit,
                              "nextpath": "/tasks/accept_proposals/reject"
                          })

    # Requeue this task for continuation
    except DeadlineExceededError:
        if org:
            params["orgkey"] = org.key().id_or_name()

        taskqueue.add(url=request.path, params=params)

    # Exit this task successfully
    return responses.terminateTask()
Ejemplo n.º 13
0
def spawnRemindersForProjectSurvey(request, *args, **kwargs):
    """Spawns tasks for each StudentProject in the given Program.

  Expects the following to be present in the POST dict:
    program_key: Specifies the program key name for which to loop over all the
                 StudentProjects for
    survey_key: specifies the key name for the ProjectSurvey to send reminders
                for
    survey_type: either project or grading depending on the type of Survey
    project_key: optional to specify which project was the last for which a
                 task was spawn

  Args:
    request: Django Request object
  """

    from soc.modules.gsoc.logic.models.program import logic as program_logic
    from soc.modules.gsoc.logic.models.student_project import logic as \
        student_project_logic

    # set default batch size
    batch_size = 10

    post_dict = request.POST

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

    if not (program_key and survey_key and survey_type):
        # invalid task data, log and return OK
        return error_handler.logErrorAndReturnOK(
            'Invalid sendRemindersForProjectSurvey 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)

    # check and retrieve the project_key that has been done last
    if 'project_key' in post_dict:
        project_start_key = post_dict['project_key']
    else:
        project_start_key = None

    # get all valid StudentProjects from starting key
    fields = {'program': program_entity, 'status': 'accepted'}

    if project_start_key:
        # retrieve the last project that was done
        project_start = student_project_logic.getFromKeyName(project_start_key)

        if not project_start:
            # invalid starting project key specified, log and return OK
            return error_handler.logErrorAndReturnOK(
                'Invalid Student Project Key specified: %s' %
                (project_start_key))

        fields['__key__ >'] = project_start.key()

    project_entities = student_project_logic.getForFields(fields,
                                                          limit=batch_size)

    for project_entity in project_entities:
        # pass along these params as POST to the new task
        task_params = {
            'survey_key': survey_key,
            'survey_type': survey_type,
            'project_key': project_entity.key().id_or_name()
        }
        task_url = '/tasks/surveys/projects/send_reminder/send'

        new_task = taskqueue.Task(params=task_params, url=task_url)
        new_task.add('mail')

    if len(project_entities) == batch_size:
        # spawn new task starting from the last
        new_project_start = project_entities[batch_size - 1].key().id_or_name()

        # pass along these params as POST to the new task
        task_params = {
            'program_key': program_key,
            'survey_key': survey_key,
            'survey_type': survey_type,
            'project_key': new_project_start
        }
        task_url = '/tasks/surveys/projects/send_reminder/spawn'

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

    # return OK
    return http.HttpResponse()
Ejemplo n.º 14
0
def spawnRemindersForProjectSurvey(request, *args, **kwargs):
  """Spawns tasks for each StudentProject in the given Program.

  Expects the following to be present in the POST dict:
    program_key: Specifies the program key name for which to loop over all the
                 StudentProjects for
    survey_key: specifies the key name for the ProjectSurvey to send reminders
                for
    survey_type: either project or grading depending on the type of Survey
    project_key: optional to specify which project was the last for which a
                 task was spawn

  Args:
    request: Django Request object
  """

  from soc.modules.gsoc.logic.models.program import logic as program_logic
  from soc.modules.gsoc.logic.models.student_project import logic as \
      student_project_logic

  # set default batch size
  batch_size = 10

  post_dict = request.POST

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

  if not (program_key and survey_key and survey_type):
    # invalid task data, log and return OK
    return error_handler.logErrorAndReturnOK(
        'Invalid sendRemindersForProjectSurvey 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)

  # check and retrieve the project_key that has been done last
  if 'project_key' in post_dict:
    project_start_key = post_dict['project_key']
  else:
    project_start_key = None

  # get all valid StudentProjects from starting key
  fields = {'program': program_entity,
            'status': 'accepted'}

  if project_start_key:
    # retrieve the last project that was done
    project_start = student_project_logic.getFromKeyName(project_start_key)

    if not project_start:
      # invalid starting project key specified, log and return OK
      return error_handler.logErrorAndReturnOK(
          'Invalid Student Project Key specified: %s' %(project_start_key))

    fields['__key__ >'] = project_start.key()

  project_entities = student_project_logic.getForFields(fields,
                                                        limit=batch_size)

  for project_entity in project_entities:
    # pass along these params as POST to the new task
    task_params = {'survey_key': survey_key,
                   'survey_type': survey_type,
                   'project_key': project_entity.key().id_or_name()}
    task_url = '/tasks/surveys/projects/send_reminder/send'

    new_task = taskqueue.Task(params=task_params, url=task_url)
    new_task.add('mail')

  if len(project_entities) == batch_size:
    # spawn new task starting from the last
    new_project_start = project_entities[batch_size-1].key().id_or_name()

    # pass along these params as POST to the new task
    task_params = {'program_key': program_key,
                   'survey_key': survey_key,
                   'survey_type': survey_type,
                   'project_key': new_project_start}
    task_url = '/tasks/surveys/projects/send_reminder/spawn'

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

  # return OK
  return http.HttpResponse()
Ejemplo n.º 15
0
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()
Ejemplo n.º 16
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()