from tortoise import fields, models from helper.mask import Mask from helper.utils import timezone_now from models import Role, ModuleMenu class User(models.Model): id = fields.UUIDField(pk=True) username = fields.CharField(max_length=255, unique=True, description='账号') password_digest = fields.CharField(max_length=255, description='密码') name = fields.CharField(max_length=255, description='姓名') locked = fields.BooleanField(default=False, description='是否锁定') # role_id = fields.IntField(description='用户角色') role = fields.ForeignKeyField('rms.Role', description='用户角色') department = fields.ForeignKeyField('rms.Department', on_delete=fields.CASCADE, null=True, description='所属部门') login_frozen_count = fields.SmallIntField(default=0, description='登录失败次数') last_attempt_at = fields.DatetimeField(null=True, description='最后尝试时间') last_login_at = fields.DatetimeField(null=True, description='最后登录时间') password_expired_at = fields.DatetimeField(null=True, description='密码时效期') face = fields.BinaryField(null=True, description='人脸二进制') drawers = fields.JSONField(null=True, default=[], description='可访问抽屉') sex = fields.IntField(default=0, null=True, description='0未知 1男 2女') phone = fields.CharField(null=True, description="手机号", max_length=11) email = fields.CharField(max_length=255, null=True, description='邮箱') created_at = fields.DatetimeField(auto_now_add=True) updated_at = fields.DatetimeField(auto_now=True) login_key = fields.CharField(null=True,max_length=255, description='账号标识') raw = fields.CharField(null=True,max_length=255, description='卡片登录') keys = fields.JSONField(null=True, description='钥匙权限') class Meta: table = 'users' table_description = '用户表' def as_json(self): return dict(id=self.id, username=self.username, name=self.name, role_id=self.role_id, locked=self.locked, sex=self.sex, phone=self.phone, emali=self.email,raw=self.raw ) # @classmethod # async def fetch(cls, id: str, reload: bool = False, expire: int = 1800): # key = f'rms_user_{id}' # user = await User.get_or_none(id = id) # await redis.hset(key, mapping = user.as_json()) # print(await redis.hgetall(key)) # if reload: # await redis.delete(key) # cache = await redis.get(key) # if not cache: # user = await User.get_or_none(id = id) # if not user: # return None # await redis.set(key, json.dumps(user.as_json()), ex = expire) # return user.as_json() # return cache @property async def profile(self): """登录用户信息""" permission = await self.permission role = await Role.get(id=self.role_id) return dict(id=self.id, name=self.name, username=self.username, permission=permission, protion=role.portion, password_expired=self.password_expired, grade=role.grade) def __str__(self): return 'User(id={0.id} username={0.username}, name={0.name}, role.id={0.role_id})'.format(self) # @property # def frozen(self) -> bool: # '''是否被冻结''' # return setting.LOGIN_FROZEN_COUNT > 0 and self.login_frozen_count >= setting.LOGIN_FROZEN_COUNT @property def password_expired(self) -> bool: '''密码是否已过期''' if self.password_expired_at is None: return True return self.password_expired_at < timezone_now() @property def nickname(self): '''用户昵称''' return self.name or self.username async def cabinets(self): '''用户可见柜体''' pass @property async def permission(self): '''用户可见模块权限''' role = await Role.get(id=self.role_id) masks = role.masks menu = await ModuleMenu.all().order_by("rank") map = {str(m.id): m.name for m in menu} return [{'id': int(k), 'name': v, 'mask': masks[k]} for k, v in map.items() if k in masks] async def permit(self, menu_id: str, mask: Mask): '''用户对指定模块是否有动作权限''' role = await Role.get(id=self.role_id) masks = role.masks return (int(masks.get(menu_id, 0)) & mask) == mask @staticmethod async def parse_id_user(user_ids: list): """用户id列表转换为用户名""" user_name_list = list() for user_id in user_ids: user_obj = await User.get_or_none(id=user_id) user_name = user_obj.name if user_obj else "" user_name_list.append(user_name) return ",".join(user_name_list)