コード例 #1
0
ファイル: tests.py プロジェクト: der-gabe/journal-manager
    def test_read_only(self):
        """Check all read-only objects/methods are really read only"""
        journal = models.Journal(owner=self.user1,
                                 uid=self.get_random_hash(),
                                 content=b'test')
        journal.save()
        self.client.force_authenticate(user=self.user1)

        # Not allowed to change UID
        journal2 = models.Journal(owner=self.user1,
                                  uid=self.get_random_hash(),
                                  content=b'test')
        response = self.client.put(
            reverse('journal-detail', kwargs={'uid': journal.uid}),
            self.serializer(journal2).data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(journal, models.Journal.objects.get(uid=journal.uid))

        # Not allowed to change version
        journal.version = 137
        response = self.client.put(
            reverse('journal-detail', kwargs={'uid': journal.uid}),
            self.serializer(journal2).data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(journal, models.Journal.objects.get(uid=journal.uid))
コード例 #2
0
ファイル: tests.py プロジェクト: der-gabe/journal-manager
    def test_version(self):
        """Check version behaves correctly"""
        journal = models.Journal(owner=self.user1,
                                 uid=self.get_random_hash(),
                                 content=b'test')
        journal.save()
        self.client.force_authenticate(user=self.user1)

        # Default version is 1
        response = self.client.get(
            reverse('journal-detail', kwargs={'uid': journal.uid}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # Saving version works
        journal = models.Journal(owner=self.user1,
                                 uid=self.get_random_hash(),
                                 content=b'test',
                                 version=12)
        response = self.client.post(reverse('journal-list'),
                                    self.serializer(journal).data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(journal.version,
                         models.Journal.objects.get(uid=journal.uid).version)

        # Version readonly is handled in test_read_only
        pass
コード例 #3
0
ファイル: tests.py プロジェクト: der-gabe/journal-manager
    def test_read_only(self):
        """Tests for read only JournalMembers"""
        journal1 = models.Journal(owner=self.user1,
                                  uid=self.get_random_hash(),
                                  content=b'user1')
        journal1.save()
        journal2 = models.Journal(owner=self.user2,
                                  uid=self.get_random_hash(),
                                  content=b'user2')
        journal2.save()

        # List
        self.client.force_authenticate(user=self.user1)
        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)

        self.client.force_authenticate(user=self.user2)
        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)

        # Give user1 read only access to user2's journal2
        journal_member = models.JournalMember(user=self.user1,
                                              key=b'somekey',
                                              readOnly=True)
        self.client.force_authenticate(user=self.user2)
        response = self.client.post(
            reverse('journal-members-list',
                    kwargs={'journal_uid': journal2.uid}),
            self.serializer(journal_member).data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # Adding an entry when have read only access
        self.client.force_authenticate(user=self.user1)
        entry = models.Entry(uid=self.get_random_hash(), content=b'test')
        response = self.client.post(
            reverse('journal-entries-list',
                    kwargs={'journal_uid': journal2.uid}),
            serializers.EntrySerializer(entry).data)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

        # Adding an entry when owner and there's a read only member
        self.client.force_authenticate(user=self.user2)
        entry = models.Entry(uid=self.get_random_hash(), content=b'test')
        response = self.client.post(
            reverse('journal-entries-list',
                    kwargs={'journal_uid': journal2.uid}),
            serializers.EntrySerializer(entry).data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # Verify the entries list is actually shared with a read only user
        self.client.force_authenticate(user=self.user1)
        response = self.client.get(
            reverse('journal-entries-list',
                    kwargs={'journal_uid': journal2.uid}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)
コード例 #4
0
ファイル: tests.py プロジェクト: pixelandpen/janeway
    def create_journals():
        """
        Creates a set of dummy journals for testing
        :return: a 2-tuple of two journals
        """
        journal_one = journal_models.Journal(code="TST", domain="testserver")
        journal_one.save()

        journal_two = journal_models.Journal(code="TSA", domain="journal2.localhost")
        journal_two.save()

        return journal_one, journal_two
コード例 #5
0
ファイル: tests.py プロジェクト: jackmac92/journal-manager
    def setUp(self):
        super().setUp()
        self.serializer = serializers.EntrySerializer

        self.journal = models.Journal(owner=self.user1,
                                      uid=self.get_random_hash(),
                                      content=b'test')
        self.journal.save()
コード例 #6
0
    def handle(self, *args, **options):
        """Installs Janeway

        :param args: None
        :param options: None
        :return: None
        """
        call_command('makemigrations', 'sites')
        call_command('migrate')
        print("Please answer the following questions.\n")
        translation.activate('en')
        with transaction.atomic():
            test_one = press_models.Press.objects.all()
            if not test_one:
                press = press_models.Press()
                press.name = input('Press name: ')
                press.domain = input('Press domain: ')
                press.main_contact = input('Press main contact (email): ')
                press.save()

            print("Thanks! We will now set up out first journal.\n")
            journal = journal_models.Journal()
            journal.code = input('Journal #1 code: ')
            journal.domain = input('Journal #1 domain: ')
            journal.save()

            print("Installing settings fixtures... ", end="")
            update_settings(journal, management_command=False)
            print("[okay]")
            print("Installing license fixtures... ", end="")
            update_license(journal, management_command=False)
            print("[okay]")
            print("Installing role fixtures")
            roles_path = os.path.join(settings.BASE_DIR, ROLES_RELATIVE_PATH)
            call_command('loaddata', roles_path)
            journal.name = input('Journal #1 name: ')
            journal.description = input('Journal #1 description: ')
            journal.save()
            journal.setup_directory()

            print("Thanks, Journal #1 has been saved.\n")

            call_command('show_configured_journals')
            call_command('sync_journals_to_sites')
            call_command('build_assets')
            print("Installing plugins.")
            call_command('install_plugins')
            print("Installing Cron jobs")
            try:
                call_command('install_cron')
            except FileNotFoundError:
                self.stderr.write("Error Installing cron")
            print('Create a super user.')
            call_command('createsuperuser')
            print(
                'Open your browser to your new journal domain {domain}/install/ to continue this setup process.'
                .format(domain=journal.domain))
            print(JANEWAY_ASCII)
コード例 #7
0
    def create_journal():
        """
        Creates a dummy journal for testing
        :return: a journal
        """
        journal_one = journal_models.Journal(code="TST", domain="testserver")
        journal_one.save()

        return journal_one
コード例 #8
0
    def create_journal():
        """
        Creates a dummy journal for testing
        :return: a journal
        """
        update_xsl_files()
        journal_one = journal_models.Journal(code="TST", domain="testserver")
        journal_one.title = "Test Journal: A journal of tests"
        journal_one.save()
        update_settings(journal_one, management_command=False)

        return journal_one
コード例 #9
0
def create_journals():
    """
    Creates a set of dummy journals for testing
    :return: a 2-tuple of two journals
    """
    journal_one = journal_models.Journal(code="TST", domain="testserver")
    journal_one.save()

    journal_two = journal_models.Journal(code="TSA",
                                         domain="journal2.localhost")
    journal_two.save()

    out = StringIO()
    sys.stdout = out

    call_command('load_default_settings', stdout=out)

    journal_one.name = 'Journal One'
    journal_two.name = 'Journal Two'

    return journal_one, journal_two
コード例 #10
0
    def handle(self, *args, **options):
        """Installs Janeway

        :param args: None
        :param options: None
        :return: None
        """
        call_command('makemigrations')
        call_command('migrate')
        print("Please answer the following questions.\n")
        translation.activate('en')

        test_one = press_models.Press.objects.all()
        if not test_one:
            press = press_models.Press()
            press.name = input('Press name: ')
            press.domain = input('Press domain: ')
            press.main_contact = input('Press main contact (email): ')
            press.save()

        print("Thanks! We will now set up out first journal.\n")
        journal = journal_models.Journal()
        journal.code = input('Journal #1 code: ')
        journal.domain = input('Journal #1 domain: ')
        journal.save()
        install.update_settings(journal, management_command=True)
        install.update_license(journal, management_command=True)
        journal.name = input('Journal #1 name: ')
        journal.description = input('Journal #1 description: ')
        journal.save()

        print("Thanks, Journal #1 has been saved.\n")

        call_command('show_configured_journals')
        call_command('sync_journals_to_sites')
        call_command('build_assets')
        call_command('install_plugins')
        call_command('install_cron')
        call_command('loaddata', 'utils/install/roles.json')

        print('Create a super user.')
        call_command('createsuperuser')
        print(
            'Open your browser to your domain /install/ to continue this setup process.'
        )
コード例 #11
0
ファイル: tests.py プロジェクト: der-gabe/journal-manager
    def test_errors_basic(self):
        """Test basic validation errors"""
        # Not saved on purpose
        journal = models.Journal(content=b'test')
        self.client.force_authenticate(user=self.user1)

        # Put bad/empty uid
        response = self.client.post(reverse('journal-list'),
                                    self.serializer(journal).data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        journal.uid = "12"
        response = self.client.post(reverse('journal-list'),
                                    self.serializer(journal).data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # Put none/empty content
        journal.uid = self.get_random_hash()
        journal.content = b''
        response = self.client.post(reverse('journal-list'),
                                    self.serializer(journal).data)
        # FIXME self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        journal.content = None
        response = self.client.post(reverse('journal-list'),
                                    self.serializer(journal).data)
        # FIXME self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # Put existing uid
        journal.uid = self.get_random_hash()
        journal.content = b'test'
        response = self.client.post(reverse('journal-list'),
                                    self.serializer(journal).data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        response = self.client.post(reverse('journal-list'),
                                    self.serializer(journal).data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
コード例 #12
0
ファイル: tests.py プロジェクト: der-gabe/journal-manager
    def test_basic(self):
        """Basic tests for JournalMembers"""
        journal1 = models.Journal(owner=self.user1,
                                  uid=self.get_random_hash(),
                                  content=b'user1')
        journal1.save()
        journal2 = models.Journal(owner=self.user2,
                                  uid=self.get_random_hash(),
                                  content=b'user2')
        journal2.save()

        # List
        self.client.force_authenticate(user=self.user1)
        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)

        self.client.force_authenticate(user=self.user2)
        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)

        # Give access to yourself which updates the key, but doesn't show in list
        journal_member = models.JournalMember(user=self.user2, key=b'somekey')
        self.client.force_authenticate(user=self.user2)
        response = self.client.post(
            reverse('journal-members-list',
                    kwargs={'journal_uid': journal2.uid}),
            self.serializer(journal_member).data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        response = self.client.get(
            reverse('journal-members-list',
                    kwargs={'journal_uid': journal2.uid}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 0)

        # Give user1 access to user2's journal2
        journal_member = models.JournalMember(user=self.user1, key=b'somekey')
        self.client.force_authenticate(user=self.user2)
        response = self.client.post(
            reverse('journal-members-list',
                    kwargs={'journal_uid': journal2.uid}),
            self.serializer(journal_member).data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # Give a user access to non-existent journal
        self.client.force_authenticate(user=self.user1)
        response = self.client.post(
            reverse('journal-members-list', kwargs={'journal_uid': 'aaa'}),
            self.serializer(journal_member).data)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        # List
        self.client.force_authenticate(user=self.user1)
        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 2)

        self.client.force_authenticate(user=self.user2)
        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)

        # Journals return different owners
        self.client.force_authenticate(user=self.user1)
        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        owners = {}
        for journal in response.data:
            owners[journal['owner']] = journal
        self.assertIn(self.user1.username, owners)
        self.assertIn(self.user2.username, owners)

        # Check key is set as expected
        self.assertIs(owners[self.user1.username]['key'], None)
        self.assertIsNot(owners[self.user2.username]['key'], None)

        # Get the members of own journal vs someone else's
        self.client.force_authenticate(user=self.user1)
        response = self.client.get(
            reverse('journal-members-list',
                    kwargs={'journal_uid': journal2.uid}))
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

        self.client.force_authenticate(user=self.user2)
        response = self.client.get(
            reverse('journal-members-list',
                    kwargs={'journal_uid': journal2.uid}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)
        self.assertEqual(response.data[0]['user'], self.user1.username)

        # Get the members of a non-existent journal
        self.client.force_authenticate(user=self.user1)
        response = self.client.get(
            reverse('journal-members-list', kwargs={'journal_uid': 'aaaa'}))
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        # Try to edit a journal when not owner but have access
        self.client.force_authenticate(user=self.user1)
        response = self.client.put(
            reverse('journal-detail', kwargs={'uid': journal2.uid}),
            serializers.JournalSerializer(journal2).data)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

        # Adding an entry when have access
        self.client.force_authenticate(user=self.user1)
        entry = models.Entry(uid=self.get_random_hash(), content=b'test')
        response = self.client.post(
            reverse('journal-entries-list',
                    kwargs={'journal_uid': journal2.uid}),
            serializers.EntrySerializer(entry).data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # Trying to give a user with access access again
        journal_member_user = getattr(journal_member.user, User.USERNAME_FIELD)
        self.client.force_authenticate(user=self.user2)
        response = self.client.post(
            reverse('journal-members-list',
                    kwargs={'journal_uid': journal2.uid}),
            self.serializer(journal_member).data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # Patch is not allowed
        self.client.force_authenticate(user=self.user2)
        response = self.client.patch(
            reverse('journal-members-detail',
                    kwargs={
                        'journal_uid': journal2.uid,
                        'username': journal_member_user
                    }),
            self.serializer(journal_member).data)
        self.assertEqual(response.status_code,
                         status.HTTP_405_METHOD_NOT_ALLOWED)

        # Revoking access
        self.client.force_authenticate(user=self.user2)
        response = self.client.delete(
            reverse('journal-members-detail',
                    kwargs={
                        'journal_uid': journal2.uid,
                        'username': journal_member_user
                    }),
            self.serializer(journal_member).data)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # Try to edit a journal when not owner and don't have access
        self.client.force_authenticate(user=self.user1)
        response = self.client.put(
            reverse('journal-detail', kwargs={'uid': journal2.uid}),
            serializers.JournalSerializer(journal2).data)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        # Adding an entry when no access
        self.client.force_authenticate(user=self.user1)
        entry = models.Entry(uid=self.get_random_hash(), content=b'test')
        response = self.client.post(
            reverse('journal-entries-list',
                    kwargs={'journal_uid': journal2.uid}),
            serializers.EntrySerializer(entry).data)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        # Revoking when there's nothingto revoke
        response = self.client.delete(
            reverse('journal-members-detail',
                    kwargs={
                        'journal_uid': journal2.uid,
                        'username': journal_member_user
                    }),
            self.serializer(journal_member).data)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        # Making sure access was really revoked but journal still exists
        self.client.force_authenticate(user=self.user1)
        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)

        self.client.force_authenticate(user=self.user2)
        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)

        # Invalid json request
        journal_member = models.JournalMember(user=self.user1, key=b'somekey')
        self.client.force_authenticate(user=self.user2)
        response = self.client.post(
            reverse('journal-members-list',
                    kwargs={'journal_uid': journal2.uid}), {})
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # Just to complete coverage
        str(journal_member)
コード例 #13
0
ファイル: tests.py プロジェクト: der-gabe/journal-manager
    def test_only_owner(self):
        """Check all the endpoints correctly require authentication"""
        journal = models.Journal(owner=self.user1,
                                 uid=self.get_random_hash(),
                                 content=b'test')
        journal.save()

        # List
        self.client.force_authenticate(user=self.user1)
        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)

        self.client.force_authenticate(user=self.user2)
        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertListEqual(response.data, [])

        # Get
        self.client.force_authenticate(user=self.user1)
        response = self.client.get(
            reverse('journal-detail', kwargs={'uid': journal.uid}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.client.force_authenticate(user=self.user2)
        response = self.client.get(
            reverse('journal-detail', kwargs={'uid': journal.uid}))
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        # Update
        self.client.force_authenticate(user=self.user1)
        response = self.client.put(
            reverse('journal-detail', kwargs={'uid': journal.uid}),
            self.serializer(journal).data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.client.force_authenticate(user=self.user2)
        response = self.client.put(
            reverse('journal-detail', kwargs={'uid': journal.uid}),
            self.serializer(journal).data)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        # Destroy
        self.client.force_authenticate(user=self.user2)
        response = self.client.delete(
            reverse('journal-detail', kwargs={'uid': journal.uid}))
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        ## This actuall destroys the object, so has to be last.
        self.client.force_authenticate(user=self.user1)
        response = self.client.delete(
            reverse('journal-detail', kwargs={'uid': journal.uid}))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # Post directly (without it existing)
        journal.uid = self.get_random_hash()
        self.client.force_authenticate(user=self.user1)
        response = self.client.post(
            reverse('journal-detail', kwargs={'uid': journal.uid}),
            self.serializer(journal).data)
        self.assertEqual(response.status_code,
                         status.HTTP_405_METHOD_NOT_ALLOWED)

        journal.uid = self.get_random_hash()
        self.client.force_authenticate(user=self.user2)
        response = self.client.post(
            reverse('journal-detail', kwargs={'uid': journal.uid}),
            self.serializer(journal).data)
        self.assertEqual(response.status_code,
                         status.HTTP_405_METHOD_NOT_ALLOWED)
コード例 #14
0
ファイル: tests.py プロジェクト: der-gabe/journal-manager
 def test_filler(self):
     """Extra calls to cheat coverage (things we don't really care about)"""
     str(models.Journal(uid=self.get_random_hash(), content=b'1'))
コード例 #15
0
ファイル: tests.py プロジェクト: der-gabe/journal-manager
    def test_crud_basic(self):
        """Test adding/removing/changing journals"""
        # Not saved
        journal = models.Journal(uid=self.get_random_hash(),
                                 content=b'test',
                                 owner=self.user1)
        self.client.force_authenticate(user=self.user1)

        # Add
        response = self.client.post(reverse('journal-list'),
                                    self.serializer(journal).data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # Get
        response = self.client.get(
            reverse('journal-detail', kwargs={'uid': journal.uid}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertDictEqual(response.data, self.serializer(journal).data)

        response = self.client.get(
            reverse('journal-detail', kwargs={'uid': self.get_random_hash()}))
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        # Update
        response = self.client.put(
            reverse('journal-detail', kwargs={'uid': journal.uid}),
            self.serializer(journal).data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # Partial update
        response = self.client.patch(
            reverse('journal-detail', kwargs={'uid': journal.uid}),
            self.serializer(journal).data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # List
        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertDictEqual(response.data[0], self.serializer(journal).data)

        # Destroy
        ## This actually destroys the object, so has to be last.
        response = self.client.delete(
            reverse('journal-detail', kwargs={'uid': journal.uid}))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        ## Verify not returned in api but still in db (both list and get)
        response = self.client.get(
            reverse('journal-detail', kwargs={'uid': journal.uid}))
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        response = self.client.get(reverse('journal-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 0)

        ## And that we can't update it
        journal2 = models.Journal.objects.get(uid=journal.uid)
        journal2.content = b'different'
        response = self.client.put(
            reverse('journal-detail', kwargs={'uid': journal.uid}),
            self.serializer(journal2).data)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
        journal2 = models.Journal.objects.get(uid=journal.uid)
        self.assertEqual(journal.content, journal2.content)

        journal = models.Journal.objects.get(uid=journal.uid)
        self.assertEqual(journal.deleted, True)

        # Put directly (without it existing)
        journal.uid = self.get_random_hash()
        self.client.force_authenticate(user=self.user1)
        response = self.client.post(
            reverse('journal-detail', kwargs={'uid': journal.uid}),
            self.serializer(journal).data)
        self.assertEqual(response.status_code,
                         status.HTTP_405_METHOD_NOT_ALLOWED)