class ChannelCollectionModel(Model): DefaultName = TextField("dn", default=ModelDefaultValueExt.Required, must_have_content=True) Name = DictionaryField("n", allow_none=False, default={}) Platform = PlatformField("p", default=ModelDefaultValueExt.Required) Token = TextField("t", default=ModelDefaultValueExt.Required, must_have_content=True) BotAccessible = BooleanField("acc", default=True) ChildChannelOids = ArrayField("ch", ObjectId)
class RemoteControlEntryModel(Model): UserOid = ObjectIDField("uid", default=ModelDefaultValueExt.Required, stores_uid=True) LocaleCode = TextField("loc", default="Asia/Taipei") SourceChannelOid = ObjectIDField("src", default=ModelDefaultValueExt.Required) TargetChannelOid = ObjectIDField("dst", default=ModelDefaultValueExt.Required) ExpiryUtc = DateTimeField("exp", default=ModelDefaultValueExt.Required) @property def expiry(self): tzinfo = LocaleInfo.get_tzinfo(self.locale_code) return localtime(self.expiry_utc, tzinfo) @property def target_channel(self): from mongodb.factory import ChannelManager return ChannelManager.get_channel_oid(self.target_channel_oid) @property def expiry_str(self) -> str: return self.expiry.strftime("%Y-%m-%d %H:%M:%S (UTC%Z)")
class MessageRecordModel(Model): ChannelOid = ObjectIDField("ch", default=ModelDefaultValueExt.Required) UserRootOid = ObjectIDField("u", default=ModelDefaultValueExt.Required, stores_uid=True) MessageType = MessageTypeField("t", default=ModelDefaultValueExt.Required) MessageContent = TextField("ct", default=ModelDefaultValueExt.Required) ProcessTimeSecs = FloatField("pt", default=ModelDefaultValueExt.Optional) Timestamp = DateTimeField("ts")
class TimerModel(Model): ChannelOid = ObjectIDField("ch", default=ModelDefaultValueExt.Required) Keyword = TextField("k", default=ModelDefaultValueExt.Required) Title = TextField("t", default=ModelDefaultValueExt.Required) TargetTime = DateTimeField("tt", default=ModelDefaultValueExt.Required) DeletionTime = DateTimeField("del", default=ModelDefaultValueExt.Optional) Countup = BooleanField("c", default=False) PeriodSeconds = IntegerField("p") Notified = BooleanField("nt", default=False) NotifiedExpired = BooleanField("nt-e", default=False) @property def is_periodic(self) -> bool: return self.period_seconds > 0 def get_target_time_diff(self, dt: datetime): return abs(self.target_time - make_tz_aware(dt)) def is_after(self, dt: datetime) -> bool: """Check if the target time of the timer is after the given ``dt``.""" return self.target_time >= make_tz_aware(dt)
class APIStatisticModel(Model): Timestamp = DateTimeField("t", default=ModelDefaultValueExt.Required, allow_none=False) SenderOid = ObjectIDField("sd", default=ModelDefaultValueExt.Optional, allow_none=True, stores_uid=True) ApiAction = APICommandField("a") Parameter = DictionaryField("p", allow_none=True) PathParameter = DictionaryField("pp", allow_none=True) Response = DictionaryField("r", allow_none=True) Success = BooleanField("s", allow_none=True) PathInfo = TextField("pi", default=ModelDefaultValueExt.Required, must_have_content=True, allow_none=False) PathInfoFull = TextField("pf", default=ModelDefaultValueExt.Required, must_have_content=True, allow_none=False)
class ChannelProfileModel(Model): # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # !!! Check `ProfileManager.process_create_profile_kwargs` when changing the variable name of this class. !!! # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ChannelOid = ObjectIDField("c", default=ModelDefaultValueExt.Required) Name = TextField("n", default="-", must_have_content=True) Color = ColorField("col") # 0 means no need to vote, > 0 means # votes needed to get this profile PromoVote = IntegerField("promo", positive_only=True) Permission = DictionaryField( "perm", default=ProfilePermissionDefault.get_default_code_str_dict(), allow_none=False) PermissionLevel = PermissionLevelField("plv") EmailKeyword = ArrayField("e-kw", str) @property def is_mod(self): return self.permission_level >= PermissionLevel.MOD @property def is_admin(self): return self.permission_level >= PermissionLevel.ADMIN @property def permission_list(self) -> List[ProfilePermission]: ret = set() for cat, permitted in self.permission.items(): if permitted: perm = ProfilePermission.cast(cat, silent_fail=True) if perm: ret.add(perm) ret = ret.union( ProfilePermissionDefault.get_overridden_permissions( self.permission_level)) return list(sorted(ret, key=lambda x: x.code)) def pre_iter(self): # Will be used when the data will be passed to MongoDB d = [ p.code_str for p in ProfilePermissionDefault.get_overridden_permissions( self.permission_level) ] for perm_cat in ProfilePermission: k = perm_cat.code_str if k not in self.permission: self.permission[k] = k in d
class ChannelConfigModel(Model): WITH_OID = False # Votes needed to promote a member to be moderator VotePromoMod = IntegerField("v-m", default=ChannelConfig.VotesToPromoteMod) # Votes needed to promote a member to be admin VotePromoAdmin = IntegerField("v-a", default=ChannelConfig.VotesToPromoteAdmin) EnableAutoReply = BooleanField("e-ar", default=True) EnableTimer = BooleanField("e-tmr", default=True) EnableCalculator = BooleanField("e-calc", default=True) EnableBotCommand = BooleanField("e-bot", default=True) InfoPrivate = BooleanField("prv", default=False) DefaultProfileOid = ObjectIDField("d-prof", allow_none=True) DefaultName = TextField("d-name", allow_none=True)
class ExtraContentModel(Model): Type = ExtraContentTypeField("tp") Title = TextField("t", default=ModelDefaultValueExt.Optional) Content = GeneralField("c", default=ModelDefaultValueExt.Required) Timestamp = DateTimeField("e", default=ModelDefaultValueExt.Required) ChannelOid = ObjectIDField("ch", default=ModelDefaultValueExt.Optional) @property def expires_on(self): return self.timestamp + timedelta( seconds=Database.ExtraContentExpirySeconds) @property def content_html(self) -> str: return ExtraContentHTMLTransformer.transform(self)
class ChannelModel(Model): Platform = PlatformField("p", default=ModelDefaultValueExt.Required) Token = TextField("t", default=ModelDefaultValueExt.Required, must_have_content=True) Name = DictionaryField("n", allow_none=False, default={}) Config = ModelField("c", ChannelConfigModel) BotAccessible = BooleanField("acc", default=True) def get_channel_name(self, root_oid: ObjectId): oid_str = str(root_oid) if oid_str in self.name: return self.name[oid_str] else: return self.config.default_name or self.token
class ShortUrlRecordModel(Model): # CHANGE THE KEY NAME AS WELL FOR github.com/RaenonX/Jelly-Bot-ShortURL IF CHANGING THE KEY NAME OF THESE FIELDS Code = TextField("cd", default=ModelDefaultValueExt.Required) Target = UrlField("tgt", default=ModelDefaultValueExt.Required) CreatorOid = ObjectIDField("cr", default=ModelDefaultValueExt.Required, stores_uid=True) UsedTimestamp = ArrayField("ts", datetime) Disabled = BooleanField("d", default=False) @property def used_count(self) -> int: return len(self.used_timestamp) @property def short_url(self) -> str: return f"{os.environ['SERVICE_SHORT_URL']}/{self.code}"
class ModelTest(Model): FModel = ModelField("m", SubModel) FInt = IntegerField("i", default=ModelDefaultValueExt.Required) FModelArray = ModelArrayField("ma", SubModel, default=ModelDefaultValueExt.Optional) FDict = DictionaryField("d") FFloat = FloatField("f", default=7.5) FBool = BooleanField("b") FUrl = UrlField("u", default=ModelDefaultValueExt.Optional) FText = TextField("t") FOid = ObjectIDField("o") FGeneral = GeneralField("g") FDatetime = DateTimeField("dt") FColor = ColorField("c") FArray = ArrayField("a", int, default=[17, 21]) FArContent = AutoReplyContentTypeField("ac")
def get_field(self) -> BaseField: return TextField("k", allow_none=True)
def get_field(self) -> BaseField: return TextField("k")
def test_default_no_content(self): with self.assertRaises(FieldInvalidDefaultValue): TextField("k", default="", must_have_content=True)
def test_default_regex_not_match(self): with self.assertRaises(FieldInvalidDefaultValue): TextField("k", default="ABCDE", regex=r"[A-E]{4}")
def get_field(self) -> BaseField: return TextField("k", maxlen=500)
def get_field(self) -> BaseField: return TextField("k", regex="[A-F]{8}", default="AAAAAAAA")
def get_field(self) -> BaseField: return TextField("k", must_have_content=True, default="default")
def get_field(self) -> BaseField: return TextField("k", auto_cast=False)
def test_repair_t(self): self.missing_has_default("t", {"t": TextField.none_obj()})