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)
예제 #2
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)
  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)
예제 #4
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)
  def testCalculateThroughPostWithoutCorrectXsrfToken(self):
    """Tests that calculating duplicate is forbidden without correct XSRF token.

    Through HTTP POST without correct XSRF token, the task of
    calculating the duplicate proposals in a given program for a student on
    a per organization basis is forbidden.
    """
    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)}
    response = self.client.post(url, postdata)
    self.assertEqual(response.status_code, httplib.FORBIDDEN)
예제 #6
0
    def testCalculateThroughPostWithoutCorrectXsrfToken(self):
        """Tests that calculating duplicate is forbidden without correct XSRF token.

    Through HTTP POST without correct XSRF token, the task of
    calculating the duplicate proposals in a given program for a student on
    a per organization basis is forbidden.
    """
        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)
        }
        response = self.client.post(url, postdata)
        self.assertEqual(response.status_code, httplib.FORBIDDEN)
예제 #7
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()
예제 #8
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()
예제 #9
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()
예제 #10
0
    def slots(self,
              request,
              acces_type,
              page_name=None,
              params=None,
              **kwargs):
        """Returns a JSON object with all orgs allocation.

    Args:
      request: the standard Django HTTP request object
      access_type : the name of the access type which should be checked
      page_name: the page name displayed in templates as page and header title
      params: a dict with params for this View, not used
    """

        program_entity = program_logic.getFromKeyFieldsOr404(kwargs)
        program_slots = program_entity.slots

        filter = {
            'scope': program_entity,
            'status': ['new', 'active', 'inactive'],
        }

        query = org_logic.getQueryForFields(filter=filter)
        organizations = org_logic.getAll(query)

        if request.method == 'POST' and 'result' in request.POST:
            result = request.POST['result']
            submit = request.GET.get('submit')
            load = request.GET.get('load')
            stored = program_entity.slots_allocation

            if load and stored:
                result = stored

            if submit:
                program_entity.slots_allocation = result
                program_entity.put()

        orgs = {}
        applications = {}
        max = {}

        for org in organizations:
            orgs[org.link_id] = org
            applications[org.link_id] = org.nr_applications
            max[org.link_id] = org.slots_desired

        max_slots_per_org = program_entity.max_slots
        min_slots_per_org = program_entity.min_slots
        algorithm = 2

        allocator = allocations.Allocator(orgs.keys(), applications, max,
                                          program_slots, max_slots_per_org,
                                          min_slots_per_org, algorithm)

        from_json = simplejson.loads(program_entity.slots_allocation)
        locked_slots = dicts.groupDictBy(from_json, 'locked', 'slots')

        result = allocator.allocate(locked_slots)

        data = []

        for link_id in orgs.keys():
            data.append({
                'link_id': link_id,
                'slots': result.get(link_id, 0),
                'locked': bool(locked_slots.get(link_id))
            })

        return self.json(request, data)
예제 #11
0
  def slots(self, request, acces_type, page_name=None, params=None, **kwargs):
    """Returns a JSON object with all orgs allocation.

    Args:
      request: the standard Django HTTP request object
      access_type : the name of the access type which should be checked
      page_name: the page name displayed in templates as page and header title
      params: a dict with params for this View, not used
    """

    program_entity = program_logic.getFromKeyFieldsOr404(kwargs)
    program_slots = program_entity.slots

    filter = {
          'scope': program_entity,
          'status': ['new', 'active', 'inactive'],
          }

    query = org_logic.getQueryForFields(filter=filter)
    organizations = org_logic.getAll(query)

    if request.method == 'POST' and 'result' in request.POST:
      result = request.POST['result']
      submit = request.GET.get('submit')
      load = request.GET.get('load')
      stored = program_entity.slots_allocation

      if load and stored:
        result = stored

      if submit:
        program_entity.slots_allocation = result
        program_entity.put()

    orgs = {}
    applications = {}
    max = {}

    for org in organizations:
      orgs[org.link_id] = org
      applications[org.link_id] = org.nr_applications
      max[org.link_id] = org.slots_desired

    max_slots_per_org = program_entity.max_slots
    min_slots_per_org = program_entity.min_slots
    algorithm = 2

    allocator = allocations.Allocator(orgs.keys(), applications, max,
                                      program_slots, max_slots_per_org,
                                      min_slots_per_org, algorithm)

    from_json = simplejson.loads(program_entity.slots_allocation)
    locked_slots = dicts.groupDictBy(from_json, 'locked', 'slots')

    result = allocator.allocate(locked_slots)

    data = []

    for link_id in orgs.keys():
      data.append({
          'link_id': link_id,
          'slots': result.get(link_id,0),
          'locked': bool(locked_slots.get(link_id))
          })

    return self.json(request, data)
예제 #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()