Ejemplo n.º 1
0
    def test_set_project_perms_to_xform(self):
        """
        Test set_project_perms_to_xform(xform, project)
        """
        self._publish_transportation_form()
        # Alice has data entry role to default project
        alice = self._create_user('alice', 'alice', create_profile=True)
        DataEntryRole.add(alice, self.project)
        set_project_perms_to_xform(self.xform, self.project)
        self.assertTrue(DataEntryRole.user_has_role(alice, self.xform))
        self.assertTrue(self.project.pk, self.xform.project_id)

        # Create other project and transfer xform to new project
        project_b = Project(name='Project B',
                            created_by=self.user,
                            organization=self.user)
        project_b.save()
        self.xform.project = project_b
        self.xform.save()
        self.xform.refresh_from_db()
        self.assertTrue(self.project.pk, self.xform.project_id)

        # set permissions for new project
        set_project_perms_to_xform(self.xform, project_b)

        # Alice should have no data entry role to transfered form
        self.assertFalse(DataEntryRole.user_has_role(alice, self.xform))
Ejemplo n.º 2
0
    def test_publish_to_public_project_public_form(self):
        public_project = Project(name='demo',
                                 shared=True,
                                 metadata=json.dumps({'description': ''}),
                                 created_by=self.user,
                                 organization=self.user)
        public_project.save()

        self.project = public_project

        data = {
            'owner': 'http://testserver/api/v1/users/%s'
            % self.project.organization.username,
            'public': True,
            'public_data': True,
            'description': u'transportation_2011_07_25',
            'downloadable': True,
            'allows_sms': False,
            'encrypted': False,
            'sms_id_string': u'transportation_2011_07_25',
            'id_string': u'transportation_2011_07_25',
            'title': u'transportation_2011_07_25',
            'bamboo_dataset': u''
        }
        self._publish_xls_form_to_project(publish_data=data, merge=False)

        self.assertEquals(self.xform.shared, True)
        self.assertEquals(self.xform.shared_data, True)
Ejemplo n.º 3
0
    def test_publish_to_public_project_public_form(self):
        public_project = Project(name='demo',
                                 shared=True,
                                 metadata=json.dumps({'description': ''}),
                                 created_by=self.user,
                                 organization=self.user)
        public_project.save()

        self.project = public_project

        data = {
            'owner': 'http://testserver/api/v1/users/%s'
            % self.project.organization.username,
            'public': True,
            'public_data': True,
            'description': u'transportation_2011_07_25',
            'downloadable': True,
            'allows_sms': False,
            'encrypted': False,
            'sms_id_string': u'transportation_2011_07_25',
            'id_string': u'transportation_2011_07_25',
            'title': u'transportation_2011_07_25',
            'bamboo_dataset': u''
        }
        self._publish_xls_form_to_project(publish_data=data, merge=False)

        self.assertEquals(self.xform.shared, True)
        self.assertEquals(self.xform.shared_data, True)
Ejemplo n.º 4
0
    def test_set_project_perms_to_xform(self):
        """
        Test set_project_perms_to_xform(xform, project)
        """
        self._publish_transportation_form()
        # Alice has data entry role to default project
        alice = self._create_user('alice', 'alice', create_profile=True)
        DataEntryRole.add(alice, self.project)
        set_project_perms_to_xform(self.xform, self.project)
        self.assertTrue(DataEntryRole.user_has_role(alice, self.xform))
        self.assertTrue(self.project.pk, self.xform.project_id)

        # Create other project and transfer xform to new project
        project_b = Project(
            name='Project B', created_by=self.user, organization=self.user)
        project_b.save()
        self.xform.project = project_b
        self.xform.save()
        self.xform.refresh_from_db()
        self.assertTrue(self.project.pk, self.xform.project_id)

        # set permissions for new project
        set_project_perms_to_xform(self.xform, project_b)

        # Alice should have no data entry role to transfered form
        self.assertFalse(DataEntryRole.user_has_role(alice, self.xform))
Ejemplo n.º 5
0
    def test_publish_to_public_project(self):
        public_project = Project(name='demo',
                                 shared=True,
                                 metadata=json.dumps({'description': ''}),
                                 created_by=self.user,
                                 organization=self.user)
        public_project.save()

        self.project = public_project
        self._publish_xls_form_to_project(public=True)

        self.assertEquals(self.xform.shared, True)
        self.assertEquals(self.xform.shared_data, True)
Ejemplo n.º 6
0
    def test_publish_to_public_project(self):
        public_project = Project(name='demo',
                                 shared=True,
                                 metadata=json.dumps({'description': ''}),
                                 created_by=self.user,
                                 organization=self.user)
        public_project.save()

        self.project = public_project
        self._publish_xls_form_to_project(public=True)

        self.assertEquals(self.xform.shared, True)
        self.assertEquals(self.xform.shared_data, True)
Ejemplo n.º 7
0
    def restore_object(self, attrs, instance=None):
        if instance:
            metadata = JsonField.to_json(attrs.get('metadata'))
            owner = attrs.get('organization')

            if self.partial and metadata:
                if not isinstance(instance.metadata, dict):
                    instance.metadata = {}

                instance.metadata.update(metadata)
                attrs['metadata'] = instance.metadata

            if self.partial and owner:
                # give the new owner permissions
                set_owners_permission(owner, instance)

                # clear cache
                safe_delete('{}{}'.format(PROJ_PERM_CACHE, self.object.pk))

            return super(ProjectSerializer,
                         self).restore_object(attrs, instance)

        if 'request' in self.context:
            created_by = self.context['request'].user

            return Project(
                name=attrs.get('name'),
                organization=attrs.get('organization'),
                created_by=created_by,
                metadata=attrs.get('metadata'),
            )

        return attrs
Ejemplo n.º 8
0
    def restore_object(self, attrs, instance=None):
        if instance:
            metadata = JsonField.to_json(attrs.get('metadata'))

            if self.partial and metadata:
                if not isinstance(instance.metadata, dict):
                    instance.metadata = {}

                instance.metadata.update(metadata)
                attrs['metadata'] = instance.metadata

            return super(ProjectSerializer,
                         self).restore_object(attrs, instance)

        if 'request' in self.context:
            created_by = self.context['request'].user

            return Project(
                name=attrs.get('name'),
                organization=attrs.get('organization'),
                created_by=created_by,
                metadata=attrs.get('metadata'),
            )

        return attrs
Ejemplo n.º 9
0
    def test_user_can_view_public_projects(self):
        public_project = Project(name='demo',
                                 shared=True,
                                 metadata=json.dumps({'description': ''}),
                                 created_by=self.user,
                                 organization=self.user)
        public_project.save()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        self._login_user_and_profile(alice_data)

        view = ProjectViewSet.as_view({'get': 'retrieve'})
        request = self.factory.get('/', **self.extra)
        response = view(request, pk=public_project.pk)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data['public'], True)
        self.assertEqual(response.data['projectid'], public_project.pk)
        self.assertEqual(response.data['name'], 'demo')
Ejemplo n.º 10
0
    def test_public_form_private_project(self):
        self.project = Project(name='demo', shared=False,
                               metadata=json.dumps({'description': ''}),
                               created_by=self.user, organization=self.user)
        self.project.save()
        self._publish_xls_form_to_project()

        self.assertFalse(self.xform.shared)
        self.assertFalse(self.xform.shared_data)
        self.assertFalse(self.project.shared)

        # when xform.shared is true, project settings does not override
        self.xform.shared = True
        self.xform.save()
        self.project.save()
        self.xform.reload()
        self.project.reload()
        self.assertTrue(self.xform.shared)
        self.assertFalse(self.xform.shared_data)
        self.assertFalse(self.project.shared)

        # when xform.shared_data is true, project settings does not override
        self.xform.shared = False
        self.xform.shared_data = True
        self.xform.save()
        self.project.save()
        self.xform.reload()
        self.project.reload()
        self.assertFalse(self.xform.shared)
        self.assertTrue(self.xform.shared_data)
        self.assertFalse(self.project.shared)

        # when xform.shared is true, submissions are made,
        # project settings does not override
        self.xform.shared = True
        self.xform.shared_data = False
        self.xform.save()
        self.project.save()
        self._make_submissions()
        self.xform.reload()
        self.project.reload()
        self.assertTrue(self.xform.shared)
        self.assertFalse(self.xform.shared_data)
        self.assertFalse(self.project.shared)
Ejemplo n.º 11
0
    def test_user_can_view_public_projects(self):
        public_project = Project(name='demo',
                                 shared=True,
                                 metadata=json.dumps({'description': ''}),
                                 created_by=self.user,
                                 organization=self.user)
        public_project.save()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        self._login_user_and_profile(alice_data)

        view = ProjectViewSet.as_view({
            'get': 'retrieve'
        })
        request = self.factory.get('/', **self.extra)
        response = view(request, pk=public_project.pk)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data['public'], True)
        self.assertEqual(response.data['projectid'], public_project.pk)
        self.assertEqual(response.data['name'], 'demo')
Ejemplo n.º 12
0
    def test_upload_to_with_project_and_xform_instance(self):
        model_instance = Project(created_by=self.user)
        metadata = MetaData(data_type="media")
        metadata.content_object = model_instance

        filename = "filename"

        self.assertEquals(upload_to(metadata, filename),
                          "{}/{}/{}".format(self.user.username,
                                            'formid-media',
                                            filename))
        model_instance = XForm(user=self.user, created_by=self.user)
        metadata = MetaData(data_type="media")
        metadata.content_object = model_instance

        filename = "filename"

        self.assertEquals(upload_to(metadata, filename),
                          "{}/{}/{}".format(self.user.username,
                                            'formid-media',
                                            filename))
Ejemplo n.º 13
0
class TestProjectViewSet(TestAbstractViewSet):

    def setUp(self):
        super(self.__class__, self).setUp()
        self.view = ProjectViewSet.as_view({
            'get': 'list',
            'post': 'create'
        })

    @patch('urllib2.urlopen')
    def test_publish_xlsform_using_url_upload(self,  mock_urlopen):
        with HTTMock(enketo_mock):
            self._project_create()
            view = ProjectViewSet.as_view({
                'post': 'forms'
            })

            pre_count = XForm.objects.count()
            project_id = self.project.pk
            xls_url = 'https://ona.io/examples/forms/tutorial/form.xlsx'
            path = os.path.join(
                settings.PROJECT_ROOT, "apps", "main", "tests", "fixtures",
                "transportation", "transportation_different_id_string.xlsx")

            xls_file = open(path)
            mock_urlopen.return_value = xls_file

            post_data = {'xls_url': xls_url}
            request = self.factory.post('/', data=post_data, **self.extra)
            response = view(request, pk=project_id)

            mock_urlopen.assert_called_with(xls_url)
            xls_file.close()
            self.assertEqual(response.status_code, 201)
            self.assertEqual(XForm.objects.count(), pre_count + 1)

    def test_projects_list(self):
        self._project_create()
        request = self.factory.get('/', **self.extra)
        response = self.view(request)
        self.assertNotEqual(response.get('Last-Modified'), None)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data, [self.project_data])
        self.assertIn('created_by', response.data[0].keys())

    def test_projects_get(self):
        self._project_create()
        view = ProjectViewSet.as_view({
            'get': 'retrieve'
        })
        request = self.factory.get('/', **self.extra)
        response = view(request, pk=self.project.pk)
        user_props = ['user', 'first_name', 'last_name', 'role', 'gravatar',
                      'metadata', 'permissions']
        user_props.sort()

        self.assertNotEqual(response.get('Last-Modified'), None)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data, self.project_data)
        res_user_props = response.data['users'][0].keys()
        res_user_props.sort()
        self.assertEqual(res_user_props, user_props)

    def test_projects_tags(self):
        self._project_create()
        view = ProjectViewSet.as_view({
            'get': 'labels',
            'post': 'labels',
            'delete': 'labels'
        })
        list_view = ProjectViewSet.as_view({
            'get': 'list',
        })
        project_id = self.project.pk
        # no tags
        request = self.factory.get('/', **self.extra)
        response = view(request, pk=project_id)
        self.assertNotEqual(response.get('Last-Modified'), None)
        self.assertEqual(response.data, [])
        # add tag "hello"
        request = self.factory.post('/', data={"tags": "hello"}, **self.extra)
        response = view(request, pk=project_id)
        self.assertEqual(response.status_code, 201)
        self.assertEqual(response.data, [u'hello'])

        # check filter by tag
        request = self.factory.get('/', data={"tags": "hello"}, **self.extra)

        request.user = self.user
        self.project_data = ProjectSerializer(
            self.project, context={'request': request}).data
        response = list_view(request, pk=project_id)
        self.assertNotEqual(response.get('Last-Modified'), None)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data, [self.project_data])

        request = self.factory.get('/', data={"tags": "goodbye"}, **self.extra)
        response = list_view(request, pk=project_id)
        self.assertNotEqual(response.get('Last-Modified'), None)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data, [])

        # remove tag "hello"
        request = self.factory.delete('/', **self.extra)
        response = view(request, pk=project_id, label='hello')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.get('Last-Modified'), None)
        self.assertEqual(response.data, [])

    def test_projects_create(self):
        self._project_create()
        self.assertIsNotNone(self.project_data)

        projects = Project.objects.all()
        self.assertEqual(len(projects), 1)

        for project in projects:
            self.assertEqual(self.user, project.created_by)
            self.assertEqual(self.user, project.organization)

    def test_projects_create_no_metadata(self):
        data = {
            'name': u'demo',
            'owner':
            'http://testserver/api/v1/users/%s' % self.user.username,
            'public': False
        }
        self._project_create(project_data=data,
                             merge=False)
        self.assertIsNotNone(self.project)
        self.assertIsNotNone(self.project_data)

        projects = Project.objects.all()
        self.assertEqual(len(projects), 1)

        for project in projects:
            self.assertEqual(self.user, project.created_by)
            self.assertEqual(self.user, project.organization)

    def test_projects_create_many_users(self):
        self._project_create()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        self._login_user_and_profile(alice_data)
        self._project_create()
        projects = Project.objects.filter(created_by=self.user)
        self.assertEqual(len(projects), 1)

        for project in projects:
            self.assertEqual(self.user, project.created_by)
            self.assertEqual(self.user, project.organization)

    def test_publish_xls_form_to_project(self):
        self._publish_xls_form_to_project()
        project_name = u'another project'
        self._project_create({'name': project_name})
        self._publish_xls_form_to_project()

    def test_num_datasets(self):
        self._publish_xls_form_to_project()
        request = self.factory.post('/', data={}, **self.extra)
        request.user = self.user
        self.project_data = ProjectSerializer(
            self.project, context={'request': request}).data
        self.assertEqual(self.project_data['num_datasets'], 1)

    def test_last_submission_date(self):
        self._publish_xls_form_to_project()
        self._make_submissions()
        request = self.factory.post('/', data={}, **self.extra)
        request.user = self.user
        self.project_data = ProjectSerializer(
            self.project, context={'request': request}).data
        date_created = self.xform.instances.order_by(
            '-date_created').values_list('date_created', flat=True)[0]
        self.assertEqual(str(self.project_data['last_submission_date']),
                         str(date_created))

    def test_view_xls_form(self):
        self._publish_xls_form_to_project()
        view = ProjectViewSet.as_view({
            'get': 'forms'
        })
        request = self.factory.get('/', **self.extra)
        response = view(request, pk=self.project.pk)
        self.assertNotEqual(response.get('Last-Modified'), None)
        self.assertEqual(response.status_code, 200)
        resultset = MetaData.objects.filter(Q(xform_id=self.xform.pk), Q(
            data_type='enketo_url') | Q(data_type='enketo_preview_url'))
        url = resultset.get(data_type='enketo_url')
        preview_url = resultset.get(data_type='enketo_preview_url')
        self.form_data['metadata'] = [{
            'id': preview_url.pk,
            'xform': self.xform.pk,
            'data_value': u'https://enketo.ona.io/webform/preview?'
            'server=http://testserver/%s/&id=transportation_2011_07_25' %
            self.xform.user.username,
            'data_type': u'enketo_preview_url',
            'data_file': u'',
            'data_file_type': None,
            u'url': u'http://testserver/api/v1/metadata/%s' % preview_url.pk,
            'file_hash': None,
            'media_url': None
        }, {
            'id': url.pk,
            'data_value': u'https://dmfrm.enketo.org/webform',
            'xform': self.xform.pk,
            'data_file': u'',
            'data_type': u'enketo_url',
            u'url': u'http://testserver/api/v1/metadata/%s' % url.pk,
            'data_file_type': None,
            'file_hash': None,
            'media_url': None
        }]

        self.form_data['metadata'].sort()
        response.data[0]['metadata'].sort()

        self.assertEqual(response.data, [self.form_data])

    def test_assign_form_to_project(self):
        view = ProjectViewSet.as_view({
            'post': 'forms',
            'get': 'retrieve'
        })
        self._publish_xls_form_to_project()
        formid = self.xform.pk
        old_project = self.project
        project_name = u'another project'
        self._project_create({'name': project_name})
        self.assertTrue(self.project.name == project_name)

        project_id = self.project.pk
        post_data = {'formid': formid}
        request = self.factory.post('/', data=post_data, **self.extra)
        response = view(request, pk=project_id)
        self.assertEqual(response.status_code, 201)
        self.assertTrue(self.project.xform_set.filter(pk=self.xform.pk))
        self.assertFalse(old_project.xform_set.filter(pk=self.xform.pk))

        # check if form added appears in the project details
        request = self.factory.get('/', **self.extra)
        response = view(request, pk=self.project.pk)
        self.assertIn('forms', response.data.keys())
        self.assertEqual(len(response.data['forms']), 1)

    def test_project_manager_can_assign_form_to_project(self):
        view = ProjectViewSet.as_view({
            'post': 'forms',
            'get': 'retrieve'
        })
        self._publish_xls_form_to_project()
        # alice user as manager to both projects
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        alice_profile = self._create_user_profile(alice_data)
        ShareProject(self.project, 'alice', 'manager').save()
        self.assertTrue(ManagerRole.user_has_role(alice_profile.user,
                                                  self.project))

        formid = self.xform.pk
        old_project = self.project
        project_name = u'another project'
        self._project_create({'name': project_name})
        self.assertTrue(self.project.name == project_name)
        ShareProject(self.project, 'alice', 'manager').save()
        self.assertTrue(ManagerRole.user_has_role(alice_profile.user,
                                                  self.project))
        self._login_user_and_profile(alice_data)

        project_id = self.project.pk
        post_data = {'formid': formid}
        request = self.factory.post('/', data=post_data, **self.extra)
        response = view(request, pk=project_id)
        self.assertEqual(response.status_code, 201)
        self.assertTrue(self.project.xform_set.filter(pk=self.xform.pk))
        self.assertFalse(old_project.xform_set.filter(pk=self.xform.pk))

        # check if form added appears in the project details
        request = self.factory.get('/', **self.extra)
        response = view(request, pk=self.project.pk)
        self.assertIn('forms', response.data.keys())
        self.assertEqual(len(response.data['forms']), 1)

    def test_project_manager_can_assign_form_to_project_no_perm(self):
        # user must have owner/manager permissions
        view = ProjectViewSet.as_view({
            'post': 'forms',
            'get': 'retrieve'
        })
        self._publish_xls_form_to_project()
        # alice user is not manager to both projects
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        alice_profile = self._create_user_profile(alice_data)
        self.assertFalse(ManagerRole.user_has_role(alice_profile.user,
                                                   self.project))

        formid = self.xform.pk
        project_name = u'another project'
        self._project_create({'name': project_name})
        self.assertTrue(self.project.name == project_name)
        ManagerRole.add(alice_profile.user, self.project)
        self.assertTrue(ManagerRole.user_has_role(alice_profile.user,
                                                  self.project))
        self._login_user_and_profile(alice_data)

        project_id = self.project.pk
        post_data = {'formid': formid}
        request = self.factory.post('/', data=post_data, **self.extra)
        response = view(request, pk=project_id)
        self.assertEqual(response.status_code, 403)

    def test_project_users_get_readonly_role_on_add_form(self):
        self._project_create()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        alice_profile = self._create_user_profile(alice_data)
        ReadOnlyRole.add(alice_profile.user, self.project)
        self.assertTrue(ReadOnlyRole.user_has_role(alice_profile.user,
                                                   self.project))
        self._publish_xls_form_to_project()
        self.assertTrue(ReadOnlyRole.user_has_role(alice_profile.user,
                                                   self.xform))
        self.assertFalse(OwnerRole.user_has_role(alice_profile.user,
                                                 self.xform))

    @patch('onadata.apps.api.viewsets.project_viewset.send_mail')
    def test_project_share_endpoint(self, mock_send_mail):
        # create project and publish form to project
        self._publish_xls_form_to_project()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        alice_profile = self._create_user_profile(alice_data)
        projectid = self.project.pk

        ROLES = [ReadOnlyRoleNoDownload,
                 ReadOnlyRole,
                 DataEntryRole,
                 EditorRole,
                 ManagerRole,
                 OwnerRole]
        for role_class in ROLES:
            self.assertFalse(role_class.user_has_role(alice_profile.user,
                                                      self.project))

            data = {'username': '******', 'role': role_class.name,
                    'email_msg': 'I have shared the project with you'}
            request = self.factory.post('/', data=data, **self.extra)

            view = ProjectViewSet.as_view({
                'post': 'share'
            })
            response = view(request, pk=projectid)

            self.assertEqual(response.status_code, 204)
            self.assertTrue(mock_send_mail.called)

            self.assertTrue(role_class.user_has_role(alice_profile.user,
                                                     self.project))
            self.assertTrue(role_class.user_has_role(alice_profile.user,
                                                     self.xform))
            # Reset the mock called value to False
            mock_send_mail.called = False

            data = {'username': '******', 'role': ''}
            request = self.factory.post('/', data=data, **self.extra)
            response = view(request, pk=projectid)

            self.assertEqual(response.status_code, 400)
            self.assertEqual(response.get('Last-Modified'), None)
            self.assertFalse(mock_send_mail.called)

            role_class._remove_obj_permissions(alice_profile.user,
                                               self.project)

    @patch('onadata.apps.api.viewsets.project_viewset.send_mail')
    def test_project_share_endpoint_form_published_later(self, mock_send_mail):
        # create project
        self._project_create()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        alice_profile = self._create_user_profile(alice_data)
        projectid = self.project.pk

        ROLES = [ReadOnlyRole,
                 DataEntryRole,
                 EditorRole,
                 ManagerRole,
                 OwnerRole]
        for role_class in ROLES:
            self.assertFalse(role_class.user_has_role(alice_profile.user,
                                                      self.project))

            data = {'username': '******', 'role': role_class.name,
                    'email_msg': 'I have shared the project with you'}
            request = self.factory.post('/', data=data, **self.extra)

            view = ProjectViewSet.as_view({
                'post': 'share'
            })
            response = view(request, pk=projectid)

            self.assertEqual(response.status_code, 204)
            self.assertTrue(mock_send_mail.called)

            self.assertTrue(role_class.user_has_role(alice_profile.user,
                                                     self.project))

            # publish form after project sharing
            self._publish_xls_form_to_project()
            self.assertTrue(role_class.user_has_role(alice_profile.user,
                                                     self.xform))
            # Reset the mock called value to False
            mock_send_mail.called = False

            data = {'username': '******', 'role': ''}
            request = self.factory.post('/', data=data, **self.extra)
            response = view(request, pk=projectid)

            self.assertEqual(response.status_code, 400)
            self.assertEqual(response.get('Last-Modified'), None)
            self.assertFalse(mock_send_mail.called)

            role_class._remove_obj_permissions(alice_profile.user,
                                               self.project)
            self.xform.delete()

    def test_project_share_remove_user(self):
        self._project_create()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        alice_profile = self._create_user_profile(alice_data)
        view = ProjectViewSet.as_view({
            'post': 'share'
        })
        projectid = self.project.pk
        role_class = ReadOnlyRole
        data = {'username': '******', 'role': role_class.name}
        request = self.factory.post('/', data=data, **self.extra)
        response = view(request, pk=projectid)

        self.assertEqual(response.status_code, 204)
        self.assertTrue(role_class.user_has_role(alice_profile.user,
                                                 self.project))

        view = ProjectViewSet.as_view({
            'post': 'share'
        })
        data['remove'] = True
        request = self.factory.post('/', data=data, **self.extra)
        response = view(request, pk=projectid)
        self.assertEqual(response.status_code, 204)
        self.assertFalse(role_class.user_has_role(alice_profile.user,
                                                  self.project))

    def test_project_filter_by_owner(self):
        self._project_create()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        self._login_user_and_profile(alice_data)

        ReadOnlyRole.add(self.user, self.project)

        view = ProjectViewSet.as_view({
            'get': 'retrieve'
        })
        request = self.factory.get('/', **self.extra)
        response = view(request, pk=self.project.pk)
        updated_project_data = response.data

        self._project_create({'name': 'another project'})

        # both bob's and alice's projects
        request = self.factory.get('/', **self.extra)
        response = self.view(request)
        self.assertEqual(response.status_code, 200)
        self.assertIn(updated_project_data, response.data)
        self.assertIn(self.project_data, response.data)

        # only bob's project
        request = self.factory.get('/', {'owner': 'bob'}, **self.extra)
        response = self.view(request)
        self.assertEqual(response.status_code, 200)
        self.assertIn(updated_project_data, response.data)
        self.assertNotIn(self.project_data, response.data)

        # only alice's project
        request = self.factory.get('/', {'owner': 'alice'}, **self.extra)
        response = self.view(request)
        self.assertEqual(response.status_code, 200)
        self.assertNotIn(updated_project_data, response.data)
        self.assertIn(self.project_data, response.data)

        # none existent user
        request = self.factory.get('/', {'owner': 'noone'}, **self.extra)
        response = self.view(request)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data, [])

        # authenticated user can view public project
        joe_data = {'username': '******', 'email': '*****@*****.**'}
        self._login_user_and_profile(joe_data)

        # should not show private projects when filtered by owner
        request = self.factory.get('/', {'owner': 'alice'}, **self.extra)
        response = self.view(request)
        self.assertEqual(response.status_code, 200)
        self.assertNotIn(updated_project_data, response.data)
        self.assertNotIn(self.project_data, response.data)

        # should show public project when filtered by owner
        self.project.shared = True
        self.project.save()
        request.user = self.user
        self.project_data = ProjectSerializer(
            self.project, context={'request': request}).data

        request = self.factory.get('/', {'owner': 'alice'}, **self.extra)
        response = self.view(request)
        self.assertEqual(response.status_code, 200)
        self.assertIn(self.project_data, response.data)

    def test_project_partial_updates(self):
        self._project_create()
        view = ProjectViewSet.as_view({
            'patch': 'partial_update'
        })
        projectid = self.project.pk
        metadata = '{"description": "Lorem ipsum",' \
                   '"location": "Nakuru, Kenya",' \
                   '"category": "water"' \
                   '}'
        json_metadata = json.loads(metadata)
        data = {'metadata': metadata}
        request = self.factory.patch('/', data=data, **self.extra)
        response = view(request, pk=projectid)
        project = Project.objects.get(pk=projectid)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(project.metadata, json_metadata)

    def test_project_put_updates(self):
        self._project_create()
        view = ProjectViewSet.as_view({
            'put': 'update'
        })
        projectid = self.project.pk
        data = {
            'name': u'updated name',
            'owner': 'http://testserver/api/v1/users/%s' % self.user.username,
            'metadata': {'description': 'description',
                         'location': 'Nairobi, Kenya',
                         'category': 'health'}
        }
        data.update({'metadata': json.dumps(data.get('metadata'))})
        request = self.factory.put('/', data=data, **self.extra)
        response = view(request, pk=projectid)
        data.update({'metadata': json.loads(data.get('metadata'))})
        self.assertDictContainsSubset(data, response.data)

    def test_project_partial_updates_to_existing_metadata(self):
        self._project_create()
        view = ProjectViewSet.as_view({
            'patch': 'partial_update'
        })
        projectid = self.project.pk
        metadata = '{"description": "Changed description"}'
        json_metadata = json.loads(metadata)
        data = {'metadata': metadata}
        request = self.factory.patch('/', data=data, **self.extra)
        response = view(request, pk=projectid)
        project = Project.objects.get(pk=projectid)
        json_metadata.update(project.metadata)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(project.metadata, json_metadata)

    def test_project_update_shared_cascades_to_xforms(self):
        self._publish_xls_form_to_project()
        view = ProjectViewSet.as_view({
            'patch': 'partial_update'
        })
        projectid = self.project.pk
        data = {'public': 'true'}
        request = self.factory.patch('/', data=data, **self.extra)
        response = view(request, pk=projectid)
        xforms_status = XForm.objects.filter(project__pk=projectid)\
            .values_list('shared', flat=True)
        self.assertTrue(xforms_status[0])
        self.assertEqual(response.status_code, 200)

    def test_project_add_star(self):
        self._project_create()
        self.assertEqual(len(self.project.user_stars.all()), 0)

        view = ProjectViewSet.as_view({
            'post': 'star'
        })
        request = self.factory.post('/', **self.extra)
        response = view(request, pk=self.project.pk)
        self.project.reload()

        self.assertEqual(response.status_code, 204)
        self.assertEqual(response.get('Last-Modified'), None)
        self.assertEqual(len(self.project.user_stars.all()), 1)
        self.assertEqual(self.project.user_stars.all()[0], self.user)

    def test_project_delete_star(self):
        self._project_create()

        view = ProjectViewSet.as_view({
            'delete': 'star',
            'post': 'star'
        })
        request = self.factory.post('/', **self.extra)
        response = view(request, pk=self.project.pk)
        self.project.reload()
        self.assertEqual(len(self.project.user_stars.all()), 1)
        self.assertEqual(self.project.user_stars.all()[0], self.user)

        request = self.factory.delete('/', **self.extra)
        response = view(request, pk=self.project.pk)
        self.project.reload()

        self.assertEqual(response.status_code, 204)
        self.assertEqual(len(self.project.user_stars.all()), 0)

    def test_project_get_starred_by(self):
        self._project_create()

        # add star as bob
        view = ProjectViewSet.as_view({
            'get': 'star',
            'post': 'star'
        })
        request = self.factory.post('/', **self.extra)
        response = view(request, pk=self.project.pk)

        # ensure email not shared
        user_profile_data = self.user_profile_data()
        del user_profile_data['email']

        alice_data = {'username': '******', 'email': '*****@*****.**'}
        self._login_user_and_profile(alice_data)

        # add star as alice
        request = self.factory.post('/', **self.extra)
        response = view(request, pk=self.project.pk)

        # get star users as alice
        request = self.factory.get('/', **self.extra)
        response = view(request, pk=self.project.pk)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.data), 2)

        alice_profile, bob_profile = sorted(response.data,
                                            key=itemgetter('username'))
        self.assertEquals(sorted(bob_profile.items()),
                          sorted(user_profile_data.items()))
        self.assertEqual(alice_profile['username'], 'alice')

    def test_user_can_view_public_projects(self):
        public_project = Project(name='demo',
                                 shared=True,
                                 metadata=json.dumps({'description': ''}),
                                 created_by=self.user,
                                 organization=self.user)
        public_project.save()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        self._login_user_and_profile(alice_data)

        view = ProjectViewSet.as_view({
            'get': 'retrieve'
        })
        request = self.factory.get('/', **self.extra)
        response = view(request, pk=public_project.pk)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data['public'], True)
        self.assertEqual(response.data['projectid'], public_project.pk)
        self.assertEqual(response.data['name'], 'demo')

    def test_projects_same_name_diff_case(self):
        data1 = {
            'name': u'demo',
            'owner':
            'http://testserver/api/v1/users/%s' % self.user.username,
            'metadata': {'description': 'Some description',
                         'location': 'Naivasha, Kenya',
                         'category': 'governance'},
            'public': False
        }
        self._project_create(project_data=data1,
                             merge=False)
        self.assertIsNotNone(self.project)
        self.assertIsNotNone(self.project_data)

        projects = Project.objects.all()
        self.assertEqual(len(projects), 1)

        data2 = {
            'name': u'DEMO',
            'owner':
            'http://testserver/api/v1/users/%s' % self.user.username,
            'metadata': {'description': 'Some description',
                         'location': 'Naivasha, Kenya',
                         'category': 'governance'},
            'public': False
        }
        view = ProjectViewSet.as_view({
            'post': 'create'
        })

        request = self.factory.post(
            '/', data=json.dumps(data2),
            content_type="application/json", **self.extra)

        response = view(request, owner=self.user.username)
        self.assertEqual(response.status_code, 400)
        self.assertEqual(response.get('Last-Modified'), None)
        projects = Project.objects.all()
        self.assertEqual(len(projects), 1)

        for project in projects:
            self.assertEqual(self.user, project.created_by)
            self.assertEqual(self.user, project.organization)

    def test_projects_get_exception(self):
        view = ProjectViewSet.as_view({
            'get': 'retrieve'
        })
        request = self.factory.get('/', **self.extra)

        # does not exists
        response = view(request, pk=11111)
        self.assertEqual(response.status_code, 404)
        self.assertEqual(response.data, {u'detail': u'Not found'})

        # invalid id
        response = view(request, pk='1w')
        self.assertEqual(response.status_code, 400)
        error_data = {u'detail': u"Invalid value for project_id '1w' must be a"
                                 " positive integer."}
        self.assertEqual(response.data, error_data)

    def test_publish_to_public_project(self):
        public_project = Project(name='demo',
                                 shared=True,
                                 metadata=json.dumps({'description': ''}),
                                 created_by=self.user,
                                 organization=self.user)
        public_project.save()

        self.project = public_project
        self._publish_xls_form_to_project(public=True)

        self.assertEquals(self.xform.shared, True)
        self.assertEquals(self.xform.shared_data, True)

    def test_public_form_private_project(self):
        self.project = Project(name='demo', shared=False,
                               metadata=json.dumps({'description': ''}),
                               created_by=self.user, organization=self.user)
        self.project.save()
        self._publish_xls_form_to_project()

        self.assertFalse(self.xform.shared)
        self.assertFalse(self.xform.shared_data)
        self.assertFalse(self.project.shared)

        # when xform.shared is true, project settings does not override
        self.xform.shared = True
        self.xform.save()
        self.project.save()
        self.xform.reload()
        self.project.reload()
        self.assertTrue(self.xform.shared)
        self.assertFalse(self.xform.shared_data)
        self.assertFalse(self.project.shared)

        # when xform.shared_data is true, project settings does not override
        self.xform.shared = False
        self.xform.shared_data = True
        self.xform.save()
        self.project.save()
        self.xform.reload()
        self.project.reload()
        self.assertFalse(self.xform.shared)
        self.assertTrue(self.xform.shared_data)
        self.assertFalse(self.project.shared)

        # when xform.shared is true, submissions are made,
        # project settings does not override
        self.xform.shared = True
        self.xform.shared_data = False
        self.xform.save()
        self.project.save()
        self._make_submissions()
        self.xform.reload()
        self.project.reload()
        self.assertTrue(self.xform.shared)
        self.assertFalse(self.xform.shared_data)
        self.assertFalse(self.project.shared)

    def test_publish_to_public_project_public_form(self):
        public_project = Project(name='demo',
                                 shared=True,
                                 metadata=json.dumps({'description': ''}),
                                 created_by=self.user,
                                 organization=self.user)
        public_project.save()

        self.project = public_project

        data = {
            'owner': 'http://testserver/api/v1/users/%s'
            % self.project.organization.username,
            'public': True,
            'public_data': True,
            'description': u'transportation_2011_07_25',
            'downloadable': True,
            'allows_sms': False,
            'encrypted': False,
            'sms_id_string': u'transportation_2011_07_25',
            'id_string': u'transportation_2011_07_25',
            'title': u'transportation_2011_07_25',
            'bamboo_dataset': u''
        }
        self._publish_xls_form_to_project(publish_data=data, merge=False)

        self.assertEquals(self.xform.shared, True)
        self.assertEquals(self.xform.shared_data, True)

    def test_project_all_users_can_share_remove_themselves(self):
        self._publish_xls_form_to_project()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        self._login_user_and_profile(alice_data)

        view = ProjectViewSet.as_view({
            'put': 'share'
        })

        data = {'username': '******', 'remove': True}
        for role_name, role_class in role.ROLES.iteritems():

            ShareProject(self.project, 'alice', role_name).save()

            self.assertTrue(role_class.user_has_role(self.user,
                                                     self.project))
            self.assertTrue(role_class.user_has_role(self.user,
                                                     self.xform))
            data['role'] = role_name

            request = self.factory.put('/', data=data, **self.extra)
            response = view(request, pk=self.project.pk)

            self.assertEqual(response.status_code, 204)

            self.assertFalse(role_class.user_has_role(self.user,
                                                      self.project))
            self.assertFalse(role_class.user_has_role(self.user,
                                                      self.xform))

    def test_owner_cannot_remove_self_if_no_other_owner(self):
        self._project_create()

        view = ProjectViewSet.as_view({
            'put': 'share'
        })

        ManagerRole.add(self.user, self.project)

        tom_data = {'username': '******', 'email': '*****@*****.**'}
        bob_profile = self._create_user_profile(tom_data)

        OwnerRole.add(bob_profile.user, self.project)

        data = {'username': '******', 'remove': True, 'role': 'owner'}

        request = self.factory.put('/', data=data, **self.extra)
        response = view(request, pk=self.project.pk)

        self.assertEqual(response.status_code, 400)
        error = {'remove': [u"Project requires at least one owner"]}
        self.assertEquals(response.data, error)

        self.assertTrue(OwnerRole.user_has_role(bob_profile.user,
                                                self.project))

        alice_data = {'username': '******', 'email': '*****@*****.**'}
        profile = self._create_user_profile(alice_data)

        OwnerRole.add(profile.user, self.project)

        view = ProjectViewSet.as_view({
            'put': 'share'
        })

        data = {'username': '******', 'remove': True, 'role': 'owner'}

        request = self.factory.put('/', data=data, **self.extra)
        response = view(request, pk=self.project.pk)

        self.assertEqual(response.status_code, 204)

        self.assertFalse(OwnerRole.user_has_role(bob_profile.user,
                                                 self.project))

    def test_last_date_modified_changes_when_adding_new_form(self):
        self._project_create()
        last_date = self.project.date_modified
        self._publish_xls_form_to_project()

        self.project.reload()
        current_last_date = self.project.date_modified

        self.assertNotEquals(last_date, current_last_date)

        self._make_submissions()

        self.project.reload()
        self.assertNotEquals(current_last_date, self.project.date_modified)

    def test_anon_project_form_endpoint(self):
        self._project_create()
        self._publish_xls_form_to_project()

        view = ProjectViewSet.as_view({
            'get': 'forms'
        })

        request = self.factory.get('/')
        response = view(request, pk=self.project.pk)

        self.assertEqual(response.status_code, 404)

    def test_project_manager_can_delete_xform(self):
        # create project and publish form to project
        self._publish_xls_form_to_project()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        alice_profile = self._create_user_profile(alice_data)
        alice = alice_profile.user
        projectid = self.project.pk

        self.assertFalse(ManagerRole.user_has_role(alice, self.project))

        data = {'username': '******', 'role': ManagerRole.name,
                'email_msg': 'I have shared the project with you'}
        request = self.factory.post('/', data=data, **self.extra)

        view = ProjectViewSet.as_view({
            'post': 'share'
        })
        response = view(request, pk=projectid)

        self.assertEqual(response.status_code, 204)
        self.assertTrue(ManagerRole.user_has_role(alice, self.project))
        self.assertTrue(alice.has_perm('delete_xform', self.xform))

    def test_move_project_owner(self):
        # create project and publish form to project
        self._publish_xls_form_to_project()

        alice_data = {'username': '******', 'email': '*****@*****.**'}
        alice_profile = self._create_user_profile(alice_data)
        alice = alice_profile.user
        projectid = self.project.pk

        self.assertFalse(OwnerRole.user_has_role(alice, self.project))

        view = ProjectViewSet.as_view({
            'patch': 'partial_update'
        })

        data_patch = {
            'owner': 'http://testserver/api/v1/users/%s' % alice.username
        }
        request = self.factory.patch('/', data=data_patch, **self.extra)
        response = view(request, pk=projectid)

        self.project.reload()
        self.assertEqual(response.status_code, 200)
        self.assertEquals(self.project.organization, alice)
        self.assertTrue(OwnerRole.user_has_role(alice, self.project))

    def test_cannot_share_project_to_owner(self):
        # create project and publish form to project
        self._publish_xls_form_to_project()

        data = {'username': self.user.username, 'role': ManagerRole.name,
                'email_msg': 'I have shared the project with you'}
        request = self.factory.post('/', data=data, **self.extra)

        view = ProjectViewSet.as_view({
            'post': 'share'
        })
        response = view(request, pk=self.project.pk)

        self.assertEqual(response.status_code, 400)
        self.assertEqual(response.data['username'], [u"Cannot share project"
                                                     u" with the owner"])
        self.assertTrue(OwnerRole.user_has_role(self.user, self.project))

    def test_project_share_readonly(self):
        # create project and publish form to project
        self._publish_xls_form_to_project()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        alice_profile = self._create_user_profile(alice_data)
        projectid = self.project.pk

        self.assertFalse(ReadOnlyRole.user_has_role(alice_profile.user,
                                                    self.project))

        data = {'username': '******', 'role': ReadOnlyRole.name}
        request = self.factory.put('/', data=data, **self.extra)

        view = ProjectViewSet.as_view({
            'put': 'share'
        })
        response = view(request, pk=projectid)

        self.assertEqual(response.status_code, 204)

        self.assertTrue(ReadOnlyRole.user_has_role(alice_profile.user,
                                                   self.project))
        self.assertTrue(ReadOnlyRole.user_has_role(alice_profile.user,
                                                   self.xform))

        perms = role.get_object_users_with_permissions(self.project)
        for p in perms:
            user = p.get('user')

            if user == alice_profile.user:
                r = p.get('role')
                self.assertEquals(r, ReadOnlyRole.name)

    def test_move_project_owner_org(self):
        # create project and publish form to project
        self._org_create()
        self._publish_xls_form_to_project()

        projectid = self.project.pk

        view = ProjectViewSet.as_view({
            'patch': 'partial_update'
        })
        old_org = self.project.organization

        data_patch = {
            'owner': 'http://testserver/api/v1/users/%s' %
                     self.organization.user.username
        }
        request = self.factory.patch('/', data=data_patch, **self.extra)
        response = view(request, pk=projectid)

        self.assertEqual(response.status_code, 200)
        project = Project.objects.get(pk=projectid)

        self.assertNotEqual(old_org, project.organization)

    def test_project_share_inactive_user(self):
        # create project and publish form to project
        self._publish_xls_form_to_project()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        alice_profile = self._create_user_profile(alice_data)

        # set the user inactive
        self.assertTrue(alice_profile.user.is_active)
        alice_profile.user.is_active = False
        alice_profile.user.save()

        projectid = self.project.pk

        self.assertFalse(ReadOnlyRole.user_has_role(alice_profile.user,
                                                    self.project))

        data = {'username': '******', 'role': ReadOnlyRole.name}
        request = self.factory.put('/', data=data, **self.extra)

        view = ProjectViewSet.as_view({
            'put': 'share'
        })
        response = view(request, pk=projectid)

        self.assertEqual(response.status_code, 400)
        self.assertEqual(response.data, {'username': [u'User is not active']})

        self.assertFalse(ReadOnlyRole.user_has_role(alice_profile.user,
                                                    self.project))
        self.assertFalse(ReadOnlyRole.user_has_role(alice_profile.user,
                                                    self.xform))

    def test_project_share_remove_inactive_user(self):
        # create project and publish form to project
        self._publish_xls_form_to_project()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        alice_profile = self._create_user_profile(alice_data)

        projectid = self.project.pk

        self.assertFalse(ReadOnlyRole.user_has_role(alice_profile.user,
                                                    self.project))

        data = {'username': '******', 'role': ReadOnlyRole.name}
        request = self.factory.put('/', data=data, **self.extra)

        view = ProjectViewSet.as_view({
            'put': 'share'
        })
        response = view(request, pk=projectid)

        self.assertEqual(response.status_code, 204)

        self.assertTrue(ReadOnlyRole.user_has_role(alice_profile.user,
                                                   self.project))
        self.assertTrue(ReadOnlyRole.user_has_role(alice_profile.user,
                                                   self.xform))

        # set the user inactive
        self.assertTrue(alice_profile.user.is_active)
        alice_profile.user.is_active = False
        alice_profile.user.save()

        data = {'username': '******', 'role': ReadOnlyRole.name, "remove": True}
        request = self.factory.put('/', data=data, **self.extra)

        self.assertEqual(response.status_code, 204)

        self.assertFalse(ReadOnlyRole.user_has_role(alice_profile.user,
                                                    self.project))
        self.assertFalse(ReadOnlyRole.user_has_role(alice_profile.user,
                                                    self.xform))

    def test_project_share_readonly_no_downloads(self):
        # create project and publish form to project
        self._publish_xls_form_to_project()
        alice_data = {'username': '******', 'email': '*****@*****.**'}
        alice_profile = self._create_user_profile(alice_data)

        tom_data = {'username': '******', 'email': '*****@*****.**'}
        tom_data = self._create_user_profile(tom_data)
        projectid = self.project.pk

        self.assertFalse(
            ReadOnlyRoleNoDownload.user_has_role(alice_profile.user,
                                                 self.project))

        data = {'username': '******', 'role': ReadOnlyRoleNoDownload.name}
        request = self.factory.post('/', data=data, **self.extra)

        view = ProjectViewSet.as_view({
            'post': 'share',
            'get': 'retrieve'
        })
        response = view(request, pk=projectid)

        self.assertEqual(response.status_code, 204)

        data = {'username': '******', 'role': ReadOnlyRole.name}
        request = self.factory.post('/', data=data, **self.extra)

        response = view(request, pk=projectid)

        self.assertEqual(response.status_code, 204)

        request = self.factory.get('/', **self.extra)

        response = view(request, pk=self.project.pk)

        # get the users
        users = response.data.get('users')

        self.assertEqual(len(users), 3)

        for user in users:
            if user.get('user') == 'bob':
                self.assertEquals(user.get('role'), 'owner')
            elif user.get('user') == 'alice':
                self.assertEquals(user.get('role'), 'readonly-no-download')
            elif user.get('user') == 'tom':
                self.assertEquals(user.get('role'), 'readonly')