def test_update_checkpoint(self):
        """Can't change a checkpoint to an invalid status, based on tasks."""
        # One checkpoint with one tasks.
        orig_config = organization_tasks.tasklist_template
        tasklist_tmpl = [
            {
                'name':
                "Checkpoint Foo",
                'label':
                'checkpoint label foo',
                'tasks': [{
                    'label': 'foo',
                    'non_admin_may_edit': True
                }, {
                    'label': 'bar',
                    'non_admin_may_edit': True
                }]
            },
        ]
        organization_tasks.tasklist_template = tasklist_tmpl

        user = User.create(email='*****@*****.**', user_type='user')
        org = Organization.create(name='org',
                                  tasklist_template=tasklist_tmpl,
                                  liaison_id=user.uid)
        user.owned_organizations = [org.uid]
        org.put()
        user.put()

        # Make one task complete, the other stays incomplete by default.
        org.tasklist.tasks[0].status = 'complete'
        org.tasklist.tasks[0].put()

        # This is an unsaved, in-memory dict, and thus doesn't contain defaults
        # set in the table definition.
        ckpt = org.tasklist.checkpoints[0]
        # Fetch the checkpoint by id to pick up those defaults.
        ckpt = Checkpoint.get_by_id(ckpt.uid)

        # The derived checkpoint status is 'incomplete'. Setting it this way
        # should work.
        response = self.testapp.put_json(
            '/api/checkpoints/{}'.format(ckpt.uid),
            ckpt.to_client_dict(),
            headers=login_headers(user.uid),
        )

        # Shouldn't be able to set the checkpoint to any other value.
        ckpt.status = 'foo'
        response = self.testapp.put_json(
            '/api/checkpoints/{}'.format(ckpt.uid),
            ckpt.to_client_dict(),
            headers=login_headers(user.uid),
            status=500,
        )

        organization_tasks.tasklist_template = orig_config
    def test_related_org_permissions(self):
        """Who besides the specified user can get related orgs?"""
        # Also creates 3 orgs, where user owns one and is assc with one.
        super_admin, program_admin, user = self.create_entities_to_get()

        # Besides the user specified in the URL, super admins can reach the
        # resource, but others can't.
        response = self.testapp.get('/api/users/{}/organizations'.format(
            user.uid),
                                    headers=login_headers(super_admin.uid),
                                    status=200)
        response = self.testapp.get('/api/users/{}/organizations'.format(
            user.uid),
                                    headers=login_headers(program_admin.uid),
                                    status=403)
    def test_user_tasklist(self):
        """Get everything you need for a tasklist in one query."""
        query, expected = self.tasklist_query_expected(
            *self.create_project_cohort())
        project_cohort_id = expected['project_cohort']['uid']
        org_id = expected['project_cohort']['organization']['uid']

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

        # Now that there's an org-level user, expect another in the users list.
        # They'll always come second b/c the org's users are sorted by email.
        expected['project_cohort']['organization']['users'].append(
            user.to_client_dict())

        response = self.testapp.get(
            '/api/tasklists/{}'.format(project_cohort_id),
            headers=login_headers(user.uid),
        )

        self.assertEqual(response.body, json.dumps(expected))
    def test_update_task(self):
        """Org admins can't change some tasks."""
        org = Organization.create(name='org')
        org.put()
        user = User.create(email='*****@*****.**',
                           user_type='user',
                           owned_organizations=[org.uid])
        user.put()

        orig_config = organization_tasks.tasklist_template
        organization_tasks.tasklist_template = [{
            'tasks': [{
                'label': 'task_foo',
                'non_admin_may_edit': False,
            }]
        }]

        task = Task.create('task_foo', 1, 'checkpoint_foo', parent=org)
        task.put()

        # Org admin shouldn't be able to mark the task as complete, even though
        # they own the task.
        task.status = 'complete'
        response = self.testapp.put_json('/api/tasks/{}'.format(task.uid),
                                         task.to_client_dict(),
                                         headers=login_headers(user.uid),
                                         status=403)

        organization_tasks.tasklist_template = orig_config
예제 #5
0
    def test_get_all_tasks(self):
        super_user = User.create(email='*****@*****.**',
                                 user_type='super_admin')
        super_user.put()
        org, tasks = self.create_org_tasks(super_user)

        query = '''
        query GetAllTasks {
            tasks {
                label
            }
        }
        '''

        expected = {
            # Should be ordered by ordinal
            'tasks': [{
                'label': t.label
            } for t in tasks],
        }

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

        self.assertEqual(json.loads(response.body), expected)
    def test_get_all_orgs(self):
        # Also creates 3 orgs, where user owns one and is assc with one.
        super_admin, program_admin, user = self.create_entities_to_get()

        # Super sees all
        response = self.testapp.get('/api/organizations',
                                    headers=login_headers(super_admin.uid))
        self.assertEqual(len(json.loads(response.body)), 3)

        # Org and Program admins are forbidden.
        response = self.testapp.get('/api/organizations',
                                    headers=login_headers(user.uid),
                                    status=403)
        response = self.testapp.get('/api/organizations',
                                    headers=login_headers(program_admin.uid),
                                    status=403)
    def test_get_all_checkpoints(self):
        checkpoints = self.create_checkpoints()
        user = User.create(email='*****@*****.**', user_type='super_admin')
        user.put()

        query = '''
        query GetAllCheckpoints {
            checkpoints {
                label
            }
        }
        '''

        expected = {
            # Should be ordered by ordinal
            'checkpoints': [{'label': c.label} for c in checkpoints],
        }

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

        self.assertEqual(json.loads(response.body), expected)
예제 #8
0
    def test_get_many_tasks(self):
        """Queries aren't limited to an arbitrarily small number."""
        super_user = User.create(email='*****@*****.**',
                                 user_type='super_admin')
        super_user.put()

        num_orgs = 10
        # Assumes only one org checkpoint.
        num_org_tasks = len(organization_tasks.tasklist_template[0]['tasks'])

        for x in range(num_orgs):
            self.create_org_tasks(super_user)

        query = '''
        query GetAllTasks {
            tasks {
                label
            }
        }
        '''

        response = self.testapp.post_json(
            '/api/graphql',
            {'query': query},
            headers=login_headers(super_user.uid),
        )
        response_dict = json.loads(response.body)

        self.assertEqual(len(response_dict['tasks']), num_org_tasks * num_orgs)
예제 #9
0
    def test_create_project(self):
        """Creating a project through the api makes a TR for all org owners."""
        user1 = User.create(email='*****@*****.**', user_type='user')
        user2 = User.create(email='*****@*****.**', user_type='user')
        org = Organization.create(name="Foo Org", liaison_id=user1.uid)
        user1.owned_organizations = [org.uid]
        user2.owned_organizations = [org.uid]
        user1.put()
        user2.put()
        org.put()

        # Bring org 2 into consistency, assuming they've been part of the org
        # for some time. Don't bring org 1 into consistency, to simulate
        # joining an org and creating a project within a short timespan, which
        # we expect.
        user2.key.get()

        response = self.testapp.post_json(
            '/api/projects',
            {
                'organization_id': org.uid,
                'program_label': 'demo-program',
                'liaison_id': user1.uid
            },
            headers=login_headers(user1.uid),
        )
        project_dict = json.loads(response.body)

        trs1 = TaskReminder.get(ancestor=user1)
        trs2 = TaskReminder.get(ancestor=user2)
        self.assertEqual(len(trs1), 1)
        self.assertEqual(len(trs2), 1)
        self.assertEqual(trs1[0].context_id, project_dict['uid'])
    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,
        )
예제 #11
0
    def test_close_tasklist(self):
        """Should delete all associated task reminders."""
        user1 = User.create(email='*****@*****.**', user_type='user')
        user2 = User.create(email='*****@*****.**', user_type='user')
        org = Organization.create(name="Foo Org", liaison_id=user1.uid)
        user1.owned_organizations = [org.uid]
        user2.owned_organizations = [org.uid]
        user1.put()
        user2.put()
        org.put()

        response = self.testapp.post_json(
            '/api/projects',
            {
                'organization_id': org.uid,
                'program_label': 'demo-program',
                'liaison_id': user1.uid
            },
            headers=login_headers(user1.uid),
        )
        project_dict = json.loads(response.body)
        project = Project.get_by_id(project_dict['uid'])

        # Simulate time passing and the datastore reaching consistency.
        trs1 = TaskReminder.get(ancestor=user1)
        trs2 = TaskReminder.get(ancestor=user2)

        Tasklist(project).close()

        self.assertEqual(len(TaskReminder.get(ancestor=user1)), 0)
        self.assertEqual(len(TaskReminder.get(ancestor=user2)), 0)
예제 #12
0
    def test_update_checkpoint_waiting(self):
        user = User.create(email='*****@*****.**', user_type='super_admin')
        user.put()
        org = Organization.create(name='Foo Org')
        org.put()

        # Work with the first checkpoint (generally there's only one anyway).
        c = org.tasklist.checkpoints[0]

        # Our org tasklist doesn't change much; break down its structure.
        tasks = [t for t in org.tasklist.tasks if t.checkpoint_id == c.uid]
        invite_task, liaison_task, approve_task = tasks

        # Marking the first two complete should change the checkpoint to
        # waiting, since the last is for super admins only.
        for task in (invite_task, liaison_task):
            task.status = 'complete'
            self.testapp.put_json(
                '/api/tasks/{}'.format(task.uid),
                task.to_client_dict(),
                headers=login_headers(user.uid),
            )

        fetched_c = Checkpoint.get_by_id(c.uid)
        self.assertEqual(fetched_c.status, 'waiting')
예제 #13
0
    def test_get_all_surveys(self):
        surveys = self.create_surveys()
        user = User.create(email='*****@*****.**', user_type='super_admin')
        user.put()

        query = '''
        query GetAllSurveys {
            surveys {
                uid
            }
        }
        '''

        expected = {
            # Should be ordered by ordinal
            'surveys': [{
                "uid": s.uid
            } for s in surveys],
        }

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

        self.assertEqual(response.body, json.dumps(expected))
예제 #14
0
    def test_get_all_projects(self):
        user = User.create(email="*****@*****.**", user_type='super_admin')
        user.put()

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

        project1 = Project.create(organization_id=org.uid,
                                  program_label='demo-program')
        project2 = Project.create(organization_id=org.uid,
                                  program_label='demo-program')
        project1.put()
        project2.put()

        query = '''
        query GetAllProjects {
            projects {
                uid
            }
        }
        '''

        response = self.testapp.post_json(
            '/api/graphql',
            {'query': query},
            headers=login_headers(user.uid),
        )
        received = json.loads(response.body)

        # No particular order.
        self.assertIn({'uid': project1.uid}, received['projects'])
        self.assertIn({'uid': project2.uid}, received['projects'])
예제 #15
0
    def test_get_single_project(self):
        user = User.create(email="*****@*****.**", user_type='super_admin')
        user.put()

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

        project = Project.create(
            organization_id=org.uid,
            program_label='demo-program',
            account_manager_id='User_001',
            liaison_id='User_002',
            priority=True,
            deidentification_method='total',
            loa_notes="Some stuff happened.",
            last_active=datetime.datetime.now(),
        )
        project.put()

        query = '''
        query GetSingleProject($uid: String!) {
            project(uid: $uid) {
                account_manager_id
                created
                deidentification_method
                deleted
                last_active
                liaison_id
                loa_notes
                modified
                organization_id
                organization_name
                organization_status
                priority
                program_description
                program_label
                program_name
                short_uid
                uid
            }
        }
        '''

        response = self.testapp.post_json(
            '/api/graphql',
            # See http://graphql.org/learn/serving-over-http/#post-request
            {
                'query': query,
                'variables': {
                    'uid': project.uid
                },
            },
            headers=login_headers(user.uid),
        )

        self.assertEqual(
            response.body,
            json.dumps({'project': project.to_client_dict()}),
        )
예제 #16
0
    def test_get_assc_org(self):
        """You CAN get an org you're merely associated with."""
        # Also creates 3 orgs, where user owns one and is assc with one.
        super_admin, program_admin, user = self.create_entities_to_get()

        assc_id = user.assc_organizations[0]
        response = self.testapp.get('/api/organizations/' + assc_id,
                                    headers=login_headers(user.uid))
예제 #17
0
 def test_get_nonexistent_resource(self):
     user = User.create(email='*****@*****.**')
     user.put()
     for klass in self.get_all_models():
         resource_name = util.camel_to_separated(klass.__name__)
         response = self.testapp.get('/api/{}/foo'.format(resource_name),
                                     headers=login_headers(user.uid),
                                     status=404)
 def test_user_tasklist_not_found(self):
     user = User.create(email='*****@*****.**', user_type='user')
     user.put()
     self.testapp.get(
         '/api/tasklists/foo',
         headers=login_headers(user.uid),
         status=404,
     )
예제 #19
0
    def test_join_org(self):
        """Joining an org makes task reminders for all contained tasklists."""
        program_label = 'demo-program'
        cohort_label = 'demo-cohort'

        # Guarantee the dates will work by mocking the cohort config.
        cohort_config = {
            'label': cohort_label,
            'name': 'Demo Cohort',
            'open_date': str(datetime.date.today()),
            'close_date': str(datetime.date.today()),
        }
        Program.mock_program_config(
            program_label,
            {'cohorts': {
                cohort_label: cohort_config
            }},
        )

        program = Program.get_config(program_label)
        tasklist_template = program['surveys'][0]['survey_tasklist_template']

        owner = User.create(email='*****@*****.**', user_type='user')
        org = Organization.create(name="Foo Org", liaison_id=owner.uid)
        owner.owned_organizations = [org.uid]
        project = Project.create(program_label=program_label,
                                 organization_id=org.uid)
        survey = Survey.create(tasklist_template,
                               project_id=project.uid,
                               organization_id=org.uid,
                               program_label=program_label,
                               ordinal=1,
                               cohort_label=cohort_label)
        owner.put()
        org.put()
        project.put()
        survey.put()

        # The assumption here is the org and its contents are long-standing,
        # so force consistency with all.
        org.key.get()
        project.key.get()
        survey.key.get()

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

        self.testapp.post_json(
            '/api/users/{}/organizations'.format(joiner.uid),
            org.to_client_dict(),
            headers=login_headers(owner.uid),
        )

        # One TaskReminder for each of: org tasklist, project tasklist, survey
        # tasklist.
        self.assertEqual(len(TaskReminder.get(ancestor=joiner)), 3)

        return (org, project, survey, owner, joiner)
예제 #20
0
    def test_get_unrelated_org(self):
        """You can't get an org you're enitrely unrelated to."""
        # Also creates 3 orgs, where user owns one and is assc with one.
        super_admin, program_admin, user = self.create_entities_to_get()

        unrelated_id = super_admin.owned_organizations[0]
        response = self.testapp.get('/api/organizations/' + unrelated_id,
                                    headers=login_headers(user.uid),
                                    status=403)
예제 #21
0
    def test_register_page_as_user(self):
        user = User.create(email='*****@*****.**')
        user.put()
        headers = login_headers(user.uid)

        response = self.testapp.get('/register', headers=headers)
        # Should redirect to the dashboard.
        self.assertEqual(response.status_int, 302)
        self.assertRegexpMatches(
            response.headers.get('Location'), r'/dashboard$')
    def test_completion_csv_invalid_token(self):
        user = User.create(email='*****@*****.**')
        user.put()

        self.testapp.get(
            '/api/project_cohorts/ProjectCohort_foo/completion/ids.csv',
            headers=login_headers(user.uid),
            # no auth token, request invalid
            status=400,
        )
 def test_user_tasklist_forbidden(self):
     """Forbidden if you aren't on the org."""
     liaison, org, project, pc, surveys = self.create_project_cohort()
     user = User.create(email='*****@*****.**', user_type='user')
     user.put()
     self.testapp.get(
         '/api/tasklists/{}'.format(pc.uid),
         headers=login_headers(user.uid),
         status=403,
     )
예제 #24
0
    def test_get_single_user(self):
        user = User.create(email="*****@*****.**",
                           user_type='super_admin',
                           owned_organizations=['Organization_001'])
        user.hashed_password = User.hash_password('abcdefgh')
        user.put()

        query = '''
        query GetSingleUser($uid: String!) {
            user(uid: $uid) {
                assc_organizations
                assc_projects
                created
                deleted
                email
                google_id
                hashed_password
                last_login
                modified
                name
                notification_option
                owned_data_requests
                owned_data_tables
                owned_organizations
                owned_programs
                owned_projects
                phone_number
                role
                short_uid
                uid
                user_type
            }
        }
        '''

        response = self.testapp.post_json(
            '/api/graphql',
            # See http://graphql.org/learn/serving-over-http/#post-request
            {
                'query': query,
                'variables': {
                    'uid': user.uid
                },
            },
            headers=login_headers(user.uid),
        )

        # Using the api gives the user a value for last_login. Refetch them to
        # get an accurate reference.
        user = user.key.get()

        self.assertEqual(
            response.body,
            json.dumps({'user': user.to_client_dict()}),
        )
예제 #25
0
    def test_join_existing_project(self):
        project_dict, user = self.test_user_create()

        # Try to make another one, which should _succeed_, now that we support
        # multiple projects at an org.
        self.testapp.post_json(
            '/api/projects',
            {'organization_id': self.org_id,
             'program_label': self.program_label},
            headers=login_headers(user.uid),
        )
예제 #26
0
    def test_related_query_forbidden(self):
        """Can't query for owners of an org you don't own."""
        org = Organization.create()
        user = User.create(email="*****@*****.**")
        org.put()
        user.put()

        response = self.testapp.get('/api/organizations/{}/users'.format(
            org.uid),
                                    headers=login_headers(user.uid),
                                    status=403)
예제 #27
0
    def test_add_self_to_organization(self):
        """Can't give org ownership if you're not an owner."""
        org = Organization.create()
        joiner = User.create(email="*****@*****.**")
        org.put()
        joiner.put()

        response = self.testapp.put('/api/organizations/{}/users/{}'.format(
            org.uid, joiner.uid),
                                    headers=login_headers(joiner.uid),
                                    status=403)
예제 #28
0
    def test_get_owned_org(self):
        """You can get an org you own."""
        # Also creates 3 orgs, where user owns one and is assc with one.
        super_admin, program_admin, user = self.create_entities_to_get()

        owned_id = user.owned_organizations[0]
        response = self.testapp.get('/api/organizations/' + owned_id,
                                    headers=login_headers(user.uid))
        org = json.loads(response.body)
        self.assertIs(type(org), dict)
        self.assertEquals(org['uid'], owned_id)
예제 #29
0
    def test_leave_org(self):
        """Leaving an org deletes task reminders for all related task lists."""

        org, project, survey, owner, joiner = self.test_join_org()

        self.testapp.delete(
            '/api/users/{}/organizations/{}'.format(joiner.uid, org.uid),
            headers=login_headers(owner.uid),
        )

        self.assertEqual(len(TaskReminder.get(ancestor=joiner)), 0)
    def test_super_tasklist_forbidden(self):
        """Forbidden if you're not a super."""
        user = User.create(email='*****@*****.**', user_type='user')
        user.put()

        self.testapp.post_json(
            '/api/graphql',
            {},
            headers=login_headers(user.uid),
            status=403,
        )