Beispiel #1
0
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
Beispiel #3
0
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
Beispiel #4
0
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!"
                )
Beispiel #5
0
def migrate(migrator, database, fake=False, **kwargs):
    migrator.add_fields(
        Event,
        has_clip=pw.BooleanField(default=True),
        has_snapshot=pw.BooleanField(default=True),
    )
Beispiel #6
0
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)
Beispiel #8
0
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
Beispiel #9
0
class User(db.Model):

    name = pw.CharField(255)
    title = pw.CharField(127, null=True)
    active = pw.BooleanField(default=True)
    rating = pw.IntegerField(default=0)
Beispiel #10
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()
Beispiel #11
0
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
Beispiel #12
0
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
Beispiel #13
0
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
Beispiel #14
0
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.')
Beispiel #15
0
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)
Beispiel #16
0
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)
Beispiel #17
0
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)
Beispiel #18
0
class Job(Base):
    "A request job"
    url = pw.CharField()
    headers = pw.CharField()
    completed = pw.BooleanField(default=False)
    pipeline = pw.ForeignKeyField(Pipeline, on_delete="CASCADE")
Beispiel #19
0
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)
Beispiel #20
0
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'
    )
Beispiel #21
0
 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)
Beispiel #22
0
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)
Beispiel #24
0
class Follow(BaseModel):
    follower = pw.ForeignKeyField(User, backref='follows')
    followed = pw.ForeignKeyField(User, backref='requests')
    approved = pw.BooleanField(default=False)
Beispiel #25
0
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}
Beispiel #28
0
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()
Beispiel #29
0
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")
Beispiel #30
0
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