class Broker(MySQLModel): broker_id = pw.PrimaryKeyField() email = pw.CharField(index=True) active = pw.BooleanField(default=False) rep_id = pw.ForeignKeyField(User)
class Item(BaseModel): class Rarity(Enum): junk = 1 common = 2 uncommon = 3 rare = 4 legendary = 5 @property def color(self): if self == self.junk: return discord.Color.from_rgb(168, 115, 77) elif self == self.common: return discord.Color.from_rgb(196, 100, 70) elif self == self.uncommon: return discord.Color.from_rgb(196, 100, 70) elif self == self.rare: return discord.Color.from_rgb(196, 100, 70) elif self == self.legendary: return discord.Color.from_rgb(196, 100, 70) @property def weight(self): if self == self.junk: return 40 elif self == self.common: return 30 elif self == self.uncommon: return 20 elif self == self.rare: return 10 elif self == self.legendary: return 6 name = peewee.CharField (null = False) code = peewee.CharField (max_length = 45) description = peewee.TextField (null = False) image_url = peewee.TextField (null = False) rarity = EnumField (Rarity, null = False, default = Rarity.common) explorable = peewee.BooleanField (null = False, default = False) usable = peewee.BooleanField (null = False, default = False) category = peewee.ForeignKeyField (ItemCategory, null = True) chance = peewee.IntegerField (null = False) @classmethod def get_random(cls): query = """ SELECT results.* FROM ( SELECT {table_name}.*, @running_total AS previous_total, @running_total := @running_total + {chance_column_name} AS running_total, until.rand FROM ( SELECT round(rand() * init.max) AS rand FROM ( SELECT sum({chance_column_name}) - 1 AS max FROM {table_name} {where} ) AS init ) AS until, (SELECT * FROM {table_name} {where}) AS {table_name}, ( SELECT @running_total := 0.00 ) AS vars ) AS results WHERE results.rand >= results.previous_total AND results.rand < results.running_total; """ query = query.format( table_name = cls._meta.table_name, where = "WHERE (category_id != 1 OR category_id IS NULL) AND explorable = 1", chance_column_name = "chance" ) for item in cls.raw(query): return item @property def embed(self): embed = discord.Embed(color = self.rarity.color) embed.set_thumbnail(url = self.image_url) embed.title = self.name embed.description = self.description return embed
class Entry(db.Model): title = peewee.CharField() slug = peewee.CharField(unique=True) content = peewee.TextField() published = peewee.BooleanField(index=True) series = peewee.CharField(index=True, null=True) part = peewee.IntegerField(null=True) timestamp = peewee.DateTimeField(default=datetime.datetime.now, index=True) github_file = peewee.CharField(unique=True) @property def html_content(self): """ Generate HTML representation of the markdown-formatted blog entry, and also convert any media URLs into rich media objects such as video players or images. """ hilite = CodeHiliteExtension(linenums=False, css_class='highlight') extras = ExtraExtension() markdown_content = markdown(self.content, extensions=[hilite, extras]) oembed_content = parse_html( markdown_content, oembed_providers, urlize_all=True, # maxwidth=app.config['SITE_WIDTH']) maxwidth=800) # TODO get from blueprint return Markup(oembed_content) def save(self, *args, **kwargs): # if not self.slug: if self.series and self.part: base_slug = re.sub(r'[^\w]+', '-', self.series.lower()).strip('-') self.slug = f"{base_slug}-{self.part}" else: self.slug = re.sub(r'[^\w]+', '-', self.title.lower()).strip('-') # if kwargs.pop('load_from_disk', False): # self.load_from_disk(kwargs.pop('markdown_path'), # kwargs.pop('data_path')) # elif kwargs.pop('to_disk', False): # self.save_to_disk() ret = super(Entry, self).save(*args, **kwargs) self.update_search_index() return ret @classmethod def _parse_markdown(cls, markdown_path): with open(markdown_path) as markdown_file: title = markdown_file.readline().lstrip('# ').rstrip(' \r\n') # TODO: only in math context content = markdown_file.read().lstrip(' \r\n') content = re.sub(r'\\\\', r'\\newline', content) return title, content @classmethod def create_or_update_from_disk(cls, markdown_path, data_path): docid = markdown_path.name.split('_', 1)[0] if cls.exists(docid): self = cls.get(cls.id == docid) else: self = cls(title='', content='', docid=docid) self.docid = markdown_path.name.split('_', 1)[0] self.title, self.content = cls._parse_markdown(markdown_path) self.github_file = markdown_path.resolve().name # get file name, not link name with open(data_path) as data_file: for line in data_file: attr, value = line.rstrip('\n').split(': ') attr = attr.lower() if not hasattr(self.__class__, attr): raise MetaFileError(f"{attr} is not a valid field of {self.__class__}") if attr == 'published': value = bool(value) elif attr == 'timestamp': value = datetime.datetime(*map(int, value.split(','))) setattr(self, attr, value) # self.slug = data_file.readline().rstrip('\n').split(': ')[-1] # self.published = bool(data_file.readline().rstrip('\n').split(' ')[-1]) # time_str = data_file.readline().rstrip('\n').split(': ')[-1] # if time_str: # self.time = datetime.datetime(*map(int, time_str.split(','))) if not hasattr(self, 'timestamp'): time_str = ','.join(map(str, datetime.datetime.now().timetuple()[:7])) with open(data_path, 'a') as data_file: data_file.write(f"Timestamp: {time_str}\n") self.time = datetime.datetime(*map(int, time_str.split(','))) # if not hasattr(self, 'series') or not hasattr(self, 'part'): # self.series = 'None' # self.part = -1 return self def update_search_index(self): # Create a row in the FTSEntry table with the post content. This will # allow us to use SQLite's awesome full-text search extension to # search our entries. content = '\n'.join((self.title, self.content)) if self.exists(self.docid): (FTSEntry .update({FTSEntry.content: content}) .where(FTSEntry.docid == self.id) .execute()) else: FTSEntry.insert({ FTSEntry.docid: self.id, FTSEntry.content: content}).execute() @classmethod def exists(cls, docid): return (FTSEntry .select(FTSEntry.docid) .where(FTSEntry.docid == docid) .exists()) @classmethod def get_series(cls, series): return cls.select().where(cls.series == series) @classmethod def public(cls): return cls.select().where(cls.published == True) @classmethod def drafts(cls): return cls.select().where(cls.published == False) @classmethod def search(cls, query): words = [word.strip() for word in query.split() if word.strip()] if not words: # Return an empty query. return Entry.noop() else: search = ' '.join(words) # Query the full-text search index for entries matching the given # search query, then join the actual Entry data on the matching # search result. return (Entry .select(Entry, FTSEntry.rank().alias('score')) .join(FTSEntry, on=(Entry.id == FTSEntry.docid)) .where( FTSEntry.match(search) & (Entry.published == True)) .order_by(SQL('score'))) class Meta: database = db.database
class User(UserMixin, BaseModel): name = 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) def follow(self, idol): from models.fanidol import FanIdol # check whether the relationship already existed if self.follow_status(idol) == None: relationship = FanIdol(idol=idol, fan=self.id) if not idol.is_private: relationship.is_approved = True return relationship.save() else: return 0 def unfollow(self, idol): from models.fanidol import FanIdol return FanIdol.delete().where(FanIdol.fan == self.id, FanIdol.idol == idol).execute() def follow_status(self, idol): from models.fanidol import FanIdol return FanIdol.get_or_none(FanIdol.fan == self.id, FanIdol.idol == idol.id) @hybrid_property def idols(self): from models.fanidol import FanIdol # get a list of idols user idols = FanIdol.select(FanIdol.idol).where(FanIdol.fan == self.id, FanIdol.is_approved == True) return User.select().where(User.id.in_(idols)) # user_idol = [] # for row in idols: # user_idol.append(row.idol) # return user_idol @hybrid_property def fans(self): from models.fanidol import FanIdol # get a list of fans user fans = FanIdol.select(FanIdol.fan).where(FanIdol.idol == self.id, FanIdol.is_approved == True) return User.select().where(User.id.in_(fans)) @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)) @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)) 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() @hybrid_property def full_image_path(self): from app import app if self.image_path: return app.config.get("S3_LOCATION") + self.image_path else: return app.config.get("S3_LOCATION") + "blank-profile-picture.png" 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) 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!" )
def migrate(migrator, database, fake=False, **kwargs): migrator.add_fields( Event, has_clip=pw.BooleanField(default=True), has_snapshot=pw.BooleanField(default=True), )
class Follower(BaseModel): user = orm.ForeignKeyField(User) username = orm.CharField() unfollow_date = orm.DateTimeField(default=future_rand_date) following = orm.BooleanField(default=True) times_followed = orm.IntegerField(default=1)
class User(UserMixin, BaseModel): name = pw.CharField(unique=False) password = pw.CharField(unique=False) username = pw.CharField(unique=True) email = pw.CharField(unique=True) profile_image = pw.CharField( unique=False, default='http://sebagram.s3.amazonaws.com/user.png') private = pw.BooleanField(default=False) @hybrid_property def followers(self): return [x.follower for x in self.follower] @hybrid_property def sum_followers(self): return len(self.followers) @hybrid_property def followings(self): return [x.following for x in self.following] @hybrid_property def sum_followings(self): return len(self.followings) @hybrid_property def pending_requests(self): from models.followers import Followstate query = Followstate.select().where(Followstate.following_id == self.id, Followstate.approved == False) return [x.follower for x in query] @hybrid_property def sum_pending_request(self): return len(self.pending_requests) # @hybrid_property def validate(self): duplicate_username = User.get_or_none(User.username == self.username) duplicate_name = User.get_or_none(User.name == self.name) if duplicate_name: self.errors.append('Name has been taken') if duplicate_username: self.errors.append('Username has been taken') if len(self.password) < 6: self.errors.append('Password has to be at least 6 characters') # pattern= '[A-Z]+[a-z]+$' # if re.search(pattern, self.password) is None: # self.errors.append('Password must have 1 of each upper, lower and special charatcer') email_pattern = r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)" if re.search(email_pattern, self.email) is None: self.errors.append('Please enter a valid email') else: # this is an update, not create if self.id: self.password = self.password else: self.password = generate_password_hash(self.password)
class User(UserMixin,BaseModel): username = pw.CharField(unique=True) email = pw.CharField(unique=True) password = pw.CharField() profile_image = pw.TextField(default="blank-profile-picture.png") 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_image_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) password_regex = r"^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$" # create new user if self.id == None: if duplicate_username: self.errors.append("Username not unique") if duplicate_email: self.errors.append("Email not unique") if re.search(password_regex, self.password) == None: self.errors.append("Minimum eight characters, at least one letter and one number") else : self.password = generate_password_hash(self.password) # update current user else: # handle change password if self.password != None : if re.search(password_regex, self.password) == None: self.errors.append("Minimum eight characters, at least one letter and one number") else : self.password = generate_password_hash(self.password) # handle change username or email else: 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") else: # save the original password self.password = User.get_by_id(self.id).password
class User(db.Model): name = pw.CharField(255) title = pw.CharField(127, null=True) active = pw.BooleanField(default=True) rating = pw.IntegerField(default=0)
class Link(Model): """ A link as stored in the database """ url = peewee.TextField() name = peewee.TextField() description = peewee.TextField() # TODO: do we need to track modified time? created = peewee.DateTimeField() # is the field entirely private? private = peewee.BooleanField() # owned by user = peewee.ForeignKeyField(User, backref="links") def link_url(self) -> str: return f"/u/{self.user.name}/l/{self.id}" @staticmethod def by_id(id: int) -> Optional["Link"]: return Link.get_or_none(id=id) @staticmethod def get_all(as_user: Optional[User], page: int) -> Tuple[List["Link"], v.Pagination]: links = ( Link.select().where( (Link.user == as_user) | (Link.private == False)) # noqa: E712 .order_by(-Link.created).paginate(page, c.app.per_page)) link_views = [link.to_view(as_user) for link in links] pagination = v.Pagination.from_total(page, Link.select().count()) return link_views, pagination @staticmethod def from_request(user: User, link: r.Link) -> "Link": new_link = Link.create( url=link.url, name=link.name, description=link.description, private=link.private, created=link.created or datetime.datetime.now(), user=user, ) for tag_name in link.tags: tag = Tag.get_or_create_tag(user, tag_name) HasTag.get_or_create(link=new_link, tag=tag) return new_link def update_from_request(self, user: User, link: r.Link): with self.atomic(): req_tags = set(link.tags) for hastag in self.tags: # type: ignore name = hastag.tag.name if name not in req_tags: hastag.delete_instance() else: req_tags.remove(name) for tag_name in req_tags: t = Tag.get_or_create_tag(user, tag_name) HasTag.get_or_create(link=self, tag=t) Tag.clean() self.url = link.url self.name = link.name self.description = link.description self.private = link.private self.save() def to_view(self, as_user: Optional[User]) -> v.Link: return v.Link( id=self.id, url=self.url, name=self.name, description=self.description, private=self.private, tags=self.get_tags_view(), created=self.created, is_mine=self.user.id == as_user.id if as_user else False, link_url=self.link_url(), user=self.user.name, ) def get_tags_view(self) -> List[v.Tag]: return [ v.Tag(url=f"/u/{self.user.name}/t/{ht.tag.name}", name=ht.tag.name) for ht in HasTag().select(Tag.name).join(Tag).where( HasTag.link == self) ] def full_delete(self): self.delete_instance(recursive=True) Tag.clean()
class User(Model): """ A user! you know tf this is about """ name = peewee.TextField(unique=True) passhash = peewee.TextField() is_admin = peewee.BooleanField(default=False) @staticmethod def from_request(user: r.User) -> "User": passhash = pwd.hash(user.password) try: return User.create( name=user.name, passhash=passhash, ) except peewee.IntegrityError: raise e.UserExists(name=user.name) def change_password(self, req: r.PasswordChange): if not pwd.verify(req.old, self.passhash): raise e.BadPassword(name=self.name) self.passhash = pwd.hash(req.n1) self.save() @staticmethod def from_invite(user: r.User, token: str) -> "User": invite = UserInvite.by_code(token) if invite.claimed_by is not None or invite.claimed_at is not None: raise e.AlreadyUsedInvite(invite=token) u = User.from_request(user) invite.claimed_at = datetime.datetime.now() invite.claimed_by = u invite.save() return u def authenticate(self, password: str) -> bool: return pwd.verify(password, self.passhash) def set_as_admin(self): self.is_admin = True self.save() @staticmethod def login(user: r.User) -> Tuple["User", str]: u = User.by_slug(user.name.strip()) if not u.authenticate(user.password.strip()): raise e.BadPassword(name=user.name) return u, user.to_token() @staticmethod def by_slug(slug: str) -> "User": u = User.get_or_none(name=slug) if u is None: raise e.NoSuchUser(name=slug) return u def base_url(self) -> str: return f"/u/{self.name}" def config_url(self) -> str: return f"/u/{self.name}/config" def get_links(self, as_user: Optional["User"], page: int) -> Tuple[List[v.Link], v.Pagination]: query = Link.select().where((Link.user == self) & ((self == as_user) | (Link.private == False)) # noqa: E712 ) links = query.order_by(-Link.created).paginate(page, c.app.per_page) link_views = [link.to_view(as_user) for link in links] pagination = v.Pagination.from_total(page, query.count()) return link_views, pagination def get_link(self, link_id: int) -> "Link": try: return Link.get((Link.user == self) & (Link.id == link_id)) except Link.DoesNotExist: raise e.NoSuchLink(link_id) def get_tag(self, tag_name: str) -> "Tag": return Tag.get((Tag.user == self) & (Tag.name == tag_name)) def to_dict(self) -> dict: return {"id": self.id, "name": self.name} def get_config(self, status_msg: Optional[int]) -> v.Config: admin_pane = None if self.is_admin: user_invites = [ v.UserInvite( claimed=ui.claimed_by is not None, claimant=ui.claimed_by and ui.claimed_by.name, token=ui.token, ) for ui in UserInvite.select().where( UserInvite.created_by == self) ] admin_pane = v.AdminPane(invites=user_invites) return v.Config(username=self.name, admin_pane=admin_pane, msg=status_msg) def import_pinboard_data(self, stream): try: links = json.load(stream) except json.decoder.JSONDecodeError: raise e.BadFileUpload("could not parse file as JSON") if not isinstance(links, list): raise e.BadFileUpload("expected a list") # create and (for this session) cache the tags tags = {} for link in links: if "tags" not in link: raise e.BadFileUpload("missing key {exn.args[0]}") for t in link["tags"].split(): if t in tags: continue tags[t] = Tag.get_or_create_tag(self, t) with self.atomic(): for link in links: try: time = datetime.datetime.strptime(link["time"], "%Y-%m-%dT%H:%M:%SZ") ln = Link.create( url=link["href"], name=link["description"], description=link["extended"], private=link["shared"] == "no", created=time, user=self, ) except KeyError as exn: raise e.BadFileUpload(f"missing key {exn.args[0]}") for t in link["tags"].split(): HasTag.get_or_create(link=ln, tag=tags[t]) def get_tags(self) -> List[v.Tag]: return sorted( (t.to_view() for t in self.tags), # type: ignore key=lambda t: t.name.upper(), ) def get_related_tags(self, tag: "Tag") -> List[v.Tag]: # SELECT * from has_tag t1, has_tag t2, link l # WHERE t1.link_id == l.id AND t2.link_id == l.id # AND t1.id != t2.id AND t1 = self SelfTag = HasTag.alias() query = (HasTag.select(HasTag.tag).join( Link, on=(HasTag.link == Link.id)).join( SelfTag, on=(SelfTag.link == Link.id )).where((SelfTag.tag == tag) & (SelfTag.id != HasTag.id)).group_by(HasTag.tag)) return sorted( (t.tag.to_view() for t in query), key=lambda t: t.name, ) def get_string_search(self, needle: str, as_user: Optional["User"], page: int) -> Tuple[List[v.Link], v.Pagination]: """ Find all links that contain the string `needle` somewhere in their URL or title """ query = Link.select().where( (Link.user == self) & ((self == as_user) | (Link.private == False)) # noqa: E712 & (Link.name.contains(needle) | Link.description.contains(needle))) links = query.order_by(-Link.created).paginate(page, c.app.per_page) link_views = [link.to_view(as_user) for link in links] pagination = v.Pagination.from_total(page, query.count()) return link_views, pagination
class Document(BaseModel): """Base data model for all document classes """ DocumentID = pw.PrimaryKeyField() title = pw.CharField() author = pw.CharField() cost = pw.IntegerField() keywords = pw.CharField() active = pw.BooleanField(default=True) def get_document_copies(self): """Get list of copies of speciific document """ doc_class = class_to_name()[type(self)] query = Copy.select().where(Copy.docClass == doc_class, Copy.docId == self.DocumentID) res = [] for entry in query: res.append(entry) return res @classmethod def get_by_id(cls, doc_id): """Get document by id """ return cls.get(DocumentID=doc_id) @classmethod def add(cls, args): """Creates a new entity of selected type. Takes on input dictionary of values """ return cls.create(**args) @classmethod def remove(cls, doc_id): """Removes an entity with specific DocumentID """ entry = cls.get(DocumentID=doc_id) entry.active = False entry.save() copies = cls.get_document_copies(entry) for c in copies: Copy.remove(c.CopyID) @classmethod def edit(cls, doc_id, new_values): """Edit certain values in an entity with specific DocumentID """ temp = cls.get(DocumentID=doc_id) for k in new_values.keys(): temp.__dict__['_data'][k] = new_values[k] temp.save() print(temp.__dict__) #TODO : Add number of pages #Use SQL count() for pages @classmethod def get_list(cls, rows_number, page, active=0): """Returns a content from certain page of document list """ #Active - 1, Not active = -1, All = 0 if (active == 0): query = cls.select().offset(0 + (page - 1) * rows_number).limit( rows_number).order_by(cls.title.asc()) elif (active == 1): query = cls.select().where(cls.active == True).offset( 0 + (page - 1) * rows_number).limit(rows_number).order_by( cls.title.asc()) elif (active == -1): query = cls.select().where(cls.active == False).offset( 0 + (page - 1) * rows_number).limit(rows_number).order_by( cls.title.asc()) else: return ([]) res = [] for entry in query: res.append(entry) return res @classmethod def get_fields(cls): """Returns list of fields of specific document type """ temp = {**Document.__dict__, **cls.__dict__} temp.pop('__doc__') temp.pop('__module__') res = [] for key in temp.keys(): if (isinstance(temp[key], pw.FieldDescriptor)): res.append(key) return res @classmethod def get_fields_dict(cls): """Returns dictionary with field name as a key and type of field as a value """ map_to_types = { pw.IntegerField: int, pw.CharField: str, pw.TextField: str } temp = {**Document.__dict__, **cls.__dict__} temp.pop('__doc__') temp.pop('__module__') res = {} for key in temp.keys(): if (isinstance(temp[key], pw.FieldDescriptor)): if (isinstance(temp[key].field, pw.IntegerField) or isinstance(temp[key].field, pw.BigIntegerField)): res[key] = int elif (isinstance(temp[key].field, pw.CharField) or isinstance(temp[key].field, pw.TextField)): res[key] = str elif (isinstance(temp[key].field, pw.BooleanField)): res[key] = bool elif (isinstance(temp[key].field, pw.ForeignKeyField)): res[key] = 'foreign' return res
class TemporaryChannel(BaseModel): class Status(Enum): pending = 0 accepted = 1 denied = 2 class Type(Enum): normal = 0 mini = 1 guild_id = peewee.BigIntegerField(null=False) name = EmojiField(null=False) topic = EmojiField(null=False) channel_id = peewee.BigIntegerField(null=True) user_id = peewee.BigIntegerField(null=False) expiry_date = peewee.DateTimeField(null=True) active = peewee.BooleanField(null=False, default=True) status = EnumField(Status, null=False, default=Status.pending) deny_reason = peewee.TextField(null=True) pending_items = peewee.IntegerField(null=True) type = EnumField(Type, null=False, default=Type.normal) @property def item_code(self): if self.type == self.Type.normal: return "milky_way" elif self.type == self.Type.mini: return "orions_belt" @property def alias_name(self): if self.type == self.Type.normal: return "milkyway" elif self.type == self.Type.mini: return "orion" @property def days(self): if self.type == self.Type.normal: return 7 elif self.type == self.Type.mini: return 1 @property def ticket_embed(self): embed = discord.Embed(color=self.bot.get_dominant_color(None)) embed.set_author(icon_url=self.user.avatar_url, name=str(self.user)) embed.description = f"A temporary channel was requested.\nName: `{self.name}`\nTopic: `{self.topic}`" footer = [] footer.append( f"Use '/{self.alias_name} deny {self.id} <reason>' to deny this request" ) footer.append( f"Use '/{self.alias_name} accept {self.id}' to accept this request" ) embed.set_footer(text="\n".join(footer)) return embed def get_topic(self): return f"{self.topic}\nexpires at {self.expiry_date} UTC" async def update_channel_topic(self): await self.channel.edit(topic=self.get_topic()) def set_expiry_date(self, delta): if self.expiry_date is None: self.expiry_date = datetime.datetime.utcnow() self.expiry_date = self.expiry_date + delta async def create_channel(self): for category in self.guild.categories: if category.id == 764486536783462442: break channel = await self.guild.create_text_channel(name=self.name, topic=self.get_topic(), category=category) self.channel_id = channel.id return channel
class User(BaseModel): first_name = pw.CharField(null=True) last_name = pw.CharField() email = pw.CharField(unique=True, null=False) username = pw.CharField(unique=True, null=False) password = pw.CharField(null=False) photo = pw.CharField(null=True) private = pw.BooleanField(default=True) @hybrid_property def profile_picture_url(self): from instagram_web.util.helpers import S3_LOCATION if self.photo: return S3_LOCATION + self.photo else: return "https://afcm.ca/wp-content/uploads/2018/06/no-photo.png" def is_authenticated(self): return True def is_active(self): return True def is_following(self, user): for idol in self.idols: if idol.idol_id == user: return True # def validate_update(self, id): # self.errors = [] # self.check_form() # update_user = User.get_by_id(id) # check_password = check_password_hash(update_user.password, self.password) # if not check_password: # self.errors.append('Incorrect password') # if len(self.errors) == 0: # return True # else: # return False def validate(self): self.check_form() duplicate_username = User.get_or_none(User.username == self.username) if len(self.username) < 4: self.errors.append('Please provide a longer username.') if duplicate_username: self.errors.append('Username is not available.') def check_form(self): duplicate_email = User.get_or_none(User.email == self.email) if len(self.password) < 6: self.errors.append('Please enter a longer password') else: self.password = generate_password_hash(self.password) if len(self.first_name) < 1: self.errors.append('Please enter a first name.') if len(self.last_name) < 1: self.errors.append('Please enter a last name.') if duplicate_email: self.errors.append('Provided email is already in use.')
class Query(ModelTimestampsMixin, BaseModel, BelongsToOrgMixin): id = peewee.PrimaryKeyField() org = peewee.ForeignKeyField(Organization, related_name="queries") 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, with_last_modified_by=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_source_id } if with_user: d['user'] = self.user.to_dict() else: d['user_id'] = self.user_id if with_last_modified_by: d['last_modified_by'] = self.last_modified_by.to_dict( ) if self.last_modified_by is not None else None else: d['last_modified_by_id'] = self.last_modified_by_id 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, groups): q = Query.select(Query, User, QueryResult.retrieved_at, QueryResult.runtime)\ .join(QueryResult, join_type=peewee.JOIN_LEFT_OUTER)\ .switch(Query).join(User)\ .join(DataSourceGroup, on=(Query.data_source==DataSourceGroup.data_source))\ .where(Query.is_archived==False)\ .where(DataSourceGroup.group << groups)\ .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, groups): # TODO: 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 query_ids = cls.select(peewee.fn.Distinct(cls.id))\ .join(DataSourceGroup, on=(Query.data_source==DataSourceGroup.data_source)) \ .where(where) \ .where(DataSourceGroup.group << groups) return cls.select().where(cls.id << query_ids) @classmethod def recent(cls, groups, user_id=None, limit=20): query = cls.select(Query, User).where(Event.created_at > peewee.SQL("current_date - 7")).\ join(Event, on=(Query.id == Event.object_id.cast('integer'))). \ join(DataSourceGroup, on=(Query.data_source==DataSourceGroup.data_source)). \ switch(Query).join(User).\ where(Event.action << ('edit', 'execute', 'edit_name', 'edit_description', 'view_source')).\ where(~(Event.object_id >> None)).\ where(Event.object_type == 'query'). \ where(DataSourceGroup.group << groups).\ where(cls.is_archived == False).\ group_by(Event.object_id, Query.id, User.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 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.user_id), 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 @property def groups(self): if self.data_source is None: return {} return self.data_source.groups def __unicode__(self): return unicode(self.id)
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 Dashboard(ModelTimestampsMixin, BaseModel, BelongsToOrgMixin): id = peewee.PrimaryKeyField() org = peewee.ForeignKeyField(Organization, related_name="dashboards") 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, user=None): layout = json.loads(self.layout) if with_widgets: widget_list = 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 = {} for w in widget_list: if w.visualization_id is None: widgets[w.id] = w.to_dict() elif user and has_access(w.visualization.query.groups, user, view_only): widgets[w.id] = w.to_dict() else: widgets[w.id] = project( w.to_dict(), ('id', 'width', 'dashboard_id', 'options', 'created_at', 'updated_at')) widgets[w.id]['restricted'] = True # 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) else: widgets_layout = None return { 'id': self.id, 'slug': self.slug, 'name': self.name, 'user_id': self.user_id, '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 all(cls, org, groups, user_id): query = cls.select().\ join(Widget, peewee.JOIN_LEFT_OUTER, on=(Dashboard.id == Widget.dashboard)). \ join(Visualization, peewee.JOIN_LEFT_OUTER, on=(Widget.visualization == Visualization.id)). \ join(Query, peewee.JOIN_LEFT_OUTER, on=(Visualization.query == Query.id)). \ join(DataSourceGroup, peewee.JOIN_LEFT_OUTER, on=(Query.data_source == DataSourceGroup.data_source)). \ where(Dashboard.is_archived == False). \ where((DataSourceGroup.group << groups) | (Dashboard.user == user_id) | (~(Widget.dashboard >> None) & (Widget.visualization >> None))). \ where(Dashboard.org == org). \ group_by(Dashboard.id) return query @classmethod def recent(cls, org, groups, user_id, for_user=False, limit=20): query = cls.select().where(Event.created_at > peewee.SQL("current_date - 7")). \ join(Event, peewee.JOIN_LEFT_OUTER, on=(Dashboard.id == Event.object_id.cast('integer'))). \ join(Widget, peewee.JOIN_LEFT_OUTER, on=(Dashboard.id == Widget.dashboard)). \ join(Visualization, peewee.JOIN_LEFT_OUTER, on=(Widget.visualization == Visualization.id)). \ join(Query, peewee.JOIN_LEFT_OUTER, on=(Visualization.query == Query.id)). \ join(DataSourceGroup, peewee.JOIN_LEFT_OUTER, on=(Query.data_source == DataSourceGroup.data_source)). \ where(Event.action << ('edit', 'view')). \ where(~(Event.object_id >> None)). \ where(Event.object_type == 'dashboard'). \ where(Dashboard.is_archived == False). \ where(Dashboard.org == org). \ where((DataSourceGroup.group << groups) | (Dashboard.user == user_id) | (~(Widget.dashboard >> None) & (Widget.visualization >> None))). \ group_by(Event.object_id, Dashboard.id). \ order_by(peewee.SQL("count(0) desc")) if for_user: query = query.where(Event.user == user_id) query = query.limit(limit) return query @classmethod def get_by_slug_and_org(cls, slug, org): return cls.get(cls.slug == slug, cls.org == org) 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 Job(Base): "A request job" url = pw.CharField() headers = pw.CharField() completed = pw.BooleanField(default=False) pipeline = pw.ForeignKeyField(Pipeline, on_delete="CASCADE")
class ImageLike(BaseModel): user = pw.ForeignKeyField(User, backref='likes', on_delete='CASCADE') image = pw.ForeignKeyField(Image, backref='likes', on_delete='CASCADE') is_like = pw.BooleanField(default=False)
class TestSuite(BaseModel): init_pmax = peewee.DoubleField( help_text='Pmax value with which the test suite was started', null=False ) is_approved = peewee.BooleanField(null=True) factor = peewee.DoubleField(null=False) succ_num = peewee.IntegerField(null=True) is_succ = peewee.BooleanField(null=True) # Avg fields avg_NFE = peewee.DoubleField(null=True) avg_iter_num = peewee.DoubleField(null=True) avg_avg_health = peewee.DoubleField(null=True) avg_max_health = peewee.DoubleField(null=True) avg_std_health = peewee.DoubleField(null=True) avg_avg_health_deviation_to_opt_abs = peewee.DoubleField(null=True) avg_best_health_deviation_to_opt_abs = peewee.DoubleField(null=True) avg_avg_health_deviation_to_opt_rel = peewee.DoubleField(null=True) avg_best_health_deviation_to_opt_rel = peewee.DoubleField(null=True) avg_eucl_d_to_extremum = peewee.DoubleField(null=True) avg_hamm_d_to_extremum = peewee.DoubleField(null=True) avg_best_ind = peewee.DoubleField(null=True) avg_best_ind_n = peewee.DoubleField(null=True) # Best fields best_NFE = peewee.IntegerField(null=True) best_iter_num = peewee.IntegerField(null=True) best_avg_health = peewee.DoubleField(null=True) best_max_health = peewee.DoubleField(null=True) best_std_health = peewee.DoubleField(null=True) best_avg_health_deviation_to_opt_abs = peewee.DoubleField(null=True) best_best_health_deviation_to_opt_abs = peewee.DoubleField(null=True) best_avg_health_deviation_to_opt_rel = peewee.DoubleField(null=True) best_best_health_deviation_to_opt_rel = peewee.DoubleField(null=True) best_eucl_d_to_extremum = peewee.DoubleField(null=True) best_hamm_d_to_extremum = peewee.IntegerField(null=True) best_best_ind = peewee.IntegerField(null=True) best_best_ind_n = peewee.IntegerField(null=True) exp_suite_before = peewee.ForeignKeyField( ExperimentsSuite, null=True, on_delete='RESTRICT', lazy_load=True, backref='before_test_suites' ) exp_suite_after = peewee.ForeignKeyField( ExperimentsSuite, null=True, on_delete='RESTRICT', lazy_load=True, backref='after_test_suites' )
class BaseDocumentModel(peewee.Model): created = peewee.DateTimeField(null=False, default=datetime.now, formats=["%s"]) edited = peewee.DateTimeField(null=False, default=datetime.now, index=True, formats=["%s"]) is_deleted = peewee.BooleanField(null=False, default=False) owner = peewee.ForeignKeyField(User, null=True)
class Follow(BaseModel): follower_user_id = pw.ForeignKeyField(User, backref='followed') followed_user_id = pw.ForeignKeyField(User, backref='follower') approved_status = pw.BooleanField(default=True)
class FanIdol(BaseModel): fan = pw.ForeignKeyField(User, backref='idols') idol = pw.ForeignKeyField(User, backref='fans') approved = pw.BooleanField(default=False)
class Follow(BaseModel): follower = pw.ForeignKeyField(User, backref='follows') followed = pw.ForeignKeyField(User, backref='requests') approved = pw.BooleanField(default=False)
class UserServer(BaseModel, HttpSessionMixin): HOST = "0.0.0.0" METRIC_FIELDS = { "upload_traffic", "download_traffic", "tcp_conn_num", "ip_list" } __attr_accessible__ = {"port", "method", "password", "enable"} __running_servers__ = defaultdict(dict) __user_metrics__ = defaultdict(dict) __user_limiters__ = defaultdict(dict) user_id = pw.IntegerField(primary_key=True) port = pw.IntegerField(unique=True) method = pw.CharField() password = pw.CharField() enable = pw.BooleanField(default=True) @classmethod def shutdown(cls): for us in cls.select(): us.close_server() @classmethod def flush_metrics_to_remote(cls, url): data = [] need_reset_user_ids = [] for user_id, metric in cls.__user_metrics__.items(): if (metric["upload_traffic"] + metric["download_traffic"]) > 0: data.append({ "user_id": user_id, "upload_traffic": metric["upload_traffic"], "download_traffic": metric["download_traffic"], "ip_list": list(metric["ip_list"]), }) need_reset_user_ids.append(user_id) cls.http_session.request("post", url, json={"data": data}) for user_id in need_reset_user_ids: cls.__user_metrics__[user_id].update(cls.init_new_metric()) @property def host(self): return "0.0.0.0" @property def is_running(self): return self.user_id in self.__running_servers__ @property def tcp_server(self): return self.__running_servers__[self.user_id].get("tcp") @property def udp_server(self): return self.__running_servers__[self.user_id].get("udp") @tcp_server.setter def tcp_server(self, server): if self.tcp_server: self.tcp_server.close() self.__running_servers__[self.user_id]["tcp"] = server @udp_server.setter def udp_server(self, server): if self.udp_server: self.udp_server.close() self.__running_servers__[self.user_id]["udp"] = server @staticmethod def init_new_metric(): return {"upload_traffic": 0, "download_traffic": 0, "ip_list": set()} @property def metrics(self): return self.__user_metrics__[self.user_id] @metrics.setter def metrics(self, data): self.__user_metrics__[self.user_id].update(data) @property def traffic_limiter(self): return self.__user_limiters__[self.user_id].get("traffic") @traffic_limiter.setter def traffic_limiter(self, limiter): self.__user_limiters__[self.user_id]["traffic"] = limiter @property def tcp_limiter(self): return self.__user_limiters__[self.user_id].get("tcp") @tcp_limiter.setter def tcp_limiter(self, limiter): self.__user_limiters__[self.user_id]["tcp"] = limiter @property def limited(self): if self.tcp_limiter.limited or self.traffic_limiter.limited: return True else: return False async def init_server(self, user): # TODO remove this from shadowsocks.app import current_app self.is_running and self.check_user_server(user) if self.is_running or user.enable is False: return loop = asyncio.get_event_loop() try: tcp_server = await loop.create_server(LocalTCP(user), self.HOST, user.port) udp_server, _ = await loop.create_datagram_endpoint( LocalUDP(user), (self.HOST, user.port)) self.tcp_server = tcp_server self.udp_server = udp_server self.traffic_limiter = TrafficRateLimit(user.speed_limit) self.tcp_limiter = TcpConnRateLimit( current_app.user_tcp_conn_limit) self.metrics = self.init_new_metric() self.update_from_dict(user.to_dict()) self.save() logging.info("user:{} method:{} password:{} port:{} 已启动".format( user, user.method, user.password, user.port)) except OSError as e: logging.warning(e) def log_limited_msg(self): msg = "user: {} reach limit now tcp_conn_num:{} traffic_rate: {}".format( self.user_id, self.tcp_limiter.tcp_conn_num, self.traffic_limiter.cur_rate) logging.warning(msg) def check_user_server(self, user): need_check_fields = ["method", "port", "password"] for field in need_check_fields: if getattr(self, field) != getattr(user, field) or user.enable is False: self.close_server() return def close_server(self): if self.user_id not in self.__running_servers__: return server_data = self.__running_servers__.pop(self.user_id) server_data["tcp"].close() server_data["udp"].close() logging.info(f"user:{self.user_id} port:{self.port} 已关闭!") def record_ip(self, peername): if not peername: return self.metrics["ip_list"].add(peername[0]) def record_traffic(self, used_u, used_d): self.metrics["upload_traffic"] += used_u self.metrics["download_traffic"] += used_d def record_traffic_rate(self, data_lens): self.traffic_limiter.consume(data_lens) def incr_tcp_conn_num(self, num): self.tcp_limiter.incr_tcp_conn_num(num)
class Dataset(BaseModel): name = orm.CharField(unique=True) created = orm.TimestampField() meta = orm.BlobField() session = orm.BooleanField()
class Human(BaseModel): user_id = peewee.BigIntegerField (null = False, unique = True) gold = peewee.BigIntegerField (null = False, default = 250) timezone = peewee.TextField (null = True) date_of_birth = peewee.DateField (null = True) city = peewee.TextField (null = True) country = CountryField (null = True, column_name = "country_code") tester = peewee.BooleanField (null = False, default = False) currencies = CurrenciesField (null = False, default = lambda : set()) class Meta: indexes = ( (('user_id',), True), ) @property def all_currencies(self): currencies = set() if self.country: for currency in self.country.currencies(): currencies.add(currency) if self.currencies is not None: for currency in self.currencies: currencies.add(currency) return set(x for x in currencies if x is not None) @property def mention(self): return f"<@{self.user_id}>" @property def pigeon(self): for pigeon in self.pigeons: if pigeon.condition == pigeon.Condition.active: return pigeon @property def current_time(self): if self.timezone is not None: return Timezone(self.timezone).current_time @property def age_delta(self): if self.date_of_birth is not None: return relativedelta(datetime.datetime.utcnow(), self.date_of_birth) @property def age(self): if self.date_of_birth is not None: return self.age_delta.years @property def birthday(self): if self.date_of_birth is None: return False current_date = datetime.datetime.utcnow() return self.date_of_birth.day == current_date.day and self.date_of_birth.month == current_date.month def calculate_timezone(self): if self.city is not None and self.country is not None: city = self.bot.owm_api.by_q(self.city, self.country.alpha_2) if city is not None: return str(city.timezone) elif self.country is not None: if self.country.alpha_2 not in ("US", "CA"): latlng = self.country.capital_latlng() return Timezone.from_location(*latlng[::-1]).name def add_item(self, item, amount = 1, found = False): human_item, created = HumanItem.get_or_create(item = item, human = self) if created: human_item.amount = amount else: human_item.amount += amount if found: human_item.found = True human_item.save() return human_item @property def next_birthday(self): if self.date_of_birth is None: return None current_date = datetime.datetime.utcnow() if current_date.month >= self.date_of_birth.month and current_date.day >= self.date_of_birth.day: return datetime.datetime(current_date.year + 1, self.date_of_birth.month, self.date_of_birth.day) else: return datetime.datetime(current_date.year, self.date_of_birth.month, self.date_of_birth.day) @property def minutes_until_birthday(self): return abs((datetime.datetime.utcnow() - self.next_birthday).minutes) @property def days_until_birthday(self): return abs((datetime.datetime.utcnow() - self.next_birthday).days) @property def zodiac_sign(self): if self.date_of_birth is not None: return ZodiacSign.from_date(self.date_of_birth) def get_embed_field(self, show_all = False): #TODO: clean up. name = self.user.name if show_all and self.country: name += f" {self.country.flag_emoji}" values = [] if self.date_of_birth is not None: days_until_birthday = self.days_until_birthday age = self.age value = f"{self.zodiac_sign.emoji} {age}" if days_until_birthday < 10: value += f" (days left: {days_until_birthday})" values.append(value) elif show_all: values.append("🎂 N/A") if self.timezone is not None: timezone = Timezone(self.timezone) time = str(timezone.current_time.strftime('%H:%M')) values.append(f"🕑 {time}") elif show_all: values.append("🕑 N/A") if self.pigeon is not None: values.append("<:pigeon:767362416941203456> " + self.pigeon.name) elif show_all: values.append("<:pigeon:767362416941203456> N/A") if self.city is not None: city = self.bot.owm_api.by_q(self.city, self.country.alpha_2 if self.country else None) if city is not None: values.append(f"{city.weather_infos[0].emoji} {city.temperature_info.temperature}{city.unit.symbol}") elif show_all: values.append("🌡️ N/A") if self.gold is not None: values.append(f"{self.bot.gold_emoji} {self.gold}") elif show_all: values.append(f"{self.bot.gold_emoji} N/A") if len(values) == 0: values.append("N/A") sep = "\n" if not show_all: sep += "\n" return {"name" : name, "value" : sep.join(values), "inline" : True}
class User(BaseModel, HttpSessionMixin): __attr_protected__ = {"user_id"} __attr_accessible__ = { "port", "method", "password", "enable", "speed_limit" } user_id = pw.IntegerField(primary_key=True, unique=True) port = pw.IntegerField(index=True) method = pw.CharField() password = pw.CharField(unique=True) enable = pw.BooleanField(default=True) speed_limit = pw.IntegerField(default=0) access_order = pw.BigIntegerField(index=True, default=0) # NOTE find_access_user order need_sync = pw.BooleanField(default=False, index=True) # metrics field ip_list = IPSetField(default=set()) tcp_conn_num = pw.IntegerField(default=0) upload_traffic = pw.BigIntegerField(default=0) download_traffic = pw.BigIntegerField(default=0) @classmethod def _create_or_update_user_from_data(cls, data): user_id = data.pop("user_id") user, created = cls.get_or_create(user_id=user_id, defaults=data) if not created: user.update_from_dict(data) user.save() logging.debug(f"正在创建/更新用户:{user}的数据") return user @classmethod def list_by_port(cls, port): fields = [ cls.user_id, cls.method, cls.password, cls.enable, cls.ip_list, cls.access_order, ] return (cls.select(*fields).where(cls.port == port).order_by( cls.access_order.desc())) @classmethod def create_or_update_from_json(cls, path): with open(path, "r") as f: data = json.load(f) for user_data in data["users"]: cls._create_or_update_user_from_data(user_data) @classmethod def create_or_update_from_remote(cls, url): res = cls.http_session.request("get", url) for user_data in res.json()["users"]: cls._create_or_update_user_from_data(user_data) @classmethod def flush_metrics_to_remote(cls, url): data = [] need_reset_user_ids = [] fields = [ cls.user_id, cls.ip_list, cls.tcp_conn_num, cls.upload_traffic, cls.download_traffic, ] for user in cls.select(*fields).where(cls.need_sync == True): data.append({ "user_id": user.user_id, "ip_list": list(user.ip_list), "tcp_conn_num": user.tcp_conn_num, "upload_traffic": user.upload_traffic, "download_traffic": user.download_traffic, }) need_reset_user_ids.append(user.user_id) cls.http_session.request("post", url, json={"data": data}) with db.atomic(): cls.update(ip_list=set(), upload_traffic=0, download_traffic=0, need_sync=False).where( cls.user_id << need_reset_user_ids).execute() @db.atomic() def record_ip(self, peername): if not peername: return self.ip_list.add(peername[0]) User.update( ip_list=self.ip_list, need_sync=True).where(User.user_id == self.user_id).execute() @db.atomic() def record_traffic(self, used_u, used_d): User.update( download_traffic=User.download_traffic + used_d, upload_traffic=User.upload_traffic + used_u, need_sync=True, ).where(User.user_id == self.user_id).execute() @db.atomic() def incr_tcp_conn_num(self, num): filters = [User.user_id == self.user_id] if num < 0: filters.append(User.tcp_conn_num > 0) User.update( tcp_conn_num=User.tcp_conn_num + num, need_sync=True, ).where(*filters).execute()
class User(BaseModel, UserMixin): username = pw.CharField(unique=True) email = pw.CharField(unique=True) password_hash = pw.CharField(unique=False) image_path = pw.CharField(null=True) password = None is_private = pw.BooleanField(default=False) def follow(self, idol): from models.fan_idol import FanIdol # check whether current user follow idol before # relationship = FanIdol.get_or_none(fan=self.id, idol=idol.id) if self.follow_status(idol) == None: new_rel = FanIdol(fan=self.id, idol=idol.id) if idol.is_private == False: # public idol new_rel.is_approved = True return new_rel.save() else: return 0 def unfollow(self, idol): from models.fan_idol import FanIdol return FanIdol.delete().where(FanIdol.idol == idol.id, FanIdol.fan == self.id).execute() def follow_status(self, idol): from models.fan_idol import FanIdol return FanIdol.get_or_none(fan=self.id, idol=idol.id) @hybrid_property def idols(self): # return a list of idol user instances that only approved from models.fan_idol import FanIdol idols_id = FanIdol.select(FanIdol.idol).where( FanIdol.fan == self.id, FanIdol.is_approved == True) idols = User.select().where(User.id.in_(idols_id)) return idols @hybrid_property def fans(self): # return a list of fan user instances that only approved from models.fan_idol import FanIdol fans_id = FanIdol.select(FanIdol.fan).where( FanIdol.idol == self.id, FanIdol.is_approved == True) fans = User.select().where(User.id.in_(fans_id)) return fans @hybrid_property def idol_requests(self): from models.fan_idol import FanIdol idols_id = FanIdol.select(FanIdol.idol).where( FanIdol.fan == self.id, FanIdol.is_approved == False) return User.select().where(User.id.in_(idols_id)) @hybrid_property def fan_requests(self): from models.fan_idol import FanIdol fans_id = FanIdol.select(FanIdol.fan).where( FanIdol.idol == self.id, FanIdol.is_approved == False) return User.select().where(User.id.in_(fans_id)) def approve(self, fan): from models.fan_idol import FanIdol relationship = FanIdol.get_or_none(idol=self.id, fan=fan.id) relationship.is_approved = True return relationship.save() @hybrid_property def image_feed(self): from models.fan_idol import FanIdol from models.image import Image approved_idols_id = FanIdol.select(FanIdol.idol).where( FanIdol.fan == self.id, FanIdol.is_approved == True) idols_with_me = [x.idol for x in approved_idols_id ] # return a list of idols' id idols_with_me.append(self.id) # add your own id return Image.select().where(Image.user.in_(idols_with_me)).order_by( Image.created_at.desc()) @hybrid_property def profile_image_path(self): from app import app if not self.image_path: return app.config.get("AWS_S3_DOMAIN") + "mickey.jpg" return app.config.get("AWS_S3_DOMAIN") + self.image_path def validate(self): existing_email = User.get_or_none(User.email == self.email) existing_username = User.get_or_none(User.username == self.username) print("User validation in process") if existing_email and self.id != existing_email.id: self.errors.append("Email must be unique") if existing_username and self.id != existing_username.id: self.errors.append("Username must be unique") 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: print("No errors detected") self.password_hash = generate_password_hash(self.password) if not self.password_hash: self.errors.append("Password must be present")
class User(pw.Model): chat_id = pw.IntegerField(primary_key=True) user_name = pw.CharField(index=True, null=True) full_name = pw.CharField(index=True, null=True) daily_catalog_requests_limit = pw.IntegerField( default=int(env('SETTINGS_FREE_DAILY_REQUESTS', 5))) catalog_requests_blocked = pw.BooleanField(default=False, index=True) subscribe_to_wb_categories_updates = pw.BooleanField(default=False, index=True) created_at = pw.DateTimeField(index=True) updated_at = pw.DateTimeField(index=True) def can_send_more_catalog_requests(self) -> bool: """Throttling here.""" if self.catalog_requests_blocked is True: return False if self.today_catalog_requests_count( ) >= self.daily_catalog_requests_limit: return False return True def today_catalog_requests_count(self) -> int: """Get catalog requests count based on requests log.""" time_from = datetime.now() - timedelta(hours=24) return LogCommandItem.select().where( LogCommandItem.user == self.chat_id, LogCommandItem.command == 'wb_catalog', LogCommandItem.status == 'success', LogCommandItem.created_at >= time_from).count() def catalog_requests_left_count(self) -> int: return self.daily_catalog_requests_limit - self.today_catalog_requests_count( ) def next_free_catalog_request_time(self) -> datetime: if self.today_catalog_requests_count( ) < self.daily_catalog_requests_limit: return datetime.now() oldest_request = LogCommandItem.select().where( LogCommandItem.user == self.chat_id, LogCommandItem.command == 'wb_catalog', ).order_by(LogCommandItem.created_at).limit( self.daily_catalog_requests_limit).first() return oldest_request.created_at + timedelta(hours=24) def save(self, *args, **kwargs): """Add timestamps for creating and updating items.""" if not self.created_at: self.created_at = datetime.now() self.updated_at = datetime.now() return super(User, self).save(*args, **kwargs) class Meta: database = db