Example #1
0
def upload_file_to_row_property(client, row, path, property_name):
    path = str(path)
    mimetype = mimetypes.guess_type(path)[0] or "text/plain"
    filename = os.path.split(path)[-1]
    data = client.post(
        "getUploadFileUrl",
        {
            "bucket": "secure",
            "name": filename,
            "contentType": mimetype
        },
    ).json()
    # Return url, signedGetUrl, signedPutUrl
    mangled_property_name = [
        e["id"] for e in row.schema if e["name"] == property_name
    ][0]

    with open(path, "rb") as f:
        response = requests.put(data["signedPutUrl"],
                                data=f,
                                headers={"Content-type": mimetype})
        response.raise_for_status()
    simpleurl = data['signedGetUrl'].split('?')[0]
    op1 = build_operation(id=row.id,
                          path=["properties", mangled_property_name],
                          args=[[filename, [["a", simpleurl]]]],
                          table="block",
                          command="set")
    file_id = simpleurl.split("/")[-2]
    op2 = build_operation(id=row.id,
                          path=["file_ids"],
                          args={"id": file_id},
                          table="block",
                          command="listAfter")
    client.submit_transaction([op1, op2])
Example #2
0
    def move_to(self, target_block: "Block", position="last-child"):
        assert position in ["first-child", "last-child", "before", "after"]

        if "child" in position:
            new_parent_id = target_block.id
            new_parent_table = "block"
        else:
            new_parent_id = target_block.get("parent_id")
            new_parent_table = target_block.get("parent_table")

        if position in ["first-child", "before"]:
            list_command = "listBefore"
        else:
            list_command = "listAfter"

        list_args = {"id": self.id}
        if position in ["before", "after"]:
            list_args[position] = target_block.id

        with self._client.as_atomic_transaction():

            # First, remove the node, before we re-insert and re-activate it at the target location
            self.remove()

            if not self.is_alias:
                # Set the parent_id of the moving block to the new parent, and mark it as active again
                self._client.submit_transaction(
                    build_operation(
                        id=self.id,
                        path=[],
                        args={
                            "alive": True,
                            "parent_id": new_parent_id,
                            "parent_table": new_parent_table,
                        },
                        command="update",
                    ))
            else:
                self._alias_parent = new_parent_id

            # Add the moving block's ID to the "content" list of the new parent
            self._client.submit_transaction(
                build_operation(
                    id=new_parent_id,
                    path=["content"],
                    args=list_args,
                    command=list_command,
                ))

        # update the local block cache to reflect the updates
        self._client.refresh_records(block=[
            self.id,
            self.get("parent_id"),
            target_block.id,
            target_block.get("parent_id"),
        ])
Example #3
0
    def create_record(self, table: str, parent: Record, **kwargs):
        """
        Create new record.


        Arguments
        ---------
        table : str
            Table value.

        parent : Record
            Parent for the newly created record.


        Returns
        -------
        str
            ID of newly created record.
        """
        # make up a new UUID; apparently we get to choose our own!
        record_id = str(uuid.uuid4())
        child_list_key = kwargs.get("child_list_key") or parent.child_list_key

        args = {
            "id": record_id,
            "version": 1,
            "alive": True,
            "created_by": self.current_user.id,
            "created_time": now(),
            "parent_id": parent.id,
            "parent_table": parent._table,
            **kwargs,
        }

        with self.as_atomic_transaction():

            # create the new record
            self.submit_transaction(
                build_operation(
                    args=args, command="set", id=record_id, path=[], table=table
                )
            )

            # add the record to the content list of the parent, if needed
            if child_list_key:
                self.submit_transaction(
                    build_operation(
                        id=parent.id,
                        path=[child_list_key],
                        args={"id": record_id},
                        command="listAfter",
                        table=parent._table,
                    )
                )

        return record_id
Example #4
0
    def remove(self, permanently: bool = False):
        """
        Remove the node from its parent, and mark it as inactive.

        This corresponds to what happens in the Notion UI when you
        delete a block. Note that it doesn't *actually* delete it,
        just orphan it, unless `permanently` is set to True,
        in which case we make an extra call to hard-delete.


        Arguments
        ---------
        permanently : bool, optional
            Whether or not to hard-delete the block.
            Defaults to False.
        """
        if self.is_alias:
            # only remove it from the alias parent's content list
            return self._client.submit_transaction(
                build_operation(
                    id=self._alias_parent,
                    path="content",
                    args={"id": self.id},
                    command="listRemove",
                ))

        with self._client.as_atomic_transaction():
            # Mark the block as inactive
            self._client.submit_transaction(
                build_operation(id=self.id,
                                path=[],
                                args={"alive": False},
                                command="update"))

            # Remove the block's ID from a list on its parent, if needed
            if self.parent.child_list_key:
                self._client.submit_transaction(
                    build_operation(
                        id=self.parent.id,
                        path=[self.parent.child_list_key],
                        args={"id": self.id},
                        command="listRemove",
                        table=self.parent._table,
                    ))

        if permanently:
            self._client.post("deleteBlocks", {
                "blockIds": [self.id],
                "permanentlyDelete": True
            })
            del self._client._store._values["block"][self.id]
Example #5
0
    def add_alias(self, block: Block) -> Block:
        """
        Adds an alias to the provided `block`, i.e. adds the block's ID to the parent's content list,
        but doesn't change the block's parent_id.


        Arguments
        ---------
        block : Block
            Instance of block to alias.


        Returns
        -------
        Block
            Aliased block.
        """

        # add the block to the content list of the parent
        self._client.submit_transaction(
            build_operation(
                id=self._parent.id,
                path=[self.child_list_key],
                args={"id": block.id},
                command="listAfter",
            ))

        return self._get_block(block.id)
Example #6
0
 def remove(self):
     # Mark the block as inactive
     self._client.submit_transaction(
         build_operation(id=self.id,
                         path=[],
                         args={"alive": False},
                         command="update"))
Example #7
0
    def set(self, path, value):
        """
        Set a specific `value` under the specific `path`
        on the record's data structure on the server.


        Arguments
        ---------
        path : list of str or str
            Specifies the field to which set the value.

        value
            Value to set under provided path.
        """
        self._client.submit_transaction(
            build_operation(id=self.id,
                            path=path,
                            args=value,
                            table=self._table))
Example #8
0
    def change_lock(self, locked: bool):
        """
        Set or free the lock according to the value passed in `locked`.


        Arguments
        ---------
        locked : bool
            Whether or not to lock the block.
        """
        args = dict(block_locked=locked,
                    block_locked_by=self._client.current_user.id)

        with self._client.as_atomic_transaction():
            self._client.submit_transaction(
                build_operation(
                    id=self.id,
                    path=["format"],
                    args=args,
                    command="update",
                ))

        # update the local block cache to reflect the updates
        self._client.refresh_records(block=[self.id])