Пример #1
0
    def export_card(self, repo, file_name, card_name, file_format='CSV'):
        """
        Exports the results of a card to a new file in the repo.

        Any existing file with that name is overwritten.

        Raises PermissionDenied on insufficient privileges or bad query.
        """
        DataHubManager.has_repo_file_privilege(
            self.username, self.repo_base, repo, 'write')

        card = Card.objects.get(repo_base=self.repo_base,
                                repo_name=repo, card_name=card_name)
        query = card.query

        # to export a card, the user must be able to successfully execute
        # the query from their own database user.
        try:
            self.execute_sql(query)
        except Exception:
            raise PermissionDenied(
                'Either missing required privileges or bad query')

        # create the user data folder if it doesn't already exist
        DataHubManager.create_user_data_folder(self.repo_base, repo)

        file_name = clean_file_name(file_name)
        file_path = user_data_path(
            self.repo_base, repo, file_name, file_format)

        self.user_con.export_query(query=query,
                                   file_path=file_path,
                                   file_format=file_format)
Пример #2
0
    def delete_repo(self, repo, force=False):
        """
        Deletes a repo.

        Pass force=True to delete the repo even if it is not empty.

        Returns True on success.

        Raises ValueError if repo has invalid characters.
        Raises LookupError if the repo doesn't exist.
        Raises InternalError if the repo is not empty and force is not True.
        Raises PermissionDenied if not repo_base owner.
        """
        # Only a repo owner can delete repos.
        if self.repo_base != self.username:
            raise PermissionDenied()

        # remove related collaborator objects
        Collaborator.objects.filter(
            repo_name=repo, repo_base=self.repo_base).delete()

        # finally, delete the actual schema
        res = self.user_con.delete_repo(repo=repo, force=force)
        DataHubManager.delete_user_data_folder(self.repo_base, repo)
        return res
Пример #3
0
    def create_card(self, repo, card_name, query):
        """
        Creates a card in a repo from a given query.

        Returns the card on success.

        Raises IntegrityError if card with same name already exists.
        Raises ValueError if card name is not alphanumeric with underscores
          or if the card name is blank
        Raises PermissionDenied on insufficient privileges or bad query.
        """
        DataHubManager.has_repo_file_privilege(
            self.username, self.repo_base, repo, 'write')

        # reject card names that have non alphanumeric characters
        if not re.match(r'^[A-Za-z0-9_]+$', card_name):
            raise ValueError(
                'Only numbers, letters, and '
                'underscores are allowed in card names')

        # to create a card, the user must be able to successfully execute
        # the query from their own database user.
        try:
            self.execute_sql(query)
        except Exception:
            raise PermissionDenied(
                'Either missing required privileges or bad query')

        card, created = Card.objects.get_or_create(
            repo_base=self.repo_base, repo_name=repo,
            card_name=card_name, query=query)

        return card
Пример #4
0
    def create_card(self, repo, card_name, query):
        """
        Creates a card in a repo from a given query.

        Returns the card on success.

        Raises IntegrityError if card with same name already exists.
        Raises PermissionDenied on insufficient privileges or bad query.
        """
        DataHubManager.has_repo_file_privilege(self.username, self.repo_base,
                                               repo, 'write')

        # to create a card, the user must be able to successfully execute
        # the query from their own database user.
        try:
            self.execute_sql(query)
        except Exception:
            raise PermissionDenied(
                'Either missing required privileges or bad query')

        card, created = Card.objects.get_or_create(repo_base=self.repo_base,
                                                   repo_name=repo,
                                                   card_name=card_name,
                                                   query=query)

        return card
Пример #5
0
    def has_repo_db_privilege(login, repo_base, repo, privilege):
        """
        Raises PermissonDenied if user does not have the DATABASE privilege
        passed in the argument, e.g. 'USAGE'.

        Relies on database role management, so this is a pretty straightforward
        call.
        """
        repo = repo.lower()
        repo_base = repo_base.lower()
        with _superuser_connection(repo_base) as conn:
            result = conn.has_repo_db_privilege(
                login=login, repo=repo, privilege=privilege)
        if not result:
            raise PermissionDenied()
Пример #6
0
    def update_card(self,
                    repo,
                    card_name,
                    new_query=None,
                    new_name=None,
                    public=None):
        """
        Updates a card's name, query, and/or public visibility.

        Returns the card on success.

        Raises ValueError if new_name is the empty string.
        Raises TypeError on invalid public parameter.
        Raises PermissionDenied on insufficient privileges or bad new_query.
        """
        DataHubManager.has_repo_file_privilege(self.username, self.repo_base,
                                               repo, 'write')

        card = Card.objects.get(repo_base=self.repo_base,
                                repo_name=repo,
                                card_name=card_name)
        # update the card
        if new_query is not None:
            # Queries for cards must work
            try:
                self.execute_sql(new_query)
            except Exception:
                raise PermissionDenied(
                    'Either missing required privileges or bad query')
            card.query = new_query
        if new_name is not None:
            if len(new_name) < 1:
                raise ValueError("new_name must be longer than zero "
                                 "characters")
            card.card_name = new_name
        if public is not None:
            if type(public) is not bool:
                raise TypeError("public must be of type bool")
            card.public = public

        card.save()
        return card
Пример #7
0
def _convert_pg_exception(e):
    # Convert some psycopg2 errors into exceptions meaningful to
    # Django.
    if (e.pgcode == errorcodes.INSUFFICIENT_PRIVILEGE):
        raise PermissionDenied()
    if (e.pgcode == errorcodes.INVALID_PARAMETER_VALUE
            or e.pgcode == errorcodes.UNDEFINED_OBJECT):
        raise ValueError("Invalid parameter in query.")
    if e.pgcode == errorcodes.INVALID_SCHEMA_NAME:
        error = ('Repo not found. '
                 'You must specify a repo in your query. '
                 'i.e. select * from REPO_NAME.TABLE_NAME. ')
        raise LookupError(error)
    if e.pgcode == errorcodes.UNDEFINED_TABLE:
        raise LookupError("Table or view not found.")
    if e.pgcode == errorcodes.DUPLICATE_SCHEMA:
        raise ValueError("A repo with that name already exists.")
    if e.pgcode == errorcodes.DUPLICATE_TABLE:
        raise ValueError("A table with that name already exists.")
    raise e
Пример #8
0
    def has_repo_file_privilege(login, repo_base, repo, privilege):
        """
        Raises PermissonDenied if user does not have the FILE privilege passed
        in the argument, e.g. 'read'.
        """
        repo = repo.lower()
        repo_base = repo_base.lower()

        # Users always have privileges over their own files.
        if login == repo_base:
            return

        # Check if the current user or the public user has the privilege on
        # this repo.
        # The anonymous user is never explicitly shared with, so we don't need
        # to check for that.
        permitted_collaborators = Collaborator.objects.filter(
            repo_base=repo_base,
            repo_name=repo,
            file_permission__contains=privilege,
            user__username__in=[settings.PUBLIC_ROLE, login])
        if not next((c for c in permitted_collaborators), None):
            raise PermissionDenied()
Пример #9
0
    def rename_repo(self, repo, new_name):
        """
        Renames a repo.

        Returns True on success.

        Raises ValueError if either name has invalid characters.
        Raises LookupError if the repo doesn't exist.
        Raises ValueError if the new name is taken.
        Raises PermissionDenied if not repo_base owner.
        """
        # only a repo owner can rename a repo:
        if self.repo_base != self.username:
            raise PermissionDenied()

        # rename in user_con
        success = self.user_con.rename_repo(repo=repo, new_name=new_name)
        if success:
            # update collaborator(s), if there are any
            Collaborator.objects.filter(
                repo_name=repo, repo_base=self.repo_base).update(
                    repo_name=new_name)

        return success