Esempio n. 1
0
class WebsiteSettings(node_models.Node):

    maintenance = node_models.Property(required=True)

    logo = node_models.Property(sftp=True)

    name = node_models.Property()

    def __str__(self):
        return f'<WebsiteSettings object>'

    def __repr__(self):
        return f'<WebsiteSettings object>'

    @classmethod
    def get(cls, uuid=None):
        response = gdbh.r_transaction('MATCH (w:WebsiteSettings) RETURN (w)')

        if response:
            fake_permission_instance = FakeClass()
            fake_permission_instance.__class__ = cls

            property_dict = response[0]["w"]._properties

            for property_name, property_value in property_dict.items():
                setattr(fake_permission_instance, property_name, property_value)

            return fake_permission_instance

        else:
            return None

    def delete(self):
        gdbh.w_transaction("""
        MATCH (w:WebsiteSettings)
        DETACH DELETE (w)
        """)
Esempio n. 2
0
class User(node_models.Node):

    # Default groups
    is_super_user = node_models.Property(default=False)

    is_staff_user = node_models.Property(default=False)

    is_active_user = node_models.Property(default=True)

    first_name = node_models.Property(required=True)

    last_name = node_models.Property(required=True)

    email = node_models.Property(required=True, unique=True)

    password = node_models.Property(required=True)

    registration_datetime = node_models.Property(default=datetime.datetime.now)

    permissions = UserPermissionsRelationship()

    groups = UserGroupsRelationship()

    session = UserSessionRelationsip()

    email_confirmation_key = None

    email_is_confirmed = None

    if settings.BULB_REGISTRATION_USE_EMAIL_CONFIRMATION:
        email_confirmation_key = node_models.Property()

        email_is_confirmed = node_models.Property(default=False)

    def __str__(self):
        return f'<User object(first_name="{self.first_name}", last_name="{self.last_name}", uuid="{self.uuid}")>'

    def __repr__(self):
        return f'<User object(first_name="{self.first_name}", last_name="{self.last_name}", uuid="{self.uuid}")>'

    @classmethod
    def create(cls, **extrafields):

        extrafields.setdefault('is_super_user', False)
        extrafields.setdefault('is_staff_user', False)
        extrafields.setdefault('is_active_user', True)

        extrafields['password'] = _hash_password(extrafields['password'])

        new_user = cls(**extrafields)

        if settings.BULB_REGISTRATION_USE_EMAIL_CONFIRMATION:
            # Generate the email confirmation key.
            email_confirmation_key = make_uuid()

            # Apply it to the new User instance.
            new_user.update('email_confirmation_key', email_confirmation_key)

            target_email = extrafields[settings.BULB_USER_EMAIL_PROPERTY_NAME]
            confirmation_url = settings.BULB_CONFIRMATION_VIEW_PATH + email_confirmation_key

            send_mail(
                from_email=settings.BULB_EMAIL_CONFIRMATION_SENDER_NAME,
                subject=settings.BULB_EMAIL_CONFIRMATION_SUBJECT,
                recipient_list=[f"{target_email}"],
                message=settings.BULB_EMAIL_CONFIRMATION_DEFAULT_MESSAGE +
                confirmation_url,
                html_message=render_to_string(
                    settings.BULB_EMAIL_CONFIRMATION_TEMPLATE_PATH,
                    {"confirmation_url": confirmation_url}))

        return new_user

    @classmethod
    def create_super_user(cls, **extrafields):
        extrafields.setdefault('is_super_user', True)
        extrafields.setdefault('is_staff_user', True)
        extrafields.setdefault('is_active_user', True)

        extrafields['password'] = _hash_password(extrafields['password'])

        is_super_user = extrafields.get('is_super_user')
        is_staff_user = extrafields.get('is_staff_user')
        if not is_super_user:
            bulb_logger.error(
                'ValueError(\'A SuperUser must have "is_super_user = True".\')'
            )
            raise ValueError('A SuperUser must have "is_super_user = True".')

        elif not is_staff_user:
            bulb_logger.error(
                'ValueError(\'A SuperUser must have "is_staff_user = True".\')'
            )
            raise ValueError('A SuperUser must have "is_staff_user = True".')

        else:
            new_super_user = User(**extrafields)

            return new_super_user

    @classmethod
    def get(cls,
            uuid=None,
            email=None,
            email_confirmation_key=None,
            order_by=None,
            limit=None,
            skip=None,
            desc=False,
            only=None,
            filter=None,
            distinct=False,
            handmade=None,
            return_query=False):
        """
        This method allow the retrieving of User (or of one of its children classes) instances.

        :param email (required if there is neither uuid nor email_confirmation_key) : The email of a user to get an unique user instance.

        :param uuid (required if there is neither email nor email_confirmation_key) : The Universal Unique Identifier of a node to get
                                                                                      an unique instance.

        :param email_confirmation_key (required if there is neither email nor uuid) : The confirmation key for the email validation part.

        :param order_by (optional, default=None) : Must be the name of the property with which the returned datas will be sorted.
                                                   Examples : "datetime", "first_name", etc...

        :param limit (optional, default=None) : Must be an integer. This parameter defines the number of returned elements.

        :param skip (optional, default=None) : Must be an integer. This parameter defines the number of skipped elements. For example
                                               if self.skip = 3, the 3 first returned elements will be skipped.

        :param desc (optional, default=False) : Must be a boolean. If it is False the elements will be returned in an increasing order,
                                                but it is True, they will be returned in a descending order.

        :param only (optional, default=None) : Must be a list of field_names. If this parameter is filled, the return will not be Node
                                               instances, but a dict with "only" the mentioned fields.

        :param filter (optional, default=None) : Must be Q statement. You must use the Q class stored in bulb.db
                                                 Example: Q(name__contains="al") | Q(age__year__lte=8)

        :param distinct (optional, default=False) : Must be a boolean. If it is True, the returned list will be only composed with
                                                    unique elements.

        :param handmade: If this param is filled, no other must be filled. With 'handmade', you can insert your own get query and
                         the function will transform the objects returned by the database into Python instance of this class. WARNING :
                         Please consider using the gdbh.r_transaction() method (imported from bulb.db) if your request no returns full
                         Neo4j objects but a list of properties.
                         Examples :
                         ❌ : MATCH (u) RETURN u.first_name, u.last_name
                         ✅ : MATCH (u) RETURN u

                         In addition, note that the RETURN must absolutely be named 'u' like "user".

        :param return_query (optional, default=False) : Must be a boolean. If true, the method will return the cypher query.

        :return: If uuid is None, a list will be returned. Else it will be a unique instance.
        """

        if handmade is None:
            where_statement = ""
            property_statement = ""
            order_by_statement = ""
            limit_statement = ""
            skip_statement = ""
            desc_statement = ""

            # Build the property_statement.
            if uuid is not None and email is not None:
                property_statement = "{uuid:'%s', email:'%s'}" % (uuid, email)

            elif uuid is not None:
                property_statement = "{uuid:'%s'}" % uuid

            elif email is not None:
                property_statement = "{email:'%s'}" % email

            elif email_confirmation_key is not None:
                property_statement = "{email_confirmation_key:'%s'}" % email_confirmation_key

            # Build the match_statement.
            cyher_labels = node_models.DatabaseNode.format_labels_to_cypher(
                cls._get_labels())
            match_statement = f"MATCH (u:{cyher_labels} {property_statement})"

            # Build the where statement.
            if filter is not None:
                # where_statement = "WHERE " + filter #removed to fix

                if not filter[0] != "n":
                    where_statement = "WHERE " + filter

                else:
                    where_statement = filter

                where_statement = where_statement.replace("n.", "u.")

            # Build the with_statement.
            with_statement = "WITH u"

            # Build order_by statements.
            if order_by is not None:
                order_by_statement = f"ORDER BY u.{order_by}"

            # Build return_statement statements.
            if not only:
                if not distinct:
                    return_statement = "RETURN (u)"

                else:
                    return_statement = "RETURN DISTINCT (u)"

            else:
                only_statement_list = []

                for element in only:
                    only_statement_list.append(f"u.{element}")

                only_statement = ", ".join(only_statement_list)

                if not distinct:
                    return_statement = f"RETURN {only_statement}"

                else:
                    return_statement = f"RETURN DISTINCT {only_statement}"

            # Build limit_statement.
            if limit is not None:
                if not isinstance(limit, str) and not isinstance(limit, int):
                    bulb_logger.error(
                        f'BULBNodeError("The \'limit\' parameter of the get() method of {cls.__name__} must be a string or an integer.")'
                    )
                    raise BULBNodeError(
                        f"The 'limit' parameter of the get() method of {cls.__name__} must be a string or an integer."
                    )

                else:
                    limit_statement = f"LIMIT {limit}"

            # Build skip_statement and add its required variable.
            if skip is not None:
                if not isinstance(skip, str) and not isinstance(skip, int):
                    bulb_logger.error(
                        f'BULBNodeError("The \'skip\' parameter of the get() method of {cls.__name__} must be a string or an integer.")'
                    )
                    raise BULBNodeError(
                        f"The 'skip' parameter of the get() method of {cls.__name__} must be a string or an integer."
                    )

                else:
                    skip_statement = f"SKIP {skip}"

            # Build desc_statement.
            if not isinstance(desc, bool):
                bulb_logger.error(
                    f'BULBNodeError("The \'desc\' parameter of the get() method of {cls.__name__} must be a boolean.")'
                )
                raise BULBNodeError(
                    f"The 'desc' parameter of the get() method of {cls.__name__} must be a boolean."
                )

            else:
                if desc is True:
                    desc_statement = "DESC"

            request_statement = """
                   %s
                   %s
                   %s
                   %s
                   %s
                   %s
                   %s
                   %s
                   """ % (match_statement, where_statement, with_statement,
                          order_by_statement, desc_statement, skip_statement,
                          limit_statement, return_statement)

            if return_query is False:

                response = gdbh.r_transaction(request_statement)

                if response:
                    if only is None:

                        fake_instances_list = []

                        for user_object in response:
                            fake_instances_list.append(
                                cls.build_fake_instance(
                                    user_object["u"],
                                    forced_fake_instance_class=cls))

                        if uuid is not None or email is not None or email_confirmation_key is not None:
                            return fake_instances_list[0]

                        else:
                            return fake_instances_list

                    else:
                        return response

                else:
                    if uuid is not None or email is not None or email_confirmation_key is not None:
                        if settings.BULB_ANONYMOUSUSER_NODE_MODEL_FILE:  # TODO : This line is maybe useless, check it.
                            AnonymousUser_node_model = get_anonymoususer_node_model(
                            )
                            return AnonymousUser_node_model()

                    else:
                        return None
            else:
                return request_statement

        else:
            response = gdbh.r_transaction(handmade)

            fake_instances_list = []

            for node_object in response:
                fake_instances_list.append(
                    cls.build_fake_instance(node_object["u"],
                                            forced_fake_instance_class=cls))

            return fake_instances_list

    @classmethod
    def count(cls,
              uuid=None,
              email=None,
              email_confirmation_key=None,
              order_by=None,
              limit=None,
              skip=None,
              desc=False,
              only=None,
              filter=None,
              distinct=False,
              handmade=None,
              **extrafields):
        request_statement = cls.get(
            uuid=uuid,
            email=email,
            email_confirmation_key=email_confirmation_key,
            order_by=order_by,
            limit=limit,
            skip=skip,
            desc=desc,
            only=only,
            filter=filter,
            handmade=handmade,
            return_query=True,
            **extrafields)

        request_count_statement = None

        if not distinct:
            request_count_statement = request_statement.split(
                "RETURN")[0] + "RETURN COUNT(u)"

        else:
            request_count_statement = request_statement.split(
                "RETURN")[0] + "RETURN COUNT(DISTINCT u)"

        response = gdbh.r_transaction(request_count_statement)

        if not distinct:
            return response[0]["COUNT(u)"]

        else:
            return response[0]["COUNT(DISTINCT u)"]

    def set_password(self, new_password):
        self.update("password", _hash_password(new_password))

    def has_perm(self, permission_code_name):
        if self.is_super_user:
            return True

        if not self.is_active_user:
            return False

        else:
            permission_to_test = Permission.get(codename=permission_code_name)
            all_user_permissions = self.permissions.get()

            if all_user_permissions is not None:
                if permission_to_test in all_user_permissions:
                    return True
            return False
Esempio n. 3
0
class Group(node_models.Node):

    name = node_models.Property(unique=True, required=True)

    permissions = GroupPermissionsRelationship()

    users = GroupUsersRelationship()

    def __str__(self):
        return f'<Group object(name="{self.name}", uuid="{self.uuid}")>'

    def __repr__(self):
        return f'<Group object(name="{self.name}", uuid="{self.uuid}")>'

    @classmethod
    def get(cls,
            uuid=None,
            name=None,
            order_by=None,
            limit=None,
            skip=None,
            desc=False,
            only=None,
            filter=None,
            distinct=False,
            handmade=None,
            return_query=False):
        """
        This method allow the retrieving of Group (or of one of its children classes) instances.

        :param name (required if there is no uuid) : The name of a group to get an unique group instance.

        :param uuid (required if there is no name) : The Universal Unique Identifier of a node to get an unique instance.

        :param order_by (optional, default=None) : Must be the name of the property with which the returned datas will be sorted.
                                                   Examples : "datetime", "first_name", etc...

        :param limit (optional, default=None) : Must be an integer. This parameter defines the number of returned elements.

        :param skip (optional, default=None) : Must be an integer. This parameter defines the number of skipped elements. For example
                                               if self.skip = 3, the 3 first returned elements will be skipped.

        :param desc (optional, default=False) : Must be a boolean. If it is False the elements will be returned in an increasing order,
                                                but it is True, they will be returned in a descending order.

        :param only (optional, default=None) : Must be a list of field_names. If this parameter is filled, the return will not be Node
                                               instances, but a dict with "only" the mentioned fields.

        :param filter (optional, default=None) : Must be Q statement. You must use the Q class stored in bulb.db
                                                 Example: Q(name__contains="al") | Q(age__year__lte=8)

        :param distinct (optional, default=False) : Must be a boolean. If it is True, the returned list will be only composed with
                                                    unique elements.

        :param handmade: If this param is filled, no other must be filled. With 'handmade', you can insert your own get query and
                         the function will transform the objects returned by the database into Python instance of this class. WARNING :
                         Please consider using the gdbh.r_transaction() method (imported from bulb.db) if your request no returns full
                         Neo4j objects but a list of properties.
                         Examples :
                         ❌ : MATCH (g) RETURN g.first_name, g.last_name
                         ✅ : MATCH (g) RETURN g

                         In addition, note that the RETURN must absolutely be named 'g' like "group".

        :param return_query (optional, default=False) : Must be a boolean. If true, the method will return the cypher query.

        :return: If uuid is None, a list will be returned. Else it will be a unique instance.
        """

        if handmade is None:

            where_statement = ""
            property_statement = ""
            order_by_statement = ""
            limit_statement = ""
            skip_statement = ""
            desc_statement = ""

            # Build the property_statement.
            if uuid is not None and name is not None:
                property_statement = "{uuid:'%s', name:'%s'}" % (uuid, name)

            elif uuid is not None:
                property_statement = "{uuid:'%s'}" % uuid

            elif name is not None:
                property_statement = "{name:'%s'}" % name

            # Build the match_statement.
            cyher_labels = node_models.DatabaseNode.format_labels_to_cypher(
                cls._get_labels())
            match_statement = f"MATCH (g:{cyher_labels} {property_statement})"

            # Build the where statement.
            if filter is not None:
                if not filter[0] != "n":
                    where_statement = "WHERE " + filter

                else:
                    where_statement = filter

                where_statement = where_statement.replace("n.", "g.")

            # Build the with_statement.
            with_statement = "WITH g"

            # Build order_by statements.
            if order_by is not None:
                order_by_statement = f"ORDER BY g.{order_by}"

            # Build return_statement statements.
            if not only:
                if not distinct:
                    return_statement = "RETURN (g)"

                else:
                    return_statement = "RETURN DISTINCT (g)"

            else:
                only_statement_list = []

                for element in only:
                    only_statement_list.append(f"g.{element}")

                only_statement = ", ".join(only_statement_list)

                if not distinct:
                    return_statement = f"RETURN {only_statement}"

                else:
                    return_statement = f"RETURN DISTINCT {only_statement}"

            # Build limit_statement.
            if limit is not None:
                if not isinstance(limit, str) and not isinstance(limit, int):
                    bulb_logger.error(
                        f'BULBNodeError("The \'limit\' parameter of the get() method of {cls.__name__} must be a string or an integer.")'
                    )
                    raise BULBNodeError(
                        f"The 'limit' parameter of the get() method of {cls.__name__} must be a string or an integer."
                    )

                else:
                    limit_statement = f"LIMIT {limit}"

            # Build skip_statement and add its required variable.
            if skip is not None:
                if not isinstance(skip, str) and not isinstance(skip, int):
                    bulb_logger.error(
                        f'BULBNodeError("The \'skip\' parameter of the get() method of {cls.__name__} must be a string or an integer.")'
                    )
                    raise BULBNodeError(
                        f"The 'skip' parameter of the get() method of {cls.__name__} must be a string or an integer."
                    )

                else:
                    skip_statement = f"SKIP {skip}"

            # Build desc_statement.
            if not isinstance(desc, bool):
                bulb_logger.error(
                    f'BULBNodeError("The \'desc\' parameter of the get() method of {cls.__name__} must be a boolean.")'
                )
                raise BULBNodeError(
                    f"The 'desc' parameter of the get() method of {cls.__name__} must be a boolean."
                )

            else:
                if desc is True:
                    desc_statement = "DESC"

            request_statement = """
                %s
                %s
                %s
                %s
                %s
                %s
                %s
                %s
                """ % (match_statement, where_statement, with_statement,
                       order_by_statement, desc_statement, skip_statement,
                       limit_statement, return_statement)

            if return_query is False:
                response = gdbh.r_transaction(request_statement)

                if response:
                    if only is None:
                        fake_instances_list = []

                        for group_object in response:
                            fake_instances_list.append(
                                cls.build_fake_instance(
                                    group_object["g"],
                                    forced_fake_instance_class=cls))

                        if uuid is not None or name is not None:
                            return fake_instances_list[0]
                        else:
                            return fake_instances_list

                    else:
                        return response

                else:
                    return None

            else:
                return request_statement

        else:
            response = gdbh.r_transaction(handmade)

            fake_instances_list = []

            for node_object in response:
                fake_instances_list.append(
                    cls.build_fake_instance(node_object["g"],
                                            forced_fake_instance_class=cls))

            return fake_instances_list

    @classmethod
    def count(cls,
              uuid=None,
              name=None,
              order_by=None,
              limit=None,
              skip=None,
              desc=False,
              only=None,
              filter=None,
              distinct=False,
              handmade=None,
              **extrafields):
        request_statement = cls.get(uuid=uuid,
                                    name=name,
                                    order_by=order_by,
                                    limit=limit,
                                    skip=skip,
                                    desc=desc,
                                    only=only,
                                    filter=filter,
                                    handmade=handmade,
                                    return_query=True,
                                    **extrafields)
        request_count_statement = None

        if not distinct:
            request_count_statement = request_statement.split(
                "RETURN")[0] + "RETURN COUNT(g)"

        else:
            request_count_statement = request_statement.split(
                "RETURN")[0] + "RETURN COUNT(DISTINCT g)"

        response = gdbh.r_transaction(request_count_statement)

        if not distinct:
            return response[0]["COUNT(g)"]

        else:
            return response[0]["COUNT(DISTINCT g)"]
Esempio n. 4
0
class Session(node_models.Node, AbstractBaseSession):
    """
    Django provides full support for anonymous sessions. The session
    framework lets you store and retrieve arbitrary data on a
    per-site-visitor basis. It stores data on the server side and
    abstracts the sending and receiving of cookies. Cookies contain a
    session ID -- not the data itself.

    The Django sessions framework is entirely cookie-based. It does
    not fall back to putting session IDs in URLs. This is an intentional
    design decision. Not only does that behavior make URLs ugly, it makes
    your site vulnerable to session-ID theft via the "Referer" header.

    For complete documentation on using Sessions in your code, consult
    the sessions documentation that is shipped with Django (also available
    on the Django Web site).
    """

    session_key = node_models.Property(
        required=True, unique=True)  # TODO : add max_length = 40

    session_data = node_models.Property()

    expire_date = node_models.Property()  # TODO : add db_index = True

    related_user = RelatedUserRelationship()

    def __str__(self):
        return f'<Session object(session_key="{self.session_key}", expire_date="{str(self.expire_date)}")>'

    def __repr__(self):
        return f'<Session object(session_key="{self.session_key}", expire_date="{str(self.expire_date)}")>'

    @classmethod
    def get_session_store_class(cls):
        from bulb.contrib.sessions.backends.db import SessionStore
        return SessionStore

    @classmethod
    def get(cls,
            uuid=None,
            session_key=None,
            order_by=None,
            limit=None,
            skip=None,
            desc=False,
            only=None,
            filter=None,
            return_query=False):
        """
        This method allow the retrieving of Session (or of one of its children classes) instances.


        :param uuid: The Universal Unique Identifier of a session to get an unique session instance.

        :param session_key: The session_key of a session to get an unique session instance.

        :param order_by: Must be the name of the property with which the returned datas will be sorted.
                         Examples : "datetime", "first_name", etc...

        :param limit: Must be an integer. This parameter defines the number of returned elements.

        :param skip: Must be an integer. This parameter defines the number of skipped elements. For example if
                     self.skip = 3, the 3 first returned elements will be skipped.

        :param desc: Must be a boolean. If it is False the elements will be returned in an increasing order, but it is
                     True, they will be returned in a descending order.

        :param only: Must be a list of field_names. If this parameter is filled, the return will not be Permission
                     instances, but a dict with "only" the mentioned fields.

        :param filter: Must be Q statement. You must use the Q class stored in bulb.db
               Example: Q(name__contains="al") | Q(age__year__lte=8)

        :param return_query: Must be a boolean. If true, the method will return the cypher query.

        :return: If uuid is None, a list will be returned. Else it will be a unique instance.
        """
        where_statement = ""
        property_statement = ""
        order_by_statement = ""
        limit_statement = ""
        skip_statement = ""
        desc_statement = ""

        # Build the property_statement.
        if uuid is not None and session_key is not None:
            property_statement = "{uuid:'%s', session_key:'%s'}" % (
                uuid, session_key)

        elif uuid is not None:
            property_statement = "{uuid:'%s'}" % uuid

        elif session_key is not None:
            property_statement = "{session_key:'%s'}" % session_key

        # Build the match_statement.
        cyher_labels = node_models.DatabaseNode.format_labels_to_cypher(
            cls._get_labels())
        match_statement = f"MATCH (s:{cyher_labels} {property_statement})"

        # Build the where statement.
        if filter is not None:
            where_statement = "WHERE " + filter
            where_statement = where_statement.replace("n.", "s.")

        # Build the with_statement.
        with_statement = "WITH s"

        # Build order_by statements.
        if order_by is not None:
            order_by_statement = f"ORDER BY s.{order_by}"

        # Build return_statement statements.
        if not only:
            return_statement = "RETURN (s)"

        else:
            only_statement_list = []

            for element in only:
                only_statement_list.append(f"s.{element}")

            only_statement = ", ".join(only_statement_list)

            return_statement = f"RETURN {only_statement}"

        # Build limit_statement.
        if limit is not None:
            if not isinstance(limit, str) and not isinstance(limit, int):
                raise BULBSessionError(
                    f"The 'limit' parameter of the get() method of {cls.__name__} must be a string or an integer."
                )

            else:
                limit_statement = f"LIMIT {limit}"

        # Build skip_statement and add its required variable.
        if skip is not None:
            if not isinstance(skip, str) and not isinstance(skip, int):
                raise BULBSessionError(
                    f"The 'skip' parameter of the get() method of {cls.__name__} must be a string or an integer."
                )

            else:
                skip_statement = f"SKIP {skip}"

        # Build desc_statement.
        if not isinstance(desc, bool):
            raise BULBSessionError(
                f"The 'desc' parameter of the get() method of {cls.__name__} must be a boolean."
            )

        else:
            if desc is True:
                desc_statement = "DESC"

        request_statement = """
             %s
             %s
             %s
             %s
             %s
             %s
             %s
             %s
             """ % (match_statement, where_statement, with_statement,
                    order_by_statement, desc_statement, skip_statement,
                    limit_statement, return_statement)

        if return_query is False:
            response = gdbh.r_transaction(request_statement)

            if response:
                if only is None:
                    fake_instances_list = []

                    for session_object in response:
                        fake_instances_list.append(
                            cls.build_fake_instance(
                                session_object["s"],
                                forced_fake_instance_class=cls))

                    if uuid is not None or session_key is not None:
                        return fake_instances_list[0]

                    else:
                        return fake_instances_list

                else:
                    return response

            else:
                return None

        else:
            return request_statement

    @classmethod
    def count(cls,
              uuid=None,
              order_by=None,
              limit=None,
              skip=None,
              desc=False,
              only=None,
              filter=None,
              **extrafields):
        request_statement = cls.get(uuid=uuid,
                                    order_by=order_by,
                                    limit=limit,
                                    skip=skip,
                                    desc=desc,
                                    only=only,
                                    filter=filter,
                                    return_query=True,
                                    **extrafields)
        request_count_statement = request_statement.split(
            "RETURN")[0] + "RETURN COUNT(s)"
        response = gdbh.r_transaction(request_count_statement)

        return response[0]["COUNT(s)"]

    @classmethod
    def exists(cls, session_key):
        response = cls.get(session_key=session_key)

        if response:
            return True

        else:
            return False

    @classmethod
    def delete_session(cls, session_key):
        response = cls.get(session_key=session_key)

        if response:
            gdbh.w_transaction(
                "MATCH (s:Session {session_key:'%s'}) DETACH DELETE (s)" %
                session_key)

        else:
            raise BULBSessionDoesNotExist(
                f"No session with session_key = '{session_key}'. So it cannot be deleted."
            )

    @classmethod
    def clear_expired_sessions(cls):
        gdbh.r_transaction("""
            MATCH (s:Session) 
            WHERE s.expire_date < datetime('%s') 
            DETACH DELETE (s)
            """ % str(timezone.now()).replace(' ', 'T'))
Esempio n. 5
0
class Permission(node_models.Node):

    codename = node_models.Property(unique=True, required=True)

    description = node_models.Property(unique=True, required=True)

    def __str__(self):
        return f'<Permission object(codename="{self.codename}", description="{self.description}")>'

    def __repr__(self):
        return f'<Permission object(codename="{self.codename}", description="{self.description}")>'

    def __hash__(self):
        return hash(self.codename) + hash(self.description)

    @classmethod
    def get(cls,
            uuid=None,
            codename=None,
            order_by=None,
            limit=None,
            skip=None,
            desc=False,
            only=None,
            filter=None,
            distinct=False,
            return_query=False):
        """
        This method allow the retrieving of Permission (or of one of its children classes) instances.

        :param codename (required if there is no uuid) : The codename of a permission to get an unique permission instance.

        :param uuid (required if there is no codename) : The Universal Unique Identifier of a node to get an unique instance.

        :param order_by (optional, default=None) : Must be the name of the property with which the returned datas will be sorted.
                                                   Examples : "datetime", "first_name", etc...

        :param limit (optional, default=None) : Must be an integer. This parameter defines the number of returned elements.

        :param skip (optional, default=None) : Must be an integer. This parameter defines the number of skipped elements. For example
                                               if self.skip = 3, the 3 first returned elements will be skipped.

        :param desc (optional, default=False) : Must be a boolean. If it is False the elements will be returned in an increasing order,
                                                but it is True, they will be returned in a descending order.

        :param only (optional, default=None) : Must be a list of field_names. If this parameter is filled, the return will not be Node
                                               instances, but a dict with "only" the mentioned fields.

        :param filter (optional, default=None) : Must be Q statement. You must use the Q class stored in bulb.db
                                                 Example: Q(name__contains="al") | Q(age__year__lte=8)

        :param distinct (optional, default=False) : Must be a boolean. If it is True, the returned list will be only composed with
                                                    unique elements.

        :param return_query (optional, default=False) : Must be a boolean. If true, the method will return the cypher query.

        :return: If uuid is None, a list will be returned. Else it will be a unique instance.
        """
        where_statement = ""
        property_statement = ""
        order_by_statement = ""
        limit_statement = ""
        skip_statement = ""
        desc_statement = ""

        # Build the property_statement.
        if uuid is not None and codename is not None:
            property_statement = "{uuid:'%s', codename:'%s'}" % (uuid,
                                                                 codename)

        elif uuid is not None:
            property_statement = "{uuid:'%s'}" % uuid

        elif codename is not None:
            property_statement = "{codename:'%s'}" % codename

        # Build the match_statement.
        cyher_labels = node_models.DatabaseNode.format_labels_to_cypher(
            cls._get_labels())
        match_statement = f"MATCH (p:{cyher_labels} {property_statement})"

        # Build the where statement.
        if filter is not None:
            if not filter[0] != "n":
                where_statement = "WHERE " + filter

            else:
                where_statement = filter

            where_statement = where_statement.replace("n.", "p.")

        # Build the with_statement.
        with_statement = "WITH p"

        # Build order_by statements.
        if order_by is not None:
            order_by_statement = f"ORDER BY p.{order_by}"

        # Build return_statement statements.
        if not only:
            if not distinct:
                return_statement = "RETURN (p)"

            else:
                return_statement = "RETURN DISTINCT (p)"

        else:
            only_statement_list = []

            for element in only:
                only_statement_list.append(f"p.{element}")

            only_statement = ", ".join(only_statement_list)

            if not distinct:
                return_statement = f"RETURN {only_statement}"

            else:
                return_statement = f"RETURN DISTINCT {only_statement}"

        # Build limit_statement.
        if limit is not None:
            if not isinstance(limit, str) and not isinstance(limit, int):
                raise BULBGetPermissionError(
                    f"The 'limit' parameter of the get() method of {cls.__name__} must be a string or an integer."
                )

            else:
                limit_statement = f"LIMIT {limit}"

        # Build skip_statement and add its required variable.
        if skip is not None:
            if not isinstance(skip, str) and not isinstance(skip, int):
                raise BULBGetPermissionError(
                    f"The 'skip' parameter of the get() method of {cls.__name__} must be a string or an integer."
                )

            else:
                skip_statement = f"SKIP {skip}"

        # Build desc_statement.
        if not isinstance(desc, bool):
            raise BULBGetPermissionError(
                f"The 'desc' parameter of the get() method of {cls.__name__} must be a boolean."
            )

        else:
            if desc is True:
                desc_statement = "DESC"

        request_statement = """
            %s
            %s
            %s
            %s
            %s
            %s
            %s
            %s
            """ % (match_statement, where_statement, with_statement,
                   order_by_statement, desc_statement, skip_statement,
                   limit_statement, return_statement)

        if return_query is False:
            response = gdbh.r_transaction(request_statement)

            if response:
                if only is None:
                    fake_instances_list = []

                    for permission_object in response:
                        fake_instances_list.append(
                            cls.build_fake_instance(
                                permission_object["p"],
                                forced_fake_instance_class=cls))

                    if uuid is not None or codename is not None:
                        return fake_instances_list[0]
                    else:
                        return fake_instances_list

                else:
                    return response

            else:
                return None

        else:
            return request_statement

    @classmethod
    def count(cls,
              uuid=None,
              codename=None,
              order_by=None,
              limit=None,
              skip=None,
              desc=False,
              only=None,
              filter=None,
              distinct=False,
              **extrafields):
        request_statement = cls.get(uuid=None,
                                    codename=None,
                                    order_by=None,
                                    limit=None,
                                    skip=None,
                                    desc=False,
                                    only=None,
                                    filter=None,
                                    distinct=False,
                                    return_query=True,
                                    **extrafields)

        request_count_statement = None

        if not distinct:
            request_count_statement = request_statement.split(
                "RETURN")[0] + "RETURN COUNT(p)"

        else:
            request_count_statement = request_statement.split(
                "RETURN")[0] + "RETURN COUNT(DISTINCT p)"

        response = gdbh.r_transaction(request_count_statement)

        if not distinct:
            return response[0]["COUNT(p)"]

        else:
            return response[0]["COUNT(DISTINCT p)"]