def test_dataset_elements_creation(self):
        """
        Factory can create multiple dataset's elements at once.
        """
        creator = TokenDAO("normal user privileged with link", 1, 3, "user1",
                           privileges=Privileges.CREATE_DATASET + Privileges.ADD_ELEMENTS
                           )

        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none", tags=["example", "0"])

        self.session.flush()

        creator = creator.link_dataset(dataset)

        # Creator can create elements into the dataset
        elements_kwargs = [
            dict(title="New element", description="Description unknown", tags=["example_tag"], content=b"hello"),
            dict(title="New element2", description="Description unknown2", tags=["example_tag2"], content=b"hello2"),
            dict(title="New element3", description="Description unknown3", tags=["example_tag3"], content=b"hello3"),
        ]

        elements = DatasetElementFactory(creator, dataset).create_elements(elements_kwargs)

        self.assertEqual(len(elements), 3)

        content = storage.get_file(elements[0].file_ref_id).content
        self.assertEqual(content, b"hello")
        content = storage.get_file(elements[1].file_ref_id).content
        self.assertEqual(content, b"hello2")
        content = storage.get_file(elements[2].file_ref_id).content
        self.assertEqual(content, b"hello3")
        dataset = dataset.update()

        self.assertEqual(len(dataset.elements), 3)
    def test_dataset_elements_info_by_pages(self):
        """
        Factory can retrieve multiple elements at once by pages.
        """

        editor = TokenDAO("normal user privileged with link", 1, 5, "user1",
                          privileges=Privileges.RO_WATCH_DATASET
                          )

        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none",
                             tags=["example", "0"])

        self.session.flush()

        editor = editor.link_dataset(dataset)

        elements = [DatasetElementDAO("example{}".format(x), "none", None, dataset=dataset).title for x in range(5)]

        self.session.flush()

        dataset = dataset.update()

        page_size = global_config.get_page_size()
        for page in range(len(elements) // page_size + int(len(elements) % page_size > 0)):
            retrieved_elements = DatasetElementFactory(editor, dataset).get_elements_info(page)

            for x in retrieved_elements:
                self.assertIn(x.title, elements)
    def test_dataset_multiple_elements_content_retrieval(self):
        """
        Factory can retrieve content of multiple elements at once.
        """
        editor = TokenDAO("normal user privileged with link", 1, 1, "user1",
                          privileges=Privileges.RO_WATCH_DATASET
                          )

        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none",
                             tags=["example", "0"])

        self.session.flush()

        editor = editor.link_dataset(dataset)

        file_id1 = storage.put_file_content(b"content1")
        file_id2 = storage.put_file_content(b"content2")

        element = DatasetElementDAO("example1", "none", file_id1, dataset=dataset)
        element2 = DatasetElementDAO("example2", "none", file_id1, dataset=dataset)
        element3 = DatasetElementDAO("example3", "none", file_id2, dataset=dataset)

        self.session.flush()
        dataset = dataset.update()

        with self.assertRaises(RequestedRangeNotSatisfiable) as ex:
            contents = DatasetElementFactory(editor, dataset).get_elements_content([element._id, element2._id, element3._id])

        contents = DatasetElementFactory(editor, dataset).get_elements_content([element._id, element3._id])

        self.assertEqual(contents[element._id], b"content1")
        self.assertEqual(contents[element3._id], b"content2")
예제 #4
0
    def test_factory_can_get_tokens(self):
        """
        Factory can retrieve tokens.
        """
        token = TokenDAO("example1", 5, 5, "uri1")
        token2 = TokenDAO("example2", 5, 5, "uri2")
        token3 = TokenDAO("example3",
                          5,
                          5,
                          "uri2",
                          privileges=Privileges.USER_EDIT_TOKEN)
        token4 = TokenDAO("example3",
                          5,
                          5,
                          "uri2",
                          privileges=Privileges.ADMIN_EDIT_TOKEN)

        self.session.flush()
        new_token = TokenFactory(token).get_token(token.token_gui)

        self.assertEqual(token.token_gui, new_token.token_gui)
        self.assertEqual(token.description, new_token.description)
        self.assertEqual(token.url_prefix, new_token.url_prefix)

        # Cannot request info from a different token
        with self.assertRaises(Unauthorized):
            new_token = TokenFactory(token).get_token(token2.token_gui)

        # Cannot request all the tokens if not privileged.
        with self.assertRaises(Unauthorized):
            new_token = TokenFactory(token).get_tokens()

        # Can request all the tokens if has privilege for user edit tokens.
        token_list = TokenFactory(token3).get_tokens()

        self.assertEqual(len(token_list), 3)

        # Can not request all the tokens from a different url prefix
        with self.assertRaises(Unauthorized):
            token_list = TokenFactory(token3).get_tokens(url_prefix="uri1")

        # Admin can request tokens from all the url prefixes
        token_list = TokenFactory(token4).get_tokens()
        self.assertEqual(len(token_list), 4)

        token_list = TokenFactory(token4).get_tokens(url_prefix="uri1")
        self.assertEqual(len(token_list), 1)

        token_list = TokenFactory(token4).get_tokens(url_prefix="uri2")
        self.assertEqual(len(token_list), 3)

        token_list = TokenFactory(token4).get_tokens(url_prefix="UNKNOWN")
        self.assertEqual(len(token_list), 0)

        # Invalid token-GUI raises exception
        with self.assertRaises(BadRequest):
            token_list = TokenFactory(token4).get_token(
                token_gui="INVALID_GUI")
예제 #5
0
    def test_dataset_fork(self):
        """
        Factory can fork a dataset
        :return:
        """
        viewer = TokenDAO("normal user only view dataset", 2, 10, "viewer", privileges=Privileges.RO_WATCH_DATASET)
        creator = TokenDAO("normal user privileged", 2, 10, "creator", privileges=Privileges.CREATE_DATASET)

        d = DatasetDAO("viewer/dataset", "dataset", "description for dataset", "none", ["d1", "d2"])

        self.session.flush()

        element1 = DatasetElementDAO("a", "a", None, "noneaa", ["taga"], dataset=d)
        element2 = DatasetElementDAO("b", "b", None, "nonebb", ["tagb"], dataset=d)

        self.session.flush()

        d = d.update()

        self.assertEqual(len(d.elements), 2)

        viewer = viewer.link_dataset(d)
        d.update()

        # Creator can clone it from viewer.
        forked_dataset = DatasetFactory(creator).fork_dataset(d.url_prefix, viewer, title="dataset_cloned",
                                             url_prefix="dataset", description="desc", reference="none",
                                             tags=["d2", "d1"])

        self.assertEqual(forked_dataset.url_prefix, "creator/dataset")
        self.assertEqual(forked_dataset.title, "dataset_cloned")
        self.assertEqual(forked_dataset.description, "desc")
        self.assertEqual(forked_dataset.tags, ["d2", "d1"])

        self.assertEqual(len(forked_dataset.elements), 2)

        elements_titles = [element1.title, element2.title]

        self.assertIn(forked_dataset.elements[0].title, elements_titles)
        self.assertIn(forked_dataset.elements[1].title, elements_titles)

        # viewer can NOT clone it from creator.
        with self.assertRaises(Unauthorized) as ex:
            forked_dataset = DatasetFactory(viewer).fork_dataset(forked_dataset.url_prefix, creator, title="dataset_cloned",
                                                 url_prefix="dataset", description="desc", reference="none",
                                                 tags=["d2", "d1"])

        # Dataset can be forked omitting some options
        forked_dataset2 = DatasetFactory(creator).fork_dataset(d.url_prefix, viewer,
                                             url_prefix="dataset2")

        self.assertEqual(forked_dataset2.title, d.title)
        self.assertEqual(forked_dataset2.description, d.description)
        self.assertEqual(forked_dataset2.tags, d.tags)
        self.assertEqual(forked_dataset2.reference, d.reference)
    def test_clone_element(self):
        """
        Factory can clone elements.
        """
        editor = TokenDAO("normal user privileged with link", 2, 1, "user1",
                         privileges=Privileges.RO_WATCH_DATASET + Privileges.EDIT_DATASET + Privileges.ADD_ELEMENTS
                         )

        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none",
                             tags=["example", "0"])
        dataset2 = DatasetDAO("user1/dataset2", "example_dataset2", "dataset2 for testing purposes", "none",
                              tags=["example", "1"])

        self.session.flush()

        editor = editor.link_dataset(dataset)

        file_id1 = storage.put_file_content(b"content1")
        file_id2 = storage.put_file_content(b"content2")

        element = DatasetElementDAO("example1", "none", file_id1, dataset=dataset)
        element2 = DatasetElementDAO("example2", "none", file_id1, dataset=dataset)
        element3 = DatasetElementDAO("example3", "none", file_id2, dataset=dataset)

        self.session.flush()
        dataset = dataset.update()
        dataset2 = dataset2.update()

        self.assertEqual(len(dataset.elements), 3)
        self.assertEqual(len(dataset2.elements), 0)

        with self.assertRaises(Unauthorized) as ex:
            new_element = DatasetElementFactory(editor, dataset).clone_element(element._id, dataset2.url_prefix)

        editor = editor.link_dataset(dataset2)
        self.assertEqual(len(element.dataset_id), 1)
        new_element = DatasetElementFactory(editor, dataset).clone_element(element._id, dataset2.url_prefix)

        dataset2 = dataset2.update()

        self.assertEqual(len(dataset2.elements), 1)

        self.assertEqual(new_element.file_ref_id, element.file_ref_id)
        self.assertEqual(new_element.title, element.title)
        self.assertEqual(new_element.description, element.description)
        self.assertEqual(new_element.tags, element.tags)
        self.assertEqual(new_element._id, element._id)
        self.assertEqual(len(new_element.dataset_id), 2)
        self.assertEqual(len(element.dataset_id), 2)

        with self.assertRaises(Unauthorized) as ex:
            new_element = DatasetElementFactory(editor, dataset).clone_element(element2._id, dataset2.url_prefix)
예제 #7
0
 def test_token_can_be_created_and_destroyed(self):
     """
     Tests that tokens are successfully created and removed.
     :return:
     """
     token = TokenDAO("example", 2, 3, "dalap")
     token_gui = token.token_gui
     self.assertTrue(len(token.token_gui) > 10)
     self.session.flush()
     token = TokenDAO.query.get(token_gui=token_gui)
     self.assertEqual(token.token_gui, token_gui)
     token.delete()
     token = TokenDAO.query.get(token_gui)
     self.assertIsNone(token)
예제 #8
0
    def testDatasetCreationLimit(self):
        """
        Factory limits creation of dataset depending on the token used to create it.
        """
        creator = TokenDAO("normal user privileged", 1, 1, "user1", privileges=Privileges.CREATE_DATASET)

        # Creator should not be able to create more than 1 dataset
        dataset1 = DatasetFactory(creator).create_dataset(url_prefix="creator", title="Creator dataset", description="Dataset example creator", reference="Unknown")

        creator = creator.link_dataset(dataset1)

        self.session.flush()
        with self.assertRaises(Unauthorized) as ex:
            dataset2 = DatasetFactory(creator).create_dataset(url_prefix="creator2", title="Creator dataset2", description="Dataset2 example creator", reference="Unknown")
예제 #9
0
    def test_factory_can_delete_tokens(self):
        """
        Factory can remove tokens.
        :return:
        """
        token = TokenDAO("example1", 5, 5, "uri1")
        token_demo1 = TokenDAO("example2", 5, 5, "uri1")
        token_demo2 = TokenDAO("exampleN", 5, 5, "uri2")
        token3 = TokenDAO("example3",
                          5,
                          5,
                          "uri2",
                          privileges=Privileges.USER_DESTROY_TOKEN)
        token4 = TokenDAO("example4",
                          5,
                          5,
                          "uri2",
                          privileges=Privileges.ADMIN_DESTROY_TOKEN)

        self.session.flush()

        # Unauthorized token can't delete tokens on same url_prefix
        with self.assertRaises(Unauthorized) as ex:
            TokenFactory(token).delete_token(token_demo1.token_gui)

        # Unauthorized token can't delete tokens on other url_prefix
        with self.assertRaises(Unauthorized) as ex:
            TokenFactory(token).delete_token(token_demo2.token_gui)

        # Unauthorized token can't delete himself
        with self.assertRaises(Unauthorized) as ex:
            TokenFactory(token_demo1).delete_token(token_demo1.token_gui)

        # Authorized token can't delete other's tokens
        with self.assertRaises(Unauthorized) as ex:
            TokenFactory(token3).delete_token(token_demo1.token_gui)

        # Authorized token can't delete admin tokens
        with self.assertRaises(Unauthorized) as ex:
            TokenFactory(token3).delete_token(token4.token_gui)

        # Authorized token can delete token on same uri prefix
        TokenFactory(token3).delete_token(token_demo2.token_gui)

        # Authorized token can delete itself
        TokenFactory(token3).delete_token(token3.token_gui)

        # Admin token can delete anything
        TokenFactory(token4).delete_token(token_demo1.token_gui)
예제 #10
0
    def test_dataset_modification(self):
        """
        Factory can modify datasets
        :return:
        """
        dataset = DatasetDAO("foo/hello", "notitle", "desc", "ref")
        dataset2 = DatasetDAO("bar/hello", "notitle", "desc", "ref")

        token_unprivileged = TokenDAO("unprivileged", 0, 0, "bar")
        token_privileged = TokenDAO("privileged", 0, 0, "bar", privileges=Privileges.EDIT_DATASET)
        token_admin = TokenDAO("admin", 0, 0, "bar", privileges=Privileges.ADMIN_EDIT_TOKEN)

        self.session.flush()

        # Unprivileged token cannot modify dataset
        with self.assertRaises(Unauthorized) as ex:
            DatasetFactory(token_unprivileged).edit_dataset(dataset.url_prefix, title="hello")

        # Privileged token cannot modify dataset if not in same url prefix
        with self.assertRaises(Unauthorized) as ex:
            DatasetFactory(token_privileged).edit_dataset(dataset.url_prefix, title="hello")

        # Privileged token can modify dataset if in same url prefix
        # NOT: Because dataset is not linked with the token.
        with self.assertRaises(Unauthorized) as ex:
            dataset2 = DatasetFactory(token_privileged).edit_dataset(dataset2.url_prefix, title="hello")

        # If we link it, then it does:
        token_privileged = token_privileged.link_dataset(dataset2)
        dataset2 = DatasetFactory(token_privileged).edit_dataset(dataset2.url_prefix, title="hello")

        self.assertEqual(dataset2.title, "hello")

        # Admin token can modify any dataset
        dataset = DatasetFactory(token_admin).edit_dataset(dataset.url_prefix, title="hello2")
        self.assertEqual(dataset.title, "hello2")

        # Privileged can partially modify url prefix
        dataset2 = DatasetFactory(token_privileged).edit_dataset(dataset2.url_prefix, url_prefix="new_prefix")
        self.assertEqual(dataset2.url_prefix, "bar/new_prefix")

        with self.assertRaises(BadRequest) as ex:
            dataset2 = DatasetFactory(token_privileged).edit_dataset(dataset2.url_prefix, url_prefix="bar2/new_prefix")

        # Admin can modify url prefix without problems
        dataset2 = DatasetFactory(token_admin).edit_dataset(dataset2.url_prefix, url_prefix="bar2/new_prefix")

        self.assertEqual(dataset2.url_prefix, "bar2/new_prefix")
    def test_dataset_elements_removal(self):
        """
        Factory can remove mutliple elements from datasets at once.
        """
        destructor = TokenDAO("normal user privileged with link", 1, 1, "user1",
                           privileges=Privileges.DESTROY_DATASET + Privileges.DESTROY_ELEMENTS
                           )


        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none", tags=["example", "0"])

        self.session.flush()

        destructor = destructor.link_dataset(dataset)

        file_id1 = storage.put_file_content(b"content1")
        file_id2 = storage.put_file_content(b"content2")

        element  = DatasetElementDAO("example1", "none", file_id1, dataset=dataset)
        element2 = DatasetElementDAO("example2", "none", file_id1, dataset=dataset)
        element3 = DatasetElementDAO("example3", "none", file_id2, dataset=dataset)

        self.session.flush()
        dataset = dataset.update()

        self.assertEqual(len(dataset.elements), 3)

        with self.assertRaises(RequestedRangeNotSatisfiable) as ex:
            DatasetElementFactory(destructor, dataset).destroy_elements([element._id, element2._id, element3._id])

        DatasetElementFactory(destructor, dataset).destroy_elements([element._id, element2._id])

        dataset = dataset.update()

        self.assertEqual(len(dataset.elements), 1)
        self.assertEqual(dataset.elements[0]._id, element3._id)

        element  = DatasetElementDAO("example1", "none", file_id1, dataset=dataset)
        element2 = DatasetElementDAO("example2", "none", file_id1, dataset=dataset)

        self.session.flush()
        dataset = dataset.update()

        DatasetElementFactory(destructor, dataset).destroy_elements()
    def test_dataset_specific_elements_info(self):
        """
        Factory can retrieve multiple elements at once by specific sets.
        """

        editor = TokenDAO("normal user privileged with link", 1, 1, "user1",
                          privileges=Privileges.RO_WATCH_DATASET
                          )

        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none",
                             tags=["example", "0"])

        self.session.flush()

        editor = editor.link_dataset(dataset)

        elements = [DatasetElementDAO("example{}".format(x), "none", None, dataset=dataset) for x in range(5)]
        titles = [element.title for element in elements]
        ids = [element._id for element in elements]

        self.session.flush()

        dataset = dataset.update()

        # Can't retrieve more elements than the page size at once.
        with self.assertRaises(RequestedRangeNotSatisfiable) as ex:
            retrieved_elements = [x for x in DatasetElementFactory(editor, dataset).get_specific_elements_info(ids)]

        request1 = ids[0:2]
        retrieved_elements = [x for x in DatasetElementFactory(editor, dataset).get_specific_elements_info(request1)]

        self.assertEqual(len(retrieved_elements), 2)
        self.assertIn(retrieved_elements[0].title, titles)
        self.assertIn(retrieved_elements[1].title, titles)

        request2 = ids[1:3]
        retrieved_elements2 = [x for x in DatasetElementFactory(editor, dataset).get_specific_elements_info(request2)]
        self.assertEqual(len(retrieved_elements2), 2)
        self.assertIn(retrieved_elements2[0].title, titles)
        self.assertIn(retrieved_elements2[1].title, titles)
        self.assertNotEqual(retrieved_elements[0].title, retrieved_elements2[0].title)
        self.assertNotEqual(retrieved_elements[1].title, retrieved_elements2[1].title)
        self.assertEqual(retrieved_elements[1].title, retrieved_elements2[0].title)
    def test_dataset_elements_edit(self):
        """
        Factory can edit multiple elements from datasets at once.
        """
        editor = TokenDAO("normal user privileged with link", 1, 1, "user1",
                           privileges=Privileges.EDIT_DATASET + Privileges.EDIT_ELEMENTS
                           )

        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none", tags=["example", "0"])

        self.session.flush()

        editor = editor.link_dataset(dataset)

        file_id1 = storage.put_file_content(b"content1")
        file_id2 = storage.put_file_content(b"content2")

        element  = DatasetElementDAO("example1", "none", file_id1, dataset=dataset)
        element2 = DatasetElementDAO("example2", "none", file_id1, dataset=dataset)
        element3 = DatasetElementDAO("example3", "none", file_id2, dataset=dataset)

        self.session.flush()
        dataset = dataset.update()

        self.assertEqual(len(dataset.elements), 3)

        modifications = {
            element._id: dict(title="asd6", content=b"content4"),
            element3._id: dict(description="ffff", content=b"New Content!")
        }

        DatasetElementFactory(editor, dataset).edit_elements(modifications)

        self.session.flush()

        dataset = dataset.update()
        element = element.update()
        element3 = element3.update()

        self.assertEqual(element.title, "asd6")
        self.assertEqual(storage.get_file(element.file_ref_id).content, b"content4")
        self.assertEqual(element3.description, "ffff")
        self.assertEqual(storage.get_file(element3.file_ref_id).content, b"New Content!")
    def test_dataset_elements_info_by_different_pages_size(self):
        """
        Factory can retrieve multiple elements with different page sizes.
        """
        initial_page_size = global_config.get_page_size()
        global_config.set_page_size(10)

        editor = TokenDAO("normal user privileged with link", 1, 5, "user1",
                          privileges=Privileges.RO_WATCH_DATASET
                          )

        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none",
                             tags=["example", "0"])

        self.session.flush()

        editor = editor.link_dataset(dataset)

        elements = [DatasetElementDAO("example{}".format(x), "none", None, dataset=dataset).title for x in range(5)]

        self.session.flush()

        dataset = dataset.update()

        # We need to know the order of the elements
        ordered_elements = [l for l in DatasetElementFactory(editor, dataset).get_elements_info(page_size=len(elements))]

        pages_size = [1, 2, 3, 4, 5]

        for page_size in pages_size:
            num_pages = len(elements) // page_size + int(len(elements) % page_size > 0)

            for page in range(num_pages):
                retrieved_elements = [l for l in DatasetElementFactory(editor, dataset).get_elements_info(page, page_size=page_size)]
                for retrieved_element, ordered_element in zip(retrieved_elements, ordered_elements[page*page_size:(page+1)*page_size]):
                    self.assertEqual(retrieved_element._id, ordered_element._id)

        with self.assertRaises(Conflict):
            retrieved_elements = DatasetElementFactory(editor, dataset).get_elements_info(page_size=global_config.get_page_size()+1)

        global_config.set_page_size(initial_page_size)
    def test_dataset_element_creation_limit(self):
        """
        Factory limits creation of dataset's elements depending on the token used to create it.
        """
        creator = TokenDAO("normal user privileged", 1, 1, "user1", privileges=Privileges.CREATE_DATASET+Privileges.ADD_ELEMENTS)

        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none",
                             tags=["example", "0"])

        self.session.flush()

        # Creator should not be able to create more than 1 element in any dataset
        creator = creator.link_dataset(dataset)

        element1 = DatasetElementFactory(creator, dataset).create_element(title="New element1", description="Description unknown",
                                                               tags=["example_tag"], content=b"hello")
        dataset = dataset.update()

        with self.assertRaises(Unauthorized) as ex:
            element2 = DatasetElementFactory(creator, dataset).create_element(title="New element2",
                                                                              description="Description unknown",
                                                                              tags=["example_tag"], content=b"hello")
예제 #16
0
    def test_dataset_creation(self):
        """
        Factory can create datasets
        :return:
        """
        anonymous = TokenDAO("Anonymous", 1, 1, "anonymous")
        watcher = TokenDAO("normal user", 1, 1, "user1")
        creator = TokenDAO("normal user privileged", 1, 1, "user1", privileges=Privileges.CREATE_DATASET)
        admin = TokenDAO("admin user", 1, 1, "admin", privileges=Privileges.ADMIN_CREATE_TOKEN + Privileges.ADMIN_EDIT_TOKEN + Privileges.ADMIN_DESTROY_TOKEN)

        # Anonymous or watcher can't create datasets
        with self.assertRaises(Unauthorized) as ex:
            dataset = DatasetFactory(anonymous).create_dataset(url_prefix="anonymous", title="Anonymous dataset", description="Dataset example anonymous", reference="Unknown")
        with self.assertRaises(Unauthorized) as ex:
            dataset = DatasetFactory(watcher).create_dataset(url_prefix="watcher", title="Watcher dataset", description="Dataset example watcher", reference="Unknown")

        # Creator can create a dataset
        dataset = DatasetFactory(creator).create_dataset(url_prefix="creator", title="Creator dataset", description="Dataset example creator", reference="Unknown")
        self.assertEqual(join_prefixes(creator.url_prefix, "creator"), dataset.url_prefix)
        self.assertEqual(dataset.description, "Dataset example creator")

        # Not all prefixes allowed (for example, "/" char is protected)
        illegal_chars = "/*;:,.ç´`+Ǩ^><¿?'¡¿!\"·$%&/()@~¬"

        for illegal_char in illegal_chars:
            with self.assertRaises(BadRequest) as ex:
                dataset = DatasetFactory(creator).create_dataset(url_prefix="creator{}da".format(illegal_char), title="Creator dataset", description="Dataset example creator", reference="Unknown")

        # Admin can create dataset
        dataset = DatasetFactory(admin).create_dataset(url_prefix="admin", title="Admin dataset", description="Dataset example admin", reference="Unknown")
        self.assertEqual(join_prefixes(admin.url_prefix, "admin"), dataset.url_prefix)
        self.assertEqual(dataset.description, "Dataset example admin")

        # Admin can create dataset on other's url prefixes
        dataset = DatasetFactory(admin).create_dataset(url_prefix="user1/admin", title="Admin dataset", description="Dataset example admin", reference="Unknown")
        self.assertEqual(join_prefixes(creator.url_prefix, "admin"), dataset.url_prefix)
        self.assertEqual(dataset.description, "Dataset example admin")
예제 #17
0
    def test_dataset_retrieval(self):
        """
        Factory can retrieve datasets.
        :return:
        """
        anonymous = TokenDAO("Anonymous", 1, 1, "anonymous")
        watcher = TokenDAO("normal user", 1, 1, "user1", privileges=0)
        creator = TokenDAO("normal user privileged", 1, 1, "user1", privileges=Privileges.CREATE_DATASET)
        creator2 = TokenDAO("normal user privileged", 1, 1, "user2", privileges=Privileges.CREATE_DATASET)
        admin = TokenDAO("admin user", 1, 1, "admin", privileges=Privileges.ADMIN_CREATE_TOKEN + Privileges.ADMIN_EDIT_TOKEN + Privileges.ADMIN_DESTROY_TOKEN)

        dataset = DatasetFactory(creator).create_dataset(url_prefix="creator", title="Creator dataset", description="Dataset example creator", reference="Unknown")
        dataset2 = DatasetFactory(creator2).create_dataset(url_prefix="creator", title="Creator dataset", description="Dataset example creator", reference="Unknown")
        self.session.flush()

        # anonymous should not be able to get info from the dataset
        with self.assertRaises(Unauthorized) as ex:
            dataset3 =DatasetFactory(anonymous).get_dataset(dataset.url_prefix)

        # watcher should not be able to get info from the dataset
        with self.assertRaises(Unauthorized) as ex:
            dataset3 =DatasetFactory(watcher).get_dataset(dataset.url_prefix)

        # creator should not be able to get info from the dataset
        with self.assertRaises(Unauthorized) as ex:
            dataset3 =DatasetFactory(creator).get_dataset(dataset.url_prefix)

        # admin should be able to get info from the dataset
        dataset3 =DatasetFactory(admin).get_dataset(dataset.url_prefix)
        self.assertEqual(dataset3.url_prefix, dataset.url_prefix)

        anonymous = anonymous.link_dataset(dataset)

        # anonymous should now be able to get info from the dataset
        dataset3 =DatasetFactory(anonymous).get_dataset(dataset.url_prefix)
        self.assertEqual(dataset3.url_prefix, dataset.url_prefix)

        # The privilege RO_WATCH_DATASET is always required except for admin

        watcher = watcher.link_dataset(dataset)
        with self.assertRaises(Unauthorized) as ex:
            dataset3 =DatasetFactory(watcher).get_dataset(dataset.url_prefix)
예제 #18
0
    def create_token(self, *args, **kwargs):
        kwargs = dict(kwargs)
        can_create_others = bool(self.token.privileges
                                 & Privileges.ADMIN_CREATE_TOKEN)
        can_create_all_inner_tokens = bool(self.token.privileges
                                           & Privileges.USER_CREATE_TOKEN)

        if "url_prefix" in kwargs:
            url_prefix = kwargs["url_prefix"]
            del kwargs["url_prefix"]
        else:
            url_prefix = args[3]

        if not can_create_others:
            if "privileges" in kwargs:
                privileges = kwargs["privileges"]

                # We need to check privileges creation. An exploit would be to allow creation of tokens with highest privileges
                # from non-trusted tokens.
                if not self._compatible_privileges(self.token.privileges,
                                                   privileges):
                    abort(409,
                          message=
                          "This token can't create such privileged tokens.")

            if not can_create_all_inner_tokens:
                abort(
                    401,
                    message="This token can't create such privileged tokens.")

            if url_prefix != self.token.url_prefix:
                abort(
                    401,
                    message=
                    "This token can't create tokens outside of its url prefix."
                )

        kwargs["url_prefix"] = url_prefix

        token = TokenDAO(*args, **kwargs)
        self.session.flush()

        return token
예제 #19
0
    def test_dataset_destruction(self):
        """
        Factory can destroy datasets
        :return:
        """
        anonymous = TokenDAO("Anonymous", 1, 1, "anonymous")
        watcher = TokenDAO("normal user", 1, 1, "user1")
        creator = TokenDAO("normal user privileged", 1, 1, "user1", privileges=Privileges.CREATE_DATASET)
        creator2 = TokenDAO("normal user privileged", 1, 1, "user2", privileges=Privileges.CREATE_DATASET)
        destructor = TokenDAO("normal user privileged", 1, 1, "user1", privileges=Privileges.DESTROY_DATASET)
        admin = TokenDAO("admin user", 1, 1, "admin", privileges=Privileges.ADMIN_CREATE_TOKEN + Privileges.ADMIN_EDIT_TOKEN + Privileges.ADMIN_DESTROY_TOKEN)

        dataset = DatasetFactory(creator).create_dataset(url_prefix="creator", title="Creator dataset", description="Dataset example creator", reference="Unknown")
        dataset2 = DatasetFactory(creator2).create_dataset(url_prefix="creator", title="Creator dataset", description="Dataset example creator", reference="Unknown")
        self.session.flush()

        # Anonymous or watcher can't destroy datasets
        with self.assertRaises(Unauthorized) as ex:
            DatasetFactory(anonymous).destroy_dataset(url_prefix="user1/creator")
        with self.assertRaises(Unauthorized) as ex:
            DatasetFactory(watcher).destroy_dataset(url_prefix="user1/creator")

        # creator can't destroy a dataset
        with self.assertRaises(Unauthorized) as ex:
            DatasetFactory(creator).destroy_dataset(url_prefix="user1/creator")

        # destructor can't destroy other's datasets
        with self.assertRaises(Unauthorized) as ex:
            DatasetFactory(destructor).destroy_dataset(url_prefix="user2/creator")

        # destructor can destroy within his url-prefix datasets
        DatasetFactory(destructor).destroy_dataset(url_prefix="user1/creator")

        self.session.flush()
        self.session.clear()

        dataset = DatasetDAO.query.get(url_prefix="user1/creator")
        self.assertIsNone(dataset, None)

        # destructor can destroy within any url-prefix datasets
        DatasetFactory(admin).destroy_dataset(url_prefix="user2/creator")

        self.session.flush()
        self.session.clear()

        dataset = DatasetDAO.query.get(url_prefix="user2/creator")
        self.assertIsNone(dataset, None)
예제 #20
0
    def test_token_can_link_datasets(self):
        """
        Tests that tokens can be associated to multiple datasets and disassociated.
        :return:
        """
        token1 = TokenDAO("example_token", 2, 5, "dalap")
        token2 = TokenDAO("example_token2", 2, 5, "dalap")

        dataset1 = DatasetDAO("ex/ivan", "example1", "lalala", "none")
        dataset2 = DatasetDAO("ex/ivan2", "example2", "lalala", "none")

        token1 = token1.link_datasets([dataset1, dataset2])
        token2 = token2.link_dataset(dataset2)
        self.session.flush()

        self.assertEqual(len(token1.datasets), 2)
        self.assertEqual(len(token2.datasets), 1)

        token1 = token1.unlink_dataset(dataset2)
        self.assertEqual(len(token1.datasets), 1)
예제 #21
0
def __create_token__(namespace, description, max_datasets, max_elements_per_dataset, privileges, duration_in_days, end_date=None):

    illegal_chars = "/*;:,.ç´`+Ǩ^><¿?'¡¿!\"·$%&()@~¬"
    if any([i in namespace for i in illegal_chars]):
        print("[ERROR] The namespace can't hold any of the following chars:\n\"{}\"".format(illegal_chars))
        exit(-1)

    from mldatahub.odm.dataset_dao import DatasetDAO
    from mldatahub.odm.token_dao import TokenDAO

    if end_date is not None:
        end_date = end_date
    else:
        end_date = now()+relativedelta(days=+duration_in_days)

    token = TokenDAO(description=description, max_dataset_count=max_datasets, max_dataset_size=max_elements_per_dataset,
                     url_prefix=namespace, end_date=end_date,
                     privileges=privileges)

    global_config.get_session().flush()

    return token
예제 #22
0
    def test_factory_creation_token(self):
        """
        Factory can create tokens.
        :return:
        """

        token = TokenDAO("example1", 5, 5, "url1")
        token2 = TokenDAO("example3",
                          5,
                          5,
                          "url2",
                          privileges=Privileges.USER_CREATE_TOKEN +
                          Privileges.RO_WATCH_DATASET)
        token3 = TokenDAO("example3",
                          5,
                          5,
                          "url2",
                          privileges=Privileges.ADMIN_CREATE_TOKEN)

        # Unprivileged token should not be able to create new tokens
        with self.assertRaises(Unauthorized) as ex:
            new_token = TokenFactory(token).create_token(
                description="example1",
                max_dataset_count=4,
                max_dataset_size=4,
                url_prefix="url1")

        # Privileged token should be able to create new tokens in his prefix
        new_token = TokenFactory(token2).create_token(description="example2",
                                                      max_dataset_count=4,
                                                      max_dataset_size=4,
                                                      url_prefix="url2")

        self.assertEqual(new_token.url_prefix, "url2")
        self.assertEqual(new_token.description, "example2")

        # Privileged token should be not able to create new tokens out of his prefix
        with self.assertRaises(Unauthorized) as ex:
            new_token = TokenFactory(token2).create_token(
                description="example3",
                max_dataset_count=4,
                max_dataset_size=4,
                url_prefix="url1")

        # Admin token should be able to create new tokens in his prefix
        new_token = TokenFactory(token3).create_token(description="example4",
                                                      max_dataset_count=4,
                                                      max_dataset_size=4,
                                                      url_prefix="url2")

        self.assertEqual(new_token.url_prefix, "url2")
        self.assertEqual(new_token.description, "example4")

        # Admin token should be able to create new tokens out of his prefix
        new_token = TokenFactory(token3).create_token(description="example5",
                                                      max_dataset_count=4,
                                                      max_dataset_size=4,
                                                      url_prefix="url1")

        self.assertEqual(new_token.url_prefix, "url1")
        self.assertEqual(new_token.description, "example5")

        # Privileged token should not be able to create new tokens out of his privilege set.
        with self.assertRaises(Conflict) as ex:
            new_token = TokenFactory(token2).create_token(
                description="example6",
                max_dataset_count=4,
                max_dataset_size=4,
                url_prefix="url2",
                privileges=Privileges.ADMIN_CREATE_TOKEN)

        # Privileged token can create tokens with its privilege set.
        new_token = TokenFactory(token2).create_token(
            description="example7",
            max_dataset_count=4,
            max_dataset_size=4,
            url_prefix="url2",
            privileges=Privileges.USER_CREATE_TOKEN)

        self.assertEqual(new_token.url_prefix, "url2")
        self.assertEqual(new_token.description, "example7")

        # Admin token can create tokens with any privilege set.
        new_token = TokenFactory(token3).create_token(
            description="example8",
            max_dataset_count=4,
            max_dataset_size=4,
            url_prefix="url1",
            privileges=Privileges.ADD_ELEMENTS + Privileges.DESTROY_DATASET +
            Privileges.ADMIN_CREATE_TOKEN)

        self.assertEqual(new_token.description, "example8")
        self.assertEqual(new_token.url_prefix, "url1")
        self.assertEqual(
            new_token.privileges, Privileges.ADD_ELEMENTS +
            Privileges.DESTROY_DATASET + Privileges.ADMIN_CREATE_TOKEN)
예제 #23
0
    def test_dataset_can_be_unlinked_with_token(self):
        """
        Factory can unlink datasets.
        :return:
        """
        token = TokenDAO("linker",
                         1,
                         1,
                         "testinglink",
                         privileges=Privileges.RO_WATCH_DATASET +
                         Privileges.CREATE_DATASET)
        token2 = TokenDAO("linker",
                          1,
                          1,
                          "testinglink2",
                          privileges=Privileges.RO_WATCH_DATASET +
                          Privileges.USER_EDIT_TOKEN)
        token21 = TokenDAO("linker",
                           1,
                           1,
                           "testinglink2",
                           privileges=Privileges.RO_WATCH_DATASET +
                           Privileges.USER_EDIT_TOKEN)
        dataset = DatasetDAO("{}/{}".format(token.url_prefix, "dataset"),
                             "dataset1", "dataset example", "none")
        dataset2 = DatasetDAO("{}/{}".format(token2.url_prefix, "dataset2"),
                              "dataset2", "dataset example2", "none")

        token3 = TokenDAO("linked",
                          1,
                          1,
                          "testinglink2",
                          privileges=Privileges.RO_WATCH_DATASET +
                          Privileges.ADMIN_EDIT_TOKEN)
        self.session.flush()

        token = token.link_datasets([dataset, dataset2])
        token21 = token21.link_datasets([dataset2])

        # Not privileged token can't link a dataset.
        with self.assertRaises(Unauthorized) as ex:
            token21 = TokenFactory(token).unlink_datasets(
                token21.token_gui, [dataset2.url_prefix])

        with self.assertRaises(Unauthorized) as ex:
            token = TokenFactory(token).unlink_datasets(
                token.token_gui, [dataset.url_prefix])

        # Privileged token can unlink a dataset.
        token21 = TokenFactory(token2).unlink_datasets(token21.token_gui,
                                                       [dataset2.url_prefix])
        self.assertEqual(len(token21.datasets), 0)

        token21 = token21.link_datasets([dataset])

        # Privileged token can NOT unlink a dataset of other url prefix
        with self.assertRaises(Unauthorized) as ex:
            token21 = TokenFactory(token2).unlink_datasets(
                token21.token_gui, [dataset.url_prefix])

        # Privileged token can NOT unlink a dataset from a token of other url prefix
        with self.assertRaises(Unauthorized) as ex:
            token = TokenFactory(token2).unlink_datasets(
                token.token_gui, [dataset.url_prefix])

        # Admin can do all of the above cases.
        token21 = TokenFactory(token3).unlink_datasets(token21.token_gui,
                                                       [dataset.url_prefix])
        token = TokenFactory(token3).unlink_datasets(token.token_gui,
                                                     [dataset.url_prefix])

        self.assertEqual(len(token21.datasets), 0)
        self.assertEqual(len(token.datasets), 1)
예제 #24
0
    def test_factory_can_modify_tokens(self):
        """
        Factory can modify tokens depending on privileges of main token.
        :return:
        """
        token = TokenDAO("example1", 5, 5, "uri1")
        token2 = TokenDAO("example2", 5, 5, "uri2")
        token3 = TokenDAO("example3",
                          5,
                          5,
                          "uri2",
                          privileges=Privileges.USER_EDIT_TOKEN)
        token4 = TokenDAO("example3",
                          5,
                          5,
                          "uri2",
                          privileges=Privileges.ADMIN_EDIT_TOKEN)

        self.session.flush()

        # token is not allowed to change token2
        with self.assertRaises(Unauthorized):
            new_token = TokenFactory(token).edit_token(
                token_gui=token2.token_gui, description="New description")

        # token3 should be allowed to change token2
        new_token = TokenFactory(token3).edit_token(
            token_gui=token2.token_gui, description="New description")

        self.assertEqual(token2.token_gui, new_token.token_gui)
        self.assertEqual("New description", new_token.description)
        self.assertEqual("uri2", new_token.url_prefix)

        # token4 should be allowed to change token2
        new_token = TokenFactory(token4).edit_token(
            token_gui=token2.token_gui, description="New description2")

        self.assertEqual(token2.token_gui, new_token.token_gui)
        self.assertEqual("New description2", new_token.description)
        self.assertEqual("uri2", new_token.url_prefix)

        # token is not allowed to change itself
        with self.assertRaises(Unauthorized):
            new_token = TokenFactory(token).edit_token(
                token_gui=token.token_gui, description="New description")

        # Non valid token GUI should raise exception
        with self.assertRaises(BadRequest):
            new_token = TokenFactory(token).edit_token(
                token_gui="INVALID", description="New description")

        # Token3 should not be able to change url prefix
        with self.assertRaises(Unauthorized):
            new_token = TokenFactory(token3).edit_token(
                token_gui=token2.token_gui, url_prefix="new_prefix")

        # However, Token4 should be able to change url prefix
        new_token = TokenFactory(token4).edit_token(token_gui=token2.token_gui,
                                                    url_prefix="new_prefix")
        self.assertEqual("new_prefix", new_token.url_prefix)

        # token3 should not be allowed to change admin token token4
        with self.assertRaises(Unauthorized) as ex:
            new_token = TokenFactory(token3).edit_token(
                token_gui=token4.token_gui, description="New description")
    def test_dataset_element_removal(self):
        """
        Factory can remove elements from datasets.
        """
        anonymous = TokenDAO("Anonymous", 1, 1, "anonymous")

        destructor = TokenDAO("normal user privileged with link", 1, 1, "user1",
                           privileges=Privileges.DESTROY_DATASET + Privileges.DESTROY_ELEMENTS
                           )
        destructor2 = TokenDAO("normal user unprivileged", 1, 1, "user1",
                           privileges=Privileges.DESTROY_DATASET
                           )
        admin = TokenDAO("admin user", 1, 1, "admin", privileges=Privileges.ADMIN_CREATE_TOKEN + Privileges.ADMIN_EDIT_TOKEN + Privileges.ADMIN_DESTROY_TOKEN)

        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none", tags=["example", "0"])
        dataset2 = DatasetDAO("user1/dataset2", "example_dataset2", "dataset2 for testing purposes", "none", tags=["example", "1"])

        self.session.flush()

        destructor = destructor.link_dataset(dataset)
        destructor2 = destructor2.link_dataset(dataset2)

        file_id1 = storage.put_file_content(b"content1")
        file_id2 = storage.put_file_content(b"content2")

        element  = DatasetElementDAO("example1", "none", file_id1, dataset=dataset)
        element2 = DatasetElementDAO("example2", "none", file_id1, dataset=dataset)
        element3 = DatasetElementDAO("example3", "none", file_id2, dataset=dataset2)

        self.session.flush()
        dataset = dataset.update()
        dataset2 = dataset2.update()

        self.assertEqual(len(dataset.elements), 2)
        self.assertEqual(len(dataset2.elements), 1)

        # Destructor can not destroy elements from a dataset that is not linked to
        with self.assertRaises(Unauthorized) as ex:
            DatasetElementFactory(destructor, dataset2).destroy_element(element._id)

        with self.assertRaises(Unauthorized) as ex:
            DatasetElementFactory(destructor, dataset2).destroy_element(element2._id)

        with self.assertRaises(Unauthorized) as ex:
            DatasetElementFactory(destructor, dataset2).destroy_element(element3._id)

        # Destructor can not destroy elements if they exist but are not inside his dataset
        with self.assertRaises(Unauthorized) as ex:
            DatasetElementFactory(destructor, dataset).destroy_element(element3._id)

        # Destructor can not destroy elements if they don't exist
        with self.assertRaises(Unauthorized) as ex:
            DatasetElementFactory(destructor, dataset).destroy_element("randomID")

        # Destructor can destroy elements if they exist and are  inside his dataset
        DatasetElementFactory(destructor, dataset).destroy_element(element._id)

        # Even though element is destroyed, file referenced should still exist
        self.assertEqual(storage.get_file(file_id1).content, b"content1")

        dataset = dataset.update()

        self.assertEqual(len(dataset.elements), 1)

        # Admin can remove elements form any source
        DatasetElementFactory(admin, dataset).destroy_element(element2._id)
        DatasetElementFactory(admin, dataset2).destroy_element(element3._id)

        self.session.flush()

        dataset = dataset.update()
        dataset2 = dataset2.update()

        self.assertEqual(len(dataset.elements), 0)
        self.assertEqual(len(dataset2.elements), 0)
    def test_dataset_fork_element_modification(self):
        """
        Elements modified from a forked dataset do not affect the main dataset.
        :return:
        """
        editor = TokenDAO("normal user privileged with link", 100, 200, "user1",
                     privileges=Privileges.RO_WATCH_DATASET + Privileges.CREATE_DATASET + Privileges.EDIT_DATASET +
                                Privileges.ADD_ELEMENTS + Privileges.EDIT_ELEMENTS + Privileges.DESTROY_ELEMENTS
                 )

        main_dataset = DatasetFactory(editor).create_dataset(url_prefix="foobar", title="foo", description="bar",
                                                             reference="none", tags=["a"])

        editor = editor.link_dataset(main_dataset)

        elements_proto = [{
            'title': 't{}'.format(i),
            'description': 'desc{}'.format(i),
            'http_ref': 'none',
            'tags': ['none'],
            'content': "content{}".format(i).encode()
        } for i in range(4)]

        elements = [DatasetElementFactory(editor, main_dataset).create_element(**element_proto) for element_proto in elements_proto]
        self.session.flush()

        self.assertEqual(len(elements), len(main_dataset.elements))
        forked_dataset = DatasetFactory(editor).fork_dataset(main_dataset.url_prefix, editor, url_prefix="foo")
        editor.link_dataset(forked_dataset)
        self.session.flush()
        self.assertEqual(len(forked_dataset.elements), len(main_dataset.elements))
        DatasetElementFactory(editor, forked_dataset).destroy_element(forked_dataset.elements[0]._id)

        self.session.flush()
        self.assertEqual(len(forked_dataset.elements), len(main_dataset.elements)-1)
        self.assertEqual(forked_dataset.elements[0].title, "t1")

        DatasetElementFactory(editor, main_dataset).destroy_element(main_dataset.elements[1]._id)

        self.session.flush()
        self.assertEqual(len(forked_dataset.elements), len(main_dataset.elements))
        self.assertEqual(forked_dataset.elements[0].title, "t1")
        self.assertEqual(forked_dataset.elements[1].title, "t2")
        self.assertEqual(forked_dataset.elements[2].title, "t3")
        self.assertEqual(main_dataset.elements[0].title, "t0")
        self.assertEqual(main_dataset.elements[1].title, "t2")
        self.assertEqual(main_dataset.elements[2].title, "t3")

        DatasetElementFactory(editor, forked_dataset).edit_element(main_dataset.elements[2]._id, title='tc2')
        self.session.flush()

        self.assertEqual(main_dataset.elements[2].title, "t3")
        self.assertEqual(forked_dataset.elements[2].title, "tc2")

        DatasetElementFactory(editor, main_dataset).edit_element(main_dataset.elements[1]._id, title='tc')
        self.session.flush()

        self.assertEqual(main_dataset.elements[1].title, "tc")
        self.assertEqual(forked_dataset.elements[1].title, "t2")

        main_dataset = DatasetFactory(editor).create_dataset(url_prefix="foobar2", title="foo", description="bar",
                                                             reference="none", tags=["a"])

        editor.link_dataset(main_dataset)
        self.session.flush()

        elements_proto = [{
            'title': 't{}'.format(i),
            'description': 'desc{}'.format(i),
            'http_ref': 'none',
            'tags': ['none'],
            'content': "content{}".format(i).encode()
        } for i in range(4)]

        elements = [DatasetElementFactory(editor, main_dataset).create_element(**element_proto) for element_proto in elements_proto]
        self.session.flush()

        forked_dataset2 = DatasetFactory(editor).fork_dataset(main_dataset.url_prefix, editor, url_prefix="bar")
        self.session.flush()
        editor.link_dataset(forked_dataset2)
        self.session.flush()
        mod_proto = {
            main_dataset.elements[0]._id: dict(title="t3"),
            main_dataset.elements[1]._id: dict(title="t3_2"),
        }

        self.assertEqual(forked_dataset2.elements[0]._id, main_dataset.elements[0]._id)
        self.assertEqual(forked_dataset2.elements[1]._id, main_dataset.elements[1]._id)
        self.assertEqual(forked_dataset2.elements[2]._id, main_dataset.elements[2]._id)
        self.assertEqual(forked_dataset2.elements[3]._id, main_dataset.elements[3]._id)

        DatasetElementFactory(editor, main_dataset).edit_elements(mod_proto)
        self.session.flush()
        self.assertEqual(forked_dataset2.elements[0].title, "t0")
        self.assertEqual(forked_dataset2.elements[1].title, "t1")
        self.assertEqual(forked_dataset2.elements[2].title, "t2")
        self.assertEqual(forked_dataset2.elements[3].title, "t3")
        self.assertEqual(main_dataset.elements[0].title, "t3")
        self.assertEqual(main_dataset.elements[1].title, "t3_2")
        self.assertEqual(main_dataset.elements[2].title, "t2")
        self.assertEqual(main_dataset.elements[3].title, "t3")

        self.assertNotEqual(forked_dataset2.elements[0]._id, main_dataset.elements[0]._id)
        self.assertNotEqual(forked_dataset2.elements[1]._id, main_dataset.elements[1]._id)
        self.assertEqual(forked_dataset2.elements[2]._id, main_dataset.elements[2]._id)
        self.assertEqual(forked_dataset2.elements[3]._id, main_dataset.elements[3]._id)

        mod_proto = {
            forked_dataset2.elements[2]._id: dict(title="t4"),
            forked_dataset2.elements[3]._id: dict(title="t4_2"),
        }
        DatasetElementFactory(editor, forked_dataset2).edit_elements(mod_proto)

        self.assertNotEqual(forked_dataset2.elements[0]._id, main_dataset.elements[0]._id)
        self.assertNotEqual(forked_dataset2.elements[1]._id, main_dataset.elements[1]._id)
        self.assertNotEqual(forked_dataset2.elements[2]._id, main_dataset.elements[2]._id)
        self.assertNotEqual(forked_dataset2.elements[3]._id, main_dataset.elements[3]._id)
        self.assertEqual(forked_dataset2.elements[2].title, "t4")
        self.assertEqual(forked_dataset2.elements[3].title, "t4_2")
        self.assertEqual(main_dataset.elements[2].title, "t2")
        self.assertEqual(main_dataset.elements[3].title, "t3")
    def test_dataset_element_edit(self):
        """
        Factory can edit elements from datasets.
        """
        editor = TokenDAO("normal user privileged with link", 1, 1, "user1",
                           privileges=Privileges.EDIT_DATASET + Privileges.EDIT_ELEMENTS
                           )
        editor2 = TokenDAO("normal user unprivileged", 1, 1, "user1",
                           privileges=Privileges.EDIT_DATASET
                           )
        admin = TokenDAO("admin user", 1, 1, "admin", privileges=Privileges.ADMIN_CREATE_TOKEN + Privileges.ADMIN_EDIT_TOKEN + Privileges.ADMIN_DESTROY_TOKEN)

        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none", tags=["example", "0"])
        dataset2 = DatasetDAO("user1/dataset2", "example_dataset2", "dataset2 for testing purposes", "none", tags=["example", "1"])

        self.session.flush()

        editor = editor.link_dataset(dataset)
        editor2 = editor2.link_dataset(dataset2)

        file_id1 = storage.put_file_content(b"content1")
        file_id2 = storage.put_file_content(b"content2")

        element  = DatasetElementDAO("example1", "none", file_id1, dataset=dataset)
        element2 = DatasetElementDAO("example2", "none", file_id1, dataset=dataset)
        element3 = DatasetElementDAO("example3", "none", file_id2, dataset=dataset2)

        self.session.flush()
        dataset = dataset.update()
        dataset2 = dataset2.update()

        self.assertEqual(len(dataset.elements), 2)
        self.assertEqual(len(dataset2.elements), 1)

        # editor can not edit elements from a dataset that is not linked to
        with self.assertRaises(Unauthorized) as ex:
            DatasetElementFactory(editor, dataset2).edit_element(element._id, title="asd")

        with self.assertRaises(Unauthorized) as ex:
            DatasetElementFactory(editor, dataset2).edit_element(element2._id, title="asd2")

        with self.assertRaises(Unauthorized) as ex:
            DatasetElementFactory(editor, dataset2).edit_element(element3._id, title="asd3")

        # editor can not edit elements if they exist but are not inside his dataset
        with self.assertRaises(Unauthorized) as ex:
            DatasetElementFactory(editor, dataset).edit_element(element3._id, title="asd4")

        # editor can not edit elements if they don't exist
        with self.assertRaises(NotFound) as ex:
            DatasetElementFactory(editor, dataset).edit_element("randomID", title="asd5")

        # Editor can edit elements if they exist and are inside his dataset
        DatasetElementFactory(editor, dataset).edit_element(element._id, title="asd6")

        self.session.flush()

        dataset = dataset.update()
        element = element.update()

        # Editor can not change references to files
        with self.assertRaises(Unauthorized) as ex:
            DatasetElementFactory(editor, dataset).edit_element(element._id, file_ref_id="other_reference")

        # BUT he can change the content
        DatasetElementFactory(editor, dataset).edit_element(element._id, content=b"other_content")

        element = element.update()
        self.assertEqual(storage.get_file(element.file_ref_id).content, b"other_content")

        # Admin can do whatever he wants
        DatasetElementFactory(admin, dataset).edit_element(element2._id, title="changed by admin")
        element2 = element2.update()
        self.assertEqual(element2.title, "changed by admin")

        DatasetElementFactory(admin, dataset2).edit_element(element3._id, file_ref_id=element.file_ref_id)

        element3 = element3.update()
        self.assertEqual(storage.get_file(element3.file_ref_id).content,
                         storage.get_file(element.file_ref_id).content)

        self.session.flush()
    def test_dataset_element_creation(self):
        """
        Factory can create dataset's elements.
        """
        anonymous = TokenDAO("Anonymous", 1, 1, "anonymous")

        creator = TokenDAO("normal user privileged with link", 1, 1, "user1",
                           privileges=Privileges.CREATE_DATASET + Privileges.ADD_ELEMENTS
                           )
        creator2 = TokenDAO("normal user unprivileged", 1, 1, "user1",
                           privileges=Privileges.CREATE_DATASET
                           )
        admin = TokenDAO("admin user", 1, 1, "admin", privileges=Privileges.ADMIN_CREATE_TOKEN + Privileges.ADMIN_EDIT_TOKEN + Privileges.ADMIN_DESTROY_TOKEN)

        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none", tags=["example", "0"])
        dataset2 = DatasetDAO("user1/dataset2", "example_dataset2", "dataset2 for testing purposes", "none", tags=["example", "1"])

        self.session.flush()

        creator = creator.link_dataset(dataset)
        creator2 = creator2.link_dataset(dataset)

        # Creator can create elements into the dataset
        element = DatasetElementFactory(creator, dataset).create_element(title="New element", description="Description unknown",
                                                               tags=["example_tag"], content=b"hello")

        self.assertEqual(element.tags, ["example_tag"])

        content = storage.get_file(element.file_ref_id).content
        self.assertEqual(content, b"hello")
        self.session.flush()
        # Creator can't create elements referencing existing files directly (Exploit fix)
        with self.assertRaises(Unauthorized) as ex:
            element = DatasetElementFactory(creator, dataset).create_element(title="New element2",
                                                                             description="Description unknown2",
                                                                             tags=["example_tag"],
                                                                             file_ref_id=element.file_ref_id)

        # Creator can't create elements on other's datasets if not linked with them
        with self.assertRaises(Unauthorized) as ex:
            element = DatasetElementFactory(creator, dataset2).create_element(title="New element2",
                                                                              description="Description unknown2",
                                                                              tags=["example_tag"], content=b"hello2")

        # Anonymous can't create elements
        with self.assertRaises(Unauthorized) as ex:
            element = DatasetElementFactory(anonymous, dataset).create_element(title="New element3", description="Description unknown",
                                                               tags=["example_tag"], content=b"hello3")

        # Creator2, even linked to the dataset, can't create elements as it is not privileged
        with self.assertRaises(Unauthorized) as ex:
            element = DatasetElementFactory(creator2, dataset).create_element(title="New element4",
                                                                              description="Description unknown4",
                                                                              tags=["example_tag"], content=b"hello4")

        # Admin can do any of the previous actions.
        element = DatasetElementFactory(admin, dataset).create_element(title="New element5",
                                                                          description="Description unknown5",
                                                                          tags=["example_tag"], content=b"hello5")
        self.session.flush_all()
        self.session.refresh(dataset)

        dataset = DatasetDAO.query.get(_id=dataset._id)
        self.assertIn(dataset._id, element.dataset_id)
        self.assertEqual(len(dataset.elements), 2)

        new_element = DatasetElementFactory(admin, dataset2).create_element(title="New element6",
                                                                  description="Description unknown5",
                                                                  tags=["example_tag"], file_ref_id=element.file_ref_id)

        self.assertEqual(element.file_ref_id, new_element.file_ref_id)
    def test_dataset_element_content_retrieval(self):
        """
        Factory can retrieve content of an element.
        """
        editor = TokenDAO("normal user privileged with link", 1, 1, "user1",
                          privileges=Privileges.RO_WATCH_DATASET
                          )
        editor2 = TokenDAO("normal user unprivileged", 1, 1, "user1",
                           privileges=0
                           )
        admin = TokenDAO("admin user", 1, 1, "admin",
                         privileges=Privileges.ADMIN_CREATE_TOKEN + Privileges.ADMIN_EDIT_TOKEN + Privileges.ADMIN_DESTROY_TOKEN)

        dataset = DatasetDAO("user1/dataset1", "example_dataset", "dataset for testing purposes", "none",
                             tags=["example", "0"])
        dataset2 = DatasetDAO("user1/dataset2", "example_dataset2", "dataset2 for testing purposes", "none",
                              tags=["example", "1"])

        self.session.flush()

        editor = editor.link_dataset(dataset)
        editor2 = editor2.link_dataset(dataset2)

        file_id1 = storage.put_file_content(b"content1")
        file_id2 = storage.put_file_content(b"content2")

        element = DatasetElementDAO("example1", "none", file_id1, dataset=dataset)
        element2 = DatasetElementDAO("example2", "none", file_id1, dataset=dataset)
        element3 = DatasetElementDAO("example3", "none", file_id2, dataset=dataset2)

        self.session.flush()
        dataset = dataset.update()
        dataset2 = dataset2.update()

        self.assertEqual(len(dataset.elements), 2)
        self.assertEqual(len(dataset2.elements), 1)

        # editor can see elements from his dataset
        element_content = DatasetElementFactory(editor, dataset).get_element_content(element._id)
        self.assertEqual(element_content, b"content1")

        # editor can not see elements from other's datasets
        with self.assertRaises(Unauthorized) as ex:
            element_content = DatasetElementFactory(editor, dataset2).get_element_content(element3._id)

        # editor can not see external elements within his dataset
        with self.assertRaises(Unauthorized) as ex:
            element_content = DatasetElementFactory(editor, dataset).get_element_content(element3._id)

        # editor2 is not privileged and can not see any elements of his own dataset
        with self.assertRaises(Unauthorized) as ex:
            element_content = DatasetElementFactory(editor2, dataset2).get_element_content(element3._id)

        # Or external elements
        with self.assertRaises(Unauthorized) as ex:
            element_content = DatasetElementFactory(editor2, dataset2).get_element_content(element2._id)

        # Or other datasets
        with self.assertRaises(Unauthorized) as ex:
            element_content = DatasetElementFactory(editor2, dataset).get_element_content(element2._id)

        # Admin can do anything
        element_content = DatasetElementFactory(admin, dataset).get_element_content(element._id)
        self.assertEqual(element_content, b"content1")

        # But not this: dataset2 does not have element
        with self.assertRaises(Unauthorized) as ex:
            element_content = DatasetElementFactory(admin, dataset2).get_element_content(element._id)

        element_content = DatasetElementFactory(admin, dataset2).get_element_content(element3._id)
        self.assertEqual(element_content, b"content2")