# Path: m2core/bases/base_model.py
# class BaseModel(MetaBase, EnchantedMixin):
#     """
#     Use this BaseModel class 
#     """
#     pass
# 
# Path: m2core/common/permissions.py
# class Permission:
#     def __init__(self, name: str=None, sys_name: str=None, description: str=None):
#         if name is None or not len(name):
#             raise AttributeError('`name` param should not be `None` or it\'s length should be > 0')
#         self._name = name
#         self._sys_name = sys_name
#         self._description = description
#         self.rule_chain = None
# 
#     @property
#     def sys_name(self):
#         return self._sys_name or re.sub(r'\W', '_', self._name).upper()
# 
#     @property
#     def name(self):
#         return self._name
# 
#     @property
#     def description(self):
#         return self._description
# 
#     def copy(self):
#         return Permission(name=self._name, sys_name=self._sys_name)
# 
#     def __check_type(self, _type):
#         return self.rule_chain is not None and type(self.rule_chain) is _type
# 
#     def __do_magic(self, other: 'Permission', _m_class: type(BasePermissionRule)):
#         l_side = self.rule_chain
#         r_side = other.rule_chain
#         result_perm = other.copy()
#         if l_side and r_side:
#             # we get there only after both sides have been evaluated and compiler met distinct operator
#             if type(l_side) is _m_class:
#                 l_side.append(r_side)
#                 result_perm.rule_chain = l_side
#             else:
#                 result_perm.rule_chain = _m_class(l_side, r_side)
#         elif l_side:
#             if type(l_side) is _m_class:
#                 l_side.append(other)
#                 result_perm.rule_chain = l_side
#             else:
#                 result_perm.rule_chain = _m_class(l_side, other)
#         elif r_side:
#             result_perm.rule_chain = _m_class(self, r_side)
#         else:
#             result_perm.rule_chain = _m_class(self, other)
# 
#         return result_perm
# 
#     def __and__(self, other):
#         _m_class = And
#         return self.__do_magic(other, _m_class)
# 
#     def __or__(self, other):
#         _m_class = Or
#         return self.__do_magic(other, _m_class)
# 
#     def __invert__(self):
#         result_perm = self.copy()
#         result_perm.rule_chain = Not(self.rule_chain or self)
#         return result_perm
# 
#     def __call__(self, user_permissions):
#         if self.rule_chain is None:
#             return self in user_permissions
#         else:
#             return self.rule_chain(user_permissions)
# 
#     def __repr__(self):
#         if self.rule_chain:
#             return self.rule_chain.__repr__()
#         else:
#             return f'<{self.__class__.__name__}.{self.sys_name}>'
# 
# class PermissionsEnum(metaclass=PermissionsEnumMeta):
#     AUTHORIZED = Permission('authorized')
# 
#     @classproperty
#     def ALL(cls):
#         cache_var_name = '__all_cache'
#         cached_perms = getattr(cls, cache_var_name, None)
#         if cached_perms is None:
#             setattr(cls, cache_var_name, set())
#             cached_perms = getattr(cls, cache_var_name)
#             for attr_name in dir(cls):
#                 if not attr_name.startswith('_') and attr_name != 'ALL':
#                     attr = getattr(cls, attr_name)
#                     if type(attr) is Permission:
#                         cached_perms.add(attr)
#         return cached_perms
# 
#     @classproperty
#     def SKIP(cls):
#         return lambda p: True
# 
#     @classproperty
#     def all_platform_permissions(cls):
#         sub_classes = PermissionsEnum.registry
#         all_perms = set()
#         for c in sub_classes:
#             all_perms |= c.ALL
# 
#         return all_perms
# 
# Path: m2core/utils/error.py
# class M2Error(Exception):
#     """
#     Raise this error wherever you want you exception to be raised, logged and showed up to user with custom message
#     """
#     def __init__(self, msg: str='', show_to_user: bool=False):
#         self.error_message = msg
#         self.show_to_user = show_to_user
#         self._log()
# 
#     def _log(self):
#         logger.error(self.error_message)
# 
#     def __repr__(self):
#         return self.error_message


from datetime import datetime
from sqlalchemy import (
    BigInteger,
    Boolean,
    Column,
    DateTime,
    ForeignKey,
    String,
    UniqueConstraint,
    text,
)
from sqlalchemy.exc import SQLAlchemyError
from m2core.bases.base_model import BaseModel
from m2core.common.permissions import Permission, PermissionsEnum
from m2core.utils.error import M2Error
from typing import List
    def set_permissions(self, permissions: list):
        """
        Replaces all existing permissions with new list and dumps it to Redis
        :param permissions: list of system_name's
        """
        try:
            # get all existing and delete them
            self.s.query(M2RolePermission).filter(M2RolePermission.role_id == self.get('id')).delete()
            self.s.commit()
            # add new
            for p in permissions:
                self.add_permission(p)
            # dump to db
            self.dump_role_permissions()
        except SQLAlchemyError:
            self.s.rollback()
            raise

    def add_permission(self, permission_system_name: str):
        """
        Adds existing permission to current role. You can not create new permission, because they are added
        during M2Core initialization. Do not forget to dump it in Redis!
        """
        permission = M2Permission.load_by_params(system_name=permission_system_name)
        if not permission:
            raise M2Error('Trying to add non-existent permission', True)

        M2RolePermission.load_or_create(role_id=self.get('id'), permission_id=permission.get('id'))



# Path: m2core/bases/base_model.py
# class BaseModel(MetaBase, EnchantedMixin):
#     """
#     Use this BaseModel class 
#     """
#     pass
# 
# Path: m2core/common/permissions.py
# class Permission:
#     def __init__(self, name: str=None, sys_name: str=None, description: str=None):
#         if name is None or not len(name):
#             raise AttributeError('`name` param should not be `None` or it\'s length should be > 0')
#         self._name = name
#         self._sys_name = sys_name
#         self._description = description
#         self.rule_chain = None
# 
#     @property
#     def sys_name(self):
#         return self._sys_name or re.sub(r'\W', '_', self._name).upper()
# 
#     @property
#     def name(self):
#         return self._name
# 
#     @property
#     def description(self):
#         return self._description
# 
#     def copy(self):
#         return Permission(name=self._name, sys_name=self._sys_name)
# 
#     def __check_type(self, _type):
#         return self.rule_chain is not None and type(self.rule_chain) is _type
# 
#     def __do_magic(self, other: 'Permission', _m_class: type(BasePermissionRule)):
#         l_side = self.rule_chain
#         r_side = other.rule_chain
#         result_perm = other.copy()
#         if l_side and r_side:
#             # we get there only after both sides have been evaluated and compiler met distinct operator
#             if type(l_side) is _m_class:
#                 l_side.append(r_side)
#                 result_perm.rule_chain = l_side
#             else:
#                 result_perm.rule_chain = _m_class(l_side, r_side)
#         elif l_side:
#             if type(l_side) is _m_class:
#                 l_side.append(other)
#                 result_perm.rule_chain = l_side
#             else:
#                 result_perm.rule_chain = _m_class(l_side, other)
#         elif r_side:
#             result_perm.rule_chain = _m_class(self, r_side)
#         else:
#             result_perm.rule_chain = _m_class(self, other)
# 
#         return result_perm
# 
#     def __and__(self, other):
#         _m_class = And
#         return self.__do_magic(other, _m_class)
# 
#     def __or__(self, other):
#         _m_class = Or
#         return self.__do_magic(other, _m_class)
# 
#     def __invert__(self):
#         result_perm = self.copy()
#         result_perm.rule_chain = Not(self.rule_chain or self)
#         return result_perm
# 
#     def __call__(self, user_permissions):
#         if self.rule_chain is None:
#             return self in user_permissions
#         else:
#             return self.rule_chain(user_permissions)
# 
#     def __repr__(self):
#         if self.rule_chain:
#             return self.rule_chain.__repr__()
#         else:
#             return f'<{self.__class__.__name__}.{self.sys_name}>'
# 
# class PermissionsEnum(metaclass=PermissionsEnumMeta):
#     AUTHORIZED = Permission('authorized')
# 
#     @classproperty
#     def ALL(cls):
#         cache_var_name = '__all_cache'
#         cached_perms = getattr(cls, cache_var_name, None)
#         if cached_perms is None:
#             setattr(cls, cache_var_name, set())
#             cached_perms = getattr(cls, cache_var_name)
#             for attr_name in dir(cls):
#                 if not attr_name.startswith('_') and attr_name != 'ALL':
#                     attr = getattr(cls, attr_name)
#                     if type(attr) is Permission:
#                         cached_perms.add(attr)
#         return cached_perms
# 
#     @classproperty
#     def SKIP(cls):
#         return lambda p: True
# 
#     @classproperty
#     def all_platform_permissions(cls):
#         sub_classes = PermissionsEnum.registry
#         all_perms = set()
#         for c in sub_classes:
#             all_perms |= c.ALL
# 
#         return all_perms
# 
# Path: m2core/utils/error.py
# class M2Error(Exception):
#     """
#     Raise this error wherever you want you exception to be raised, logged and showed up to user with custom message
#     """
#     def __init__(self, msg: str='', show_to_user: bool=False):
#         self.error_message = msg
#         self.show_to_user = show_to_user
#         self._log()
# 
#     def _log(self):
#         logger.error(self.error_message)
# 
#     def __repr__(self):
#         return self.error_message


# Path: m2core/data_schemes/db_system_scheme.py
from datetime import datetime
from sqlalchemy import (
    BigInteger,
    Boolean,
    Column,
    DateTime,
    ForeignKey,
    String,
    UniqueConstraint,
    text,
)
from sqlalchemy.exc import SQLAlchemyError
from m2core.bases.base_model import BaseModel
from m2core.common.permissions import Permission, PermissionsEnum
from m2core.utils.error import M2Error
from typing import List

    def set_permissions(self, permissions: list):
        """
        Replaces all existing permissions with new list and dumps it to Redis
        :param permissions: list of system_name's
        """
        try:
            # get all existing and delete them
            self.s.query(M2RolePermission).filter(M2RolePermission.role_id == self.get('id')).delete()
            self.s.commit()
            # add new
            for p in permissions:
                self.add_permission(p)
            # dump to db
            self.dump_role_permissions()
        except SQLAlchemyError:
            self.s.rollback()
            raise

    def add_permission(self, permission_system_name: str):
        """
        Adds existing permission to current role. You can not create new permission, because they are added
        during M2Core initialization. Do not forget to dump it in Redis!
        """
        permission = M2Permission.load_by_params(system_name=permission_system_name)
        if not permission:
            raise M2Error('Trying to add non-existent permission', True)

        M2RolePermission.load_or_create(role_id=self.get('id'), permission_id=permission.get('id'))



class M2RolePermission(BaseModel):