Exemplo n.º 1
0
class Guild(BaseModel):
    WhitelistFlags = Enum('MUSIC', 'MODLOG_CUSTOM_FORMAT', bitmask=False)

    guild_id = BigIntegerField(primary_key=True)
    owner_id = BigIntegerField(null=True)
    name = TextField(null=True)
    icon = TextField(null=True)
    splash = TextField(null=True)
    region = TextField(null=True)

    last_ban_sync = DateTimeField(null=True)

    # Rowboat specific data
    config = BinaryJSONField(null=True)
    config_raw = BlobField(null=True)

    enabled = BooleanField(default=True)
    whitelist = BinaryJSONField(default=[])

    added_at = DateTimeField(default=datetime.utcnow)

    # SQL = '''
    #     CREATE OR REPLACE FUNCTION shard (int, bigint)
    #     RETURNS bigint AS $$
    #       SELECT ($2 >> 22) % $1
    #     $$ LANGUAGE SQL;
    # '''

    class Meta:
        db_table = 'guilds'

    @classmethod
    def with_id(cls, guild_id):
        return cls.get(guild_id=guild_id)

    @classmethod
    def setup(cls, guild):
        return cls.create(guild_id=guild.id,
                          owner_id=guild.owner_id,
                          name=guild.name,
                          icon=guild.icon,
                          splash=guild.splash,
                          region=guild.region,
                          config={'web': {
                              str(guild.owner_id): 'admin'
                          }},
                          config_raw='')

    def is_whitelisted(self, flag):
        return int(flag) in self.whitelist

    def update_config(self, actor_id, raw):
        from rowboat.types.guild import GuildConfig

        parsed = yaml.load(raw)
        GuildConfig(parsed).validate()

        GuildConfigChange.create(user_id=actor_id,
                                 guild_id=self.guild_id,
                                 before_raw=self.config_raw,
                                 after_raw=raw)

        self.update(
            config=parsed,
            config_raw=raw).where(Guild.guild_id == self.guild_id).execute()
        self.emit_update()

    def emit_update(self):
        rdb.publish(
            'actions',
            json.dumps({
                'type': 'GUILD_UPDATE',
                'id': self.guild_id,
            }))

    def sync(self, guild):
        updates = {}

        for key in ['owner_id', 'name', 'icon', 'splash', 'region']:
            if getattr(guild, key) != getattr(self, key):
                updates[key] = getattr(guild, key)

        if updates:
            Guild.update(**updates).where(
                Guild.guild_id == self.guild_id).execute()

    def get_config(self, refresh=False):
        from rowboat.types.guild import GuildConfig

        if refresh:
            self.config = Guild.select(Guild.config).where(
                Guild.guild_id == self.guild_id).get().config

        if refresh or not hasattr(self, '_cached_config'):
            self._cached_config = GuildConfig(self.config)
        return self._cached_config

    def sync_bans(self, guild):
        # Update last synced time
        Guild.update(last_ban_sync=datetime.utcnow()).where(
            Guild.guild_id == self.guild_id).execute()

        try:
            bans = guild.get_bans()
        except:
            log.exception('sync_bans failed:')
            return

        log.info('Syncing %s bans for guild %s', len(bans), guild.id)

        GuildBan.delete().where((~(GuildBan.user_id << list(bans.keys())))
                                & (GuildBan.guild_id == guild.id)).execute()

        for ban in bans.values():
            GuildBan.ensure(guild, ban.user, ban.reason)
Exemplo n.º 2
0
class BaseModel(Model):
    uid = UUIDField(null=False,
                    default=uuid.uuid4,
                    unique=True,
                    help_text="uid 不是主键,但是要当做主键来用")
    is_deleted = BooleanField(default=False,
                              null=False,
                              help_text="1 delete, 0 normal")
    create_time = DateTimeField(default=datetime.now)

    class Meta:
        database = db

    @classmethod
    def get_with_uid(cls, uid):
        if not uid:
            return None
        return cls.get_or_none(cls.uid == uid, cls.is_deleted == False)

    @classmethod
    def remove(cls, uid):
        r = cls.get_with_uid(uid)
        if r:
            r.is_deleted = True
            r.save()
        return r

    @classmethod
    def _get_field_names(cls):
        return cls._meta.sorted_field_names

    @classmethod
    def _get_fields(cls):
        fields = []
        for field_name in cls.get_field_names():
            field = cls._meta.fields[field_name]
            fields.append(field)
        return fields

    @classmethod
    def verify_params(cls, **params):
        # 验证 params 中的参数,主要验证非 None 字段是否有值
        fields = cls._get_fields()
        for field in fields:
            if field.auto_increment or field.default is not None or field.null:
                continue
            if params.get(field.name) is None:
                print("{} is None".format(field.name))
                return False
            # if field.unique:
            #     r = cls.get_or_none(field==params.get(field.name))
            #     if r:
            #         print("Duplicate data, field = {}, value = {}".format(field.name, params.get(field.name)))
            #         return False
        return True

    @classmethod
    def validate(cls, **params):
        # 继承该方法,验证参数
        pass

    @classmethod
    def params_handler(cls, params):
        # Model 继承该方法,处理参数
        pass

    @classmethod
    def create_data(cls, **params):
        return cls.create(**params)

    @classmethod
    def list(cls):
        return cls.select().where(cls.is_deleted == False)

    def to_json(self):
        r = model_to_dict(self)
        # id 对使用者不可见
        r.pop("id", None)
        for k, v in r.items():
            r[k] = field_to_json(v)
        return r
Exemplo n.º 3
0
class DbBarData(Model):
    """
    Candlestick bar data for database storage.

    Index is defined unique with vt_symbol, interval and datetime.
    """

    symbol = CharField()
    exchange = CharField()
    datetime = DateTimeField()
    interval = CharField()

    volume = FloatField()
    open_price = FloatField()
    high_price = FloatField()
    low_price = FloatField()
    close_price = FloatField()

    vt_symbol = CharField()
    gateway_name = CharField()

    class Meta:
        database = DB
        indexes = ((("vt_symbol", "interval", "datetime"), True), )

    @staticmethod
    def from_bar(bar: BarData):
        """
        Generate DbBarData object from BarData.
        """
        db_bar = DbBarData()

        db_bar.symbol = bar.symbol
        db_bar.exchange = bar.exchange.value
        db_bar.datetime = bar.datetime
        db_bar.interval = bar.interval.value
        db_bar.volume = bar.volume
        db_bar.open_price = bar.open_price
        db_bar.high_price = bar.high_price
        db_bar.low_price = bar.low_price
        db_bar.close_price = bar.close_price
        db_bar.vt_symbol = bar.vt_symbol
        db_bar.gateway_name = "DB"

        return db_bar

    def to_bar(self):
        """
        Generate BarData object from DbBarData.
        """
        bar = BarData(
            symbol=self.symbol,
            exchange=Exchange(self.exchange),
            datetime=self.datetime,
            interval=Interval(self.interval),
            volume=self.volume,
            open_price=self.open_price,
            high_price=self.high_price,
            low_price=self.low_price,
            close_price=self.close_price,
            gateway_name=self.gateway_name,
        )
        return bar
Exemplo n.º 4
0
class User(BaseModel):
    user_id = BigIntegerField(primary_key=True)
    username = TextField()
    discriminator = SmallIntegerField()
    avatar = TextField(null=True)
    bot = BooleanField()

    created_at = DateTimeField(default=datetime.utcnow)

    admin = BooleanField(default=False)

    SQL = '''
        CREATE INDEX IF NOT EXISTS users_username_trgm ON users USING gin(username gin_trgm_ops);
    '''

    class Meta:
        table_name = 'users'

        indexes = ((('user_id', 'username', 'discriminator'), True), )

    def serialize(self, us=False):
        base = {
            'id': str(self.user_id),
            'username': self.username,
            'discriminator': self.discriminator,
            'avatar': self.avatar,
            'bot': self.bot,
        }

        if us:
            base['admin'] = self.admin

        return base

    @property
    def id(self):
        return self.user_id

    @classmethod
    def ensure(cls, user, should_update=True):
        return cls.from_disco_user(user)

    @classmethod
    def with_id(cls, uid):
        try:
            return User.get(user_id=uid)
        except User.DoesNotExist:
            return

    @classmethod
    def from_disco_user(cls, user, should_update=True):
        obj, _ = cls.get_or_create(user_id=user.id,
                                   defaults={
                                       'username': user.username,
                                       'discriminator': user.discriminator,
                                       'avatar': user.avatar,
                                       'bot': user.bot
                                   })

        if should_update:
            updates = {}

            if obj.username != user.username:
                updates['username'] = user.username

            if obj.discriminator != user.discriminator:
                updates['discriminator'] = user.discriminator

            if obj.avatar != user.avatar:
                updates['avatar'] = user.avatar

            if updates:
                cls.update(**updates).where(User.user_id == user.id).execute()

        return obj

    def __str__(self):
        return '{}#{}'.format(self.username, str(self.discriminator).zfill(4))
Exemplo n.º 5
0
class User(BaseModel):
    uid = IntegerField(primary_key=True)
    name = CharField(max_length=250)
    path = IntegerField()
    step = IntegerField(default=1)
    updated = DateTimeField(default=datetime.datetime.now)
Exemplo n.º 6
0
class Subscribe(BaseModel):
    user = ForeignKeyField(User)
    name = CharField(verbose_name="订阅名称", max_length=20, default="")
    keyword = CharField(verbose_name="搜索条件(json)", max_length=200, default="")
    create_at = DateTimeField(verbose_name="创建时间", null=False, default=utils.now)
Exemplo n.º 7
0
    class DbBarData(ModelBase):
        """
        Candlestick bar data for database storage.

        Index is defined unique with datetime, interval, symbol
        """

        id = AutoField()
        symbol: str = CharField()
        exchange: str = CharField()
        datetime: datetime = DateTimeField()
        interval: str = CharField()

        volume: float = FloatField()
        open_interest: float = FloatField()
        open_price: float = FloatField()
        high_price: float = FloatField()
        low_price: float = FloatField()
        close_price: float = FloatField()

        class Meta:
            database = db
            indexes = ((("symbol", "exchange", "interval", "datetime"),
                        True), )

        @staticmethod
        def from_bar(bar: BarData):
            """
            Generate DbBarData object from BarData.
            """
            db_bar = DbBarData()

            db_bar.symbol = bar.symbol
            db_bar.exchange = bar.exchange.value
            db_bar.datetime = bar.datetime
            db_bar.interval = bar.interval.value
            db_bar.volume = bar.volume
            db_bar.open_interest = bar.open_interest
            db_bar.open_price = bar.open_price
            db_bar.high_price = bar.high_price
            db_bar.low_price = bar.low_price
            db_bar.close_price = bar.close_price

            return db_bar

        def to_bar(self):
            """
            Generate BarData object from DbBarData.
            """
            bar = BarData(
                symbol=self.symbol,
                exchange=Exchange(self.exchange),
                datetime=self.datetime,
                interval=Interval(self.interval),
                volume=self.volume,
                open_price=self.open_price,
                high_price=self.high_price,
                open_interest=self.open_interest,
                low_price=self.low_price,
                close_price=self.close_price,
                gateway_name="DB",
            )
            return bar

        @staticmethod
        def save_all(objs: List["DbBarData"], progress_bar_dict=None):
            """
            save a list of objects, update if exists.
            """
            dicts = [i.to_dict() for i in objs]
            with db.atomic():
                if driver is Driver.POSTGRESQL:
                    for bar in dicts:
                        DbBarData.insert(bar).on_conflict(
                            update=bar,
                            conflict_target=(
                                DbBarData.symbol,
                                DbBarData.exchange,
                                DbBarData.interval,
                                DbBarData.datetime,
                            ),
                        ).execute()
                else:
                    total_sz = len(dicts)
                    loaded = 0
                    for c in chunked(dicts, 50):
                        DbBarData.insert_many(
                            c).on_conflict_replace().execute()
                        if 'save_progress_bar' in progress_bar_dict:
                            loaded += 50
                            percent_saved = min(
                                round(100 * loaded / total_sz, 2), 100)
                            QApplication.processEvents()
                            progress_bar_dict['save_progress_bar'].setValue(
                                percent_saved)
Exemplo n.º 8
0
class Tags(BaseModel):
    name = CharField()
    status = SmallIntegerField(default=0)
    createTime = DateTimeField(default=datetime.now)
    updateTime = DateTimeField(default=datetime.now)
Exemplo n.º 9
0
#!/usr/bin/env python

import os
from datetime import datetime

from peewee import DateTimeField, IntegerField, SqliteDatabase
from playhouse.migrate import SqliteMigrator, migrate

db = SqliteDatabase(os.getenv("DATABASE_FILE", "omegabot.db"))
migrator = SqliteMigrator(db)

with db.atomic():
    migrate(
        migrator.add_column("user", "xp", IntegerField(default=0)),
        migrator.add_column("user", "xp_last_update_time",
                            DateTimeField(default=datetime.now)),
    )
Exemplo n.º 10
0
class GymDetails(BaseModel):
    gym_id = CharField(primary_key=True)
    name = CharField()
    description = CharField(null=True)
    url = CharField()
    last_scanned = DateTimeField(default=datetime.utcnow)
Exemplo n.º 11
0
class Pokemon(BaseModel):
    # We are base64 encoding the ids delivered by the api
    # because they are too big for sqlite to handle
    encounter_id = CharField(primary_key=True, max_length=50)
    spawnpoint_id = CharField(index=True)
    pokemon_id = IntegerField(index=True)
    latitude = DoubleField()
    longitude = DoubleField()
    disappear_time = DateTimeField(index=True)

    class Meta:
        indexes = ((('latitude', 'longitude'), False), )

    @staticmethod
    def get_active(swLat, swLng, neLat, neLng):
        if swLat is None or swLng is None or neLat is None or neLng is None:
            query = (Pokemon.select().where(
                Pokemon.disappear_time > datetime.utcnow()).dicts())
        else:
            query = (Pokemon.select().where(
                (Pokemon.disappear_time > datetime.utcnow())
                & (((Pokemon.latitude >= swLat) & (Pokemon.longitude >= swLng)
                    & (Pokemon.latitude <= neLat)
                    & (Pokemon.longitude <= neLng)))).dicts())

        # Performance: Disable the garbage collector prior to creating a (potentially) large dict with append()
        gc.disable()

        pokemons = []
        for p in query:
            p['pokemon_name'] = get_pokemon_name(p['pokemon_id'])
            p['pokemon_rarity'] = get_pokemon_rarity(p['pokemon_id'])
            p['pokemon_types'] = get_pokemon_types(p['pokemon_id'])
            if args.china:
                p['latitude'], p['longitude'] = \
                    transform_from_wgs_to_gcj(p['latitude'], p['longitude'])
            pokemons.append(p)

        # Re-enable the GC.
        gc.enable()

        return pokemons

    @staticmethod
    def get_active_by_id(ids, swLat, swLng, neLat, neLng):
        if swLat is None or swLng is None or neLat is None or neLng is None:
            query = (Pokemon.select().where((Pokemon.pokemon_id << ids) & (
                Pokemon.disappear_time > datetime.utcnow())).dicts())
        else:
            query = (Pokemon.select().where(
                (Pokemon.pokemon_id << ids)
                & (Pokemon.disappear_time > datetime.utcnow())
                & (Pokemon.latitude >= swLat) & (Pokemon.longitude >= swLng)
                & (Pokemon.latitude <= neLat)
                & (Pokemon.longitude <= neLng)).dicts())

        # Performance: Disable the garbage collector prior to creating a (potentially) large dict with append()
        gc.disable()

        pokemons = []
        for p in query:
            p['pokemon_name'] = get_pokemon_name(p['pokemon_id'])
            p['pokemon_rarity'] = get_pokemon_rarity(p['pokemon_id'])
            p['pokemon_types'] = get_pokemon_types(p['pokemon_id'])
            if args.china:
                p['latitude'], p['longitude'] = \
                    transform_from_wgs_to_gcj(p['latitude'], p['longitude'])
            pokemons.append(p)

        # Re-enable the GC.
        gc.enable()

        return pokemons

    @classmethod
    def get_seen(cls, timediff):
        if timediff:
            timediff = datetime.utcnow() - timediff
        pokemon_count_query = (Pokemon.select(
            Pokemon.pokemon_id,
            fn.COUNT(Pokemon.pokemon_id).alias('count'),
            fn.MAX(Pokemon.disappear_time).alias('lastappeared')).where(
                Pokemon.disappear_time > timediff).group_by(
                    Pokemon.pokemon_id).alias('counttable'))
        query = (Pokemon.select(
            Pokemon.pokemon_id, Pokemon.disappear_time, Pokemon.latitude,
            Pokemon.longitude, pokemon_count_query.c.count).join(
                pokemon_count_query,
                on=(Pokemon.pokemon_id == pokemon_count_query.c.pokemon_id
                    )).distinct().where(
                        Pokemon.disappear_time ==
                        pokemon_count_query.c.lastappeared).dicts())

        # Performance: Disable the garbage collector prior to creating a (potentially) large dict with append()
        gc.disable()

        pokemons = []
        total = 0
        for p in query:
            p['pokemon_name'] = get_pokemon_name(p['pokemon_id'])
            pokemons.append(p)
            total += p['count']

        # Re-enable the GC.
        gc.enable()

        return {'pokemon': pokemons, 'total': total}

    @classmethod
    def get_appearances(cls, pokemon_id, last_appearance, timediff):
        '''
        :param pokemon_id: id of pokemon that we need appearances for
        :param last_appearance: time of last appearance of pokemon after which we are getting appearances
        :param timediff: limiting period of the selection
        :return: list of  pokemon  appearances over a selected period
        '''
        if timediff:
            timediff = datetime.utcnow() - timediff
        query = (Pokemon.select().where(
            (Pokemon.pokemon_id == pokemon_id)
            & (Pokemon.disappear_time > datetime.utcfromtimestamp(
                last_appearance / 1000.0))
            & (Pokemon.disappear_time > timediff)).order_by(
                Pokemon.disappear_time.asc()).dicts())

        return list(query)

    @classmethod
    def get_spawnpoints(cls, southBoundary, westBoundary, northBoundary,
                        eastBoundary):
        query = Pokemon.select(Pokemon.latitude, Pokemon.longitude,
                               Pokemon.spawnpoint_id)

        if None not in (northBoundary, southBoundary, westBoundary,
                        eastBoundary):
            query = (query.where((Pokemon.latitude <= northBoundary)
                                 & (Pokemon.latitude >= southBoundary)
                                 & (Pokemon.longitude >= westBoundary)
                                 & (Pokemon.longitude <= eastBoundary)))

        # Sqlite doesn't support distinct on columns
        if args.db_type == 'mysql':
            query = query.distinct(Pokemon.spawnpoint_id)
        else:
            query = query.group_by(Pokemon.spawnpoint_id)

        return list(query.dicts())

    @classmethod
    def get_spawnpoints_in_hex(cls, center, steps):
        log.info('Finding spawn points {} steps away'.format(steps))

        n, e, s, w = hex_bounds(center, steps)

        query = (Pokemon.select(Pokemon.latitude.alias('lat'),
                                Pokemon.longitude.alias('lng'),
                                ((Pokemon.disappear_time.minute * 60) +
                                 Pokemon.disappear_time.second).alias('time'),
                                Pokemon.spawnpoint_id))
        query = (query.where((Pokemon.latitude <= n) & (Pokemon.latitude >= s)
                             & (Pokemon.longitude >= w)
                             & (Pokemon.longitude <= e)))
        # Sqlite doesn't support distinct on columns
        if args.db_type == 'mysql':
            query = query.distinct(Pokemon.spawnpoint_id)
        else:
            query = query.group_by(Pokemon.spawnpoint_id)

        s = list(query.dicts())

        # Filter to spawns which actually fall in the hex locations
        # This loop is about as non-pythonic as you can get, I bet.
        # Oh well.
        filtered = []
        hex_locations = list(generate_location_steps(center, steps, 0.07))
        for hl in hex_locations:
            for idx, sp in enumerate(s):
                if geopy.distance.distance(
                        hl, (sp['lat'], sp['lng'])).meters <= 70:
                    filtered.append(s.pop(idx))

        # at this point, 'time' is DISAPPEARANCE time, we're going to morph it to APPEARANCE time
        for location in filtered:
            # examples: time    shifted
            #           0       (   0 + 2700) = 2700 % 3600 = 2700 (0th minute to 45th minute, 15 minutes prior to appearance as time wraps around the hour)
            #           1800    (1800 + 2700) = 4500 % 3600 =  900 (30th minute, moved to arrive at 15th minute)
            # todo: this DOES NOT ACCOUNT for pokemons that appear sooner and live longer, but you'll _always_ have at least 15 minutes, so it works well enough
            location['time'] = (location['time'] + 2700) % 3600

        return filtered
Exemplo n.º 12
0
class Trainer(BaseModel):
    name = CharField(primary_key=True)
    team = IntegerField()
    level = IntegerField()
    last_seen = DateTimeField(default=datetime.utcnow)
Exemplo n.º 13
0
class Gym(BaseModel):
    UNCONTESTED = 0
    TEAM_MYSTIC = 1
    TEAM_VALOR = 2
    TEAM_INSTINCT = 3

    gym_id = CharField(primary_key=True, max_length=50)
    team_id = IntegerField()
    guard_pokemon_id = IntegerField()
    gym_points = IntegerField()
    enabled = BooleanField()
    latitude = DoubleField()
    longitude = DoubleField()
    last_modified = DateTimeField(index=True)
    last_scanned = DateTimeField(default=datetime.utcnow)

    class Meta:
        indexes = ((('latitude', 'longitude'), False), )

    @staticmethod
    def get_gyms(swLat, swLng, neLat, neLng):
        if swLat is None or swLng is None or neLat is None or neLng is None:
            results = (Gym.select().dicts())
        else:
            results = (Gym.select().where((Gym.latitude >= swLat)
                                          & (Gym.longitude >= swLng)
                                          & (Gym.latitude <= neLat)
                                          & (Gym.longitude <= neLng)).dicts())

        # Performance: Disable the garbage collector prior to creating a (potentially) large dict with append()
        gc.disable()

        gyms = {}
        gym_ids = []
        for g in results:
            g['name'] = None
            g['pokemon'] = []
            gyms[g['gym_id']] = g
            gym_ids.append(g['gym_id'])

        if len(gym_ids) > 0:
            pokemon = (
                GymMember.select(GymMember.gym_id,
                                 GymPokemon.cp.alias('pokemon_cp'),
                                 GymPokemon.pokemon_id,
                                 Trainer.name.alias('trainer_name'),
                                 Trainer.level.alias('trainer_level')).
                join(Gym, on=(GymMember.gym_id == Gym.gym_id)).join(
                    GymPokemon,
                    on=(GymMember.pokemon_uid == GymPokemon.pokemon_uid)).join(
                        Trainer, on=(GymPokemon.trainer_name == Trainer.name))
                .where(GymMember.gym_id << gym_ids).where(
                    GymMember.last_scanned > Gym.last_modified).order_by(
                        GymMember.gym_id, GymPokemon.cp).dicts())

            for p in pokemon:
                p['pokemon_name'] = get_pokemon_name(p['pokemon_id'])
                gyms[p['gym_id']]['pokemon'].append(p)

            details = (GymDetails.select(
                GymDetails.gym_id,
                GymDetails.name).where(GymDetails.gym_id << gym_ids).dicts())

            for d in details:
                gyms[d['gym_id']]['name'] = d['name']

        # Re-enable the GC.
        gc.enable()

        return gyms
Exemplo n.º 14
0
class MainWorker(BaseModel):
    worker_name = CharField(primary_key=True, max_length=50)
    message = CharField()
    method = CharField(max_length=50)
    last_modified = DateTimeField(index=True)
Exemplo n.º 15
0
class BaseModel(Model):
    created_at = DateTimeField(default=datetime.datetime.now)

    class Meta:
        database = db
Exemplo n.º 16
0
Arquivo: api.py Projeto: hiway/piebus
class BaseModel(Model):
    timestamp = DateTimeField(default=datetime.datetime.utcnow, index=True)

    class Meta:
        database = db
Exemplo n.º 17
0
class Person(BaseModel):
    name = CharField()
    email = CharField()
    create_datetime = DateTimeField(default=datetime.datetime.now, null=True)
Exemplo n.º 18
0
class Plant(BaseModel):
    """
    A plant, i.e. the whole purpose of this application.
    """

    user = ForeignKeyField(User, backref="plants")
    user_active = ForeignKeyField(User,
                                  null=True,
                                  unique=True,
                                  backref="active_plants")
    created_at = DateTimeField(default=datetime.now)
    updated_at = DateTimeField(default=datetime.now)
    watered_at = DateTimeField(
        default=lambda: datetime.now() - timedelta(days=1))
    watered_by = ForeignKeyField(User, null=True)
    generation = IntegerField(default=1)
    score = IntegerField(default=0)
    stage = IntegerField(default=0)
    species = IntegerField(
        default=lambda: random.randrange(len(constants.SPECIES)))
    rarity = IntegerField(default=_default_rarity)
    color = IntegerField(
        default=lambda: random.randrange(len(constants.COLORS)))
    mutation = IntegerField(null=True)
    dead = BooleanField(default=False)
    name = TextField(default=fake.first_name)
    fertilized_at = DateTimeField(
        default=lambda: datetime.now() - timedelta(days=4))
    shaken_at = IntegerField(default=0)

    @classmethod
    def all_active(cls):
        return cls.filter(cls.user_active.is_null(False)).join(User)

    @property
    def color_str(self) -> str:
        return constants.COLORS[self.color]

    @property
    def stage_str(self) -> str:
        return constants.STAGES[self.stage]

    @property
    def species_str(self) -> str:
        return constants.SPECIES[self.species]

    @property
    def rarity_str(self) -> str:
        return constants.RARITIES[self.rarity]

    @property
    def mutation_str(self) -> Optional[str]:
        if self.mutation is not None:
            return constants.MUTATIONS[self.mutation]
        else:
            return None

    @property
    def description(self) -> str:
        """
        A single-line description of the plant and all of its attributes.
        """
        words: List[str] = []
        if self.stage > 2:
            words.append(self.rarity_str)
        if self.mutation_str is not None:
            words.append(self.mutation_str)
        if self.stage > 3:
            words.append(self.color_str)
        words.append(self.stage_str)
        if self.stage > 1:
            words.append(self.species_str)
        if self.dead:
            words.append("(deceased)")
        return " ".join(words)

    @property
    def age(self) -> int:
        """
        The plant's age in days.
        """
        return (datetime.now() - self.created_at).days

    @property
    def growth_rate(self) -> float:
        """
        A growth multiplier based on the plant's generation.
        """
        return 1 + 0.2 * (self.generation - 1)

    @property
    def is_wilted(self) -> bool:
        """
        Is the plant close to death?
        """
        if self.dead:
            return False
        else:
            return self.watered_at < datetime.now() - timedelta(days=3)

    @property
    def water_supply_percent(self) -> int:
        """
        The percentage of water supply remaining, as an integer from 0 to 100.
        """
        seconds_per_day = 24 * 60 * 60
        elapsed_seconds = (datetime.now() - self.watered_at).total_seconds()
        remaining_water = max(0.0, 1 - (elapsed_seconds / seconds_per_day))
        return math.ceil(remaining_water * 100)

    @property
    def fertilizer_percent(self) -> int:
        """
        The percentage of fertilizer remaining, as an integer from 0 to 100.
        """
        seconds_per_day = 3 * 24 * 60 * 60
        elapsed_seconds = (datetime.now() - self.fertilized_at).total_seconds()
        remaining_fertilizer = max(0.0,
                                   1 - (elapsed_seconds / seconds_per_day))
        return math.ceil(remaining_fertilizer * 100)

    def can_fertilize(self) -> bool:
        """
        Return if the user can apply fertilizer to the plant.
        """
        if self.dead:
            return False
        elif self.fertilizer_percent:
            return False
        elif not self.user_active.get_item_quantity(items.fertilizer):
            return False
        else:
            return True

    def get_water_gauge(self, ansi_enabled: bool = False) -> str:
        """
        Build an ascii graph that displays the plant's remaining water supply.
        """
        if self.dead:
            return "N/A"

        percent = self.water_supply_percent
        bar = ("█" * (percent // 10)).ljust(10)
        if ansi_enabled:
            # Make the water blue
            bar = colorize(bar, fg=12)
        return f"|{bar}| {percent}%"

    def get_fertilizer_gauge(self, ansi_enabled: bool = False) -> str:
        """
        Build an ascii graph that displays the plant's remaining fertilizer.
        """
        if self.dead:
            return "N/A"

        percent = self.fertilizer_percent
        bar = ("▞" * (percent // 10)).ljust(10)
        if ansi_enabled:
            # Make the fertilizer purple
            bar = colorize(bar, fg=40)
        return f"|{bar}| {percent}%"

    def get_ascii_art(self, ansi_enabled: bool = False) -> str:
        """
        Build an ascii-art picture based on the plant's generation and species.
        """
        today = date.today()
        if self.dead:
            filename = "rip.psci"
        elif (today.month, today.day) == (10, 31):
            filename = "jackolantern.psci"
        elif self.stage == 0:
            filename = "seed.psci"
        elif self.stage == 1:
            filename = "seedling.psci"
        elif self.stage == 2:
            filename = f"{self.species_str.replace(' ', '')}1.psci"
        elif self.stage in (3, 5):
            filename = f"{self.species_str.replace(' ', '')}2.psci"
        elif self.stage == 4:
            filename = f"{self.species_str.replace(' ', '')}3.psci"
        else:
            raise ValueError("Unknown stage")

        return render_art(filename, self.color_str, ansi_enabled)

    def get_observation(self, ansi_enabled: bool = False) -> str:
        """
        A long-form description of the plant.

        This includes a random observations and other specific details about
        the plant's current stage.
        """
        observation = []

        stage = 99 if self.dead else self.stage

        desc = random.choice(constants.STAGE_DESCRIPTIONS[stage])
        desc = desc.format(color=self.color_str, species=self.species_str)
        observation.append(desc)

        if stage < len(constants.STAGES) - 2:
            last_cutoff = constants.STAGE_CUTOFFS[stage]
            next_cutoff = constants.STAGE_CUTOFFS[stage + 1]
            if (self.score - last_cutoff) > 0.8 * (next_cutoff - last_cutoff):
                observation.append("You notice your plant looks different.")

        if stage == 1:
            choices = [
                constants.SPECIES[self.species],
                constants.SPECIES[(self.species - 3) % len(constants.SPECIES)],
                constants.SPECIES[(self.species + 3) % len(constants.SPECIES)],
            ]
            random.shuffle(choices)
            hint = f"It could be a(n) {choices[0]}, {choices[1]}, or {choices[2]}."
            observation.append(hint)

        elif stage == 2:
            if self.rarity > 0:
                observation.append("You feel like your plant is special.")

        elif stage == 3:
            choices = [
                constants.COLORS[self.color],
                constants.COLORS[(self.color - 3) % len(constants.COLORS)],
                constants.COLORS[(self.color + 3) % len(constants.COLORS)],
            ]
            random.shuffle(choices)
            hint = f"You can see the first hints of {choices[0]}, {choices[1]}, or {choices[2]}."
            observation.append(hint)

        return "\n".join(observation)

    def refresh(self) -> None:
        """
        Update the internal state of the plant.

        This will recompute the plant's score, remaining water supply,
        mutations, any evolutions that should be happening, etc...
        """
        last_updated = self.updated_at
        self.updated_at = datetime.now()

        # If it has been >5 days since watering, sorry plant is dead :(
        if self.updated_at - self.watered_at >= timedelta(days=5):
            self.dead = True
            return

        # Add a tick for every second since we last updated, up to 24 hours
        # after the last time the plant was watered
        min_time = max((self.watered_at, last_updated))
        max_time = min((self.watered_at + timedelta(days=1), self.updated_at))
        ticks = max((0, (max_time - min_time).total_seconds()))

        # Add a multiplier for fertilizer, up to 3 days after the last time
        # that the plant was fertilized
        min_time = max((self.fertilized_at, last_updated, self.watered_at))
        max_time = min((
            self.fertilized_at + timedelta(days=3),
            self.watered_at + timedelta(days=1),
            self.updated_at,
        ))
        bonus_ticks = max((0, (max_time - min_time).total_seconds()))
        ticks += bonus_ticks * 0.5

        ticks *= self.growth_rate
        ticks = int(ticks)
        self.score += ticks

        # Roll for a new mutation
        if self.mutation is None:
            coefficient = 200_000
            if random.random() > ((coefficient - 1) / coefficient)**ticks:
                self.mutation = random.randrange(len(constants.MUTATIONS))

        # Evolutions
        while self.stage < len(constants.STAGES) - 1:
            if self.score >= constants.STAGE_CUTOFFS[self.stage + 1]:
                self.stage += 1
            else:
                break

    def water(self, user: User = None) -> str:
        """
        Attempt to water the plant.

        Args:
            user: The user watering the plant, if not the plant's owner.

        Returns: A string with a description of the resulting action.
        """
        if self.dead:
            return "There's no point in watering a dead plant."
        elif self.water_supply_percent == 100:
            return "The soil is already damp."

        if user is None:
            self.watered_at = datetime.now()
            self.watered_by = None
            return "You sprinkle some water over your plant."

        query = Plant.select().where(
            Plant.watered_by == user,
            Plant.watered_at >= datetime.now() - timedelta(hours=0.5),
        )
        if query.exists():
            return "Your watering can is empty, try again later!"

        self.watered_at = datetime.now()
        self.watered_by = user
        info = f"You water {self.user.username}'s plant for them."

        return info

    def pick_petal(self, user: User = None) -> str:
        """
        Pick a petal from a flowering plant.

        Args:
            user: The user picking the petal, if not the plant's owner.

        Returns: A string with a description of the resulting action.
        """
        if self.dead:
            return "You shouldn't be here!"
        elif self.stage_str != "flowering":
            return "You shouldn't be here!"

        if user is None:
            user = self.user

        target = f"plant_{self.id}"

        last_event = Event.select().where(
            Event.user == user,
            Event.created_at >= datetime.now() - timedelta(days=1),
            Event.event_type == Event.PICK_PETAL,
            Event.target == target,
        )
        if last_event.exists():
            return "The ground around this plant is bare, come back tomorrow!"

        Event.create(user=user, event_type=Event.PICK_PETAL, target=target)

        if self.color_str == "rainbow":
            petal_color = random.choice(constants.COLORS_PLAIN)
        else:
            petal_color = self.color_str

        user.add_item(items.petals[petal_color])

        lines = (
            f"You spot a [{petal_color} petal] lying on the ground nearby.",
            "You pick it up and stick it in your backpack.",
        )
        return "\n".join(lines)

    def shake(self) -> str:
        """
        Shake the user's own plant to get money.

        Coins are accumulated at a rate of 1 coin per 3600 points, which is
        equal to 1 un-adjusted hour of watered plant time.
        """
        multiplier = 3600

        coins = (self.score - self.shaken_at) // multiplier

        # Leave fractional coins unclaimed
        self.shaken_at += coins * multiplier

        # Hard-cap to encourage users to shake every once and a while
        coins = min(coins, 100)

        if coins:
            self.user.add_item(items.coin, quantity=coins)

        if coins < 1:
            msg = "but nothing happens."
        elif coins < 2:
            msg = "and you hear the plink of a single coin."
        elif coins < 5:
            msg = "and a few coins come loose from the leaves."
        elif coins < 25:
            msg = "and a handful of coins sprinkle down."
        elif coins < 99:
            msg = "and coins shower down all around."
        else:
            msg = "and a golden nugget clonks you on the head."

        return f"You shake your plant, {msg}\n(+{coins} coins)"

    def fertilize(self) -> str:
        """
        Attempt to fertilize the plant.

        Returns: A string with a description of the resulting action.
        """
        if self.dead:
            return "It's time to let go."
        elif self.fertilizer_percent:
            return "The soil is still rich with nutrients."

        if not self.user.remove_item(items.fertilizer):
            return "You don't have any fertilizer to apply."

        self.fertilized_at = datetime.now()
        return "You apply a bottle of fertilizer to your plant."

    def harvest(self) -> Plant:
        """
        Harvest the plant and generate a new active plant for the user.
        """
        if self.stage == 5:
            new_generation = self.generation + 1
        else:
            new_generation = 1

        self.dead = True
        self.user_active = None
        self.save()

        return self.__class__.create(user=self.user,
                                     user_active=self.user,
                                     generation=new_generation)
Exemplo n.º 19
0
    class DbTickData(ModelBase):
        """
        Tick data for database storage.

        Index is defined unique with (datetime, symbol)
        """

        id = AutoField()

        symbol: str = CharField()
        exchange: str = CharField()
        datetime: datetime = DateTimeField()

        name: str = CharField()
        volume: float = FloatField()
        open_interest: float = FloatField()
        last_price: float = FloatField()
        last_volume: float = FloatField()
        limit_up: float = FloatField()
        limit_down: float = FloatField()

        open_price: float = FloatField()
        high_price: float = FloatField()
        low_price: float = FloatField()
        pre_close: float = FloatField()

        bid_price_1: float = FloatField()
        bid_price_2: float = FloatField(null=True)
        bid_price_3: float = FloatField(null=True)
        bid_price_4: float = FloatField(null=True)
        bid_price_5: float = FloatField(null=True)

        ask_price_1: float = FloatField()
        ask_price_2: float = FloatField(null=True)
        ask_price_3: float = FloatField(null=True)
        ask_price_4: float = FloatField(null=True)
        ask_price_5: float = FloatField(null=True)

        bid_volume_1: float = FloatField()
        bid_volume_2: float = FloatField(null=True)
        bid_volume_3: float = FloatField(null=True)
        bid_volume_4: float = FloatField(null=True)
        bid_volume_5: float = FloatField(null=True)

        ask_volume_1: float = FloatField()
        ask_volume_2: float = FloatField(null=True)
        ask_volume_3: float = FloatField(null=True)
        ask_volume_4: float = FloatField(null=True)
        ask_volume_5: float = FloatField(null=True)

        class Meta:
            database = db
            indexes = ((("symbol", "exchange", "datetime"), True), )

        @staticmethod
        def from_tick(tick: TickData):
            """
            Generate DbTickData object from TickData.
            """
            db_tick = DbTickData()

            db_tick.symbol = tick.symbol
            db_tick.exchange = tick.exchange.value
            db_tick.datetime = tick.datetime
            db_tick.name = tick.name
            db_tick.volume = tick.volume
            db_tick.open_interest = tick.open_interest
            db_tick.last_price = tick.last_price
            db_tick.last_volume = tick.last_volume
            db_tick.limit_up = tick.limit_up
            db_tick.limit_down = tick.limit_down
            db_tick.open_price = tick.open_price
            db_tick.high_price = tick.high_price
            db_tick.low_price = tick.low_price
            db_tick.pre_close = tick.pre_close

            db_tick.bid_price_1 = tick.bid_price_1
            db_tick.ask_price_1 = tick.ask_price_1
            db_tick.bid_volume_1 = tick.bid_volume_1
            db_tick.ask_volume_1 = tick.ask_volume_1

            if tick.bid_price_2:
                db_tick.bid_price_2 = tick.bid_price_2
                db_tick.bid_price_3 = tick.bid_price_3
                db_tick.bid_price_4 = tick.bid_price_4
                db_tick.bid_price_5 = tick.bid_price_5

                db_tick.ask_price_2 = tick.ask_price_2
                db_tick.ask_price_3 = tick.ask_price_3
                db_tick.ask_price_4 = tick.ask_price_4
                db_tick.ask_price_5 = tick.ask_price_5

                db_tick.bid_volume_2 = tick.bid_volume_2
                db_tick.bid_volume_3 = tick.bid_volume_3
                db_tick.bid_volume_4 = tick.bid_volume_4
                db_tick.bid_volume_5 = tick.bid_volume_5

                db_tick.ask_volume_2 = tick.ask_volume_2
                db_tick.ask_volume_3 = tick.ask_volume_3
                db_tick.ask_volume_4 = tick.ask_volume_4
                db_tick.ask_volume_5 = tick.ask_volume_5

            return db_tick

        def to_tick(self):
            """
            Generate TickData object from DbTickData.
            """
            tick = TickData(
                symbol=self.symbol,
                exchange=Exchange(self.exchange),
                datetime=self.datetime,
                name=self.name,
                volume=self.volume,
                open_interest=self.open_interest,
                last_price=self.last_price,
                last_volume=self.last_volume,
                limit_up=self.limit_up,
                limit_down=self.limit_down,
                open_price=self.open_price,
                high_price=self.high_price,
                low_price=self.low_price,
                pre_close=self.pre_close,
                bid_price_1=self.bid_price_1,
                ask_price_1=self.ask_price_1,
                bid_volume_1=self.bid_volume_1,
                ask_volume_1=self.ask_volume_1,
                gateway_name="DB",
            )

            if self.bid_price_2:
                tick.bid_price_2 = self.bid_price_2
                tick.bid_price_3 = self.bid_price_3
                tick.bid_price_4 = self.bid_price_4
                tick.bid_price_5 = self.bid_price_5

                tick.ask_price_2 = self.ask_price_2
                tick.ask_price_3 = self.ask_price_3
                tick.ask_price_4 = self.ask_price_4
                tick.ask_price_5 = self.ask_price_5

                tick.bid_volume_2 = self.bid_volume_2
                tick.bid_volume_3 = self.bid_volume_3
                tick.bid_volume_4 = self.bid_volume_4
                tick.bid_volume_5 = self.bid_volume_5

                tick.ask_volume_2 = self.ask_volume_2
                tick.ask_volume_3 = self.ask_volume_3
                tick.ask_volume_4 = self.ask_volume_4
                tick.ask_volume_5 = self.ask_volume_5

            return tick

        @staticmethod
        def save_all(objs: List["DbTickData"]):
            dicts = [i.to_dict() for i in objs]
            with db.atomic():
                if driver is Driver.POSTGRESQL:
                    for tick in dicts:
                        DbTickData.insert(tick).on_conflict(
                            update=tick,
                            conflict_target=(
                                DbTickData.symbol,
                                DbTickData.exchange,
                                DbTickData.datetime,
                            ),
                        ).execute()
                else:
                    for c in chunked(dicts, 50):
                        DbTickData.insert_many(
                            c).on_conflict_replace().execute()
Exemplo n.º 20
0
class User(BaseModel):
    """
    A user account corresponding to a TLS client certificate.
    """

    user_id = TextField(unique=True, index=True, default=gen_user_id)
    username = TextField()
    created_at = DateTimeField(default=datetime.now)
    ansi_enabled = BooleanField(default=False)  # TODO: Delete this field
    password = BlobField(null=True)

    @classmethod
    def admin(cls) -> User:
        user, _ = cls.get_or_create(user_id="0" * 32, username="******")
        return user

    @classmethod
    def initialize(cls, username: str) -> User:
        """
        Register a new player.
        """
        user = cls.create(username=username)
        user.add_item(items.paperclip)
        user.add_item(items.fertilizer, quantity=1)

        subject, body = Inbox.load_mail_file("welcome.txt")
        body = body.format(user=user)
        Inbox.create(
            user_from=User.admin(),
            user_to=user,
            subject=subject,
            body=body,
        )
        return user

    @classmethod
    def login(cls, fingerprint: str) -> Optional[Certificate]:
        """
        Load a user from their certificate fingerprint.

        Join on the active_plant to avoid making an extra query, since we will
        almost always access the user's plant later.
        """
        query = (Certificate.select().join(
            User, on=Certificate.user == User.id).join(
                Plant, JOIN.LEFT_OUTER, on=Plant.user_active == User.id).where(
                    Certificate.fingerprint == fingerprint))

        try:
            cert = query.get()
            cert.update(last_seen=datetime.now())
            cert.save()
        except Certificate.DoesNotExist:
            cert = None

        return cert

    @property
    def plant(self) -> Plant:
        """
        Return the user's current "active" plant, or generate a new one.

        This is cached locally to avoid unnecessary DB lookups.
        """
        if not hasattr(self, "_plant"):
            try:
                self._plant = self.active_plants.get()
            except Plant.DoesNotExist:
                self._plant = Plant.create(user=self, user_active=self)

        return self._plant

    def set_password(self, password: str) -> None:
        self.password = bcrypt.hashpw(password.encode(), bcrypt.gensalt())

    def check_password(self, password: str) -> bool:
        if not self.password:
            return False
        return bcrypt.checkpw(password.encode(), self.password)

    def add_item(self, item: items.Item, quantity: int = 1) -> ItemSlot:
        """
        Add an item to the user's inventory.
        """
        item_slot, _ = ItemSlot.get_or_create(user=self, item_id=item.item_id)
        item_slot.quantity += quantity
        item_slot.save()
        return item_slot

    def remove_item(self, item: items.Item, quantity: int = 1) -> bool:
        """
        Remove an item from the user's inventory.

        Returns True if the item was successfully removed.
        """
        item_slot = ItemSlot.get_or_none(user=self, item_id=item.item_id)
        if not item_slot:
            return False

        if item_slot.quantity < quantity:
            return False

        if item_slot.quantity == quantity:
            item_slot.delete_instance()
            return True

        item_slot.quantity -= quantity
        item_slot.save()
        return True

    def get_item_quantity(self, item: items.Item) -> int:
        """
        Return the number of items in the user's inventory.
        """
        item_slot = ItemSlot.get_or_none(user=self, item_id=item.item_id)
        if item_slot:
            return item_slot.quantity

        return 0
Exemplo n.º 21
0
class Game(BaseModel):
    name = TextField()
    platform = TextField()
    category = TextField()
    append_datetime = DateTimeField()
    finish_datetime = DateTimeField(null=True)
    ignored = BooleanField(default=False)
    root_alias = ForeignKeyField('self', null=True)

    class Meta:
        indexes = ((("name", "platform", "category"), True), )

    @classmethod
    def get_all_by(cls, **filters) -> List['Game']:
        return list(cls.select().filter(**filters).order_by(cls.id))

    def get_first_root(self) -> 'Game':
        # Идем вверх пока не найдем самую первую игру
        root_alias = self.root_alias
        while root_alias:
            # Если у текущей игры нет псевдонима
            if not root_alias.root_alias:
                break

            root_alias = root_alias.root_alias

        return root_alias

    @property
    def append_datetime_dt(self) -> Union[DT.datetime, DateTimeField]:
        append_datetime = self.append_datetime

        root_alias = self.get_first_root()
        if root_alias and root_alias.append_datetime is not None:
            append_datetime = root_alias.append_datetime

        if isinstance(append_datetime, str):
            return DT.datetime.fromisoformat(append_datetime)

        return append_datetime

    @property
    def finish_datetime_dt(self) -> Union[DT.datetime, DateTimeField]:
        finish_datetime = self.finish_datetime

        root_alias = self.get_first_root()
        if root_alias and root_alias.finish_datetime is not None:
            finish_datetime = root_alias.finish_datetime

        if isinstance(finish_datetime, str):
            return DT.datetime.fromisoformat(finish_datetime)

        return finish_datetime

    @classmethod
    def get_all_finished_by_year(cls, year: int) -> Iterator['Game']:
        query = (cls.select().where(cls.finish_datetime.is_null(False),
                                    cls.ignored == 0).order_by(
                                        cls.finish_datetime.desc()))
        return [game for game in query if game.finish_datetime_dt.year == year]

    @classmethod
    def get_year_by_number(cls) -> List[Tuple[int, int]]:
        fn_year = fn.strftime('%Y', cls.finish_datetime).cast('INTEGER')

        year_by_number = []
        for game in (cls.select(
                fn_year.alias('year'),
                fn.count(cls.id).alias('count')).where(
                    cls.finish_datetime.is_null(False),
                    cls.ignored == 0).group_by(fn_year).order_by(
                        fn_year.desc())):
            year_by_number.append((game.year, game.count))

        return year_by_number

    @classmethod
    def get_day_by_games(cls, year: int) -> Dict[str, List['Game']]:
        day_by_games = defaultdict(list)

        for game in Game.get_all_finished_by_year(year):
            day = game.finish_datetime_dt.strftime('%d/%m/%Y')
            day_by_games[day].append(game)

        return day_by_games
Exemplo n.º 22
0
def add_plant_fertilized_at(migrator):
    dt = datetime.now() - timedelta(days=4)
    migrate.migrate(
        migrator.add_column("plant", "fertilized_at",
                            DateTimeField(default=dt)))
Exemplo n.º 23
0
class Infraction(BaseModel):
    Types = Enum(
        'MUTE',
        'KICK',
        'TEMPBAN',
        'SOFTBAN',
        'BAN',
        'TEMPMUTE',
        'UNBAN',
        'TEMPROLE',
        'WARNING',
        bitmask=False,
    )

    guild_id = BigIntegerField()
    user_id = BigIntegerField()
    actor_id = BigIntegerField(null=True)

    type_ = IntegerField(column_name='type')
    reason = TextField(null=True)
    metadata = BinaryJSONField(default={})

    expires_at = DateTimeField(null=True)
    created_at = DateTimeField(default=datetime.utcnow)
    active = BooleanField(default=True)

    class Meta:
        table_name = 'infractions'

        indexes = ((('guild_id', 'user_id'), False), )

    def serialize(self,
                  guild=None,
                  user=None,
                  actor=None,
                  include_metadata=False):
        base = {
            'id': str(self.id),
            'guild': (guild and guild.serialize()) or {
                'id': str(self.guild_id)
            },
            'user': (user and user.serialize()) or {
                'id': str(self.user_id)
            },
            'actor': (actor and actor.serialize()) or {
                'id': str(self.actor_id)
            },
            'reason': self.reason,
            'expires_at': self.expires_at,
            'created_at': self.created_at,
            'active': self.active,
            'type': {
                'id':
                self.type_,
                'name':
                next(i.name for i in Infraction.Types.attrs
                     if i.index == self.type_)
            }
        }

        if include_metadata:
            base['metadata'] = self.metadata

        return base

    @staticmethod
    def admin_config(event):
        return getattr(event.base_config.plugins, 'admin', None)

    @classmethod
    def temprole(cls, plugin, event, member, role_id, reason, expires_at):
        User.from_disco_user(member.user)

        # TODO: modlog

        member.add_role(role_id, reason=reason)

        cls.create(guild_id=event.guild.id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.TEMPROLE,
                   reason=reason,
                   expires_at=expires_at,
                   metadata={'role': role_id})

    @classmethod
    def kick(cls, plugin, event, member, reason):
        from rowboat.plugins.modlog import Actions

        User.from_disco_user(member.user)

        # Prevent the GuildMemberRemove log event from triggering
        plugin.call('ModLogPlugin.create_debounce',
                    event, ['GuildMemberRemove'],
                    user_id=member.user.id)

        member.kick(reason=reason)

        # Create a kick modlog event
        plugin.call('ModLogPlugin.log_action_ext',
                    Actions.MEMBER_KICK,
                    event.guild.id,
                    member=member,
                    actor=event.author
                    if event.author.id != member.id else 'Automatic',
                    reason=reason or 'no reason')

        cls.create(guild_id=member.guild_id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.KICK,
                   reason=reason)

    @classmethod
    def tempban(cls, plugin, event, member, reason, expires_at):
        from rowboat.plugins.modlog import Actions
        User.from_disco_user(member.user)

        plugin.call('ModLogPlugin.create_debounce',
                    event, ['GuildMemberRemove', 'GuildBanAdd'],
                    user_id=member.user.id)

        member.ban(reason=reason)

        plugin.call(
            'ModLogPlugin.log_action_ext',
            Actions.MEMBER_TEMPBAN,
            event.guild.id,
            member=member,
            actor=event.author
            if event.author.id != member.id else 'Automatic',
            reason=reason or 'no reason',
            expires=expires_at,
        )

        cls.create(guild_id=member.guild_id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.TEMPBAN,
                   reason=reason,
                   expires_at=expires_at)

    @classmethod
    def softban(cls, plugin, event, member, reason):
        from rowboat.plugins.modlog import Actions
        User.from_disco_user(member.user)

        plugin.call('ModLogPlugin.create_debounce',
                    event,
                    ['GuildMemberRemove', 'GuildBanAdd', 'GuildBanRemove'],
                    user_id=member.user.id)

        member.ban(delete_message_days=7, reason=reason)
        member.unban(reason=reason)

        plugin.call('ModLogPlugin.log_action_ext',
                    Actions.MEMBER_SOFTBAN,
                    event.guild.id,
                    member=member,
                    actor=event.author
                    if event.author.id != member.id else 'Automatic',
                    reason=reason or 'no reason')

        cls.create(guild_id=member.guild_id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.SOFTBAN,
                   reason=reason)

    @classmethod
    def ban(cls, plugin, event, member, reason, guild, delete_message_days=0):
        from rowboat.plugins.modlog import Actions
        if isinstance(member, int):
            user_id = member
        else:
            User.from_disco_user(member.user)
            user_id = member.user.id

        plugin.call(
            'ModLogPlugin.create_debounce',
            event,
            ['GuildMemberRemove', 'GuildBanAdd'],
            user_id=user_id,
        )

        guild.create_ban(
            user_id,
            delete_message_days if delete_message_days <= 7 else 7,
            reason=reason)

        plugin.call(
            'ModLogPlugin.log_action_ext',
            Actions.MEMBER_BAN,
            guild.id,
            user=member,
            user_id=user_id,
            actor=event.author if event.author.id != user_id else 'Automatic',
            reason=reason or 'no reason')

        cls.create(guild_id=guild.id,
                   user_id=user_id,
                   actor_id=event.author.id,
                   type_=cls.Types.BAN,
                   reason=reason)

    @classmethod
    def warn(cls, plugin, event, member, reason, guild):
        from rowboat.plugins.modlog import Actions
        User.from_disco_user(member.user)
        user_id = member.user.id

        cls.create(guild_id=guild.id,
                   user_id=user_id,
                   actor_id=event.author.id,
                   type_=cls.Types.WARNING,
                   reason=reason)

        plugin.call('ModLogPlugin.log_action_ext',
                    Actions.MEMBER_WARNED,
                    event.guild.id,
                    member=member,
                    actor=event.author
                    if event.author.id != member.id else 'Automatic',
                    reason=reason or 'no reason')

    @classmethod
    def mute(cls, plugin, event, member, reason):
        from rowboat.plugins.modlog import Actions
        admin_config = cls.admin_config(event)

        if not admin_config.mute_role:
            plugin.log.warning('Cannot mute member {}, no mute role'.format(
                member.id))
            return

        plugin.call(
            'ModLogPlugin.create_debounce',
            event,
            ['GuildMemberUpdate'],
            user_id=member.user.id,
            role_id=admin_config.mute_role,
        )

        member.add_role(admin_config.mute_role, reason=reason)

        plugin.call('ModLogPlugin.log_action_ext',
                    Actions.MEMBER_MUTED,
                    event.guild.id,
                    member=member,
                    actor=event.author
                    if event.author.id != member.id else 'Automatic',
                    reason=reason or 'no reason')

        cls.create(guild_id=event.guild.id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.MUTE,
                   reason=reason,
                   metadata={'role': admin_config.mute_role})

    @classmethod
    def tempmute(cls, plugin, event, member, reason, expires_at):
        from rowboat.plugins.modlog import Actions
        admin_config = cls.admin_config(event)

        if not admin_config.mute_role:
            plugin.log.warning(
                'Cannot tempmute member {}, no mute role'.format(member.id))
            return

        plugin.call(
            'ModLogPlugin.create_debounce',
            event,
            ['GuildMemberUpdate'],
            user_id=member.user.id,
            role_id=admin_config.mute_role,
        )

        member.add_role(admin_config.mute_role, reason=reason)

        plugin.call(
            'ModLogPlugin.log_action_ext',
            Actions.MEMBER_TEMP_MUTED,
            event.guild.id,
            member=member,
            actor=event.author
            if event.author.id != member.id else 'Automatic',
            reason=reason or 'no reason',
            expires=expires_at,
        )

        cls.create(guild_id=event.guild.id,
                   user_id=member.user.id,
                   actor_id=event.author.id,
                   type_=cls.Types.TEMPMUTE,
                   reason=reason,
                   expires_at=expires_at,
                   metadata={'role': admin_config.mute_role})

    @classmethod
    def clear_active(cls, event, user_id, types):
        """
        Marks a previously active tempmute as inactive for the given event/user.
        This should be used in all locations where we either think this is no
        longer active (e.g. the mute role was removed) _or_ when we don't want to
        unmute the user any longer, e.g. they've been remuted by another command.
        """
        return cls.update(active=False).where(
            (cls.guild_id == event.guild.id) & (cls.user_id == user_id)
            & (cls.type_ << types) & (cls.active == 1)).execute() >= 1
Exemplo n.º 24
0
class Msg(BaseModel):
    tg_id = IntegerField()
    text = TextField()
    date = DateTimeField(default=datetime.now)
Exemplo n.º 25
0
class JoinTable(BaseModel):
    id = AutoField()
    code = CharField(unique=True, max_length=50)
    creation_time = DateTimeField(default=datetime.datetime.now)
    simple = ForeignKeyField(SimpleTable, backref='joins')
Exemplo n.º 26
0
class Message(BaseModel):
    content = TextField()
    channel_id = TextField()
    member = ForeignKeyField(Member, backref="messages")
    date = DateTimeField(default=datetime.datetime.now)
Exemplo n.º 27
0
class DbTickData(Model):
    """
    Tick data for database storage.

    Index is defined unique with vt_symbol, interval and datetime.
    """

    symbol = CharField()
    exchange = CharField()
    datetime = DateTimeField()

    name = CharField()
    volume = FloatField()
    last_price = FloatField()
    last_volume = FloatField()
    limit_up = FloatField()
    limit_down = FloatField()

    open_price = FloatField()
    high_price = FloatField()
    low_price = FloatField()
    close_price = FloatField()

    bid_price_1 = FloatField()
    bid_price_2 = FloatField()
    bid_price_3 = FloatField()
    bid_price_4 = FloatField()
    bid_price_5 = FloatField()

    ask_price_1 = FloatField()
    ask_price_2 = FloatField()
    ask_price_3 = FloatField()
    ask_price_4 = FloatField()
    ask_price_5 = FloatField()

    bid_volume_1 = FloatField()
    bid_volume_2 = FloatField()
    bid_volume_3 = FloatField()
    bid_volume_4 = FloatField()
    bid_volume_5 = FloatField()

    ask_volume_1 = FloatField()
    ask_volume_2 = FloatField()
    ask_volume_3 = FloatField()
    ask_volume_4 = FloatField()
    ask_volume_5 = FloatField()

    vt_symbol = CharField()
    gateway_name = CharField()

    class Meta:
        database = DB
        indexes = ((("vt_symbol", "datetime"), True), )

    @staticmethod
    def from_tick(tick: TickData):
        """
        Generate DbTickData object from TickData.
        """
        db_tick = DbTickData()

        db_tick.symbol = tick.symbol
        db_tick.exchange = tick.exchange.value
        db_tick.datetime = tick.datetime
        db_tick.name = tick.name
        db_tick.volume = tick.volume
        db_tick.last_price = tick.last_price
        db_tick.last_volume = tick.last_volume
        db_tick.limit_up = tick.limit_up
        db_tick.limit_down = tick.limit_down
        db_tick.open_price = tick.open_price
        db_tick.high_price = tick.high_price
        db_tick.low_price = tick.low_price
        db_tick.pre_close = tick.pre_close

        db_tick.bid_price_1 = tick.bid_price_1
        db_tick.ask_price_1 = tick.ask_price_1
        db_tick.bid_volume_1 = tick.bid_volume_1
        db_tick.ask_volume_1 = tick.ask_volume_1

        if tick.bid_price_2:
            db_tick.bid_price_2 = tick.bid_price_2
            db_tick.bid_price_3 = tick.bid_price_3
            db_tick.bid_price_4 = tick.bid_price_4
            db_tick.bid_price_5 = tick.bid_price_5

            db_tick.ask_price_2 = tick.ask_price_2
            db_tick.ask_price_3 = tick.ask_price_3
            db_tick.ask_price_4 = tick.ask_price_4
            db_tick.ask_price_5 = tick.ask_price_5

            db_tick.bid_volume_2 = tick.bid_volume_2
            db_tick.bid_volume_3 = tick.bid_volume_3
            db_tick.bid_volume_4 = tick.bid_volume_4
            db_tick.bid_volume_5 = tick.bid_volume_5

            db_tick.ask_volume_2 = tick.ask_volume_2
            db_tick.ask_volume_3 = tick.ask_volume_3
            db_tick.ask_volume_4 = tick.ask_volume_4
            db_tick.ask_volume_5 = tick.ask_volume_5

        db_tick.vt_symbol = tick.vt_symbol
        db_tick.gateway_name = "DB"

        return tick

    def to_tick(self):
        """
        Generate TickData object from DbTickData.
        """
        tick = TickData(
            symbol=self.symbol,
            exchange=Exchange(self.exchange),
            datetime=self.datetime,
            name=self.name,
            volume=self.volume,
            last_price=self.last_price,
            last_volume=self.last_volume,
            limit_up=self.limit_up,
            limit_down=self.limit_down,
            open_price=self.open_price,
            high_price=self.high_price,
            low_price=self.low_price,
            pre_close=self.pre_close,
            bid_price_1=self.bid_price_1,
            ask_price_1=self.ask_price_1,
            bid_volume_1=self.bid_volume_1,
            ask_volume_1=self.ask_volume_1,
            gateway_name=self.gateway_name,
        )

        if self.bid_price_2:
            tick.bid_price_2 = self.bid_price_2
            tick.bid_price_3 = self.bid_price_3
            tick.bid_price_4 = self.bid_price_4
            tick.bid_price_5 = self.bid_price_5

            tick.ask_price_2 = self.ask_price_2
            tick.ask_price_3 = self.ask_price_3
            tick.ask_price_4 = self.ask_price_4
            tick.ask_price_5 = self.ask_price_5

            tick.bid_volume_2 = self.bid_volume_2
            tick.bid_volume_3 = self.bid_volume_3
            tick.bid_volume_4 = self.bid_volume_4
            tick.bid_volume_5 = self.bid_volume_5

            tick.ask_volume_2 = self.ask_volume_2
            tick.ask_volume_3 = self.ask_volume_3
            tick.ask_volume_4 = self.ask_volume_4
            tick.ask_volume_5 = self.ask_volume_5

        return tick
Exemplo n.º 28
0
class Post(BaseModel):
    class Meta:
        table_name = 'post'

    languages = (
        ('ukr', u'Українська'),
        ('eng', 'English'),
        ('rus', u'Русский'),
    )

    post_id = AutoField(column_name='post_id')
    category = ForeignKeyField(Category, field='category_id')
    user = ForeignKeyField(User, field='user_id')

    date_posted = DateTimeField(default=datetime.now)
    date_updated = DateTimeField(default=datetime.now)

    post_text = TextField()
    title = CharField()
    slug = CharField(default='', unique=True)
    language = CharField(default=languages[0][0], choices=languages)

    likes = IntegerField(default=0)
    views = IntegerField(default=0)

    show_on_index = BooleanField(default=True)
    draft = BooleanField()
    deleted = BooleanField()

    def serialize(self):
        return {
            'id': self.post_id,
            'title': self.title,
            'date': self.date_posted.strftime(config.DEFAULT_DATE_FORMAT),
            'short_text': shorten_text(self.post_text),
            'url_id': self.url_id,
        }

    @property
    def url_id(self):
        if self.slug:
            return self.slug
        return self.post_id

    @property
    def actuality(self):
        """
        Return sophisticated value of post actuality
        """
        cv = lambda x, y: float(x) / y if x < y else 1.0  # ceil part-value
        now_time = datetime.now()
        int_posted = (now_time - self.date_posted).total_seconds()
        int_updt = (now_time - self.date_updated).total_seconds()
        int_years = timedelta(days=365 * 5).total_seconds()

        comments_weight = cv(self.comments, 10) * 15
        likes_weight = cv(self.likes, 30) * 15
        views_weight = cv(self.views, 100) * 10
        # the less time passed the higher value
        posted_weight = (1 - cv(int_posted, int_years)) * 40
        updated_weight = (1 - cv(int_updt, int_years)) * 20

        act = (comments_weight + likes_weight + views_weight + posted_weight +
               updated_weight)

        assert act < 100

        if act < 10:
            app.log('Post %d is not relevant' % self.post_id, 'warning')
        return act

    @property
    def comments(self):
        """
        Get comments count
        """
        return 10

    @property
    def tags(self):
        return Tag.select().join(Tag_to_Post).\
            where(Tag_to_Post.post_id == self.post_id)

    def save(self, *args, **kwargs):
        if not self.slug:
            slug = create_slug(self.title)
            self.slug = self.ensure_unique_slug(slug, 0)
        # Ensure lowercase
        self.slug = self.slug.lower()
        return super(Model, self).save(*args, **kwargs)

    @classmethod
    def ensure_unique_slug(cls, slug: str, post_id: int) -> str:
        new_slug = slug
        post_with_a_slug = cls.select() \
            .where(Post.slug == slug.lower()).first()
        if post_with_a_slug is None:
            return new_slug

        try:
            post_id = int(post_id)
        except:
            post_id = 0
        # Some other post have the same slug
        if post_with_a_slug.post_id != post_id:
            date_spec = datetime.now().strftime(config.SLUG_DATE_FORMAT)
            if not slug:
                slug = 'article'
            new_slug = '{}-{}'.format(date_spec, slug)

        return new_slug

    @classmethod
    def create(cls, **query):
        return super(Post, cls).create(**query)

    @classmethod
    def search(cls, query):
        return cls.get_posts().where(Post.title.contains(query))

    @classmethod
    def get_drafts(cls):
        """
        Return only draft posts
        """
        return cls.select().where(Post.deleted == False, Post.draft == True)

    @classmethod
    def get_deleted(cls):
        """
        Return only deleted
        """
        return cls.select().where(Post.deleted == True)

    @classmethod
    def get_posts(cls, index_only=False):
        """
        Get not deleted and not drafts to display in post list
        """
        queryset = cls.select().where(
            Post.deleted == False,
            Post.draft == False,
        )
        if index_only:
            queryset = queryset.where(Post.show_on_index == True)

        return queryset

    @classmethod
    def get_for_user(cls, user_id):
        """
        Get published posts for this specific user
        """
        return cls.select().where(Post.deleted == False, Post.draft == False,
                                  Post.user == user_id)

    def get_all(self):
        raise NotImplementedError()

    def __str__(self):
        return '#{post_id}. {post_title}'.format(
            post_id=self.post_id, post_title=self.title.encode('utf-8'))
Exemplo n.º 29
0
class AhvSubnetsCache(CacheTableBase):
    __cache_type__ = CACHE.ENTITY.AHV_SUBNET
    name = CharField()
    uuid = CharField()
    cluster = CharField()
    account_uuid = CharField(default="")
    cluster_uuid = CharField(
        default="")  # TODO separate out uuid and create separate table for it
    last_update_time = DateTimeField(default=datetime.datetime.now())

    def get_detail_dict(self, *args, **kwargs):
        return {
            "name": self.name,
            "uuid": self.uuid,
            "cluster": self.cluster,
            "cluster_uuid": self.cluster_uuid,
            "account_uuid": self.account_uuid,
            "last_update_time": self.last_update_time,
        }

    @classmethod
    def clear(cls):
        """removes entire data from table"""
        for db_entity in cls.select():
            db_entity.delete_instance()

    @classmethod
    def show_data(cls):
        """display stored data in table"""

        if not len(cls.select()):
            click.echo(highlight_text("No entry found !!!"))
            return

        table = PrettyTable()
        table.field_names = [
            "NAME",
            "UUID",
            "CLUSTER_NAME",
            "ACCOUNT_UUID",
            "LAST UPDATED",
        ]
        for entity in cls.select():
            entity_data = entity.get_detail_dict()
            last_update_time = arrow.get(
                entity_data["last_update_time"].astimezone(
                    datetime.timezone.utc)).humanize()
            table.add_row([
                highlight_text(entity_data["name"]),
                highlight_text(entity_data["uuid"]),
                highlight_text(entity_data["cluster"]),
                highlight_text(entity_data["account_uuid"]),
                highlight_text(last_update_time),
            ])
        click.echo(table)

    @classmethod
    def sync(cls):
        """sync the table from server"""

        # clear old data
        cls.clear()

        client = get_api_client()
        payload = {"length": 250, "filter": "state==VERIFIED;type==nutanix_pc"}
        account_name_uuid_map = client.account.get_name_uuid_map(payload)

        AhvVmProvider = get_provider("AHV_VM")
        AhvObj = AhvVmProvider.get_api_obj()

        for e_name, e_uuid in account_name_uuid_map.items():
            try:
                res = AhvObj.subnets(account_uuid=e_uuid)
            except Exception:
                LOG.warning(
                    "Unable to fetch subnets for Nutanix_PC Account(uuid={})".
                    format(e_uuid))
                continue

            for entity in res["entities"]:
                name = entity["status"]["name"]
                uuid = entity["metadata"]["uuid"]
                cluster_ref = entity["status"]["cluster_reference"]
                cluster_name = cluster_ref.get("name", "")
                cluster_uuid = cluster_ref.get("uuid", "")

                cls.create_entry(
                    name=name,
                    uuid=uuid,
                    cluster=cluster_name,
                    account_uuid=e_uuid,
                    cluster_uuid=cluster_uuid,
                )

        # For older version < 2.9.0
        # Add working for older versions too

    @classmethod
    def create_entry(cls, name, uuid, **kwargs):
        account_uuid = kwargs.get("account_uuid", "")
        if not account_uuid:
            LOG.error("Account UUID not supplied for subnet {}".format(name))
            sys.exit(-1)

        cluster_name = kwargs.get("cluster", None)
        if not cluster_name:
            LOG.error("cluster not supplied for subnet {}".format(name))
            sys.exit(-1)

        cluster_uuid = kwargs.get("cluster_uuid", "")

        # store data in table
        super().create(
            name=name,
            uuid=uuid,
            cluster=cluster_name,
            account_uuid=account_uuid,
            cluster_uuid=cluster_uuid,
        )

    @classmethod
    def get_entity_data(cls, name, **kwargs):
        query_obj = {"name": name}
        account_uuid = kwargs.get("account_uuid", "")
        if account_uuid:
            query_obj["account_uuid"] = account_uuid

        cluster_name = kwargs.get("cluster", "")
        if cluster_name:
            query_obj["cluster"] = cluster_name

        try:
            # The get() method is shorthand for selecting with a limit of 1
            # If more than one row is found, the first row returned by the database cursor
            entity = super().get(**query_obj)
            return entity.get_detail_dict()

        except DoesNotExist:
            return None

    @classmethod
    def get_entity_data_using_uuid(cls, uuid, **kwargs):
        account_uuid = kwargs.get("account_uuid", "")

        try:
            if account_uuid:
                entity = super().get(cls.uuid == uuid,
                                     cls.account_uuid == account_uuid)
            else:
                entity = super().get(cls.uuid == uuid)
            return entity.get_detail_dict()

        except DoesNotExist:
            return None

    class Meta:
        database = dsl_database
        primary_key = CompositeKey("name", "uuid", "account_uuid")
Exemplo n.º 30
0
class SystemPlatform(BaseModel):
    """system_platform table"""
    id = AutoField()
    inventory_id = UUIDStrField(null=False, unique=True)
    display_name = TextField(null=True)
    rh_account_id = ForeignKeyField(column_name="rh_account_id",
                                    model=RHAccount,
                                    field="id")
    first_reported = DateTimeField(null=False)
    s3_url = TextField(null=True)
    vmaas_json = TextField(null=True)
    json_checksum = TextField(null=True)
    last_updated = DateTimeField(null=False)
    unchanged_since = DateTimeField(null=False)
    last_evaluation = DateTimeField(null=True)
    advisor_evaluated = DateTimeField(null=True)
    opt_out = BooleanField(null=False)
    last_upload = DateTimeField(null=False)
    stale_timestamp = DateTimeField(null=True)
    stale_warning_timestamp = DateTimeField(null=True)
    culled_timestamp = DateTimeField(null=True)
    stale = BooleanField(null=False)
    when_deleted = DateTimeField(null=True)
    advisor_checksum = TextField(null=True)
    advisor_unchanged_since = DateTimeField(null=False)
    cve_count_cache = IntegerField(null=False)
    host_type = TextField(null=True)

    class Meta:
        """system_platform table metadata"""
        table_name = "system_platform"