def test_delete_code_allowed(self):
        code = 'trout viper'
        path = '/api/codes/{}'.format(code.replace(' ', '-'))
        pc = ProjectCohort.create(
            code=code,
            organization_id='triton',
            program_label='triton',
        )
        pc.put()
        pc.key.get()  # simulate consistency, code fetches are eventual
        token = jwt_helper.encode({
            'user_id': 'User_foo',
            'email': '*****@*****.**',
            'allowed_endpoints': ['DELETE //neptune{}'.format(path)],
        })
        self.testapp.delete(
            path,
            headers={'Authorization': 'Bearer ' + token},
            status=204,
        )

        # Project cohort AND Unique should be gone
        self.assertIsNone(pc.key.get())
        unique_key = ndb.Key('Unique', ProjectCohort.uniqueness_key(code))
        self.assertIsNone(unique_key.get())
Example #2
0
    def test_queue_org_welcome_back(self):
        Program.mock_program_config('p1', {'project_tasklist_template': []})

        # Case 1: New PC, returning.
        returning_pc1 = ProjectCohort.create(
            program_label='p1',
            organization_id='Organization_returning',
            project_id='Project_returning',
            cohort_label='2020',
        )
        returning_pc1.put()
        returning_pc2 = ProjectCohort.create(
            program_label='p1',
            organization_id='Organization_returning',
            project_id='Project_returning',
            cohort_label='2019',
            created=datetime.datetime.now() - datetime.timedelta(days=365))
        returning_pc2.put()

        # Case 2: New PC, but not returning.
        new_pc = ProjectCohort.create(
            program_label='p1',
            organization_id='Organization_new',
            project_id='Project_new',
        )
        new_pc.put()

        # Case 3: Old PC (not created in the day).
        old_pc = ProjectCohort.create(
            program_label='p1',
            organization_id='Organization_old',
            project_id='Project_old',
            created=datetime.datetime.now() - datetime.timedelta(hours=48),
        )
        old_pc.put()

        # Some tasks are created on put. We're not interested in these.
        creation_tasks = self.taskqueue_stub.get_filtered_tasks()

        templates = [
            self.create_mandrill_template('p1-{}'.format(
                auto_prompt.ORG_WELCOME_BACK_SUFFIX)),
        ]

        auto_prompt.queue_org_welcome_back(templates)

        tasks = self.taskqueue_stub.get_filtered_tasks()
        num_new_tasks = len(tasks) - len(creation_tasks)

        # Only the returning pc should have a task queued.
        self.assertEqual(num_new_tasks, 1)

        expected_url = '/task/email_project/Project_returning/p1-org-welcome-back'
        self.assertIn(expected_url, [t.url for t in tasks])

        Program.reset_mocks()
Example #3
0
    def test_batch_participation(self):
        user = User.create(email='*****@*****.**')
        user.put()

        pc_kwargs = {
            'program_label': self.program_label,
            'cohort_label': self.cohort_label,
        }
        pcs = [
            ProjectCohort.create(**pc_kwargs),
            ProjectCohort.create(**pc_kwargs),
        ]
        ndb.put_multi(pcs)

        all_pds = []
        for pc in pcs:
            pds = mock_one_finished_one_unfinished(
                1,
                'Participant_unfinished',
                'Participant_finished',
                pc_id=pc.uid,
                code=pc.code,
                program_label=self.program_label,
                cohort_label=self.cohort_label,
            )
            all_pds += pds

        # Forbidden without allowed endpoints.
        pc_ids = [pc.uid for pc in pcs]
        self.testapp.get(
            '/api/project_cohorts/participation?uid={}&uid={}'.format(*pc_ids),
            headers=jwt_headers(user),
            status=403)

        # Running various queries works as expected.
        self.batch_participation(user, pcs)

        # Simulate a new pd being written to the first pc by clearing that
        # memcache key. The server should fall back to sql and still give the
        # same results.
        id_key = ParticipantData.participation_by_pc_cache_key(pcs[0].uid)
        code_key = ParticipantData.participation_by_pc_cache_key(pcs[0].code)
        self.assertIsNotNone(memcache.get(id_key))
        self.assertIsNotNone(memcache.get(code_key))
        memcache.delete(id_key)
        memcache.delete(code_key)
        self.batch_participation(user, pcs)

        # Now with everything cached, clearing the db and running the same
        # queries again should have the same result.
        ParticipantData.delete_multi(all_pds)
        self.batch_participation(user, pcs)
Example #4
0
    def test_fix_open_responses(self):
        """Non-triton pcs shouldn't have the open response param."""
        non_triton_empty = ProjectCohort.create(program_label='demo-program', )
        non_triton_only = ProjectCohort.create(
            program_label='demo-program',
            survey_params_json=json.dumps({
                'show_open_response_questions':
                'true',
            }))
        non_triton_extra = ProjectCohort.create(
            program_label='demo-program',
            survey_params_json=json.dumps({
                'foo':
                'bar',
                'show_open_response_questions':
                'true',
            }),
        )
        triton = ProjectCohort.create(
            program_label='triton',
            survey_params_json=json.dumps({
                'learning_conditions':
                "feedback-for-growth",
                'show_open_response_questions':
                'true',
            }),
        )

        def get_mapped(pc):
            operation = next(fix_open_responses(pc), None)
            if operation:
                return operation.entity

        # Empty value unchanged
        mapped_non_triton_empty = get_mapped(non_triton_empty)
        self.assertEqual(mapped_non_triton_empty.survey_params, {})

        # Key removed.
        mapped_non_triton_only = get_mapped(non_triton_only)
        self.assertNotIn('show_open_response_questions',
                         mapped_non_triton_only.survey_params)

        # Key removed, other data preserved.
        mapped_non_triton_extra = get_mapped(non_triton_extra)
        self.assertNotIn('show_open_response_questions',
                         mapped_non_triton_extra.survey_params)
        self.assertIn('foo', mapped_non_triton_extra.survey_params)

        # Triton pc untouched.
        mapped_triton = get_mapped(triton)
        self.assertIsNone(mapped_triton)
    def test_completion_csv_allowed(self):
        org_id = 'Organization_foo'
        pc = ProjectCohort.create(
            organization_id=org_id,
            program_label=self.program_label,
            cohort_label=self.cohort_label,
        )
        pc.put()

        user = User.create(
            email='*****@*****.**',
            owned_organizations=[org_id],
        )
        user.put()

        t = AuthToken.create(user.uid)
        t.put()

        self.testapp.get(
            '/api/project_cohorts/{}/completion/ids.csv'.format(pc.uid),
            params={'token': t.token},
            headers=login_headers(user.uid),
            # Authenticated, one-time token valid, has permission: 200.
            status=200,
        )
    def create_pd_context(self):
        program_label = 'demo-program'
        program_config = Program.get_config(program_label)
        template = program_config['surveys'][0]['survey_tasklist_template']

        project_cohort = ProjectCohort.create(
            program_label=program_label,
            organization_id='Organization_foo',
            project_id='Project_foo',
            cohort_label='2018',
        )
        project_cohort.put()

        survey = Survey.create(
            template,
            program_label=program_label,
            organization_id='Organization_foo',
            project_cohort_id=project_cohort.uid,
            ordinal=1,
        )
        survey.put()

        participant = Participant.create(name='Pascal',
                                         organization_id='PERTS')
        participant.put()

        return (project_cohort, survey, participant)
Example #7
0
    def test_put_clears_dashboard_queries(self):
        pc = ProjectCohort.create(
            program_label='demo-program',
            organization_id='Organization_Foo',
            project_id='Project_Foo',
            cohort_label='2018',
        )

        org_key = util.cached_query_key(
            'SuperDashboard',
            organization_id=pc.organization_id,
        )
        program_cohort_key = util.cached_query_key(
            'SuperDashboard',
            program_label=pc.program_label,
            cohort_label=pc.cohort_label,
        )

        memcache.set(org_key, {'foo': 1})
        memcache.set(program_cohort_key, {'foo': 1})

        # This should clear memcache.
        pc.put()

        self.assertIsNone(memcache.get(org_key))
        self.assertIsNone(memcache.get(program_cohort_key))
Example #8
0
    def create_project_cohort(self, cohort_date=datetime.datetime.today()):
        program_label = 'demo-program'
        cohort_label = 'demo-cohort'
        program = Program.get_config(program_label)
        org_id = 'Org_Foo'
        liaison_id = 'User_liaison'
        project = Project.create(organization_id=org_id,
                                 program_label=program_label)
        project.put()

        one_day = datetime.timedelta(days=1)
        cohort_config = {
            'label': cohort_label,
            'name': 'Demo Cohort',
            'open_date': str(cohort_date - one_day),  # yesterday
            'close_date': str(cohort_date + one_day),  # tomorrow
        }
        program['cohorts'][cohort_label] = cohort_config
        Program.mock_program_config(
            program_label,
            {'cohorts': {
                cohort_label: cohort_config
            }},
        )

        pc = ProjectCohort.create(
            project_id=project.uid,
            organization_id=org_id,
            program_label=program_label,
            cohort_label=cohort_label,
            liaison_id=liaison_id,
        )
        pc.put()

        return pc
Example #9
0
def delete_for_program(entity):
    """Permanently delete anything in the datastore from a program.

    Works with Projects, ProjectCohorts, and Surveys. Also requires a param set
    in mapreduce.yaml: `program_label`.
    """
    params = context.get().mapreduce_spec.mapper.params
    if getattr(entity, 'program_label', None) != params['program_label']:
        return

    # If this is a project cohort, delete the Unique entity that serves as an
    # index of participation codes.
    key_name = ProjectCohort.uniqueness_key(getattr(entity, 'code', ''))
    unique_entity = ndb.Key('Unique', key_name).get()
    if unique_entity:
        yield op.db.Delete(unique_entity)

    # Some entities have tasks in their entity group. There's no convenient
    # way to query tasks directly, so delete them while we're handling their
    # parent.
    # Bypass DatastoreModel to make sure we get soft-deleted entities.
    for task in Task.query(ancestor=entity.key).iter():
        yield op.db.Delete(task)

    yield op.db.Delete(entity)
Example #10
0
def queue_checklist_nudge(templates):
    # Is it exactly one month before the program opens for student
    # participation for this cohort year? Find all orgs registered and send
    # them reminder email (complete checklist, participation code, etc)

    tasks = []

    month_from_now = util.datelike_to_iso_string(datetime.date.today() +
                                                 datetime.timedelta(days=30))

    to_prompt = programs_with_template(templates, CHECKLIST_NUDGE_SUFFIX)
    for program in to_prompt:
        for cohort in program['cohorts'].values():

            project_ids = set()
            if cohort['open_date'] == month_from_now:
                # This whole cohort needs a nudge. Get all the project cohorts.
                pcs = ProjectCohort.get(
                    program_label=program['label'],
                    cohort_label=cohort['label'],
                    projection=['project_id'],
                    n=float('inf'),
                )
                for pc in pcs:
                    url = '/task/email_project/{}/{}'.format(
                        pc.project_id,
                        get_slug(program['label'], CHECKLIST_NUDGE_SUFFIX))
                    task = taskqueue.add(url=url)
                    tasks.append(task)

    return tasks
Example #11
0
    def test_override_portal_message(self):
        label = 'override-program'
        config = {'override_portal_message': 'Override message.'}
        Program.mock_program_config(label, config)

        pc = ProjectCohort.create(program_label=label)
        self.assertEqual(
            pc.to_client_dict()['portal_message'],
            config['override_portal_message'],
        )
    def test_cohort(self):
        user = User.create(email='*****@*****.**', user_type='super_admin')
        user.put()
        pc = ProjectCohort.create(
            project_id='Project_001',
            organization_id='Organization_001',
            program_label=self.program_label,
            cohort_label=self.cohort_label,
            liaison_id='User_001',
        )
        pc.put()

        query = '''
        query PCWithCohort($uid: String) {
            project_cohort(uid: $uid) {
                program_cohort {
                    close_date
                    label
                    name
                    open_date
                    program_description
                    program_label
                    program_name
                    registration_close_date
                    registration_open_date
                }
            }
        }
        '''

        expected = {
            'project_cohort': {
                'program_cohort':
                OrderedDict(
                    (k, self.cohort[k]) for k in sorted(self.cohort.keys())),
            },
        }

        response = self.testapp.post_json(
            '/api/graphql',
            {
                'query': query,
                'variables': {
                    'uid': pc.uid
                },
            },
            headers=login_headers(user.uid),
        )

        self.assertEqual(
            response.body,
            json.dumps(expected),
        )
    def test_get_project_cohort_participation(self):
        """Get stats for all surveys in the project cohort."""
        pds1 = self.mock_one_finished_one_unfinished(1)
        pds2 = self.mock_one_finished_one_unfinished(2)
        project_cohort_id = pds1[0].project_cohort_id
        ProjectCohort(
            id=project_cohort_id,
            program_label=self.program_label,
        ).put()
        start = datetime.date.today()
        end = start + datetime.timedelta(days=1)

        expected = [
            {
                'value': '1',
                'n': 1,
                'survey_ordinal': 1
            },
            {
                'value': '100',
                'n': 1,
                'survey_ordinal': 1
            },
            {
                'value': '1',
                'n': 1,
                'survey_ordinal': 2
            },
            {
                'value': '100',
                'n': 1,
                'survey_ordinal': 2
            },
        ]

        result = ParticipantData.participation(
            project_cohort_id=project_cohort_id, start=start, end=end)
        self.assertEqual(result, expected)

        # The same result should also now be available in memcache, so if we
        # clear the db the result should be the same.
        ParticipantData.delete_multi(pds1 + pds2)
        result = ParticipantData.participation(
            project_cohort_id=project_cohort_id, start=start, end=end)
        self.assertEqual(result, expected)

        # It should also work if some other kwargs are set with value None.
        result = ParticipantData.participation(
            project_cohort_id=project_cohort_id,
            start=start,
            end=end,
            cohort_label=None)
        self.assertEqual(result, expected)
 def test_create_code_creates_unique(self):
     """Should be an entry in Unique to ensure unique code."""
     user = User.create(email='*****@*****.**')
     user.put()
     response = self.testapp.post_json(
         '/api/codes',
         {'organization_id': 'triton', 'program_label': 'triton'},
         headers=self.login_headers(user)
     )
     pc = ProjectCohort.query().fetch(1)
     unique = Unique.query().fetch(1)
     self.assertIsNotNone(pc)
     self.assertIsNotNone(unique)
Example #15
0
def queue_org_welcome_back(templates):
    """After joining a program for the first time, welcome them."""
    # Orgs signing up for a program generate a new ProjectCohort every year.
    # Look for recently created ones, then exclude orgs that only have one PC
    # in this program.
    yesterday = datetime.datetime.now() - datetime.timedelta(hours=24)

    # Which programs have a template?
    to_prompt = programs_with_template(templates, ORG_WELCOME_BACK_SUFFIX)
    tasks = []

    for program in to_prompt:
        # Can't use .get() from DatastoreModel because of the >= query
        query = ProjectCohort.query(
            ProjectCohort.created >= yesterday,
            ProjectCohort.deleted == False,
            ProjectCohort.program_label == program['label'],
        )

        # Gather the project ids of all applicable project cohorts. By tracking
        # unique project ids, we only email each org in this program once.
        project_ids = set()
        for pc in query.iter(projection=[ProjectCohort.project_id]):
            if pc.project_id not in project_ids:
                if ProjectCohort.count(project_id=pc.project_id) > 1:
                    project_ids.add(pc.project_id)

        # Now send an email for each org that qualifies.
        for project_id in project_ids:
            # Then this org has done this program before, they're returning
            # so welcome them back.
            url = '/task/email_project/{}/{}'.format(
                project_id, get_slug(program['label'],
                                     ORG_WELCOME_BACK_SUFFIX))
            task = taskqueue.add(url=url)
            tasks.append(task)

    return tasks
Example #16
0
    def get(self, template, context_id):
        # Attempt to treat id as as project cohort (it might be a program, or
        # invalid).
        project_cohort = ProjectCohort.get_by_id(context_id)

        def todt(s):
            return datetime.datetime.strptime(s, config.iso_date_format)

        if project_cohort:
            # This is a "real" set of instructions with data filled in.
            organization = Organization.get_by_id(
                project_cohort.organization_id)
            liaison = User.get_by_id(organization.liaison_id)
            program = Program.get_config(project_cohort.program_label)
            cohort = program['cohorts'][project_cohort.cohort_label]
            participation_open_date = todt(cohort['open_date'])
            # See notes in program config for why we take a day off for display.
            participation_close_date = (todt(cohort['close_date']) -
                                        datetime.timedelta(1))
        else:
            # This is a generic example version of the document.
            try:
                program = Program.get_config(context_id)
            except ImportError:
                return self.http_not_found()
            organization = None
            liaison = None
            project_cohort = None
            cohort = None
            participation_open_date = None
            participation_close_date = None

        if template == 'custom_portal_technical_guide':
            # This template doesn't vary by program.
            template_filename = '{}.html'.format(template)
        else:
            template_filename = '{}_{}.html'.format(program['label'], template)

        self.write(
            template_filename,
            organization=organization,
            liaison=liaison,
            program_name=program['name'],
            cohort_name=cohort['name'] if cohort else '',
            program_description=program['description'],
            project_cohort=project_cohort,
            participation_open_date=participation_open_date,
            participation_close_date=participation_close_date,
        )
Example #17
0
    def create_with_pc(self):
        project = Project.create(
            program_label='demo-program',
            organization_id='Organization_Foo',
        )
        project.put()
        pc = ProjectCohort.create(
            program_label=project.program_label,
            organization_id=project.organization_id,
            project_id=project.uid,
            cohort_label='2018',
        )
        pc.put()

        return project.key.get(), pc.key.get()
    def test_completion_anonymous_forbidden(self):
        pc = ProjectCohort.create(
            program_label=self.program_label,
            cohort_label=self.cohort_label,
        )
        pc.put()

        user = User.create(email='*****@*****.**')
        user.put()

        self.testapp.get(
            '/api/project_cohorts/{}/completion'.format(pc.uid),
            headers=login_headers(user.uid),
            # user doesn't own ProjectCohort_foo, forbidden
            status=403,
        )
Example #19
0
    def create_with_project_cohort(self):
        checkpoint_template = {
            'name': "Survey Foo",
            'label': 'demo_survey__foo',
            'body': "foo",
            'tasks': [],
        }
        config = {
            'surveys': [
                {
                    'name': "Student Module",
                    'survey_tasklist_template': [checkpoint_template],
                },
            ],
        }
        Program.mock_program_config(self.program_label, config)

        org = Organization.create(name='Foo Org')
        org.put()

        project = Project.create(
            program_label=self.program_label,
            organization_id=org.uid,
        )
        project.put()

        pc = ProjectCohort.create(
            program_label=self.program_label,
            organization_id=org.uid,
            project_id=project.uid,
        )
        pc.put()

        checkpoint = Checkpoint.create(parent_id='Survey_foo',
                                       ordinal=1,
                                       program_label=self.program_label,
                                       organization_id=org.uid,
                                       project_id=project.uid,
                                       project_cohort_id=pc.uid,
                                       status='incomplete',
                                       **checkpoint_template)
        checkpoint.put()

        pc.update_cached_properties()

        return org, project, pc, checkpoint
    def test_join_cohort(self, cohort_date=datetime.date.today()):
        """Allowed for org admin owner of project."""

        # Existing things to relate to.
        program_label = 'demo-program'
        cohort_label = 'demo-cohort'
        program = Program.get_config(program_label)
        org_id = 'Org_Foo'
        user = User.create(email="*****@*****.**",
                           owned_organizations=[org_id])
        project = Project.create(organization_id=org_id,
                                 program_label=program_label)
        user.put()
        project.put()

        # Guarantee the dates will work by mocking the cohort config.
        one_day = datetime.timedelta(days=1)
        cohort_config = {
            'label': cohort_label,
            'name': 'Demo Cohort',
            'open_date': str(cohort_date - one_day),  # yesterday
            'close_date': str(cohort_date + one_day),  # tomorrow
        }
        program['cohorts'][cohort_label] = cohort_config
        Program.mock_program_config(
            program_label,
            {'cohorts': {cohort_label: cohort_config}},
        )

        # Create the project cohort through the api. Any response other than
        # 200 will fail the test.
        response = self.testapp.post_json(
            '/api/project_cohorts',
            {
                'project_id': project.uid,
                'organization_id': org_id,
                'program_label': program_label,
                'cohort_label': cohort_label,
                'liaison_id': user.uid,
            },
            headers=login_headers(user.uid)
        )
        response_dict = json.loads(response.body)

        return (ProjectCohort.get_by_id(response_dict['uid']), user)
    def test_patch_update_codes(self):
        codes = ('trout viper', 'solid snake')
        pcs = []
        for c in codes:
            pcs.append(ProjectCohort.create(
                code=c,
                organization_id='triton',
                program_label='triton',
            ))
        ndb.put_multi(pcs)
        for pc in pcs:
            pc.key.get()  # simulate consistency, code fetches are eventual

        token = jwt_helper.encode({
            'user_id': 'User_foo',
            'email': '*****@*****.**',
            'allowed_endpoints': ['PUT //neptune{}'.format(path(c))
                                  for c in codes],
        })

        body = {'portal_message': 'hi'}
        response = self.testapp.patch_json(
            '/api/codes',
            [{'method': 'PUT', 'path': path(c), 'body': body} for c in codes],
            headers={'Authorization': 'Bearer ' + token},
        )
        task_names = [t['task_name'] for t in json.loads(response.body)]

        # PATCHing two codes should result in two tasks.
        for name in task_names:
            tasks = self.taskqueue.get_filtered_tasks(name=name)
            self.assertEqual(len(tasks), 1)
            t = tasks[0]

            # Running the tasks should update the codes.
            self.assertEqual(t.method, 'PUT')
            self.testapp.put_json(
                t.url,
                json.loads(t.payload),
                headers=t.headers,
            )

        for pc in pcs:
            fetched = pc.key.get()
            self.assertEqual(fetched.portal_message, 'hi')
    def create_demo_data(self):
        # Existing things to relate to.
        program_label = 'demo-program'
        cohort_label = 'demo-cohort'
        org_id = 'Org_Foo'
        user_id = 'User_Liaison'
        pc = ProjectCohort.create(
            project_id='Project_foo',
            organization_id=org_id,
            program_label=program_label,
            cohort_label=cohort_label,
            liaison_id=user_id,
            portal_type='custom',
            custom_portal_url='http://www.example.com',
        )
        pc.put()

        return pc
Example #23
0
    def create_org_with_pc(self):
        org = Organization.create(name="Foo College")
        org.put()
        project = Project.create(
            program_label='demo-program',
            organization_id=org.uid,
        )
        project.put()
        pc = ProjectCohort.create(
            program_label=project.program_label,
            organization_id=org.uid,
            project_id=project.uid,
            cohort_label='2018',
        )
        pc.put()

        # Simulate consistency
        return org, project.key.get(), pc.key.get()
    def test_dashboard_unlisted(self):
        """Some programs support other apps and aren't meant to be queried."""
        # See #1015
        Program.mock_program_config('ep19', {'listed': False})

        user = User.create(email='*****@*****.**', user_type='super_admin')
        user.put()

        pc = ProjectCohort.create(
            program_label='ep19',
            organization_id='Org_foo',
        )
        pc.put()

        response = self.testapp.get('/api/dashboard?program_label=ep19',
                                    headers=login_headers(user.uid))

        self.assertEqual(response.body, '[]')
Example #25
0
    def test_update_project_cohort(self):
        org, project, pc, checkpoint = self.create_with_project_cohort()

        # Now changing the status should update the cached properties of the
        # project cohort.
        checkpoint.status = 'waiting'
        checkpoint.put()

        fetched = ProjectCohort.get_by_id(pc.uid)
        # There should be one survey checkpoint that was changed
        fetched_checkpoint = [
            c for c in fetched.get_cached_properties()['checkpoints']
            if c.parent_kind == 'Survey'
        ][0]

        self.assertEqual(
            fetched_checkpoint.status,
            'waiting',
        )
Example #26
0
    def test_put_clears_dashboard_queries(self):
        org_id = 'Organization_Foo'
        program_label = 'demo-program'
        pc = ProjectCohort.create(
            program_label='demo-program',
            organization_id=org_id,
            project_id='Project_Foo',
            cohort_label='2018',
        )
        pc.put()
        program_config = Program.get_config(program_label)
        template = program_config['surveys'][0]['survey_tasklist_template']
        survey = Survey.create(
            template,
            program_label=program_label,
            organization_id=org_id,
            project_cohort_id=pc.uid,
            ordinal=1,
        )
        survey.put()

        org_key = util.cached_query_key(
            'SuperDashboard',
            organization_id=pc.organization_id,
        )
        program_cohort_key = util.cached_query_key(
            'SuperDashboard',
            program_label=pc.program_label,
            cohort_label=pc.cohort_label,
        )

        memcache.set(org_key, {'foo': 1})
        memcache.set(program_cohort_key, {'foo': 1})

        # Re-fetch the org so it doesn't have an associated tasklist, which
        # saves checkpoints. This should clear memcache without relying on those
        # checkpoints.
        survey = survey.key.get()
        survey.status = 'ready'
        survey.put()

        self.assertIsNone(memcache.get(org_key))
        self.assertIsNone(memcache.get(program_cohort_key))
 def test_update_code_allowed(self):
     code = 'trout viper'
     path = '/api/codes/{}'.format(code.replace(' ', '-'))
     pc = ProjectCohort.create(
         code=code,
         organization_id='triton',
         program_label='triton',
     )
     pc.put()
     pc.key.get()  # simulate consistency, code fetches are eventual
     token = jwt_helper.encode({
         'user_id': 'User_foo',
         'email': '*****@*****.**',
         'allowed_endpoints': ['PUT //neptune{}'.format(path)],
     })
     self.testapp.put_json(
         path,
         {'portal_message': 'hi'},
         headers={'Authorization': 'Bearer ' + token}
     )
    def test_completion_csv_forbidden(self):
        pc = ProjectCohort.create(
            program_label=self.program_label,
            cohort_label=self.cohort_label,
        )
        pc.put()

        user = User.create(email='*****@*****.**')
        user.put()

        t = AuthToken.create(user.uid)
        t.put()

        self.testapp.get(
            '/api/project_cohorts/{}/completion/ids.csv'.format(pc.uid),
            params={'token': t.token},
            headers=login_headers(user.uid),
            # user doesn't own ProjectCohort_foo, forbidden
            status=403,
        )
Example #29
0
def downloaded_identifiers(user, project_cohort_id):
    supers = User.get(user_type='super_admin')
    notes = []

    project_cohort = ProjectCohort.get_by_id(project_cohort_id)
    organization = Organization.get_by_id(project_cohort.organization_id)
    program = Program.get_config(project_cohort.program_label)
    cohort_name = program['cohorts'][project_cohort.cohort_label]['name']

    for sup in supers:
        note = Notification.create(
            parent=sup,
            context_id=project_cohort_id,
            subject="IDs Downloaded",
            body=u"{} ({}) downloaded IDs for {}: {} {}.".format(
                user.name, user.email, organization.name, program['name'],
                cohort_name),
            link='/dashboard/{}'.format(project_cohort.short_uid),
            autodismiss=True,
        )
        notes.append(note)
    ndb.put_multi(notes)
Example #30
0
def add_completed_report_task_ids_to_project_cohort(task):
    """See Issue #1020 & PR #1062. In order to facilitate creating the
    Returning Organizations report, we need to know which Project Cohorts
    are returning. Returning is defined as an Organization that has
    participated in a previous cohort and has enrolled again. We are counting
    Project Cohorts as having participated if they have a completed report
    uploaded. This job adds the UID of report tasks that have a file attached
    to the associated Project Cohort's completed_report_task_ids property."""

    report_task_labels = [
        'cg17_survey__report_1', 'cb17_survey__report_1',
        'hg17_survey__report_2', 'sse_survey__report_1'
    ]

    if task.label in report_task_labels and task.attachment:
        parent_key = task.key.parent()
        survey = parent_key.get()
        project_cohort = ProjectCohort.get_by_id(survey.project_cohort_id)

        if (project_cohort
                and task.uid not in project_cohort.completed_report_task_ids):
            project_cohort.completed_report_task_ids.append(task.uid)
            yield op.db.Put(project_cohort)