class Book(peewee.Model): author = peewee.CharField() title = peewee.TextField() class Meta: database = db
def do_migrate(src_version, dst_version, forced=False): migrator = SqliteMigrator(db.database) if (src_version, dst_version) == ('0.1.4', '0.1.5'): with db.database.atomic(): for table_name in ['media', 'template', 'note', 'card']: try: migrate( migrator.add_column( table_name, 'h', pv.TextField(unique=True, null=True))) except pv.OperationalError: pass db.create_all_tables() for record in db.Media.select(): try: record.h = '' record.save() except pv.IntegrityError: print('{} is duplicated: {}'.format( record.id, record.name)) if not forced: raise else: record.delete_instance() for record in db.Template.select(): try: record.h = '' record.save() except pv.IntegrityError: print('{} is duplicated: {}'.format( record.id, record.question + record.answer)) if not forced: raise else: record.delete_instance() for record in db.Note.select(): try: data = record.data for k, v in data.items(): record.data[k] = str(v) record.save() except pv.IntegrityError: print('{} is duplicated: {}'.format( record.id, record.data)) if not forced: raise else: record.delete_instance() for record in db.Card.select(): try: record.h = '' record.save() except pv.IntegrityError: print('{} is duplicated: {}'.format( record.id, record.question.raw)) if not forced: raise else: record.delete_instance() elif (src_version, dst_version) == ('0.1.5', '0.1.6'): migrate(migrator.add_column('model', 'js', pv.TextField(default=''))) else: raise ValueError('Not supported for {}, {}'.format( src_version, dst_version))
class Topic(Model): name = pw.CharField(index=True, unique=True) content = pw.TextField()
class ScriptRevision(BaseModel): code = pw.TextField() script = pw.ForeignKeyField(Script)
class Question(BaseModel): body = peewee.TextField(unique=True) last_date = peewee.DateField(null=True) company = peewee.TextField() data_structure = peewee.TextField() leetcode = peewee.CharField(max_length=2083, null=True)
class Desc(ModelWithCUTime): desc_name = peewee.CharField(unique=True) desc_description = peewee.TextField(default='') desc_notes = peewee.TextField(default='') metrics = peewee.TextField(null=True)
class UserProperty(components.BaseModel): user = peewee.ForeignKeyField(components.BaseUser) module = peewee.TextField(null=False) key = peewee.TextField(null=False) value = peewee.TextField(null=False)
class DataEntry(peewee.Model): date = peewee.DateField(unique=True) total_confirmed = peewee.IntegerField(null=True) remaining_confirmed = peewee.IntegerField(null=True) remaining_severe = peewee.IntegerField(null=True) remaining_suspected = peewee.IntegerField(null=True) cured = peewee.IntegerField(null=True) death = peewee.IntegerField(null=True) new_confirmed = peewee.IntegerField(null=True) new_severe = peewee.IntegerField(null=True) new_suspected = peewee.IntegerField(null=True) new_cured = peewee.IntegerField(null=True) new_death = peewee.IntegerField(null=True) total_tracked = peewee.IntegerField(null=True) new_lifted = peewee.IntegerField(null=True) remaining_quarantined = peewee.IntegerField(null=True) hb_total_confirmed = peewee.IntegerField(null=True) hb_remaining_confirmed = peewee.IntegerField(null=True) hb_remaining_severe = peewee.IntegerField(null=True) hb_remaining_suspected = peewee.IntegerField(null=True) hb_cured = peewee.IntegerField(null=True) hb_death = peewee.IntegerField(null=True) hb_new_confirmed = peewee.IntegerField(null=True) hb_new_severe = peewee.IntegerField(null=True) hb_new_suspected = peewee.IntegerField(null=True) hb_new_cured = peewee.IntegerField(null=True) hb_new_death = peewee.IntegerField(null=True) article_url = peewee.TextField(unique=True) article_title = peewee.TextField() article_body = peewee.TextField() class Meta: database = database # Calculate remaining confirmed when official report does not # include this stat. @property def remaining_confirmed_calc(self): if self.remaining_confirmed is not None: return self.remaining_confirmed if self.cured is not None and self.death is not None: return self.total_confirmed - self.cured - self.death return None # Calculate new severe cases in Hubei when official report does not # include this stat. @property def hb_new_severe_calc(self): if self.hb_new_severe is not None: return self.hb_new_severe if self.hb_remaining_severe is not None: prev_day = self.date - datetime.timedelta(days=1) try: prev_day_entry = DataEntry.get(date=prev_day) except peewee.DoesNotExist: return None if prev_day_entry.hb_remaining_severe is not None: return self.hb_remaining_severe - prev_day_entry.hb_remaining_severe return None def __getattr__(self, name): if not name.startswith("not_hb_"): raise AttributeError national_attr = name[7:] national_val = getattr(self, national_attr) if national_val is None: try: national_val = getattr(self, f"{national_attr}_calc") except AttributeError: pass hb_attr = name[4:] hb_val = getattr(self, hb_attr) if hb_val is None: try: hb_val = getattr(self, f"{hb_attr}_calc") except AttributeError: pass if national_val is not None and hb_val is not None: return national_val - hb_val else: return None
class User(BaseModel, UserMixin): name = pw.CharField(unique=False, null=False) email = pw.CharField(unique=True, null=False) password_hash = pw.CharField(unique=False, null=False) password = None is_valid = pw.BooleanField(default=0) subscription = pw.ForeignKeyField(Subscription, backref="users", on_delete="CASCADE", null=True) profile_image_url = pw.TextField(default="users/Untitled_Artwork.jpg") is_admin = pw.BooleanField(default=0) @hybrid_property def profile_image_path(self): from app import app if self.profile_image_url: return app.config.get("S3_LOCATION") + self.profile_image_url else: return app.config.get("S3_LOCATION") + "Untitled_Artwork.jpg" def validate(self): duplicate_emails = User.get_or_none(User.email == self.email) if duplicate_emails and self.id != duplicate_emails.id: self.errors.append('Email registered. Try using another email.') if self.password: if len(self.password) < 6: self.errors.append("Password must be at least 6 characters.") if not re.search("[a-z]", self.password): self.errors.append("Password must include lowercase.") if not re.search("[A-Z]", self.password): self.errors.append("Password must include uppercase.") if not re.search("[\*\^\%\!\@\#\$\&]", self.password): self.errors.append("Password must include special characters.") if len(self.errors) == 0: self.password_hash = generate_password_hash(self.password) if not self.password_hash: self.errors.append("Password must be present") def is_active(self): return True def get_id(self): return self.id def is_authenticated(self): return self.authenticated def is_anonymous(self): return False def delete_from_cart(self, recipe): from models.subscription_recipe import Subscription_Recipe import datetime return Subscription_Recipe.delete().where( Subscription_Recipe.user == self.id, Subscription_Recipe.recipe == recipe.id, Subscription_Recipe.created_at >= datetime.date.today()).execute()
class Query(ModelTimestampsMixin, BaseModel): id = peewee.PrimaryKeyField() data_source = peewee.ForeignKeyField(DataSource, null=True) latest_query_data = peewee.ForeignKeyField(QueryResult, null=True) name = peewee.CharField(max_length=255) description = peewee.CharField(max_length=4096, null=True) query = peewee.TextField() query_hash = peewee.CharField(max_length=32) api_key = peewee.CharField(max_length=40) user_email = peewee.CharField(max_length=360, null=True) user = peewee.ForeignKeyField(User) last_modified_by = peewee.ForeignKeyField(User, null=True, related_name="modified_queries") is_archived = peewee.BooleanField(default=False, index=True) schedule = peewee.CharField(max_length=10, null=True) class Meta: db_table = 'queries' def to_dict(self, with_stats=False, with_visualizations=False, with_user=True): d = { 'id': self.id, 'latest_query_data_id': self._data.get('latest_query_data', None), 'name': self.name, 'description': self.description, 'query': self.query, 'query_hash': self.query_hash, 'schedule': self.schedule, 'api_key': self.api_key, 'is_archived': self.is_archived, 'updated_at': self.updated_at, 'created_at': self.created_at, 'data_source_id': self._data.get('data_source', None) } if with_user: d['user'] = self.user.to_dict() d['last_modified_by'] = self.last_modified_by.to_dict() if self.last_modified_by is not None else None else: d['user_id'] = self._data['user'] if with_stats: d['retrieved_at'] = self.retrieved_at d['runtime'] = self.runtime if with_visualizations: d['visualizations'] = [vis.to_dict(with_query=False) for vis in self.visualizations] return d def archive(self): self.is_archived = True self.schedule = None for vis in self.visualizations: for w in vis.widgets: w.delete_instance() self.save() @classmethod def all_queries(cls): q = Query.select(Query, User, QueryResult.retrieved_at, QueryResult.runtime)\ .join(QueryResult, join_type=peewee.JOIN_LEFT_OUTER)\ .switch(Query).join(User)\ .where(Query.is_archived==False)\ .group_by(Query.id, User.id, QueryResult.id, QueryResult.retrieved_at, QueryResult.runtime)\ .order_by(cls.created_at.desc()) return q @classmethod def outdated_queries(cls): queries = cls.select(cls, QueryResult.retrieved_at, DataSource)\ .join(QueryResult)\ .switch(Query).join(DataSource)\ .where(cls.schedule != None) now = utils.utcnow() outdated_queries = {} for query in queries: if should_schedule_next(query.latest_query_data.retrieved_at, now, query.schedule): key = "{}:{}".format(query.query_hash, query.data_source.id) outdated_queries[key] = query return outdated_queries.values() @classmethod def search(cls, term): # This is very naive implementation of search, to be replaced with PostgreSQL full-text-search solution. where = (cls.name**u"%{}%".format(term)) | (cls.description**u"%{}%".format(term)) if term.isdigit(): where |= cls.id == term where &= cls.is_archived == False return cls.select().where(where).order_by(cls.created_at.desc()) @classmethod def recent(cls, user_id=None, limit=20): # TODO: instead of t2 here, we should define table_alias for Query table query = cls.select().where(Event.created_at > peewee.SQL("current_date - 7")).\ join(Event, on=(Query.id == peewee.SQL("t2.object_id::integer"))).\ where(Event.action << ('edit', 'execute', 'edit_name', 'edit_description', 'view_source')).\ where(~(Event.object_id >> None)).\ where(Event.object_type == 'query'). \ where(cls.is_archived == False).\ group_by(Event.object_id, Query.id).\ order_by(peewee.SQL("count(0) desc")) if user_id: query = query.where(Event.user == user_id) query = query.limit(limit) return query @classmethod def update_instance(cls, query_id, **kwargs): if 'query' in kwargs: kwargs['query_hash'] = utils.gen_query_hash(kwargs['query']) update = cls.update(**kwargs).where(cls.id == query_id) return update.execute() def pre_save(self, created): super(Query, self).pre_save(created) self.query_hash = utils.gen_query_hash(self.query) self._set_api_key() if self.last_modified_by is None: self.last_modified_by = self.user def post_save(self, created): if created: self._create_default_visualizations() def _create_default_visualizations(self): table_visualization = Visualization(query=self, name="Table", description='', type="TABLE", options="{}") table_visualization.save() def _set_api_key(self): if not self.api_key: self.api_key = hashlib.sha1( u''.join((str(time.time()), self.query, str(self._data['user']), self.name)).encode('utf-8')).hexdigest() @property def runtime(self): return self.latest_query_data.runtime @property def retrieved_at(self): return self.latest_query_data.retrieved_at def __unicode__(self): return unicode(self.id)
class Dashboard(ModelTimestampsMixin, BaseModel): id = peewee.PrimaryKeyField() slug = peewee.CharField(max_length=140, index=True) name = peewee.CharField(max_length=100) user_email = peewee.CharField(max_length=360, null=True) user = peewee.ForeignKeyField(User) layout = peewee.TextField() dashboard_filters_enabled = peewee.BooleanField(default=False) is_archived = peewee.BooleanField(default=False, index=True) class Meta: db_table = 'dashboards' def to_dict(self, with_widgets=False): layout = json.loads(self.layout) if with_widgets: widgets = Widget.select(Widget, Visualization, Query, User)\ .where(Widget.dashboard == self.id)\ .join(Visualization, join_type=peewee.JOIN_LEFT_OUTER)\ .join(Query, join_type=peewee.JOIN_LEFT_OUTER)\ .join(User, join_type=peewee.JOIN_LEFT_OUTER) widgets = {w.id: w.to_dict() for w in widgets} # The following is a workaround for cases when the widget object gets deleted without the dashboard layout # updated. This happens for users with old databases that didn't have a foreign key relationship between # visualizations and widgets. # It's temporary until better solution is implemented (we probably should move the position information # to the widget). widgets_layout = [] for row in layout: new_row = [] for widget_id in row: widget = widgets.get(widget_id, None) if widget: new_row.append(widget) widgets_layout.append(new_row) # widgets_layout = map(lambda row: map(lambda widget_id: widgets.get(widget_id, None), row), layout) else: widgets_layout = None return { 'id': self.id, 'slug': self.slug, 'name': self.name, 'user_id': self._data['user'], 'layout': layout, 'dashboard_filters_enabled': self.dashboard_filters_enabled, 'widgets': widgets_layout, 'is_archived': self.is_archived, 'updated_at': self.updated_at, 'created_at': self.created_at } @classmethod def get_by_slug(cls, slug): return cls.get(cls.slug == slug) @classmethod def recent(cls, user_id=None, limit=20): query = cls.select().where(Event.created_at > peewee.SQL("current_date - 7")). \ join(Event, on=(Dashboard.id == peewee.SQL("t2.object_id::integer"))). \ where(Event.action << ('edit', 'view')).\ where(~(Event.object_id >> None)). \ where(Event.object_type == 'dashboard'). \ where(Dashboard.is_archived == False). \ group_by(Event.object_id, Dashboard.id). \ order_by(peewee.SQL("count(0) desc")) if user_id: query = query.where(Event.user == user_id) query = query.limit(limit) return query def save(self, *args, **kwargs): if not self.slug: self.slug = utils.slugify(self.name) tries = 1 while self.select().where(Dashboard.slug == self.slug).first() is not None: self.slug = utils.slugify(self.name) + "_{0}".format(tries) tries += 1 super(Dashboard, self).save(*args, **kwargs) def __unicode__(self): return u"%s=%s" % (self.id, self.name)
class QueryResult(BaseModel): id = peewee.PrimaryKeyField() data_source = peewee.ForeignKeyField(DataSource) query_hash = peewee.CharField(max_length=32, index=True) query = peewee.TextField() data = peewee.TextField() runtime = peewee.FloatField() retrieved_at = DateTimeTZField() class Meta: db_table = 'query_results' def to_dict(self): return { 'id': self.id, 'query_hash': self.query_hash, 'query': self.query, 'data': json.loads(self.data), 'data_source_id': self._data.get('data_source', None), 'runtime': self.runtime, 'retrieved_at': self.retrieved_at } @classmethod def unused(cls, days=7): age_threshold = datetime.datetime.now() - datetime.timedelta(days=days) unused_results = cls.select().where(Query.id == None, cls.retrieved_at < age_threshold)\ .join(Query, join_type=peewee.JOIN_LEFT_OUTER) return unused_results @classmethod def get_latest(cls, data_source, query, max_age=0): query_hash = utils.gen_query_hash(query) if max_age == -1: query = cls.select().where(cls.query_hash == query_hash, cls.data_source == data_source).order_by(cls.retrieved_at.desc()) else: query = cls.select().where(cls.query_hash == query_hash, cls.data_source == data_source, peewee.SQL("retrieved_at + interval '%s second' >= now() at time zone 'utc'", max_age)).order_by(cls.retrieved_at.desc()) return query.first() @classmethod def store_result(cls, data_source_id, query_hash, query, data, run_time, retrieved_at): query_result = cls.create(query_hash=query_hash, query=query, runtime=run_time, data_source=data_source_id, retrieved_at=retrieved_at, data=data) logging.info("Inserted query (%s) data; id=%s", query_hash, query_result.id) sql = "UPDATE queries SET latest_query_data_id = %s WHERE query_hash = %s AND data_source_id = %s RETURNING id" query_ids = [row[0] for row in db.database.execute_sql(sql, params=(query_result.id, query_hash, data_source_id))] # TODO: when peewee with update & returning support is released, we can get back to using this code: # updated_count = Query.update(latest_query_data=query_result).\ # where(Query.query_hash==query_hash, Query.data_source==data_source_id).\ # execute() logging.info("Updated %s queries with result (%s).", len(query_ids), query_hash) return query_result, query_ids def __unicode__(self): return u"%d | %s | %s" % (self.id, self.query_hash, self.retrieved_at)
class DataSource(BaseModel): SECRET_PLACEHOLDER = '--------' id = peewee.PrimaryKeyField() name = peewee.CharField(unique=True) type = peewee.CharField() options = peewee.TextField() queue_name = peewee.CharField(default="queries") scheduled_queue_name = peewee.CharField(default="scheduled_queries") created_at = DateTimeTZField(default=datetime.datetime.now) class Meta: db_table = 'data_sources' def to_dict(self, all=False): d = { 'id': self.id, 'name': self.name, 'type': self.type, 'syntax': self.query_runner.syntax } if all: d['options'] = self.configuration d['queue_name'] = self.queue_name d['scheduled_queue_name'] = self.scheduled_queue_name return d def __unicode__(self): return self.name @property def configuration(self): configuration = json.loads(self.options) schema = self.query_runner.configuration_schema() for prop in schema.get('secret', []): if prop in configuration and configuration[prop]: configuration[prop] = self.SECRET_PLACEHOLDER return configuration def replace_secret_placeholders(self, configuration): current_configuration = json.loads(self.options) schema = self.query_runner.configuration_schema() for prop in schema.get('secret', []): if prop in configuration and configuration[prop] == self.SECRET_PLACEHOLDER: configuration[prop] = current_configuration[prop] def get_schema(self, refresh=False): key = "data_source:schema:{}".format(self.id) cache = None if not refresh: cache = redis_connection.get(key) if cache is None: query_runner = self.query_runner schema = sorted(query_runner.get_schema(), key=lambda t: t['name']) redis_connection.set(key, json.dumps(schema)) else: schema = json.loads(cache) return schema @property def query_runner(self): return get_query_runner(self.type, self.options) @classmethod def all(cls): return cls.select().order_by(cls.id.asc())
class User(UserMixin, BaseModel): username = pw.CharField(unique=True, null=False) email = pw.CharField(unique=True, null=False) password_hash = pw.TextField(null=False) password = None image_path = pw.TextField(null=True) is_private = pw.BooleanField(default=False) @hybrid_property def full_image_path(self): if self.image_path: from app import app return app.config.get("S3_LOCATION") + self.image_path else: return "" def follow_status(self, idol): from models.fanidol import FanIdol return FanIdol.get_or_none(FanIdol.fan == self.id, FanIdol.idol == idol.id) def follow(self, idol): from models.fanidol import FanIdol # if relationship/row exists, return false if FanIdol.get_or_none(FanIdol.fan == self.id, FanIdol.idol == idol.id): return False else: if idol.is_private: FanIdol.create(fan=self.id, idol=idol.id, is_approved=False) else: FanIdol.create(fan=self.id, idol=idol.id, is_approved=True) return True def unfollow(self, idol): from models.fanidol import FanIdol FanIdol.delete().where(self.id == FanIdol.fan and idol == FanIdol.idol).execute() return True @hybrid_property def fans(self): from models.fanidol import FanIdol fans = FanIdol.select().where(FanIdol.idol == self.id, FanIdol.is_approved == True) fans_list = [] for fan in fans: fans_list.append(fan.fan) return fans_list @hybrid_property def idols(self): from models.fanidol import FanIdol # get a list of idols idols = FanIdol.select().where(FanIdol.fan == self.id, FanIdol.is_approved == True) idols_list = [] for idol in idols: idols_list.append(idol.idol) return idols_list # another way: # idols = FanIdol.select(FanIdol.idol).where(FanIdol.fan==self.id, FanIdol.is_approved==True) # return User.select().where( User.id.in_(idols) ) @hybrid_property def idol_requests(self): from models.fanidol import FanIdol idols = FanIdol.select(FanIdol.idol).where( FanIdol.fan == self.id, FanIdol.is_approved == False) return User.select().where(User.id.in_(idols)) # another way: # idols_request = [] # for idol in idols_request: # idols_request.append(idol.idol) # return idols_request @hybrid_property def fan_requests(self): from models.fanidol import FanIdol fans = FanIdol.select(FanIdol.fan).where(FanIdol.idol == self.id, FanIdol.is_approved == False) return User.select().where(User.id.in_(fans)) @hybrid_property def approve_request(self, fan): from models.fanidol import FanIdol # get the relationship relationship = fan.follow_status(self) # update the is_approved to true relationship.is_approved = True return relationship.save() def validate(self): # Email should be unique existing_user_email = User.get_or_none(User.email == self.email) if existing_user_email and existing_user_email.id != self.id: self.errors.append(f"User with email {self.email} already exists!") # Username should be unique existing_user_username = User.get_or_none( User.username == self.username) # also check if current userid is not same as the newly created user so we can update details if existing_user_username and existing_user_username.id != self.id: self.errors.append( f"User with username {self.username} already exists!") # Password should be longer than 6 characters if self.password: if len(self.password) <= 6: self.errors.append("Password is less than 6 characters") # Password should have both uppercase and lowercase characters # Password should have at least one special character (REGEX comes in handy here) has_lower = re.search(r"[a-z]", self.password) has_upper = re.search(r"[A-Z]", self.password) has_special = re.search(r"[\[ \] \* \$ \% \^ \& \# \@ \? ]", self.password) if has_lower and has_upper and has_special: self.password_hash = generate_password_hash(self.password) else: self.errors.append( "Password either does not have upper, lower or special characters!" )
class Purchase(pw.Model): company_name = pw.TextField(CompanyDetails) amount = pw.TextField() class Meta: database = db
class User(UserMixin, BaseModel): username = pw.CharField(unique=True) email = pw.CharField(unique=True) password = pw.CharField() profile_image = pw.TextField(default="Braised+Pork.jpeg") private = pw.BooleanField(default=False) def follow(self,idol): from models.fanidol import FanIdol # check if has relationship in database if self.follow_status(idol)==None: return FanIdol(fan=self.id,idol=idol.id).save() else: return 0 def unfollow(self,idol): from models.fanidol import FanIdol return FanIdol.delete().where(FanIdol.fan==self.id,FanIdol.idol==idol.id).execute() def approve_request(self,fan): from models.fanidol import FanIdol return FanIdol.update(approved=True).where(FanIdol.fan==fan.id,FanIdol.idol==self.id).execute() def follow_status(self,idol): from models.fanidol import FanIdol # check following status : # if already follow => return that row, # else return None(mean not follow this idol before) return FanIdol.get_or_none(FanIdol.fan==self.id,FanIdol.idol==idol.id) @hybrid_property def get_request(self): from models.fanidol import FanIdol return FanIdol.select().where(FanIdol.idol==self.id,FanIdol.approved==False) @hybrid_property def followers(self): from models.fanidol import FanIdol # to get all fans fans = FanIdol.select(FanIdol.fan).where(FanIdol.idol==self.id,FanIdol.approved==True) return User.select().where(User.id.in_(fans)) @hybrid_property def followings(self): from models.fanidol import FanIdol # to get all idols idols = FanIdol.select(FanIdol.idol).where(FanIdol.fan==self.id,FanIdol.approved==True) return User.select().where(User.id.in_(idols)) @hybrid_property def profile_url(self): return os.getenv("AWS_DOMAIN") + self.profile_image def validate(self): duplicate_username = User.get_or_none(User.username == self.username) duplicate_email = User.get_or_none(User.email == self.email) regex_password = r"^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$" if duplicate_username and duplicate_username.id != self.id: self.errors.append('Username not unique') if duplicate_email and duplicate_email.id != self.id: self.errors.append('email not unique') if re.search(regex_password,self.password) == None: self.errors.append('Password must have minimum eight characters, at least one letter and one number') else: self.password = generate_password_hash(self.password)
class User(BaseModel): class Subscription(enum.Enum): undetermined = 0 accepted = 1 denied = 2 revoked = 3 blocked = 4 id = peewee.TextField(unique=True, default=uuid.uuid4) telegram_id = peewee.BigIntegerField(unique=True) telegram_username = peewee.TextField(null=True) subscription = peewee.IntegerField(default=0) def get_markdown_description(self) -> str: if self.telegram_username is None: username = telegram_utils.escape_v2_markdown_text('-') else: escaped_username = telegram_utils.escape_v2_markdown_text( text=f'@{self.telegram_username}', entity_type=telegram.MessageEntity.CODE) username = f'`{escaped_username}`' user_id = telegram_utils.escape_v2_markdown_text_link( text=str(self.telegram_id), url=f'tg://user?id={self.telegram_id}') return ( f'{self.rowid}{telegram_utils.ESCAPED_FULL_STOP} {telegram_utils.ESCAPED_VERTICAL_LINE} ' f'{user_id} {telegram_utils.ESCAPED_VERTICAL_LINE} ' f'{username}') def get_markdown_subscription_description(self) -> str: return ( f'{self.get_markdown_description()} {telegram_utils.ESCAPED_VERTICAL_LINE} ' f'{User.Subscription(self.subscription).name}') def get_created_at(self) -> str: date = typing.cast(datetime.datetime, self.created_at) return date.strftime(constants.GENERIC_DATE_TIME_FORMAT) def get_updated_ago(self) -> str: if self.updated_at == self.created_at: return '-' delta_seconds = round( (datetime.datetime.now() - self.updated_at).total_seconds()) time_ago = str( datetime.datetime.fromtimestamp(delta_seconds) - constants.EPOCH_DATE) return f'{time_ago} ago' def get_subscription_update_message(self) -> str: prefix = 'Subscription update:' return (f'{telegram_utils.escape_v2_markdown_text(prefix)} ' f'{self.get_markdown_subscription_description()}') def save(self, force_insert=False, only=None) -> None: self.updated_at = get_current_datetime() super().save(force_insert=force_insert, only=only) @classmethod def create_or_update_user(cls, id: int, username: typing.Optional[str], bot: telegram.Bot, admin_id: int) -> typing.Optional[User]: try: db_user: User is_created: bool (db_user, is_created) = cls.get_or_create( telegram_id=id, defaults={'telegram_username': username}) db_user.telegram_username = username if db_user.subscription == User.Subscription.blocked.value: db_user.subscription = User.Subscription.undetermined.value subscription_update_message = db_user.get_subscription_update_message( ) telegram_utils.send_subscription_update_message( bot=bot, chat_id=admin_id, text=subscription_update_message) db_user.save() if is_created: return db_user except peewee.PeeweeException as error: logger.error( f'Database error: "{error}" for id: {id} and username: {username}' ) return None @classmethod def get_users_table(cls, sorted_by_updated_at=False, include_only_subscribed=False) -> str: users_table = '' try: sort_field = cls.updated_at if sorted_by_updated_at else cls.created_at query = cls.select() if sorted_by_updated_at: query = query.where(cls.created_at != cls.updated_at) if include_only_subscribed: query = query.where( cls.subscription == cls.Subscription.accepted.value) query = query.order_by(sort_field.desc()).limit(10) for user in reversed(query): users_table += ( f'\n{user.get_markdown_subscription_description()} {telegram_utils.ESCAPED_VERTICAL_LINE} ' f'{telegram_utils.escape_v2_markdown_text(user.get_created_at())} {telegram_utils.ESCAPED_VERTICAL_LINE} ' f'{telegram_utils.escape_v2_markdown_text(user.get_updated_ago())}' ) except peewee.PeeweeException: pass if not users_table: users_table = 'No users' return users_table
class Role(pw.Model): description = pw.TextField(null=True) name = pw.CharField(max_length=255, unique=True) class Meta: db_table = "role"
class Run(ModelWithCUTime): expr = peewee.ForeignKeyField(Experiment, backref='runs') run_name = peewee.CharField(index=True) run_description = peewee.TextField(default='') run_notes = peewee.TextField(default='') command = peewee.TextField() args = peewee.TextField() configs = peewee.TextField() highlight_args = peewee.TextField() highlight_configs = peewee.TextField() metainfo_file = peewee.TextField(null=True) log_file = peewee.TextField(null=True) meter_file = peewee.TextField(null=True) tb_dir = peewee.TextField(null=True) metrics = peewee.TextField(null=True) is_master = peewee.BooleanField(default=True) refer = peewee.ForeignKeyField('self', null=True, backref='referee') class Meta: indexes = [(('expr', 'run_name'), True)]
class Software(ModelloBase): title = pee.TextField() year = pee.CharField(max_length=4) publisher = pee.TextField() country = pee.CharField(max_length=2) hash = pee.TextField(primary_key=True)
class KeyChain(pw.Model): secret = pw.TextField() message = pw.TextField() application = pw.CharField(max_length=255)
class Preview(ModelloBase): base = pee.TextField(primary_key=True) picture = pee.BlobField()
class Operator(p.Model): default_dark_config = json.dumps({ "background-color": "#303030", "text-color": "#66b3ff", "hover": "#b3b3b3", "highlight": "#b3b3b3", "autocomplete": "#303030", "highlight-text": "black", "timestamp": "#b3ffff", "operator": "#ffb3b3", "display": "#d9b3ff", "new-callback-color": "dark", "new-callback-hue": "purple", "well-bg": "#000000", "primary-pane": "#001f4d", "primary-pane-text-color": "#ccffff", "primary-button": "#001f4d", "primary-button-text-color": "white", "primary-button-hover": "#0000cc", "primary-button-hover-text-color": "white", "info-pane": "#330066", "info-pane-text-color": "#e6ccff", "info-button": "#330066", "info-button-text-color": "#f3e6ff", "info-button-hover": "#5900b3", "info-button-hover-text-color": "#f3e6ff", "success-pane": "#003300", "success-pane-text-color": "#b3ffb3", "success-button": "#004d00", "success-button-text-color": "white", "success-button-hover": "#006600", "success-button-hover-text-color": "white", "danger-pane": "#800000", "danger-pane-text-color": "white", "danger-button": "#4d0000", "danger-button-text-color": "white", "danger-button-hover": "#800000", "danger-button-hover-text-color": "white", "warning-pane": "#330000", "warning-pane-text-color": "#e6ccff", "warning-button": "#804300", "warning-button-text-color": "white", "warning-button-hover": "#b35900", "warning-button-hover-text-color": "white", "table-headers": "#000000", "operation-color": "white", "interact-button-color": "#330066", "interact-button-text": "#FFFFFF", "interact-button-dropdown": "#6666FF", "success_highlight": "#303030", "failure_highlight": "#660000", "top-caret": "white" }) default_config = json.dumps({ "background-color": "#f4f4f4", "text-color": "#000000", "hover": "#cce6ff", "highlight": "#cce6ff", "autocomplete": "#e6f3ff", "highlight-text": "blue", "timestamp": "blue", "operator": "#b366ff", "display": "red", "new-callback-color": "light", "new-callback-hue": "", "well-bg": "#E5E5E5", "primary-pane": "", "primary-pane-text-color": "", "primary-button": "", "primary-button-text-color": "", "primary-button-hover": "", "primary-button-hover-text-color": "", "info-pane": "", "info-pane-text-color": "", "info-button": "", "info-button-text-color": "", "info-button-hover": "", "info-button-hover-text-color": "", "success-pane": "", "success-pane-text-color": "", "success-button": "", "success-button-text-color": "", "success-button-hover": "", "success-button-hover-text-color": "", "danger-pane": "", "danger-pane-text-color": "", "danger-button": "", "danger-button-text-color": "", "danger-button-hover": "", "danger-button-hover-text-color": "", "warning-pane": "", "warning-pane-text-color": "", "warning-button": "", "warning-button-text-color": "", "warning-button-hover": "", "warning-button-hover-text-color": "", "table-headers": "#F1F1F1", "operation-color": "green", "interact-button-color": "", "interact-button-text": "", "interact-button-dropdown": "", "success_highlight": "#d5fdd5", "failure_highlight": "#f68d8d", "top-caret": "white" }) username = p.TextField(unique=True, null=False) password = p.TextField(null=False) admin = p.BooleanField(null=True, default=False) creation_time = p.DateTimeField(default=datetime.datetime.utcnow, null=False) last_login = p.DateTimeField(default=None, null=True) # option to simply de-activate an account instead of delete it so you keep all your relational data intact active = p.BooleanField(null=False, default=True) current_operation = p.ForeignKeyField(p.DeferredRelation('Operation'), null=True) ui_config = p.TextField(null=False, default=default_config) class Meta: ordering = ['-id', ] database = apfell_db def to_json(self): r = {} for k in self._data.keys(): try: if k == 'current_operation': r[k] = getattr(self, k).name elif k != 'password' and 'default' not in k: r[k] = getattr(self, k) except: r[k] = json.dumps(getattr(self, k)) r['creation_time'] = r['creation_time'].strftime('%m/%d/%Y %H:%M:%S') if 'last_login' in r and r['last_login'] is not None: r['last_login'] = r['last_login'].strftime('%m/%d/%Y %H:%M:%S') else: r['last_login'] = "" # just indicate that account created, but they never logged in return r def __str__(self): return str(self.to_json()) async def check_password(self, password): temp_pass = await crypto.hash_SHA512(password) return self.password.lower() == temp_pass.lower() async def hash_password(self, password): return await crypto.hash_SHA512(password)
class Manual(ModelloBase): base = pee.TextField(primary_key=True) description = pee.TextField()
class ParentTestModel(pw.Model): id = pw.AutoField() text = pw.TextField() class Meta: database = DB
class Service(pw.Model): ty2 = pw.TextField() class Meta: database = db
class Meta: db_table = 'tag' id = peewee.PrimaryKeyField() name = peewee.TextField()
class Sales(pw.Model): name = pw.TextField() amount = pw.TextField() class Meta: database = db
class Memo(BaseModel): """Database Memo Table.""" user = peewee.CharField(index=True) channel = peewee.CharField() text = peewee.TextField()
class Match(p.Model): keyword = p.CharField(max_length=32) answer = p.TextField() class Meta: database = DATABASE