Ejemplo n.º 1
0
class Paragraph(models.Model):
    content = models.TextField()

    section = models.BooleanField()

    economist = models.ForeignKey(
        Economist,
        on_delete=models.CASCADE,
    )

    words = models.IntegerField(
        default=0,
    )

    @classmethod
    def create(cls, content: str, **kwargs):
        try:
            return cls.objects.create(
                content=content,
                words=len(content.split(' ')),
                **kwargs
            )
        except Exception:
            raise EconomistError.PARAGRAPH_CREATE

    @classmethod
    def get(cls, economist: Economist):
        return cls.objects.filter(economist=economist).order_by('pk')

    def d(self):
        return self.dictify('content', 'section')
Ejemplo n.º 2
0
class Member(models.Model):
    user = models.ForeignKey(
        'User.User',
        on_delete=models.CASCADE,
    )
    # 是否准备
    is_ready = models.BooleanField(default=False)

    def d(self):
        return self.dictor('pk->mid', 'user', 'is_ready')

    def d_username(self):
        return self.user.d_username()

    def _readable_user(self):
        if self.user:
            return self.user.d()

    def ready(self):
        self.is_ready = True
        self.save()

    def unready(self):
        self.is_ready = False
        self.save()

    @classmethod
    def join_room(cls, user):
        print("######user:"******"___join_room")
        try:
            member = cls(user=user, )
            member.save()
        except Exception:
            raise RoomError.JOIN_ROOM(user.username)
        user.entered_room()
        return member

    @classmethod
    def leave_room(cls, user):
        try:
            print("######user:"******"___leave_room")
            member = Member.objects.get(user=user)
            user.leave_room()
            member.delete()
        except Exception as err:
            raise RoomError.LEAVE_ROOM(debug_message=err)
Ejemplo n.º 3
0
class Album(Resource):
    space = models.ForeignKey(
        'Space.Space',
        on_delete=models.CASCADE,
        null=False,
    )

    parent = models.ForeignKey(
        'Album',
        on_delete=models.CASCADE,
        default=None,
        null=True,
    )

    name = models.CharField(
        max_length=20,
        null=True,
    )

    grid_rows = models.IntegerField(
        min_value=8,
        max_value=20,
        default=10,
    )

    auto_arrange = models.BooleanField(
        default=True,
    )

    cover = models.ForeignKey(
        'Image.Image',
        on_delete=models.SET_NULL,
        null=True,
        related_name='cover',
    )

    def not_root_checker(self):
        if not self.parent:
            raise AlbumError.ROOT

    def born(self, name) -> 'Album':
        try:
            return Album.objects.create(
                space=self.space,
                parent=self,
                name=name,
                grid_rows=10,
                auto_arrange=True,
                cover=None,
                res_id=self.generate_res_id(),
                grid_position=None,
            )
        except Exception:
            raise AlbumError.CREATE

    def delete(self, *args, **kwargs):
        if self.cover:
            self.cover.delete()
        super().delete(*args, **kwargs)

    def set_cover(self, image):
        self.cover = image
        self.save()

    def get_image_token(self):
        return Image.get_token(
            action=ImageUploadAction.ALBUM_COVER,
            album_id=self.res_id,
        )

    def _readable_parent(self):
        if self.parent:
            return self.parent.res_id

    def d(self):
        d = dict(type='album')
        d.update(self.dictify('name', 'grid_rows', 'res_id', 'parent'))
        return d

    def d_layer(self):
        d = self.d()
        d['items'] = self.album_set.filter(
            cover__isnull=False).dict(Album.d_image) + self.image_set.dict(Image.d)
        return d

    def d_image(self):
        d = self.cover.d()
        d.update(self.d())  # res_id 不能交换顺序
        return d

    def update(self, name, grid_rows):
        self.name = name
        self.grid_rows = grid_rows
        self.save()
Ejemplo n.º 4
0
class User(models.Model):
    """
    用户类
    根超级用户id=1
    """
    ROOT_ID = 1

    username = models.CharField(
        max_length=32,
        min_length=3,
        unique=True,
        blank=True,
        null=True,
        default=None,
    )
    password = models.CharField(
        max_length=32,
        min_length=6,
    )
    salt = models.CharField(
        max_length=10,
        default=None,
    )
    pwd_change_time = models.FloatField(
        null=True,
        blank=True,
        default=0,
    )
    inviter = models.ForeignKey('User.User',
                                on_delete=models.CASCADE,
                                default=None,
                                null=True)
    invite_code = models.CharField(
        default=None,
        max_length=255,
        blank=True,
        null=True,
    )
    enter_room = models.BooleanField(default=False)

    def is_ancestor(self, user: '******'):
        while user:
            if self == user:
                return True
            user = user.inviter
        return False

    @staticmethod
    def _valid_username(username):
        """验证用户名合法"""
        if username[0] not in string.ascii_lowercase + string.ascii_uppercase:
            raise UserError.INVALID_USERNAME_FIRST
        valid_chars = '^[A-Za-z0-9_]{3,32}$'
        if re.match(valid_chars, username) is None:
            raise UserError.INVALID_USERNAME

    @staticmethod
    def _valid_password(password):
        """验证密码合法"""
        valid_chars = '^[A-Za-z0-9!@#$%^&*()_+-=,.?;:]{6,16}$'
        if re.match(valid_chars, password) is None:
            raise UserError.INVALID_PASSWORD

    @staticmethod
    def hash_password(raw_password, salt=None):
        if not salt:
            salt = get_random_string(length=6)
        hash_password = User._hash(raw_password + salt)
        return salt, hash_password

    @classmethod
    def exist_with_username(cls, username):
        try:
            cls.objects.get(username=username)
        except cls.DoesNotExist:
            return
        raise UserError.USERNAME_EXIST

    @classmethod
    def inviterjsonArr(cls, data):
        rData = []
        for item in data:
            item.__dict__.pop("_state")
            rData.append(item.__dict__)
        return rData

    @classmethod
    def return_inviter(cls, invite_code):
        try:

            cls.objects.get(invite_code=invite_code)
        except cls.DoesNotExist:
            raise UserError.NOT_FOUND_COD
        else:
            user = User.objects.get(invite_code=invite_code)
            print(user.username)
            return user

    @classmethod
    def create_invite(cls, username, password, invite_code):
        """ 创建用户(有邀请码)

                :param username: 用户名
                :param password: 密码
                :param invite_code: 邀请码
                :return: Ret对象,错误返回错误代码,成功返回用户对象
                """
        salt, hashed_password = User.hash_password(password)
        User.exist_with_username(username)
        # User.exist_with_invitecode(invite_code)
        # print(invite_code)
        inviter = User.return_inviter(invite_code)
        # print(inviter.username)
        try:
            user = cls(username=username,
                       password=hashed_password,
                       salt=salt,
                       inviter=inviter,
                       invite_code=username + "666")
            user.save()
        except Exception:
            raise UserError.CREATE_USER
        return user

    @classmethod
    def create(cls, username, password):
        """ 创建用户

        :param username: 用户名
        :param password: 密码
        :param invite_code: 邀请码
        :return: Ret对象,错误返回错误代码,成功返回用户对象
        """
        cls.validator(locals())

        salt, hashed_password = User.hash_password(password)

        User.exist_with_username(username)
        try:
            user = cls(
                username=username,
                password=hashed_password,
                salt=salt,
            )
            user.save()
        except Exception:
            raise UserError.CREATE_USER
        return user

    def change_password(self, password, old_password):
        """修改密码"""
        self.validator(locals())

        if self.password != User._hash(old_password):
            raise UserError.PASSWORD
        self.salt, self.password = User.hash_password(password)
        import datetime
        self.pwd_change_time = datetime.datetime.now().timestamp()
        self.save()

    @staticmethod
    def _hash(s):
        import hashlib
        md5_ = hashlib.md5()
        md5_.update(s.encode())
        return md5_.hexdigest()

    @staticmethod
    def get_user_by_username(username):
        """根据用户名获取用户对象"""
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            raise UserError.NOT_FOUND_USER
        return user

    @staticmethod
    def get_user_by_id(user_id):
        """根据用户ID获取用户对象"""
        try:
            user = User.objects.get(pk=user_id)
        except User.DoesNotExist:
            raise UserError.NOT_FOUND_USER
        return user

    def entered_room(self):
        self.enter_room = True
        self.save()

    def leave_room(self):
        print("######leave the room")
        self.enter_room = False
        self.save()

    @classmethod
    def authenticate(cls, username, password):
        """验证用户名和密码是否匹配"""
        cls.validator(locals())

        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist as err:
            raise UserError.NOT_FOUND_USER

        salt, hashed_password = User.hash_password(password, user.salt)
        if hashed_password == user.password:
            return user
        raise UserError.PASSWORD

    def is_beinviter(self, inviter):
        if self.username == inviter:
            return True
        else:
            inviters = User.objects.filter(inviter__exact=self.username)
            if len(inviters) > 0:
                for invite in inviters:
                    # print(inviter.username)
                    return invite.is_beinviter(inviter)
            else:
                return False

    def d(self):
        return self.dictor('pk->uid', 'username', 'inviter', 'enter_room')

    def d_invite(self):
        return self.dictor('pk->id', 'username')

    def d_username(self):
        return self.dictor('username')

    def _readable_inviter(self):
        if self.inviter:
            return self.inviter.d_base()

    def d_base(self):
        return self.dictor('pk->id', 'username')
Ejemplo n.º 5
0
class Article(models.Model):
    user = models.ForeignKey(
        'User.MiniUser',
        on_delete=models.CASCADE,
    )

    aid = models.CharField(
        verbose_name='文章ID',
        max_length=6,
        min_length=6,
        unique=True,
    )

    origin = models.CharField(
        max_length=20,
        null=True,
        default=None,
    )

    author = models.CharField(
        max_length=20,
        null=True,
        default=None,
    )

    create_time = models.DateTimeField(auto_now_add=True, )

    title = models.CharField(max_length=50, )

    self_product = models.BooleanField(
        verbose_name='原创声明',
        default=False,
        null=True,
    )

    require_review = models.BooleanField(
        verbose_name='需要审核',
        default=False,
        null=True,
    )

    allow_open_reply = models.BooleanField(
        verbose_name='允许公开回复',
        default=False,
        null=True,
    )

    @classmethod
    def get(cls, aid):
        try:
            return cls.objects.get(aid=aid)
        except cls.DoesNotExist:
            raise ArticleError.NOT_FOUND

    @classmethod
    def get_unique_id(cls):
        while True:
            aid = get_random_string(length=6)
            try:
                cls.get(aid)
            except E:
                return aid

    @classmethod
    def create(cls, user, author, origin, title, self_product, require_review,
               allow_open_reply):
        try:
            return cls.objects.create(
                user=user,
                title=title,
                author=author,
                origin=origin,
                self_product=self_product,
                require_review=require_review,
                allow_open_reply=allow_open_reply,
                aid=cls.get_unique_id(),
            )
        except Exception as err:
            raise ArticleError.CREATE(debug_message=err)

    def update(self, title, origin, author):
        self.origin = origin
        self.title = title
        self.author = author
        self.save()

    def assert_belongs_to(self, user):
        if self.user != user:
            raise ArticleError.NOT_OWNER

    def remove(self):
        self.delete()

    def get_comments(self, show_all=False, selected=True):
        comments = self.comment_set.filter(reply_to=None)
        if not show_all:
            comments = comments.filter(selected=selected)
        return comments.order_by('pk')

    def _readable_create_time(self):
        return self.create_time.timestamp()

    def _readable_comments(self, show_all=False):
        if not self.require_review and show_all:
            return
        comments = self.comment_set.filter(reply_to=None)
        if self.require_review:
            comments = comments.filter(selected=True)
        return comments.order_by('pk').dict(Comment.d_replies, show_all)

    def _readable_my_comments(self, user):
        if self.require_review:
            return self.comment_set.filter(~Q(selected=True),
                                           user=user,
                                           reply_to=None).order_by('pk').dict(
                                               Comment.d_replies)
        else:
            return []

    def _readable_user(self):
        return self.user.d()

    def d_base(self):
        return self.dictify('aid', 'title', 'origin', 'author', 'create_time',
                            'self_product', 'require_review',
                            'allow_open_reply')

    def d(self, user):
        d = self.d_base()
        if self.user == user:
            d.update(
                self.dictify('comments', 'user',
                             ('comments->all_comments', True)))
        else:
            d.update(self.dictify('comments', 'user', ('my_comments', user)))
        return d

    def d_create(self):
        return self.dictify('aid')

    def comment(self, user, content):
        return Comment.create(self, user, content)
Ejemplo n.º 6
0
class Room(models.Model):
    """
    房间类
    """

    number = models.IntegerField(
        unique=True,
        null=False,
    )
    password = models.CharField(max_length=5,
                                min_length=4,
                                null=True,
                                default=None)
    is_public = models.BooleanField(default=True)
    owner = models.ForeignKey(
        'Room.Member',
        related_name='owner',
        on_delete=models.SET_NULL,
        null=True,
    )
    member_a = models.ForeignKey(
        'Room.Member',
        related_name='member_a',
        on_delete=models.SET_NULL,
        null=True,
        default=None,
    )
    member_b = models.ForeignKey(
        'Room.Member',
        related_name='member_b',
        on_delete=models.SET_NULL,
        null=True,
        default=None,
    )
    # 房间人数0/3
    member_num = models.IntegerField(default=1, )

    status = models.BooleanField(default=False)

    # 轮到说话的人(1、2、3)(1默认房主)
    speaker = models.IntegerField(default=1, )
    create_time = models.DateTimeField(auto_now_add=True)

    def d(self):
        return self.dictor('pk->rid', 'is_public', 'number', 'password',
                           'owner', 'member_a', 'member_b', 'member_num',
                           'speaker', 'status', 'create_time')

    def d_room_list(self):
        return self.dictor('pk->rid', 'number', 'is_public', 'owner',
                           'member_a', 'member_b', 'member_num', 'create_time')

    def d_number(self):
        return self.dictor('number')

    def _readable_owner(self):
        if self.owner:
            return self.owner.d()

    def _readable_member_a(self):
        if self.member_a:
            return self.member_a.d()

    def _readable_member_b(self):
        if self.member_b:
            return self.member_b.d()

    def _readable_create_time(self):
        return self.create_time.timestamp()

    @classmethod
    def check_password(cls, room, password):
        """验证房间密码是否正确"""
        if not room.is_public:
            if room.password != password:
                raise RoomError.JOIN_ROOM_PASSWORD(room.number)

    @staticmethod
    def get_room_by_pk(pk):
        try:
            return Room.objects.get(pk=pk)
        except Exception:
            raise RoomError.GET_ROOM_BY_PK(pk)

    @staticmethod
    def get_room_by_number(number):
        try:
            room = Room.objects.get(number=number)
        except Room.DoesNotExist:
            raise RoomError.GET_ROOM_BY_NUMBER(number)
        return room

    @classmethod
    def get_room_list(cls):
        Rooms = []
        for room in Room.objects.filter(
                create_time__lte=datetime.datetime.now()):
            Rooms.append(room.d_room_list())
        return Rooms

    @classmethod
    def creat_room(cls, user, password):
        try:
            print(password)
            room = cls(number=random.randint(1000, 9999),
                       owner=Member.join_room(user),
                       password=password)
            if room.password is not None:
                room.is_public = False
            room.save()

        except Exception as err:
            user.leave_room()
            raise RoomError.Create_ROOM(debug_message=err)
        return room

    @classmethod
    def close_room(cls, room):
        try:
            if room.member_a is not None:
                Member.leave_room(room.member_a)
            if room.member_b is not None:
                Member.leave_room(room.member_b)
            if room.owner is not None:
                Member.leave_room(room.owner)
            room.delete()
            print("delete======ok")
        except Exception as err:
            raise RoomError.CLOSE_ROOM(room.number, debug_message=err)

    @classmethod
    def join_room(cls, user, room, password):
        Room.check_password(room, password)
        if room.member_num == 3:
            raise RoomError.ROOM_FULL(room.number)
        try:
            member_num = room.member_num
            if member_num == 1:
                room.member_a = Member.join_room(user)
            else:
                room.member_b = Member.join_room(user)
            room.member_num = member_num + 1
            room.save()
        except Exception:
            raise RoomError.MEMBER_JOIN_ROOM(user.username, room.number)
        return room

    @classmethod
    def change_position(cls, room):
        if room.owner is None:
            if room.member_b is not None:
                print("b->owner")
                room.owner = room.member_b
                room.member_b = None

            elif room.member_a is not None:
                print("a->owner")
                room.owner = room.member_a
                room.member_a = None
        if room.member_a is None and room.member_b is not None:
            print("b->a")
            room.member_a = room.member_b
            room.member_b = None
        room.member_num = room.member_num - 1
        print(room.member_num)
        room.save()
        if room.member_num == 0:
            cls.close_room(room)

    def get_room_member(self):
        return [self.owner, self.member_a, self.member_b]

    @staticmethod
    def room_ready_status(user, room, ready):
        if room.status:
            raise RoomError.ROOM_NOT_UNREADY(room.number)
        try:
            print(ready)
            for member in room.get_room_member():
                if member.user == user:
                    member.is_ready = ready
                    member.save()
            return room
        except Exception as err:
            raise RoomError.ROOM_CHANGE_STATUS(room.number,
                                               user.username,
                                               debug_message=err)

    @staticmethod
    def room_begin(room):
        room.status = True
        room.save()
        return room

    def room_change_speaker(self):
        try:
            self.speaker = (self.speaker + 1)
            if self.speaker == 4:
                self.speaker = 1
            self.save()
        except Exception:
            raise RoomError.ROOM_CHANGE_SPEAKER(self.number)
Ejemplo n.º 7
0
class SpaceMan(models.Model):
    class Meta:
        unique_together = ('user', 'space')

    user = models.ForeignKey(
        'User.User',
        on_delete=models.CASCADE,
    )

    avatar = models.ForeignKey(
        'Image.Image',
        on_delete=models.SET_NULL,
        null=True,
    )

    name = models.CharField(
        verbose_name='名字',
        max_length=20,
    )

    space = models.ForeignKey(
        Space,
        on_delete=models.CASCADE,
    )

    is_owner = models.BooleanField(default=False, )

    @classmethod
    def get_by_union(cls, space_user_union: str):
        space_name, user_id = space_user_union.rsplit('-', 1)
        space = Space.get(space_name)
        user = User.get(user_id)
        return space.get_member(user)

    def get_union(self):
        return '-'.join([self.space.space_id, self.user.user_id])

    def not_owner_checker(self):
        if self.is_owner:
            raise SpaceError.DELETE_OWNER

    def delete(self, *args, **kwargs):
        if self.avatar:
            self.avatar.delete()
        super(SpaceMan, self).delete(*args, **kwargs)

    # 星球居民头像

    def set_avatar(self, image):
        if self.avatar:
            self.avatar.delete()
        self.avatar = image
        self.save()

    def get_avatar_token(self):
        return Image.get_token(
            action=ImageUploadAction.SPACEMAN,
            space_user=self.get_union(),
        )

    def get_avatar(self):
        if self.avatar:
            return self.avatar.d_avatar()
        return dict(source=self.user.avatar, color='0xdddddd')

    def update(self, name):
        self.name = name
        self.save()

    def _readable_user(self):
        return self.user.d()

    def _readable_space(self, for_invite=False):
        if for_invite:
            return self.space.d_base()
        return self.space.d()

    def _readable_avatar(self):
        return self.get_avatar()

    def d_space(self):
        return self.dictify('avatar', 'name', 'is_owner', 'user')

    def d_user(self):
        return self.dictify('avatar', 'name', 'is_owner', 'space')

    def d_invite(self):
        return self.dictify('avatar', 'name', ('space', True))

    def d_user_base(self):
        return self.space.d_base()
Ejemplo n.º 8
0
class Foto(models.Model):
    foto_id = models.CharField(
        max_length=6,
        min_length=6,
        unique=True,
    )

    create_time = models.DateTimeField(auto_now_add=True, )

    key = models.CharField(
        max_length=100,
        unique=True,
    )

    width = models.IntegerField()
    height = models.IntegerField()

    color_average = models.CharField(
        max_length=20,
        null=True,
        default=None,
    )

    mime_type = models.CharField(max_length=50, )

    orientation = models.IntegerField(default=1, )

    album = models.ForeignKey(
        Album,
        on_delete=models.SET_NULL,
        default=None,
        null=True,
    )

    pinned = models.BooleanField(default=False, )

    @classmethod
    def is_id_unique(cls, foto_id):
        try:
            cls.objects.get(foto_id=foto_id)
            return False
        except cls.DoesNotExist:
            return True

    @classmethod
    def generate_foto_id(cls):
        while True:
            foto_id = get_random_string(6)
            if cls.is_id_unique(foto_id):
                return foto_id

    @classmethod
    def orientation_str2int(cls, orientation: list):
        if orientation[0] == 'TOP':
            return 1 if orientation[1] == 'LEFT' else 2
        elif orientation[0] == 'BOTTOM':
            return 4 if orientation[1] == 'LEFT' else 3
        elif orientation[1] == 'TOP':
            return 5 if orientation[1] == 'LEFT' else 6
        else:
            return 8 if orientation[1] == 'LEFT' else 7

    @classmethod
    def orientation_int2str(cls, orientation: int):
        o = orientation - 1
        s = [''] * 2

        s[o // 4] = 'TOP' if orientation in [1, 2, 5, 6] else 'BOTTOM'
        s[1 - o // 4] = 'LEFT' if orientation in [1, 4, 5, 8] else 'RIGHT'
        return '-'.join(s)

    def set_album(self, album):
        self.album = album
        self.save()

    def toggle_pin(self):
        self.pinned = not self.pinned
        self.save()

    @classmethod
    def get(cls, foto_id):
        try:
            return cls.objects.get(foto_id=foto_id)
        except cls.DoesNotExist:
            return FotoError.NOT_FOUND

    @classmethod
    def create(cls, width, height, orientation, **kwargs):
        if orientation >= 5:
            width, height = height, width

        try:
            return cls.objects.create(
                **kwargs,
                width=width,
                height=height,
                orientation=orientation,
                foto_id=cls.generate_foto_id(),
            )
        except Exception as err:
            raise FotoError.CREATE(debug_message=err)

    @classmethod
    def get_tokens(cls, num, **kwargs):
        key_prefix = hex(int(datetime.datetime.now().timestamp() * 1000))

        tokens = []
        for _ in range(num):
            key = key_prefix + '/' + get_random_string(length=16)
            tokens.append(
                qn_manager.get_upload_token(key=key,
                                            policy=policy.customize(**kwargs)))
        return tokens

    def get_source(self,
                   expires=3600,
                   auto_rotate=True,
                   resize=None,
                   quality=100):
        url = qn_manager.get_image(self.key,
                                   expires=expires,
                                   auto_rotate=auto_rotate,
                                   resize=resize,
                                   quality=quality)
        return url

    def get_exif(self, expires=3600):
        return qn_manager.get_image_exif(self.key, expires=expires)

    def resize(self):
        target = 1200
        if self.width <= target and self.height <= target:
            return self.width, self.height

        if self.width > self.height:
            return target, target * self.height // self.width

        return target * self.width // self.height, target

    def get_sources(self):
        return dict(origin=self.get_source(auto_rotate=False, resize=None),
                    square=self.get_source(auto_rotate=True,
                                           resize=(600, 600),
                                           quality=75),
                    rotate=self.get_source(auto_rotate=True,
                                           resize=self.resize(),
                                           quality=75))

    def remove(self):
        qn_manager.delete_res(self.key)
        self.delete()

    @classmethod
    def get_pinned_fotos(cls, space):
        return cls.objects.filter(pinned=True, album__space=space)

    def _readable_sources(self):
        return dict(
            color=self.color_average,
            origin=self.get_source(auto_rotate=False, resize=None),
            square=self.get_source(auto_rotate=True,
                                   resize=(600, 600),
                                   quality=75),
            rotate=self.get_source(auto_rotate=True,
                                   resize=self.resize(),
                                   quality=75),
            exif=self.get_exif(),
        )

    def _readable_orientation(self):
        return [self.orientation, self.orientation_int2str(self.orientation)]

    def _readable_album(self):
        return self.album.name

    def d(self):
        return self.dictify('sources', 'width', 'height', 'foto_id',
                            'orientation', 'album', 'pinned')

    def d_base(self):
        return self.dictify(
            'album',
            'foto_id',
        )
Ejemplo n.º 9
0
class Meat(models.Model):
    """
    肉类(任务)
    """
    # 天鹅肉
    content = models.TextField(
        default=None,
        null=True,
    )
    # 天鹅肉所有者
    toad = models.ForeignKey(
        'User.User',
        related_name='toad_user',
        on_delete=models.CASCADE,
    )
    # 目标时间
    target_time = models.DateTimeField(
        null=True
    )
    # 创建时间
    create_time = models.DateTimeField(
        auto_now_add=True

    )
    # 肉质及状态
    # 0还没熟
    # 1熟了(已到时间)
    # 2吃上了
    # 3下次一定
    status = models.IntegerField(
        default=0
    )
    # 短信提醒开关
    notification = models.BooleanField(
        # 是否开启短信提醒功能
        default=False
    )
    # 标记
    achieve = models.BooleanField(
        default=False
    )

    @classmethod
    def create(cls, user, content, target_time, notification):
        print("create++++++++++++++++")
        try:
            meat = cls(
                content=content,
                toad=user,
                target_time=target_time,
                create_time=datetime.datetime.now(),
                status=0,
                notification=notification,
                achieve=False
            )
            meat.save()
            user.add_meat_quantity()
        except Exception as err:
            raise MeatError.CREATE_MEAT(debug_message=err)
        return meat

    @classmethod
    def change_meat_status(cls, meat, status):
        try:
            meat.status = status
            meat.save()
        except Exception:
            raise MeatError.CHANGE_MEAT_STATUS
        if not meat.achieve and status > 1:
            cls.change_meat_achieve(meat, True)
        return meat

    @classmethod
    def check_target_time(cls):
        try:
            meats = cls.objects.filter(achieve=False)
            now_time = datetime.datetime.now()
            change_list = []
            for meat in meats:
                if now_time > meat.target_time:
                    m = cls.change_meat_status(meat, 1)
                    change_list.append(m.d_meat_list())
        except Exception as err:
            raise MeatError.CHECK_TARGET_TIME(debug_message=err)
        return change_list

    @staticmethod
    def change_meat_achieve(meat, achieve):
        try:
            meat.achieve = achieve
            meat.save()
        except Exception:
            raise MeatError.CHANGE_MEAT_ACHIEVE
        meat.toad.reduce_meat_quantity()

    @classmethod
    def get_meat_by_pk(cls, tid):
        try:
            return cls.objects.get(pk=tid)
        except Exception:
            raise MeatError.GET_MEAT_BY_PK

    @classmethod
    def get_meat_list(cls, user):
        pass

    def d(self):
        return self.dictor('pk->mid', 'content', 'toad', 'target_time->time', 'create_time', 'status', 'notification',
                           'achieve')

    def     d_meat_list(self):
        return self.dictor('pk->mid', 'content', 'status', 'achieve', 'target_time->time')

    def _readable_toad(self):
        if self.toad:
            return self.toad.d()

    def _readable_target_time(self):
        return self.target_time.timestamp()

    def _readable_create_time(self):
        return self.create_time.timestamp()
Ejemplo n.º 10
0
class UserApp(models.Model):
    """用户应用类"""
    user = models.ForeignKey(
        'User.User',
        on_delete=models.CASCADE,
    )
    app = models.ForeignKey(
        'App.App',
        on_delete=models.CASCADE,
    )
    user_app_id = models.CharField(
        max_length=16,
        verbose_name='用户在这个app下的唯一ID',
        unique=True,
    )
    bind = models.BooleanField(
        default=False,
        verbose_name='用户是否绑定应用',
    )
    last_auth_code_time = models.CharField(
        default=None,
        verbose_name='上一次申请auth_code的时间,防止被多次使用',
        max_length=20,
    )
    frequent_score = models.FloatField(
        verbose_name='频繁访问分数,按分值排序为常用应用',
        default=0,
    )
    last_score_changed_time = models.CharField(
        default=None,
        verbose_name='上一次分数变化的时间',
        max_length=20,
    )
    mark = models.PositiveSmallIntegerField(
        verbose_name='此用户的打分,0表示没打分',
        default=0,
    )

    def _readable_rebind(self):
        return float(self.last_auth_code_time) < self.app.field_change_time

    def d(self):
        return self.dictify('bind', 'mark', 'rebind', 'user_app_id')

    @classmethod
    def get_by_user_app(cls, user, app):
        try:
            return cls.objects.get(user=user, app=app)
        except Exception:
            raise AppError.USER_APP_NOT_FOUND

    @classmethod
    def get_by_id(cls, user_app_id, check_bind=False):
        try:
            user_app = cls.objects.get(user_app_id=user_app_id)
        except Exception:
            raise AppError.USER_APP_NOT_FOUND
        if check_bind and not user_app.bind:
            raise AppError.APP_UNBINDED
        return user_app

    @classmethod
    def get_unique_id(cls):
        while True:
            user_app_id = get_random_string(length=8)
            try:
                cls.get_by_id(user_app_id)
            except E as e:
                if e.eis(AppError.USER_APP_NOT_FOUND):
                    return user_app_id

    @classmethod
    def do_bind(cls, user, app):
        if app.is_user_full():
            raise AppError.USER_FULL

        premise_list = app.check_premise(user)
        for premise in premise_list:
            error = E.sid2e[premise['check']['identifier']]
            if not error.ok:
                raise error

        crt_timestamp = datetime.datetime.now().timestamp()

        try:
            user_app = cls.get_by_user_app(user, app)
            user_app.bind = True
            user_app.last_auth_code_time = crt_timestamp
            user_app.frequent_score += 1
            user_app.last_score_changed_time = crt_timestamp
            user_app.save()
        except E as e:
            if e.eis(AppError.USER_APP_NOT_FOUND):
                try:
                    user_app = cls(
                        user=user,
                        app=app,
                        user_app_id=cls.get_unique_id(),
                        bind=True,
                        last_auth_code_time=crt_timestamp,
                        frequent_score=1,
                        last_score_changed_time=crt_timestamp,
                    )
                    user_app.save()
                    user_app.app.user_num += 1
                    user_app.app.save()
                except Exception as err:
                    raise AppError.BIND_USER_APP(debug_message=err)
            else:
                raise e
        return JWT.encrypt(dict(
            user_app_id=user_app.user_app_id,
            type=JWType.AUTH_CODE,
            ctime=crt_timestamp
        ), replace=False, expire_second=5 * 60)

    @classmethod
    def check_bind(cls, user, app):
        try:
            user_app = cls.get_by_user_app(user, app)
            return user_app.bind
        except Exception:
            return False

    @classmethod
    def refresh_frequent_score(cls):
        from Config.models import Config
        crt_date = datetime.datetime.now().date()
        crt_time = datetime.datetime.now().timestamp()
        last_date = Config.get_value_by_key(CI.LAST_RE_FREQ_SCORE_DATE)
        last_date = datetime.datetime.strptime(last_date, '%Y-%m-%d').date()

        if last_date >= crt_date:
            raise AppError.SCORE_REFRESHED

        from OAuth.views import OAUTH_TOKEN_EXPIRE_TIME

        Config.update_value(CI.LAST_RE_FREQ_SCORE_DATE, crt_date.strftime('%Y-%m-%d'))
        for user_app in cls.objects.all():
            if crt_time - float(
                    user_app.last_auth_code_time) > OAUTH_TOKEN_EXPIRE_TIME + 24 * 60 * 60:
                if crt_time - float(user_app.last_score_changed_time) > OAUTH_TOKEN_EXPIRE_TIME:
                    user_app.frequent_score /= 2
                    user_app.last_score_changed_time = crt_time
                    user_app.save()

    def do_mark(self, mark):
        if mark < 1 or mark > 5:
            raise AppError.MARK
        original_mark = self.mark
        self.mark = mark
        self.save()

        mark_list = list(map(int, self.app.mark.split('-')))
        if 5 >= original_mark > 0:
            mark_list[original_mark - 1] -= 1
        mark_list[mark - 1] += 1
        self.app.mark = '-'.join(map(str, mark_list))
        self.app.save()
Ejemplo n.º 11
0
class User(models.Model):
    """
    用户类
    根超级用户id=1
    """
    ROOT_ID = 1

    VERIFY_STATUS_UNVERIFIED = 0
    VERIFY_STATUS_UNDER_AUTO = 1
    VERIFY_STATUS_UNDER_MANUAL = 2
    VERIFY_STATUS_DONE = 3
    VERIFY_STATUS_TUPLE = (
        (VERIFY_STATUS_UNVERIFIED, '没有认证'),
        (VERIFY_STATUS_UNDER_AUTO, '自动认证阶段'),
        (VERIFY_STATUS_UNDER_MANUAL, '人工认证阶段'),
        (VERIFY_STATUS_DONE, '成功认证'),
    )

    VERIFY_CHINA = 0
    VERIFY_ABROAD = 1
    VERIFY_TUPLE = (
        (VERIFY_CHINA, '中国大陆身份证认证'),
        (VERIFY_ABROAD, '其他地区身份认证'),
    )

    user_str_id = models.CharField(
        verbose_name='唯一随机用户ID',
        default=None,
        null=True,
        blank=True,
        max_length=32,
        unique=True,
    )
    qitian = models.CharField(
        default=None,
        unique=True,
        max_length=20,
        min_length=4,
    )
    phone = models.CharField(
        default=None,
        unique=True,
        max_length=20,
    )
    password = models.CharField(
        max_length=32,
        min_length=6,
    )
    salt = models.CharField(
        max_length=10,
        default=None,
    )
    pwd_change_time = models.FloatField(
        null=True,
        blank=True,
        default=0,
    )
    avatar = models.CharField(
        default=None,
        null=True,
        blank=True,
        max_length=1024,
    )
    nickname = models.CharField(
        max_length=10,
        default=None,
    )
    description = models.CharField(
        max_length=20,
        default=None,
        blank=True,
        null=True,
    )
    qitian_modify_time = models.IntegerField(
        verbose_name='齐天号被修改的次数',
        help_text='一般只能修改一次',
        default=0,
    )
    birthday = models.DateField(
        verbose_name='生日',
        default=None,
        null=True,
    )
    email = models.EmailField(
        verbose_name='邮箱',
        default=None,
        null=True,
    )

    verify_status = models.SmallIntegerField(
        verbose_name='是否通过实名认证',
        default=0,
        choices=VERIFY_STATUS_TUPLE,
    )
    real_verify_type = models.SmallIntegerField(
        verbose_name='实名认证类型',
        default=None,
        null=True,
    )
    real_name = models.CharField(
        verbose_name='真实姓名',
        default=None,
        max_length=32,
        null=True,
    )
    male = models.NullBooleanField(
        verbose_name='是否为男性',
        default=None,
        null=True,
    )
    idcard = models.CharField(
        verbose_name='身份证号',
        default=None,
        max_length=18,
        choices=VERIFY_TUPLE,
        null=True,
    )
    card_image_front = models.CharField(
        verbose_name='身份证正面照',
        max_length=1024,
        default=None,
        null=True,
    )
    card_image_back = models.CharField(
        verbose_name='身份证背面照',
        max_length=1024,
        default=None,
        null=True,
    )
    is_dev = models.BooleanField(
        verbose_name='是否开发者',
        default=False,
    )

    @classmethod
    def get_unique_id(cls):
        while True:
            user_str_id = get_random_string(length=6)
            try:
                cls.get_by_str_id(user_str_id)
            except E as e:
                if e.eis(UserError.USER_NOT_FOUND):
                    return user_str_id

    @classmethod
    def get_unique_qitian(cls):
        while True:
            qitian_id = get_random_string(length=8)
            try:
                cls.get_by_qitian(qitian_id)
            except E as e:
                if e.eis(UserError.USER_NOT_FOUND):
                    return qitian_id

    @staticmethod
    def _valid_qitian(qitian):
        """验证齐天号合法"""
        valid_chars = '^[A-Za-z0-9_]{4,20}$'
        if re.match(valid_chars, qitian) is None:
            raise UserError.INVALID_QITIAN

    @staticmethod
    def _valid_password(password):
        """验证密码合法"""
        valid_chars = '^[A-Za-z0-9!@#$%^&*()_+-=,.?;:]{6,16}$'
        if re.match(valid_chars, password) is None:
            raise UserError.INVALID_PASSWORD

    @staticmethod
    def _valid_birthday(birthday):
        """验证生日是否合法"""
        import datetime
        if birthday > datetime.datetime.now().date():
            raise UserError.BIRTHDAY_FORMAT

    @staticmethod
    def hash_password(raw_password, salt=None):
        if not salt:
            salt = get_random_string(length=6)
        hash_password = User._hash(raw_password + salt)
        return salt, hash_password

    @classmethod
    def create(cls, phone, password):
        salt, hashed_password = User.hash_password(password)

        User.exist_with_phone(phone)

        try:
            user = cls(
                qitian=cls.get_unique_qitian(),
                phone=phone,
                password=hashed_password,
                salt=salt,
                avatar=None,
                nickname='',
                description=None,
                qitian_modify_time=0,
                user_str_id=cls.get_unique_id(),
                birthday=None,
                verify_status=cls.VERIFY_STATUS_UNVERIFIED,
                is_dev=False,
            )
            user.save()
        except Exception as err:
            raise UserError.CREATE_USER(debug_message=err)
        return user

    def modify_password(self, password):
        self.salt, self.password = User.hash_password(password)
        import datetime
        self.pwd_change_time = datetime.datetime.now().timestamp()
        self.save()

    def change_password(self, password, old_password):
        """修改密码"""
        if self.password != User._hash(old_password + self.salt):
            raise UserError.PASSWORD
        self.salt, self.password = User.hash_password(password)
        import datetime
        self.pwd_change_time = datetime.datetime.now().timestamp()
        self.save()

    @staticmethod
    def _hash(s):
        from Base.common import md5
        return md5(s)

    @classmethod
    def get_by_str_id(cls, user_str_id):
        try:
            return cls.objects.get(user_str_id=user_str_id)
        except cls.DoesNotExist:
            raise UserError.USER_NOT_FOUND

    @classmethod
    def get_by_phone(cls, phone):
        """根据手机号获取用户对象"""
        try:
            return cls.objects.get(phone=phone)
        except cls.DoesNotExist:
            raise UserError.USER_NOT_FOUND('手机号未注册')

    @classmethod
    def exist_with_phone(cls, phone):
        try:
            cls.objects.get(phone=phone)
        except cls.DoesNotExist:
            return
        raise UserError.PHONE_EXIST

    @classmethod
    def get_by_qitian(cls, qitian_id):
        try:
            return cls.objects.get(qitian=qitian_id)
        except cls.DoesNotExist:
            raise UserError.USER_NOT_FOUND('不存在的齐天号')

    @classmethod
    def exist_with_qitian(cls, qitian_id):
        try:
            cls.objects.get(qitian=qitian_id)
        except cls.DoesNotExist:
            return
        raise UserError.QITIAN_EXIST

    @classmethod
    def get_by_id(cls, user_id):
        """根据用户ID获取用户对象"""
        try:
            return cls.objects.get(pk=user_id)
        except cls.DoesNotExist:
            raise UserError.USER_NOT_FOUND

    def allow_qitian_modify(self):
        return self.qitian_modify_time == 0

    def _readable_avatar(self):
        return self.get_avatar_url()

    def _readable_birthday(self):
        return self.birthday.strftime('%Y-%m-%d') if self.birthday else None

    def _readable_allow_qitian_modify(self):
        return int(self.allow_qitian_modify())

    def d_oauth(self):
        return self.dictify('avatar', 'nickname', 'description')

    def d_base(self):
        return self.dictify('user_str_id', 'avatar', 'nickname', 'description')

    def d(self):
        return self.dictify('birthday', 'user_str_id', 'qitian', 'avatar',
                            'nickname', 'description', 'allow_qitian_modify',
                            'verify_status', 'verify_type', 'is_dev')

    @classmethod
    def authenticate(cls, qitian, phone, password):
        """验证手机号和密码是否匹配"""
        if qitian:
            user = cls.get_by_qitian(qitian)
        else:
            user = cls.get_by_phone(phone)

        salt, hashed_password = User.hash_password(password, user.salt)
        if hashed_password == user.password:
            return user
        raise UserError.PASSWORD

    def get_avatar_url(self, small=True):
        """获取用户头像地址"""
        if self.avatar is None:
            return None
        from Base.qn import qn_public_manager
        key = "%s-small" % self.avatar if small else self.avatar
        return qn_public_manager.get_resource_url(key)

    def get_card_urls(self):
        from Base.qn import qn_res_manager
        front_url = qn_res_manager.get_resource_url(self.card_image_front) \
            if self.card_image_front else None
        back_url = qn_res_manager.get_resource_url(self.card_image_back) \
            if self.card_image_back else None
        return dict(
            front=front_url,
            back=back_url,
        )

    def modify_avatar(self, avatar):
        """修改用户头像"""
        if self.avatar:
            from Base.qn import qn_public_manager
            qn_public_manager.delete_res(self.avatar)
        self.avatar = avatar
        self.save()

    def upload_verify_front(self, card_image_front):
        from Base.qn import qn_res_manager
        if self.card_image_front:
            qn_res_manager.delete_res(self.card_image_front)

        self.card_image_front = card_image_front
        self.save()
        qn_res_manager.get_resource_url(self.card_image_front + '-small')

    def upload_verify_back(self, card_image_back):
        from Base.qn import qn_res_manager
        if self.card_image_back:
            qn_res_manager.delete_res(self.card_image_back)

        self.card_image_back = card_image_back
        self.save()
        qn_res_manager.get_resource_url(self.card_image_back + '-small')

    def modify_info(self, nickname, description, qitian, birthday):
        """修改用户信息"""
        if nickname is None:
            nickname = self.nickname
        if description is None:
            description = self.description
        if qitian is None:
            qitian = self.qitian
        if birthday is None or (self.verify_status and self.real_verify_type
                                == User.VERIFY_CHINA):
            birthday = self.birthday

        if self.allow_qitian_modify():
            if self.qitian != qitian:
                self.exist_with_qitian(qitian)
                self.qitian = qitian
                self.qitian_modify_time += 1
        self.nickname = nickname
        self.description = description
        self.birthday = birthday
        self.save()

    def update_card_info(self, real_name, male, idcard, birthday):
        self.real_name = real_name
        self.male = male
        self.idcard = idcard
        self.birthday = birthday
        try:
            self.save()
        except Exception as err:
            return IDCardError.AUTO_VERIFY_FAILED(debug_message=err)

    def update_verify_status(self, status):
        self.verify_status = status
        self.save()

    def update_verify_type(self, verify_type):
        self.real_verify_type = verify_type
        self.save()

    def developer(self):
        self.is_dev = True
        self.save()