class Dataset(Model): id = IntField(pk=True) collection = ForeignKeyField('models.Collection', related_name='datasets') discarded = BooleanField(default=False) name = TextField() status = IntField(default=0) time_added = IntField() # ms since epoch timestamp = IntField() # ms since epoch setid = custom.SetIDField(unique=True) tags = ManyToManyField('models.Tag', related_name='datasets') acn = ForeignKeyField('models.Acn', related_name='datasets', on_delete=RESTRICT) # Populated by backreferences: comments, files error = make_status_property(1) missing = make_status_property(2) outdated = make_status_property(4) pending = make_status_property(8) def __repr__(self): return f'<{type(self).__name__} {self.setid} {self.name}>'
class Moderator(Model): id = IntField(pk=True) user: ForeignKeyRelation[User] = ForeignKeyField( "models.User", related_name="moderator_on") guild: ForeignKeyRelation[Guild] = ForeignKeyField( "models.Guild", related_name="moderators") title = TextField(null=True) class Meta: table = "moderators"
class MonsterDrop(Model): item = ForeignKeyField("models.Item", related_name="drops") monster = ForeignKeyField("models.Monster", related_name="drops") rate = IntField() pickpocket_only = BooleanField(default=False) no_pickpocket = BooleanField(default=False) conditional = BooleanField(default=False) fixed = BooleanField(default=False) stealable_accordion = BooleanField(default=False)
class ClanGame(Model): clan: ForeignKeyRelation[Clan] = ForeignKeyField( "seraphsix.Clan", related_name="games", to_field="id" ) game: ForeignKeyRelation[Game] = ForeignKeyField( "seraphsix.Game", related_name="clans", to_field="id" ) class Meta: indexes = ("clan", "game")
class Modifier(Model): item = ForeignKeyField("models.Item", related_name="modifiers", null=True) item_id: Optional[int] effect = ForeignKeyField("models.Effect", related_name="modifiers", null=True) effect_id: Optional[int] key = CharField(max_length=255) numeric_value = IntField(null=True) string_value = CharField(max_length=255, null=True) expression_value = CharField(max_length=255, null=True) percentage = BooleanField(default=False)
class GameMember(Model): time_played = FloatField(null=True) completed = BooleanField(null=True) member: ForeignKeyRelation[Member] = ForeignKeyField( "seraphsix.Member", related_name="games", to_field="id" ) game: ForeignKeyRelation[Game] = ForeignKeyField( "seraphsix.Game", related_name="members", to_field="id" ) class Meta: indexes = ("member", "game")
class ClanMember(Model): platform_id = IntField() join_date = DatetimeField() is_active = BooleanField(default=True) last_active = DatetimeField(null=True) is_sherpa = BooleanField(default=False) member_type = IntField(null=True, validators=[ClanMemberRankValidator()]) clan: ForeignKeyRelation[Clan] = ForeignKeyField( "seraphsix.Clan", related_name="members", to_field="id" ) member: ForeignKeyRelation[Member] = ForeignKeyField( "seraphsix.Member", related_name="clans", to_field="id" )
class SubExclude(Model): """ Exclusion for a trigger in a specific channel. Attributes: trigger (.SubTrigger): Containing trigger instance. network (str): Network identifier that the channel belongs to. user (str): Channel's own identifier. """ trigger = ForeignKeyField("db.SubTrigger", "excludes") network = TextField() channel = TextField() @classmethod def select_related(cls): return cls.all().prefetch_related("trigger") def __repr__(self): if isinstance(self.trigger, SubTrigger): trigger = repr(self.trigger) else: trigger = "<{}: #{}>".format(SubTrigger.__name__, self.trigger_id) return "<{}: #{} {} @ {} {}>".format(self.__class__.__name__, self.id, repr(self.network), repr(self.channel), trigger)
class DataVisualization(Model): id = IntField(pk=True) image_name = CharField(max_length=100) satellite_dataset: ForeignKeyRelation[SatelliteDatasets] = ForeignKeyField( 'models.SatelliteDatasets', related_name='data_visualization')
class Comment(Model): id = IntField(pk=True) dataset = ForeignKeyField('models.Dataset', related_name='comments') author = TextField() time_added = IntField() # ms since epoch text = TextField()
class Post(Model): id = IntField(pk=True) created_at = DatetimeField(auto_now_add=True) modified_at = DatetimeField(auto_now=True) title = CharField(max_length=32) content = TextField(null=True) image_url = TextField() author: ForeignKeyRelation[User] = ForeignKeyField("models.User", "posts") comments = ReverseRelation["Comment"] class Meta: table = "posts" ordering = ["created_at"] class PydanticMeta: exclude = ("author", "comments") def __repr__(self): return ( f"Post({self.id=}, {self.created_at=}, {self.modified_at=}, " f"{self.title=}, {self.content=}, {self.image_url}, {self.author=})" ) def __str__(self): return self.__repr__()
class Panel_Widget(Model): id = IntField(pk=True) url = CharField(255) prefix = CharField(128) color_name = CharField(40) group: ForeignKeyRelation[Panel_Group] = ForeignKeyField( "models.Panel_Group", related_name="panel_widgets")
class Warn(Model): id = IntField(pk=True) moderator = BigIntField() reason = TextField(null=True) when = DatetimeField(auto_now_add=True) user: ForeignKeyRelation[User] = ForeignKeyField("models.User", related_name="warns") guild: ForeignKeyRelation[Guild] = ForeignKeyField("models.Guild", related_name="warns") class Meta: table = "warns" def __str__(self): return (f"<Warn id:{self.id} moderator:{self.moderator} " f"reason:'{self.reason}' datetime:{self.when} " f"user:{self.user.id} guild:{self.guild.id}>")
class ClanMemberApplication(Model): approved = BooleanField(default=False) message_id = BigIntField(unique=True) guild: ForeignKeyRelation[Guild] = ForeignKeyField( "seraphsix.Guild", related_name="clanmemberapplications", to_field="id" ) member: ForeignKeyRelation[Member] = ForeignKeyField( "seraphsix.Member", related_name="clanmemberapplications_created", to_field="id" ) approved_by: ForeignKeyRelation[Member] = ForeignKeyField( "seraphsix.Member", related_name="clanmemberapplications_approved", to_field="id", )
class Question(Model): id: UUIDField = UUIDField(pk=True) text: TextField = TextField() formatted_text: TextField = TextField() answer: ForeignKeyNullableRelation["Answer"] = ForeignKeyField( model_name="models.Answer", related_name="questions") def __str__(self) -> str: return f"{self.id} ({self.text[:120]}{'...' if len(self.text) > 120 else ''})"
class Mute(Model): id = IntField(pk=True) moderator = BigIntField() reason = TextField(null=True) start = DatetimeField(auto_now_add=True) end = DatetimeField() active = BooleanField(default=True) user: ForeignKeyRelation[User] = ForeignKeyField("models.User", related_name="mutes") guild: ForeignKeyRelation[Guild] = ForeignKeyField("models.Guild", related_name="mutes") class Meta: table = "mutes" def __str__(self): return ( f"<Mute id:{self.id} moderator:{self.moderator} " f"reason:'{self.reason}' start:{self.start} end:{self.end} " f"active:{self.active} user:{self.user.id} guild:{self.guild.id}>")
class File(Model): id = IntField(pk=True) dataset = ForeignKeyField('models.Dataset', related_name='files') idx = IntField() # files are counted per dataset missing = BooleanField(default=False) mtime = IntField() # ms since epoch path = TextField() size = IntField() def __repr__(self): return f"<{type(self).__name__} '{self.path}'>"
class Clan(Model): clan_id = BigIntField(unique=True) name = CharField(max_length=255) callsign = CharField(max_length=4) platform = IntField(null=True, validators=[PlatformValidator()]) the100_group_id = IntField(unique=True, null=True) activity_tracking = BooleanField(default=True) guild: ForeignKeyRelation[Guild] = ForeignKeyField( "seraphsix.Guild", related_name="clans", to_field="id" ) members: ReverseRelation["ClanMember"]
class Message(Model): id = BigIntField(pk=True) channel_id = BigIntField(null=False) user: ForeignKeyRelation[User] = ForeignKeyField('models.User', related_name='messages', null=False) user_event: ReverseRelation['Event'] bot_event: ReverseRelation['Event'] reminder: ReverseRelation['Reminder'] def __str__(self): return f'{self.__class__}: {self.id}'
class Journal(Model): id = IntField(pk=True, index=True) user: ForeignKeyRelation[User] = ForeignKeyField("models.User", related_name="journals", on_delete=CASCADE) name = TextField(null=False) name_lower = TextField(null=False) # YYYY-MM-DD or None deleted_on = DateField(null=True) entries: ReverseRelation["Entry"]
class ApiJob(Model): """API job model.""" requestor: ForeignKeyRelation[ApiUser] = ForeignKeyField( "models.ApiUser", related_name="jobs") request_time = DatetimeField(auto_now=True) complete_time = DatetimeField(null=True) in_progress = BooleanField(default=False) detail = TextField(null=True) class Meta: """Tortoise ORM Config.""" table = "api_jobs"
class Role(Model): role_id = BigIntField() platform_id = IntField(null=True) is_sherpa = BooleanField(null=True) is_clanmember = BooleanField(null=True) is_new_clanmember = BooleanField(null=True) is_non_clanmember = BooleanField(null=True) is_protected_clanmember = BooleanField(null=True) guild: ForeignKeyRelation[Guild] = ForeignKeyField( "seraphsix.Guild", related_name="roles", to_field="id" ) class Meta: indexes = ("guild", "role_id")
class Entry(Model): id = IntField(pk=True, index=True) journal: ForeignKeyRelation[Journal] = ForeignKeyField( "models.Journal", related_name="entries", on_delete=CASCADE) short = TextField(null=False) long = TextField(null=False) # YYYY-MM-DD HH:MM format in UTC timezone date = DatetimeField(null=False) # YYYY-MM-DD or None deleted_on = DateField(null=True) keywords: ReverseRelation["Keyword"]
class Comment(Model): id = IntField(pk=True) created_at = DatetimeField(auto_now_add=True) modified_at = DatetimeField(auto_now=True) content = TextField() author: ForeignKeyRelation[User] = ForeignKeyField("models.User", "comments") post: ForeignKeyRelation[Post] = ForeignKeyField("models.Post", "comments") class Meta: table = "comments" ordering = ["created_at"] class PydanticMeta: exclude = ("author", "post") def __repr__(self): return ( f"Comment({self.id=}, {self.created_at=}, {self.modified_at=}, " f"{self.content=}, {self.author=}, {self.post=})" ) def __str__(self): return self.__repr__()
class IdentityRole(Model): """ Assignment of a role to an identity. Attributes: group (.IdentityGroup): Containing group instance. role (str): Plain role identifier. """ group = ForeignKeyField("db.IdentityGroup", "roles") role = TextField() def __repr__(self): if isinstance(self.group, IdentityGroup): group = repr(self.group) else: group = "<{}: #{}>".format(IdentityGroup.__name__, self.group_id) return "<{}: #{} {} {}>".format(self.__class__.__name__, self.id, repr(self.role), group)
class IdentityLink(Model): """ Single link between an identity and a user. Attributes: group (.IdentityGroup): Containing group instance. network (str): Network identifier that the user belongs to. user (str): User identifier as given by the plug. """ group = ForeignKeyField("db.IdentityGroup", "links") network = TextField() user = TextField() def __repr__(self): if isinstance(self.group, IdentityGroup): group = repr(self.group) else: group = "<{}: #{}>".format(IdentityGroup.__name__, self.group_id) return "<{}: #{} {} @ {} {}>".format(self.__class__.__name__, self.id, repr(self.user), repr(self.network), group)
class Auth(Model): # tortoise orm does not support multiple field primary key # so currently we use a string that shape is [provider]:[id] as primary key id = TextField(pk=True) user = ForeignKeyField("models.User", related_name="auths")
class OutfitVariant(Model): outfit = ForeignKeyField("models.Outfit", related_name="variants") outfit_id: int pieces: List["libkol.Item"]
class Familiar(Model, metaclass=FamiliarMeta): id = IntField(pk=True, generated=False) name = CharField(max_length=255) image = CharField(max_length=255) # Behaviour stat_volley = BooleanField(default=False) stat_sombrero = BooleanField(default=False) item_drop = BooleanField(default=False) meat_drop = BooleanField(default=False) physical_attack = BooleanField(default=False) elemental_attack = BooleanField(default=False) drop = BooleanField(default=False) block = BooleanField(default=False) delevel = BooleanField(default=False) combat_hp = BooleanField(default=False) combat_mp = BooleanField(default=False) combat_meat = BooleanField(default=False) combat_stat = BooleanField(default=False) combat_other = BooleanField(default=False) post_hp = BooleanField(default=False) post_mp = BooleanField(default=False) post_meat = BooleanField(default=False) post_stat = BooleanField(default=False) post_other = BooleanField(default=False) passive = BooleanField(default=False) underwater = BooleanField(default=False) variable = BooleanField(default=False) # Related items hatchling = ForeignKeyField("models.Item", related_name="grows_into", null=True) hatchling_id: Optional[int] equipment = ForeignKeyField("models.Item", related_name="equipment_for", null=True) equipment_id: Optional[int] # Arena skills cave_match_skill = IntField(default=0) scavenger_hunt_skill = IntField(default=0) obstacle_course_skill = IntField(default=0) hide_and_seek_skill = IntField(default=0) # Pokefam pokefam = BooleanField(default=False) # Attributes bites = BooleanField(default=False) has_eyes = BooleanField(default=False) has_hands = BooleanField(default=False) has_wings = BooleanField(default=False) is_animal = BooleanField(default=False) is_bug = BooleanField(default=False) is_flying = BooleanField(default=False) is_hot = BooleanField(default=False) is_mechanical = BooleanField(default=False) is_quick = BooleanField(default=False) is_slayer = BooleanField(default=False) is_sleazy = BooleanField(default=False) is_undead = BooleanField(default=False) wears_clothes = BooleanField(default=False) def __ge__(self, other): if isinstance(other, str): return self.name == other elif isinstance(other, int): return self.id == other else: return self == other @property def have(self) -> bool: return self in self.kol.familiars @property def weight(self) -> Optional[int]: if self.have is False: return None return self.kol.familiars[self].weight
class Item(Model, metaclass=ItemMeta): id = IntField() name = CharField(max_length=255) desc_id = IntField() plural = CharField(max_length=255, null=True) image = CharField(max_length=255) autosell = IntField(default=0) level_required = IntField(default=0) # Level required # Consumables food = BooleanField(default=False) fullness = IntField(default=0) booze = BooleanField(default=False) inebriety = IntField(default=0) spleen = BooleanField(default=False) spleenhit = IntField(default=0) quality = CharField(max_length=255, null=True) gained_adventures_min = IntField(default=0) gained_adventures_max = IntField(default=0) gained_muscle_min = IntField(default=0) gained_muscle_max = IntField(default=0) gained_mysticality_min = IntField(default=0) gained_mysticality_max = IntField(default=0) gained_moxie_min = IntField(default=0) gained_moxie_max = IntField(default=0) # Usability usable = BooleanField(default=False) multiusable = BooleanField(default=False) combat_usable = BooleanField(default=False) reusable = BooleanField(default=False) combat_reusable = BooleanField(default=False) curse = BooleanField(default=False) # Can be used on others # Equipment hat = BooleanField(default=False) pants = BooleanField(default=False) shirt = BooleanField(default=False) weapon = BooleanField(default=False) weapon_hands = IntField(null=True) weapon_type = CharField(max_length=255, null=True) offhand = BooleanField(default=False) offhand_type = CharField(max_length=255, null=True) accessory = BooleanField(default=False) container = BooleanField(default=False) sixgun = BooleanField(default=False) familiar_equipment = BooleanField(default=False) power = IntField(null=True) required_muscle = IntField(default=0) required_mysticality = IntField(default=0) required_moxie = IntField(default=0) # Collections foldgroup = ForeignKeyField("models.FoldGroup", related_name="items", null=True) foldgroup_id: Optional[int] zapgroup = ForeignKeyField("models.ZapGroup", related_name="items", null=True) zapgroup_id: Optional[int] # NPC Store Info store_row = IntField(null=True) store_price = IntField(null=True) store = ForeignKeyField("models.Store", related_name="items", null=True) store_id: Optional[int] # Flags hatchling = BooleanField(default=False) pokepill = BooleanField(default=False) sticker = BooleanField(default=False) card = BooleanField(default=False) folder = BooleanField(default=False) bootspur = BooleanField(default=False) bootskin = BooleanField(default=False) food_helper = BooleanField(default=False) drink_helper = BooleanField(default=False) guardian = BooleanField(default=False) bounty = BooleanField(default=False) # Can appear as a bounty item candy = IntField() # 0: n/a, 1: simple, 2: complex sphere = BooleanField(default=False) # What is this for? quest = BooleanField(default=False) # is a quest item gift = BooleanField(default=False) # is a gift item tradeable = BooleanField(default=False) # is tradeable discardable = BooleanField(default=False) # is discardable def pluralize(self): return "{}s".format(self.name) if self.plural is None else self.plural @classmethod async def get_or_discover(cls, *args, **kwargs) -> "Item": result = await cls.filter(*args, **kwargs).first() if result is None: id: int = kwargs.get("id", None) desc_id: int = kwargs.get("desc_id", None) return await cls.discover(id=id, desc_id=desc_id) return result @classmethod async def discover(cls, id: int = None, desc_id: int = None): """ Discover this item using its id or description id. The description id is preferred as it provides more information, so if only an id is provided, libkol will first determine the desc_id. Note that this Returns an Item object but it is not automatically committed to the database. It is not sufficient to run `await item.save()` to do this however as tortoise-orm will attempt to `UPDATE` the row because it already has an `id` set. Instead you need to run `awaititem._insert_instance()` explicitly. :param id: Id of the item to discover :param desc_id: Description id of the item to discover """ if id is not None: desc_id = (await request.item_information(cls.kol, id).parse()).descid if desc_id is None: raise ItemNotFoundError( "Cannot discover an item without either an id or a desc_id") info = await request.item_description(cls.kol, desc_id).parse() return Item(**{k: v for k, v in info.items() if v is not None}) async def get_mall_price(self, limited: bool = False) -> int: """ Get the lowest price for this item in the mall :param limited: Include limited sales in this search """ prices = await request.mall_price(self.kol, self).parse() if limited: return prices.limited[0].price return prices.unlimited[0].price async def get_mall_listings(self, **kwargs) -> List["types.Listing"]: return await request.mall_search(self.kol, query=self, **kwargs).parse() async def buy_from_mall( self, listing: "types.Listing" = None, store_id: int = None, price: int = 0, quantity: int = 1, ): if listing is None and store_id is None: listings = await self.get_mall_listings(num_results=quantity, max_price=price) tasks = [ request.mall_purchase(self.kol, item=self, listing=l).parse() for l in listings ] return await asyncio.gather(*tasks) return await request.mall_purchase( self.kol, item=self, listing=listing, store_id=store_id, price=price, quantity=quantity, ).parse() def amount(self): return self.kol.state["inventory"][self] async def use(self, quantity: int = 1, multi_use: bool = True): if self.usable is False: raise WrongKindOfItemError("This item cannot be used") if self.multiusable and multi_use: await request.item_multi_use(self.kol, self, quantity).parse() return tasks = [ request.item_use(self.kol, self).parse() for _ in range(quantity) ] return await asyncio.gather(*tasks)