class Phrase(models.Model): phrase = models.CharField( max_length=20, unique=True, ) tags = models.CharField( max_length=255, default=None, ) @classmethod def get_phrase_by_phrase(cls, phrase): try: return cls.objects.get(phrase=phrase) except cls.DoesNotExist as err: raise PhraseError.NOT_FOUND(debug_message=err) @classmethod def create(cls, phrase, tags): phrase = cls.get_phrase_by_phrase(phrase) try: phrase = cls( phrase=phrase, tags=tags, ) phrase.save() except Exception as err: raise PhraseError.CREATE(debug_message=err) return phrase def d(self): return self.dictify('tags', 'phrase')
class Economist(models.Model): news_id = models.CharField( max_length=4, min_length=4, ) date = models.CharField( max_length=10, min_length=10, ) category = models.TextField() sub_headline = models.TextField() headline = models.TextField() description = models.TextField() image = models.TextField() url = models.TextField(default=None) @classmethod def get(cls, news_id): try: return cls.objects.get(news_id=news_id) except cls.DoesNotExist: raise EconomistError.GET @classmethod def generate_id(cls): while True: news_id = get_random_string(length=4) try: cls.get(news_id) except E as e: assert e.eis(EconomistError.GET) return news_id @classmethod def create(cls, **kwargs): try: return cls.objects.create( news_id=cls.generate_id(), **kwargs, ) except Exception: raise EconomistError.CREATE def d_list(self): return self.dictify('news_id', 'date', 'category', 'headline', 'sub_headline', 'description', 'image') def d(self): d_ = self.d_list() d_.update(dict(paragraph=Paragraph.get(self))) return d_
class Config(models.Model): MAX_L = { 'key': 100, 'value': 255, } key = models.CharField( max_length=MAX_L['key'], unique=True, ) value = models.CharField(max_length=MAX_L['value'], ) @classmethod def get_config_by_key(cls, key): cls.validator(locals()) try: return cls.objects.get(key=key) except cls.DoesNotExist as err: raise ConfigError.CONFIG_NOT_FOUND(debug_message=err) @classmethod def get_value_by_key(cls, key, default=None): try: return cls.get_config_by_key(key).value except Exception: return default @classmethod def update_value(cls, key, value): cls.validator(locals()) try: config = cls.get_config_by_key(key) config.value = value config.save() except E as e: if e.eid(ConfigError.CONFIG_NOT_FOUND): try: config = cls( key=key, value=value, ) config.save() except Exception as err: raise ConfigError.CREATE_CONFIG(debug_message=err) else: raise e except Exception as err: ConfigError.CREATE_CONFIG(debug_message=err)
class Group(models.Model): name = models.CharField( verbose_name='组名', unique=True, max_length=10, ) @classmethod def get(cls, name): try: return cls.objects.get(name=name) except cls.DoesNotExist: raise PhraseError.GROUP_NOT_FOUND(name) except Exception as err: raise PhraseError.GET_GROUP(name, debug_message=err) @classmethod def new(cls, name): try: cls.get(name) except E as e: if e.eis(PhraseError.GROUP_NOT_FOUND): try: group = cls(name=name) group.save() except Exception as err: raise PhraseError.CREATE_GROUP(name, debug_message=err) else: return e raise PhraseError.GROUP_NAME_CONFLICT(name) def push(self, phrases: List[Phrase]): return GroupSet.new(self, phrases)
class Space(models.Model): name = models.CharField( max_length=20, min_length=1, unique=True, ) @classmethod def create(cls, name): try: return cls.get_by_name(name) except Exception: pass try: return cls.objects.create(name=name) except Exception as err: raise FotoError.SPACE_CREATE(debug_message=err) @classmethod def get_by_name(cls, name): try: return cls.objects.get(name=name) except cls.DoesNotExist as err: raise FotoError.SPACE_NOT_FOUND(debug_message=err) def d(self): albums = self.album_set.dict(Album.d) fotos = Foto.get_pinned_fotos(space=self).dict(Foto.d) return dict( albums=albums, fotos=fotos, )
class Wave(models.Model): """数据食堂""" segment = models.ForeignKey( 'Segment.Segment', on_delete=models.CASCADE, db_index=True, ) label = models.CharField( verbose_name='数据标签', max_length=20, null=False, ) value = models.IntegerField( verbose_name='数据值', max_value=2147483647, ) @classmethod def new(cls, segment, label, value): try: wave = cls(segment=segment, label=label, value=value) wave.save() except Exception as err: raise SegmentError.NEW_WAVE(debug_message=err) return wave def d(self): return self.dictor('label', 'value')
class ServiceData(models.Model): """服务数据""" service = models.CharField( max_length=10, ) user = models.ForeignKey( 'User.User', on_delete=models.CASCADE, null=True, ) data = models.TextField( null=True, default=None, ) parameters = models.TextField( null=True, default=None, ) interact_times = models.IntegerField(default=1) @classmethod def get_or_create(cls, service, user): if not isinstance(service, str): service = service.name try: service_data = cls.objects.get(service=service, user=user) service_data.interact() return service_data except cls.DoesNotExist: return cls.objects.create(service=service, user=user) def interact(self): self.interact_times = F('interact_times') + 1 self.save() self.refresh_from_db() def jsonify(self): data = self.data or '{}' return json.loads(data) def classify(self): return Classify(self.jsonify()) def update(self, data): if isinstance(data, Classify): data = data.dict() self.data = json.dumps(data, ensure_ascii=False) self.save() def fetch_parameters(self): return json.loads(self.parameters or '{}') def store_parameters(self, parameters): self.parameters = json.dumps(parameters, ensure_ascii=False) self.save()
class Config(models.Model): key = models.CharField( max_length=100, unique=True, ) value = models.CharField(max_length=255, ) @classmethod def get_config_by_key(cls, key): cls.validator(locals()) try: return cls.objects.get(key=key) except cls.DoesNotExist as err: raise ConfigError.NOT_FOUND(debug_message=err) @classmethod def get_value_by_key(cls, key, default=None): try: return cls.get_config_by_key(key).value except Exception: return default @classmethod def update_value(cls, key, value): cls.validator(locals()) try: config = cls.get_config_by_key(key) config.value = value config.save() except E as e: if e == ConfigError.NOT_FOUND: try: config = cls( key=key, value=value, ) config.save() except Exception as err: raise ConfigError.CREATE(debug_message=err) else: raise e except Exception as err: raise ConfigError.CREATE(debug_message=err)
class Tag(models.Model): name = models.CharField( verbose_name='标签', max_length=10, unique=True, ) start = models.IntegerField( verbose_name='标注进展', default=0, ) @classmethod def get_by_id(cls, id_): try: return cls.objects.get(pk=id_) except cls.DoesNotExist: raise PhraseError.TAG_NOT_FOUND(id_) except Exception as err: raise PhraseError.GET_TAG(id_, debug_message=err) @classmethod def get(cls, name): try: return cls.objects.get(name=name) except cls.DoesNotExist: raise PhraseError.TAG_NOT_FOUND(name) except Exception as err: raise PhraseError.GET_TAG(name, debug_message=err) @classmethod def new(cls, name): try: cls.get(name) except E as e: if e.eis(PhraseError.TAG_NOT_FOUND): try: tag = cls(name=name, start=0) tag.save() except Exception as err: raise PhraseError.CREATE_TAG(name, debug_message=err) return tag else: return e raise PhraseError.TAG_NAME_CONFLICT(name) def put(self, name): self.name = name self.save() def remove(self): self.delete() def _readable_id(self): return self.pk def d(self): return self.dictor('name', 'start', 'id')
class Config(models.Model): """ 系统配置,如七牛密钥等 """ key = models.CharField( max_length=255, unique=True, ) value = models.CharField(max_length=255, ) @classmethod def get_config_by_key(cls, key): try: return cls.objects.get(key=key) except cls.DoesNotExist as err: raise ConfigError.CONFIG_NOT_FOUND(debug_message=err) @classmethod def get_value_by_key(cls, key, default=None): try: config = cls.get_config_by_key(key) return config.value except Exception: return default @classmethod def update_value(cls, key, value): try: config = cls.get_config_by_key(key) config.value = value config.save() except E as e: if e.eis(ConfigError.CONFIG_NOT_FOUND): try: config = cls( key=key, value=value, ) config.save() except Exception: raise ConfigError.CREATE_CONFIG else: raise ConfigError.CREATE_CONFIG
class User(models.Model): openid = models.CharField(max_length=64, unique=True) create_time = models.DateTimeField() interaction_times = models.IntegerField(default=1) inside_service = models.CharField(max_length=10, null=True, default=None) phone = models.CharField(max_length=20, null=True, default=None) @classmethod def get_or_create(cls, openid): try: user = cls.objects.get(openid=openid) user.interact() return user except cls.DoesNotExist: return cls.objects.create(openid=openid, create_time=datetime.now()) def interact(self): self.interaction_times = F('interaction_times') + 1 self.save() self.refresh_from_db() def inside(self, service): self.inside_service = service self.save() def set_phone(self, phone): self.phone = phone self.save() @property def phone_bind(self): return self.phone is not None def require_phone(self): if not self.phone: raise UserError.REQUIRE_PHONE
class Tag(models.Model): tag = models.CharField( max_length=10, unique=True, ) @classmethod def get_by_id(cls, tag_id): try: return cls.objects.get(pk=tag_id) except cls.DoesNotExist as err: raise TagError.NOT_FOUND(debug_message=err) @classmethod def get_by_tag(cls, tag): try: return cls.objects.get(tag=tag) except cls.DoesNotExist as err: raise TagError.NOT_FOUND(debug_message=err) @classmethod def get_tag_dict(cls): tags = cls.objects.all() tag_dict = {} for tag in tags: tag_dict[str(tag.pk)] = dict(tag=tag.tag) return tag_dict @classmethod def create(cls, tag): try: tag = cls( tag=tag, ) tag.save() except Exception as err: raise TagError.CREATE(debug_message=err) return tag def d(self): return self.dictify('pk->tid', 'tag')
class Project(models.Model): name = models.CharField( verbose_name='项目名称', max_length=20, ) pid = models.CharField( verbose_name='项目ID', max_length=4, unique=True, ) create_time = models.DateTimeField( verbose_name='创建时间', default=0, ) owner = models.ForeignKey( 'User.User', on_delete=models.CASCADE, default=None, ) ticket = models.CharField( verbose_name='项目录入凭证', max_length=64, default=None, ) @classmethod def get(cls, pid): try: return cls.objects.get(pid=pid) except cls.DoesNotExist: raise ProjectError.PROJECT_NOT_FOUND except Exception as err: raise ProjectError.GET_PROJECT(debug_message=err) @classmethod def get_unique_pid(cls): while True: pid = get_random_string(length=4) try: cls.get(pid) except E as e: if e.eis(ProjectError.PROJECT_NOT_FOUND): return pid @classmethod def new(cls, name, owner): crt_time = get_time() try: project = cls(name=name, pid=cls.get_unique_pid(), create_time=crt_time, owner=owner, ticket=get_random_string(length=64)) project.save() except Exception as err: raise ProjectError.NEW_PROJECT(debug_message=err) return project def _readable_create_time(self): return self.create_time.timestamp() def _readable_owner(self): return self.owner.d() def d(self): return self.dictor('name', 'pid', 'create_time', 'owner') def d_owner(self): return self.dictor('name', 'pid', 'create_time', 'owner', 'ticket') def refresh_ticket(self): self.ticket = get_random_string(length=64) self.save() def auth_ticket(self, ticket): return self.ticket == ticket
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, ) nickname = models.CharField( max_length=10, default=None, ) phone = models.CharField( default=None, unique=True, max_length=20, ) meat_quantity = models.IntegerField( # 已发布任务数目 default=0, ) 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 get_by_phone(cls, phone): """根据手机号获取用户对象""" try: cls.objects.get(phone=phone) raise UserError.PHONE_REGISTERED except cls.DoesNotExist: pass @classmethod def inviterjsonArr(cls, data): rData = [] for item in data: item.__dict__.pop("_state") rData.append(item.__dict__) return rData @classmethod def create(cls, phone, username, password, nickname): """ 创建用户 :param phone: 手机号 :param username: 用户名 :param password: 密码 :param nickname: 昵称 :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, nickname=nickname, phone=phone) user.save() except Exception as err: raise UserError.CREATE_USER(debug_message=err) return user def add_meat_quantity(self): try: self.meat_quantity = self.meat_quantity + 1 self.save() except Exception: raise UserError.ADD_MEAT_QUANTITY def reduce_meat_quantity(self): try: self.meat_quantity = self.meat_quantity - 1 self.save() except Exception: raise UserError.ADD_MEAT_QUANTITY 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 @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 change_talked(self): print(bool(1 - self.talked)) self.talked = bool(1 - self.talked) self.save() def d(self): return self.dictor('pk->uid', 'username', 'nickname') def d_base(self): return self.dictor('pk->id', 'username')
class Phrase(models.Model): cy = models.CharField( verbose_name='词语', max_length=20, db_index=True, ) py = models.CharField( verbose_name='拼音', max_length=150, ) number_py = models.CharField(verbose_name='带数字带拼音', max_length=165, default=None) clen = models.PositiveIntegerField(verbose_name='词语长度', ) plen = models.PositiveIntegerField( verbose_name='净词语长度', help_text='不包含标点符号', ) class Meta: unique_together = ('cy', 'number_py') def __str__(self): return self.cy + ' ' + ' '.join(json.loads(self.py)) @staticmethod def get_number_py(py: List): number_py = [] for py_ in py: from Service.Language.phrase import phraseService number_py.append( phraseService.format_syllable(py_, printer='number_toner')) number_py = json.dumps(number_py, ensure_ascii=False) return number_py @classmethod def _get(cls, cy, number_py): cls.validator(locals()) try: return cls.objects.get(cy=cy, number_py=number_py) except cls.DoesNotExist: raise PhraseError.PHRASE_NOT_FOUND(cy) except Exception as err: raise PhraseError.GET_PHRASE(cy, debug_message=err) @classmethod def get(cls, cy, py: Optional[list] = None): if py is None: py = pypinyin.pinyin(cy, errors='ignore', style=pypinyin.Style.TONE) py = list(map(lambda x: x[0], py)) number_py = cls.get_number_py(py) return cls._get(cy, number_py) @classmethod def get_by_id(cls, id_): try: return cls.objects.get(pk=id_) except cls.DoesNotExist: raise PhraseError.PHRASE_NOT_FOUND(id_) except Exception as err: raise PhraseError.GET_PHRASE(id_, debug_message=err) @classmethod def _new(cls, cy, py, clen, plen, number_py): cls.validator(locals()) try: phrase = cls(cy=cy, py=py, clen=clen, plen=plen, number_py=number_py) phrase.save() except Exception as err: raise PhraseError.CREATE_PHRASE(cy, debug_message=err) return phrase @classmethod def new(cls, cy, py: Optional[list] = None): if py is None: py = pypinyin.pinyin(cy, errors='ignore', style=pypinyin.Style.TONE) py = list(map(lambda x: x[0], py)) clen = len(cy) plen = len(py) number_py = cls.get_number_py(py) py = json.dumps(py, ensure_ascii=False) return cls._new(cy, py, clen, plen, number_py) def _readable_id(self): return self.pk def _readable_py(self): return json.loads(self.py) def d(self): return self.dictor('cy', 'py', 'id')
class Space(models.Model): space_id = models.CharField( max_length=20, min_length=4, unique=True, verbose_name='星球ID', null=False, ) name = models.CharField( max_length=15, min_length=2, verbose_name='星球名', default=None, null=True, ) rename_card = models.PositiveSmallIntegerField( default=1, verbose_name='星球改ID卡', ) access = models.CharField( choices=AccessChoices.list(), default=AccessChoices.ANY, max_length=10, ) create_time = models.DateTimeField(auto_now_add=True, ) default_milestone = models.ForeignKey('Milestone.Milestone', default=None, null=True, on_delete=models.SET_NULL, related_name='default_milestone') @staticmethod def _valid_space_id(space_id): if space_id[ 0] not in string.ascii_lowercase + string.ascii_uppercase + string.digits: raise SpaceError.INVALID_ID_SIDE if space_id[ -1] not in string.ascii_lowercase + string.ascii_uppercase + string.digits: raise SpaceError.INVALID_ID_SIDE valid_chars = '^[A-Za-z0-9_-]+$' if re.match(valid_chars, space_id) is None: raise SpaceError.INVALID_ID @classmethod def get_unique_id(cls): while True: space_id = get_random_string(length=8) try: cls.id_unique_checker(space_id) return space_id except E: pass # checkers @classmethod def id_unique_checker(cls, space_id: str): try: cls.objects.get(space_id__iexact=space_id.lower()) except cls.DoesNotExist: return raise SpaceError.ID_EXIST def owner_checker(self, user): if self.spaceman_set.get(is_owner=True).user != user: raise SpaceError.NOT_OWNER def member_checker(self, user): try: self.spaceman_set.get(user=user) except Exception: raise SpaceError.NOT_MEMBER def not_member_checker(self, user): try: self.spaceman_set.get(user=user) except Exception: return raise SpaceError.ALREADY_MEMBER @classmethod def get(cls, space_id: str): try: return cls.objects.get(space_id__iexact=space_id.lower()) except cls.DoesNotExist: raise SpaceError.NOT_FOUND @classmethod def create(cls, name, access, start_date, user): from Milestone.models import Milestone try: with transaction.atomic(): space = cls.objects.create( space_id=cls.get_unique_id(), rename_card=0, access=access, name=name, ) space.spaceman_set.create( user=user, avatar=None, name=user.nickname, is_owner=True, ) space.album_set.create( parent=None, name='星球主相册', grid_rows=4, grid_position=None, auto_arrange=True, cover=None, res_id=Album.generate_res_id(), ) milestone = Milestone.create(space=space, name='星球成立日', start_date=start_date) space.set_default_milestone(milestone) except Exception as err: raise SpaceError.CREATE(name, debug_message=err) return space def add_member(self, user): try: self.spaceman_set.create( user=user, avatar=None, name=user.nickname, is_owner=False, ) except Exception as err: raise SpaceError.JOIN(self.name, debug_message=err) def delete(self, *args, **kwargs): super(Space, self).delete(*args, **kwargs) def rename(self, space_id: str): if self.rename_card < 1: raise SpaceError.REQUIRE_RENAME_CARD self.id_unique_checker(space_id) self.space_id = space_id self.rename_card -= 1 self.save() # member def get_member(self, user): try: return self.spaceman_set.get(user=user) except Exception: raise SpaceError.MEMBER_NOT_FOUND # cover def get_cover_token(self): return self.default_milestone.get_image_token() def get_album(self): return self.album_set.get(parent=None) def set_default_milestone(self, milestone): self.default_milestone = milestone self.save() def _readable_create_time(self): return self.create_time.timestamp() def _readable_owner(self): return self.spaceman_set.get(is_owner=True).user.d() def _readable_cover(self, for_invite=False): if self.default_milestone.cover: if not for_invite: return self.default_milestone.cover.d_space() else: return self.default_milestone.cover.d_invite() def _readable_members(self, only_avatar=True): if only_avatar: return self.spaceman_set.dict(SpaceMan.get_avatar) return self.spaceman_set.dict(SpaceMan.d_space) def _readable_age(self): return self.default_milestone.get_duration() def _readable_milestones(self): from Milestone.models import Milestone return self.milestone_set.dict(Milestone.d) def _readable_default_milestone(self): return self.default_milestone.pk def _readable_album(self): return self.get_album().res_id def d(self): return self.dictify('name', ('members', False), 'album', 'milestones', ('cover', True), 'default_milestone') def d_create(self): return dict( space_dict=self.space_id, cover_token=self.get_cover_token(), ) def d_base(self): return self.dictify('name', 'space_id', 'cover', 'members', 'age') def d_member(self, only_avatar=True): return self._readable_members(only_avatar=only_avatar)
class EventType(models.Model): """事件组""" etid = models.CharField( max_length=6, min_length=6, unique=True, verbose_name='事件组ID', default=None, ) name = models.CharField( max_length=10, min_length=1, verbose_name='事件名称', ) emoji = models.CharField( max_length=10, min_length=1, verbose_name='事件的emoji表示', ) space = models.ForeignKey( 'Space.Space', on_delete=models.CASCADE, ) default_cover = models.ForeignKey('Image.Image', on_delete=models.SET_NULL, null=True, related_name='default_cover') current_cover = models.ForeignKey( 'Image.Image', on_delete=models.SET_NULL, null=True, related_name='current_cover', ) @classmethod def is_id_unique(cls, etid): try: cls.objects.get(etid=etid) return False except cls.DoesNotExist: return True @classmethod def generate_etid(cls): while True: etid = get_random_string(6) if cls.is_id_unique(etid): return etid @staticmethod def _valid_emoji(emoji): if emoji not in EMOJI_LIST: raise EventError.EMOJI @classmethod def get(cls, etid): try: return cls.objects.get(etid=etid) except Exception as err: raise EventError.TYPE_NOT_FOUND(debug_message=err) @classmethod def create(cls, **kwargs): try: return cls.objects.create(**kwargs, etid=cls.generate_etid()) except Exception as err: raise EventError.CREATE_TYPE(debug_message=err) def belongs_to(self, space): if self.space != space: raise EventError.TYPE_NOT_BELONG def rename(self, name, emoji): self.name = name self.emoji = emoji self.save() def participate(self, **kwargs): try: return self.event_set.create(**kwargs, event_id=Event.generate_event_id()) except Exception as err: raise EventError.CREATE(debug_message=err) def d(self): return self.dictify('name', 'emoji', 'etid') def delete(self, *args, **kwargs): if self.current_cover: self.current_cover.delete() if self.default_cover: self.default_cover.delete() super(EventType, self).delete(*args, **kwargs)
class MiniUser(models.Model): """小程序用户""" user_id = models.CharField( max_length=6, min_length=6, unique=True, ) openid = models.CharField( max_length=64, unique=True, ) avatar = models.CharField( max_length=512, default=None, null=True, blank=True, ) nickname = models.CharField( max_length=64, default=None, null=True, blank=True, ) @classmethod def get_unique_id(cls): while True: user_id = get_random_string(length=6) try: cls.get(user_id) except E: return user_id @classmethod def get(cls, user_id): try: return cls.objects.get(user_id=user_id) except cls.DoesNotExist: raise MiniUserError.NOT_FOUND @classmethod def get_or_create(cls, openid): try: return cls.objects.get(openid=openid) except cls.DoesNotExist: pass try: return cls.objects.create( openid=openid, user_id=cls.get_unique_id(), ) except Exception as err: raise MiniUserError.CREATE(debug_message=err) def get_commented_articles(self): comments = self.comment_set.values('article__aid').order_by( 'article__aid').distinct() articles = [comment["article__aid"] for comment in comments] return articles def update(self, avatar, nickname): self.validator(locals()) self.avatar = avatar self.nickname = nickname self.save() def d(self): return self.dictify('user_id', 'avatar', 'nickname')
class Collocation(models.Model): word = models.CharField(max_length=20, ) collocation = models.TextField()
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)
class Poem(models.Model): title = models.CharField( verbose_name='诗名', max_length=100, ) content = models.TextField( verbose_name='正文', ) create_time = models.DateTimeField( verbose_name='发布时间', ) user = models.ForeignKey( 'User.User', verbose_name='作者', default=None, null=True, on_delete=models.SET_NULL, ) @classmethod def create(cls, title, content, user): crt_time = datetime.datetime.now() try: poem = cls( user=user, title=title, content=content, create_time=crt_time, ) poem.save() return poem except Exception as err: raise PoemError.CREATE_POEM(debug_message=err) """ 查询函数 """ @classmethod def get_by_id(cls, poem_id): try: return cls.objects.get(pk=poem_id) except cls.DoesNotExist: raise PoemError.POEM_NOT_FOUND def belong(self, user): return self.user == user """ 筛选函数 """ @staticmethod def _search_keyword(v): return Q(title__contains=v) | Q(content__contains=v) """ 字典函数 """ def _readable_create_time(self): return self.create_time.timestamp() def d_create(self): return self.dictor('pk->id') def d_list(self): return self.dictor('pk->id', 'title', 'create_time') def d(self): return self.dictor('title', 'content', 'create_time') """ 修改函数 """ def update(self, title, content): self.title = title self.content = content self.create_time = datetime.datetime.now() self.save()
class Resource(models.Model): """ 资源类 根资源文件夹id=1 一旦新增用户,就在根目录创建一个属于新增用户的文件夹 """ ROOT_ID = 1 rname = models.CharField( verbose_name='resource name', max_length=256, ) rtype = models.IntegerField( verbose_name='file or folder', choices=RtypeChoice.list(), ) rsize = models.IntegerField(default=0, ) sub_type = models.IntegerField( verbose_name='sub type', choices=StypeChoice.list(), default=StypeChoice.FOLDER.value, ) mime = models.CharField( verbose_name='资源类型', null=True, default=True, max_length=100, ) description = models.TextField( verbose_name='description in Markdown', null=True, blank=True, default=None, ) cover = models.CharField( null=True, blank=True, default=None, max_length=1024, ) owner = models.ForeignKey( User, on_delete=models.CASCADE, ) parent = models.ForeignKey( 'Resource', null=True, blank=True, default=0, on_delete=models.CASCADE, ) dlpath = models.CharField( verbose_name='download relative path to res.6-79.cn', max_length=1024, default=None, null=True, blank=True, ) status = models.IntegerField( choices=StatusChoice.list(), verbose_name='加密状态 0公开 1仅自己可见 2需要密码', default=StatusChoice.PUBLIC.value, ) visit_key = models.CharField( max_length=16, min_length=3, verbose_name='当status为2时有效', ) vk_change_time = models.FloatField( null=True, blank=True, default=0, ) create_time = models.DateTimeField() dlcount = models.IntegerField( verbose_name='download number', default=0, ) res_str_id = models.CharField( verbose_name='唯一随机资源ID,弃用res_id', default=None, null=True, blank=True, max_length=6, unique=True, ) right_bubble = models.NullBooleanField( verbose_name='读取权限向上冒泡', default=True, ) cover_type = models.IntegerField( choices=CoverChoice.list(), verbose_name='封面类型 0 上传图片 1 与父资源相同 2 与指定资源相同 3 外部URI链接', default=CoverChoice.RANDOM.value, null=0, blank=0, ) @classmethod def get_unique_id(cls): while True: res_str_id = get_random_string(length=6) try: cls.get_by_id(res_str_id) except E as ret: if ret.eis(ResourceError.RESOURCE_NOT_FOUND): return res_str_id @staticmethod def _valid_rname(rname): """验证rname属性""" invalid_chars = '\\/*:\'"|<>?' for char in invalid_chars: if char in rname: raise ResourceError.INVALID_RNAME @staticmethod def _valid_res_parent(parent): """验证parent属性""" if not isinstance(parent, Resource): raise BaseError.STRANGE if parent.rtype != RtypeChoice.FOLDER.value: raise ResourceError.FILE_PARENT @classmethod def create_abstract(cls, rname, rtype, desc, user, parent, dlpath, rsize, sub_type, mime): crt_time = datetime.datetime.now() return cls( rname=rname, rtype=rtype, mime=mime, description=desc, cover=None, cover_type=CoverChoice.SELF.value if sub_type == StypeChoice.IMAGE.value else CoverChoice.RANDOM.value, owner=user, parent=parent, dlpath=dlpath, status=StatusChoice.PRIVATE.value, visit_key=get_random_string(length=4), create_time=crt_time, vk_change_time=crt_time.timestamp(), rsize=rsize, sub_type=sub_type, res_str_id=cls.get_unique_id(), dlcount=0, right_bubble=True, ) @classmethod def create_file(cls, rname, user, res_parent, dlpath, rsize, sub_type, mime): """ 创建文件对象 :param mime: 七牛返回的资源类型 :param rname: 文件名 :param user: 所属用户 :param res_parent: 所属目录 :param dlpath: 七牛存储的key :param rsize: 文件大小 :param sub_type: 文件分类 :return: Ret对象,错误返回错误代码,成功返回文件对象 """ try: res = cls.create_abstract( rname=rname, rtype=RtypeChoice.FILE.value, desc=None, user=user, parent=res_parent, dlpath=dlpath, rsize=rsize, sub_type=sub_type, mime=mime, ) res.save() except Exception: raise ResourceError.CREATE_FILE return res @classmethod def create_folder(cls, rname, user, res_parent, desc=None): """ 创建文件夹对象 :param rname: 文件夹名 :param user: 所属用户 :param res_parent: 所属目录 :param desc: 描述说明 :return: Ret对象,错误返回错误代码,成功返回文件夹对象 """ try: res = cls.create_abstract( rname=rname, rtype=RtypeChoice.FOLDER.value, desc=desc, user=user, parent=res_parent, dlpath=None, rsize=0, sub_type=StypeChoice.FOLDER.value, mime=None, ) res.save() except Exception: raise ResourceError.CREATE_FOLDER return res @classmethod def create_link(cls, rname, user, res_parent, dlpath): """ 创建链接对象 :param rname: 链接名称 :param user: 所属用户 :param res_parent: 所在目录 :param dlpath: 链接地址 :return: Ret对象,错误返回错误代码,成功返回链接对象 """ try: res = cls.create_abstract( rname=rname, rtype=RtypeChoice.LINK, desc=None, user=user, parent=res_parent, dlpath=dlpath, rsize=0, sub_type=StypeChoice.LINK.value, mime=None, ) res.save() except Exception: raise ResourceError.CREATE_LINK return res """ 查询方法 """ @classmethod def get_by_id(cls, res_str_id): try: res = cls.objects.get(res_str_id=res_str_id) except cls.DoesNotExist: raise ResourceError.RESOURCE_NOT_FOUND return res @classmethod def get_by_pk(cls, res_id): """根据资源id获取资源对象""" try: res = cls.objects.get(pk=res_id) except cls.DoesNotExist: raise ResourceError.RESOURCE_NOT_FOUND return res def belong(self, user): """判断资源是否属于用户""" return self.owner.pk == user.pk def is_home(self): return self.parent.pk == Resource.ROOT_ID def get_cover_urls(self): """获取封面链接""" res = self cover = None while res.pk != Resource.ROOT_ID: if res.cover_type == CoverChoice.PARENT.value: res = res.parent elif res.cover_type == CoverChoice.RESOURCE.value: try: res = Resource.get_by_id(res.cover) except E: return None, None if not res.belong(self.owner): return None, None else: cover = res.cover break if res.cover_type == CoverChoice.SELF.value: if res.sub_type == StypeChoice.IMAGE.value: from Base.qn_manager import qn_res_manager return (qn_res_manager.get_resource_url(res.dlpath), qn_res_manager.get_resource_url("%s-small" % res.dlpath)) if cover is None: return None, None if res.cover_type == CoverChoice.UPLOAD.value: from Base.qn_manager import qn_res_manager return (qn_res_manager.get_resource_url(cover), qn_res_manager.get_resource_url("%s-small" % cover)) else: return cover, cover """ 字典方法 """ def _readable_owner(self): return self.owner.d() def _readable_create_time(self): return self.create_time.timestamp() def _readable_visit_key(self): return self.visit_key if self.status == StatusChoice.PROTECT.value else None def _readable_is_home(self): return self.is_home() def _readable_secure_env(self): if self.pk == Resource.ROOT_ID or \ not self.right_bubble or \ self.status == StatusChoice.PUBLIC.value: return True res = self.parent while res.pk != Resource.ROOT_ID: if res.status == StatusChoice.PUBLIC.value: return res.rname if not res.right_bubble: break res = res.parent return True def _readable_raw_cover(self): return self.cover def _readable_parent_str_id(self): return self.parent.res_str_id def d(self): dict_ = self.dictify('res_str_id', 'rname', 'rtype', 'rsize', 'sub_type', 'description', 'cover_type', 'owner', 'parent_str_id', 'status', 'create_time', 'dlcount', 'visit_key', 'is_home', 'right_bubble', 'secure_env', 'raw_cover') cover_urls = self.get_cover_urls() dict_.update(dict( cover=cover_urls[0], cover_small=cover_urls[1], )) return dict_ def d_base(self): dict_ = self.dictify('status', 'is_home', 'owner', 'create_time', 'right_bubble') cover_urls = self.get_cover_urls() dict_.update(dict( cover=cover_urls[0], cover_small=cover_urls[1], )) return dict_ def d_child(self): dict_ = self.dictify('res_str_id', 'rname', 'rtype', 'status', 'create_time', 'sub_type', 'dlcount') cover_urls = self.get_cover_urls() dict_.update(dict(cover_small=cover_urls[1], )) return dict_ def d_layer(self): child_list = Resource.objects.filter(parent=self).dict( Resource.d_child) return dict( info=self.d(), child_list=child_list, ) def d_child_selector(self): return self.dictify('res_str_id', 'rname', 'rtype', 'sub_type') def d_selector_layer(self): child_list = Resource.objects.filter(parent=self).dict( Resource.d_child_selector) info = self.dictify('is_home', 'res_str_id', 'rname', 'parent_str_id') return dict( info=info, child_list=child_list, ) """ 查询方法 """ @classmethod def get_root_folder(cls, user): """获取当前用户的根目录""" try: res = cls.objects.get(owner=user, parent=1, rtype=RtypeChoice.FOLDER.value) except cls.DoesNotExist: raise ResourceError.GET_ROOT_FOLDER return res def readable(self, user, visit_key): """判断当前资源是否被当前用户可读""" res = self while res.pk != Resource.ROOT_ID: if res.owner == user or res.status == StatusChoice.PUBLIC.value: return True if res.status == StatusChoice.PROTECT.value and res.visit_key == visit_key: if user: UserRight.update(user, res) return True if res.status == StatusChoice.PROTECT.value and UserRight.verify( user, res): return True if not res.right_bubble: break res = res.parent visit_key = None return False def get_dl_url(self): """获取当前资源的下载链接""" self.dlcount += 1 self.save() if self.rtype == RtypeChoice.LINK: return self.dlpath from Base.qn_manager import qn_res_manager return qn_res_manager.get_resource_url(self.dlpath) def get_visit_key(self): """获取当前资源的访问密码""" if self.status == StatusChoice.PROTECT.value: return self.visit_key return None """ 修改方法 """ def modify_rname(self, rname): key = self.dlpath new_key = '%s/%s' % (key[:key.rfind('/')], rname) from Base.qn_manager import qn_res_manager qn_res_manager.move_res(key, new_key) self.rname = rname self.dlpath = new_key self.save() def modify_info(self, rname, description, status, visit_key, right_bubble, parent): """ 修改资源属性 :param rname: 资源名称 :param description: 资源介绍 :param status: 资源分享类型(公开、私有、加密) :param visit_key: 资源加密密钥 :param right_bubble: 资源读取权限是否向上查询 :param parent: 移动后的新父目录 :return: Ret对象,错误返回错误代码,成功返回资源对象 """ if rname is None: rname = self.rname if description is None: description = self.description or '' if status is None: status = self.status if visit_key is None: visit_key = self.visit_key if right_bubble is None: right_bubble = self.right_bubble if parent is None: parent = self.parent if self.rname != rname: if self.rtype == RtypeChoice.FILE.value: self.modify_rname(rname) else: self.rname = rname self.description = description self.status = status self.right_bubble = right_bubble self.parent = parent if status == StatusChoice.PROTECT.value: if self.visit_key != visit_key: self.visit_key = visit_key self.vk_change_time = datetime.datetime.now().timestamp() self.save() def modify_cover(self, cover, cover_type): """修改资源封面""" from Base.qn_manager import qn_res_manager if self.cover_type == CoverChoice.UPLOAD.value: try: qn_res_manager.delete_res(self.cover) except: pass self.cover = cover self.cover_type = cover_type self.save() return self def is_empty(self): """ 资源是否为空(针对文件夹资源) """ res_list = Resource.objects.filter(parent=self) if res_list: return False return True def remove(self): """ 删除资源 """ if self.rtype == RtypeChoice.FOLDER.value: if not self.is_empty(): raise ResourceError.REQUIRE_EMPTY_FOLDER from Base.qn_manager import qn_res_manager if self.cover and self.cover_type == CoverChoice.UPLOAD.value: qn_res_manager.delete_res(self.cover) self.cover = None self.save() if self.rtype == RtypeChoice.FILE.value: qn_res_manager.delete_res(self.dlpath) self.delete()
class User(models.Model): """ 用户类 根超级用户id=1 """ ROOT_ID = 1 avatar = models.CharField( default=None, null=True, blank=True, max_length=1024, ) nickname = models.CharField( max_length=10, default=None, blank=True, null=True, ) qt_user_app_id = models.CharField( default=None, max_length=16, unique=True, ) qtb_token = models.CharField( default=None, max_length=256, ) description = models.CharField( max_length=20, default=None, blank=True, null=True, ) """ 查询函数 """ @staticmethod def get_by_id(user_id): """根据用户ID获取用户对象""" try: user = User.objects.get(pk=user_id) except User.DoesNotExist: raise UserError.USER_NOT_FOUND return user @staticmethod def get_by_qtid(qt_user_app_id): """根据齐天用户-应用ID获取用户对象""" try: user = User.objects.get(qt_user_app_id=qt_user_app_id) except User.DoesNotExist: raise UserError.USER_NOT_FOUND return user """ 字典函数 """ def _readable_user_id(self): return self.pk def _readable_root_res(self): from Resource.models import Resource try: res = Resource.get_root_folder(self) return res.res_str_id except Exception: return None def d(self): return self.dictify('user_id', 'avatar', 'nickname', 'root_res') """ 增删函数 """ @classmethod def create(cls, qt_user_app_id, token): try: user = cls.get_by_qtid(qt_user_app_id) user.qtb_token = token user.save() except E as e: if e.eis(UserError.USER_NOT_FOUND): try: user = cls( qt_user_app_id=qt_user_app_id, qtb_token=token, ) user.save() except Exception: return UserError.CREATE_USER else: return e return user def update(self): body = qt_manager.get_user_info(self.qtb_token) self.avatar = body['avatar'] self.nickname = body['nickname'] self.description = body['description'] self.save() def remove(self): return self.delete()
class User(models.Model): avatar = models.CharField( verbose_name='头像', default=None, null=True, blank=True, max_length=1024, ) nickname = models.CharField( verbose_name='昵称', default=None, blank=True, null=True, max_length=10, ) qt_user_app_id = models.CharField( verbose_name='齐天簿ID', max_length=16, ) qt_token = models.CharField( verbose_name='齐天簿口令', max_length=256, min_length=4, ) @staticmethod def get_by_qt_user_app_id(qt_user_app_id): try: return User.objects.get(qt_user_app_id=qt_user_app_id) except User.DoesNotExist as err: raise UserError.USER_NOT_FOUND(debug_message=err) @classmethod def create(cls, qt_user_app_id, qt_token): try: user = cls.get_by_qt_user_app_id(qt_user_app_id) user.qt_token = qt_token user.save() return user except E as e: if e.eis(UserError.USER_NOT_FOUND): try: user = cls( qt_user_app_id=qt_user_app_id, qt_token=qt_token, ) user.save() except Exception as err: raise UserError.CREATE_USER(debug_message=err) else: raise e except Exception as err: raise UserError.CREATE_USER(debug_message=err) def update(self): from Base.common import qt_manager data = qt_manager.get_user_info(self.qt_token) self.avatar = data['avatar'] self.nickname = data['nickname'] self.save() def d(self): return self.dictor('nickname', 'avatar', 'qt_user_app_id->user_id')
class Milestone(models.Model): """里程碑""" space = models.ForeignKey( 'Space.Space', on_delete=models.CASCADE, ) name = models.CharField( verbose_name='里程碑信息', max_length=20, min_length=2, ) start_date = models.DateField() cover = models.ForeignKey( 'Image.Image', on_delete=models.SET_NULL, null=True, default=None, ) def space_checker(self, space): if self.space != space: raise MilestoneError.NOT_BELONG @classmethod def get(cls, mid): try: return cls.objects.get(pk=mid) except cls.DoesNotExist: raise MilestoneError.NOT_FOUND @classmethod def create(cls, space, name, start_date): try: return cls.objects.create(space=space, name=name, start_date=start_date) except Exception: raise MilestoneError.CREATE def update(self, name, start_date): self.name = name self.start_date = start_date self.save() def delete(self, *args, **kwargs): if self.cover: self.cover.delete() super(Milestone, self).delete(*args, **kwargs) def get_duration(self): start_date = self.start_date # type: datetime.date crt_date = datetime.date.today() return (crt_date - start_date).days def _readable_duration(self): return self.get_duration() def _readable_start_date(self): start_date = self.start_date # type: datetime.date return start_date.strftime('%Y-%m-%d') # return dict( # year=start_date.year, # month=start_date.month, # day=start_date.day # ) def _readable_cover(self): if self.cover: return self.cover.d_milestone() def d(self): return self.dictify('pk->mid', 'name', 'start_date', 'duration', 'cover') def d_create(self): return dict( mid=self.pk, cover_token=self.get_image_token(), ) def get_image_token(self): return Image.get_token(action=ImageUploadAction.MILESTONE, mid=self.pk) def set_cover(self, image: Image): if self.cover: self.cover.delete() self.cover = image self.save()
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()
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')
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)
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()
class Event(models.Model): event_id = models.CharField( max_length=6, min_length=6, unique=True, default=None, ) event_type = models.ForeignKey( EventType, on_delete=models.CASCADE, ) start_date = models.DateField() duration = models.PositiveIntegerField(default=1) name = models.CharField(max_length=20, ) album = models.ForeignKey( 'Album.Album', on_delete=models.SET_NULL, null=True, ) attends = models.ManyToManyField('Space.SpaceMan', ) @classmethod def get(cls, event_id): try: return cls.objects.get(event_id=event_id) except Exception: raise EventError.NOT_FOUND @classmethod def is_id_unique(cls, event_id): try: cls.objects.get(event_id=event_id) return False except cls.DoesNotExist: return True @classmethod def generate_event_id(cls): while True: event_id = get_random_string(6) if cls.is_id_unique(event_id): return event_id def update(self, name, duration, start_date): self.name = name self.duration = duration self.start_date = start_date self.save() def bind_album(self, album): if self.album: raise EventError.BIND_ALBUM self.album = album self.save() def _readable_album_id(self): if self.album: return self.album.res_id def _readable_start_date(self): return self.start_date.strftime('%Y-%m-%d') def d_et(self): return self.dictify('start_date', 'duration', 'name', 'album_id', 'event_id')