示例#1
0
class Test(Document):
    schema_version = StringField(validate=validate.Length(max=10), default='1')
    test_suite = StringField(validate=validate.Length(max=100), required=True)
    test_cases = ListField(StringField(validate=validate.Length(max=100)))
    variables = DictField()
    path = StringField(validate=validate.Length(max=300), default='')
    author = ReferenceField('User')
    create_date = DateTimeField()
    update_date = DateTimeField()
    organization = ReferenceField('Organization')
    team = ReferenceField('Team')
    staled = BooleanField(default=False)
    package = ReferenceField('Package')
    package_version = StringField()

    class Meta:
        collection_name = 'tests'

    def __eq__(self, other):
        for key, value in self.items():
            if key == 'id':
                continue
            if key == 'create_date' or key == 'update_date':
                continue
            if value != other[key]:
                # missing is substituted to None in __getitem__, ie. other[key]
                if value is missing and other[key] is None:
                    continue
                return False
        return True

    def __hash__(self):
        return hash(str(self.pk))
示例#2
0
class Task(Document):
    schema_version = StringField(validate=validate.Length(max=10), default='1')
    test = ReferenceField('Test')
    test_suite = StringField(
        validate=validate.Length(max=100))  # embedded document from Test
    testcases = ListField(StringField())
    schedule_date = DateTimeField(default=datetime.datetime.utcnow)
    run_date = DateTimeField()
    status = StringField(validate=validate.Length(max=50), default='waiting')
    comment = StringField(validate=validate.Length(max=1000))
    kickedoff = IntField(validate=validate.Range(min=0), default=0)
    endpoint_list = ListField(UUIDField())
    parallelization = BooleanField(default=False)
    endpoint_run = ReferenceField('Endpoint')
    priority = IntField(validate=validate.Range(min=QUEUE_PRIORITY_MIN,
                                                max=QUEUE_PRIORITY_MAX),
                        default=QUEUE_PRIORITY_DEFAULT)
    variables = DictField()
    tester = ReferenceField('User')
    upload_dir = StringField(validate=validate.Length(max=100))
    test_results = ListField(ReferenceField('TestResult'))
    organization = ReferenceField(
        'Organization')  # embedded document from Test
    team = ReferenceField('Team')  # embedded document from Test

    class Meta:
        collection_name = 'tasks'
示例#3
0
class User(UsersMixin):
    def _validate_industries(field, value):
        for industry in value:
            yield from industry.industry.fetch(no_data=True)

    def _validate_invited_by(field, value):
        from models.utils import is_valid_invited_by
        if not (yield from is_valid_invited_by(value)):
            raise ValidationError('There is no such user or group code.')

    fullname = fields.StrField(required=True)
    email = fields.EmailField(unique=True, required=True)
    nickname = fields.StrField(unique=True,
                               required=True,
                               validate=validate.Regexp(r'[\w\d]+'))
    birthday = fields.DateTimeField(required=True, format=DATE_FORMAT)
    phone_numbers = fields.ListField(
        fields.StrField(validate=validate.Regexp(r'[+][\w\d]+')),
        required=True)
    photo = fields.StrField(required=True)
    bio = fields.StrField(required=False, validate=validate.Length(max=320))
    organizations = fields.StrField(required=False,
                                    validate=validate.Length(max=320))
    education = fields.StrField(required=False,
                                validate=validate.Length(max=320))
    personal_invite_code = fields.StrField(
        unique=True,
        required=True,
        validate=validate.Length(equal=INVITE_CODE_LENGTH))

    social_links = fields.ListField(fields.EmbeddedField(SocialLink))
    current_location = fields.EmbeddedField(Location)
    preferred_ways_to_meet = fields.ListField(
        fields.StrField(validate=validate.OneOf(PREFERRED_WAYS_TO_MEET)),
        unique=True)

    join_date = fields.DateTimeField(missing=datetime.utcnow())
    is_active = fields.BoolField(missing=False)
    is_deleted = fields.BoolField()
    date_deleted = fields.DateTimeField()
    is_notifications_enabled = fields.BoolField(missing=True)

    skills = fields.ListField(fields.ReferenceField(Tag), required=True)
    interests = fields.ListField(fields.ReferenceField(Tag))
    industries = fields.ListField(fields.EmbeddedField(Industry),
                                  required=True,
                                  io_validate=_validate_industries)
    languages = fields.ListField(fields.EmbeddedField(Language))

    looking_for = fields.ListField(fields.ReferenceField(LookingFor))
    bubbles = fields.ListField(fields.EmbeddedField(Bubble))

    invited_type = fields.StrField(required=True,
                                   validate=validate.OneOf(INVITE_TYPE))
    invited_by = fields.StrField(required=True,
                                 io_validate=_validate_invited_by)
示例#4
0
class Event(Document):
    schema_version = StringField(validate=validate.Length(max=10), default='1')
    code = IntField(required=True)
    message = DictField()
    organization = ReferenceField('Organization', required=True)
    team = ReferenceField('Team', default=None)
    status = StringField(validate=validate.Length(max=10), default='Triggered')
    date = DateTimeField(default=datetime.datetime.utcnow)

    class Meta:
        collection_name = 'events'
示例#5
0
class Endpoint(Document):
    schema_version = StringField(validate=validate.Length(max=10), default='1')
    name = StringField(validate=validate.Length(max=100))
    tests = ListField(ReferenceField('Test'))
    status = StringField(default='Offline', validate=validate.Length(max=20))
    enable = BooleanField(default=True)
    last_run_date = DateTimeField()
    organization = ReferenceField('Organization')
    team = ReferenceField('Team')
    uid = UUIDField()

    class Meta:
        collection_name = 'endpoints'
示例#6
0
class TestResult(Document):
    schema_version = StringField(validate=validate.Length(max=10), default='1')
    test_case = StringField(validate=validate.Length(max=100), required=True)
    test_site = StringField(validate=validate.Length(max=50))
    task = ReferenceField('Task')
    test_date = DateTimeField(default=datetime.datetime.utcnow)
    duration = IntField()
    summary = StringField(validate=validate.Length(max=200))
    status = StringField(validate=validate.Length(max=10), default='FAIL')
    more_result = DictField()

    class Meta:
        collection_name = 'test_results'
示例#7
0
class Team(Document):
    schema_version = StringField(validate=validate.Length(max=10), default='1')
    name = StringField(validate=validate.Length(max=100), required=True)
    email = EmailField()
    registered_on = DateTimeField(default=datetime.datetime.utcnow)
    owner = ReferenceField('User')
    members = ListField(ReferenceField('User'), default=[])
    editors = ListField(ReferenceField('User'), default=[])
    introduction = StringField(validate=validate.Length(max=500))
    avatar = StringField(validate=validate.Length(max=100))
    organization = ReferenceField('Organization')
    path = StringField()

    class Meta:
        collection_name = 'teams'
示例#8
0
class EventQueue(Document):
    schema_version = StringField(validate=validate.Length(max=10), default='1')
    events = ListField(ReferenceField('Event'), default=[])
    rw_lock = BooleanField(default=False)

    class Meta:
        collection_name = 'event_queues'

    async def acquire_lock(self):
        for i in range(LOCK_TIMEOUT):
            if await self.collection.find_one_and_update(
                {
                    '_id': self.pk,
                    'rw_lock': False
                }, {'$set': {
                    'rw_lock': True
                }}):
                return True
            await asyncio.sleep(0.1)
        else:
            return False

    async def release_lock(self):
        await self.collection.find_one_and_update({'_id': self.pk},
                                                  {'$set': {
                                                      'rw_lock': False
                                                  }})

    async def pop(self):
        if not await self.acquire_lock():
            return None
        await self.reload()
        if len(self.events) == 0:
            await self.release_lock()
            return None
        event = self.events.pop(0)
        event = await event.fetch()
        await self.commit()
        await self.release_lock()
        return event

    async def push(self, event):
        if not await self.acquire_lock():
            raise RuntimeError('failed to acquire queue lock')
        self.events.append(event)
        await self.commit()
        await self.release_lock()

    async def flush(self, cancelled=False):
        if not await self.acquire_lock():
            raise RuntimeError('failed to acquire queue lock')
        if cancelled:
            for event in self.events:
                event.status = 'Cancelled'
                await event.commit()
        self.events = []
        await self.commit()
        await self.release_lock()
        return True
示例#9
0
class GetInviteCodeRequest(Document):
    email = fields.EmailField(unique=True, required=True)
    code = fields.StrField(unique=True,
                           required=False,
                           validate=validate.Length(equal=INVITE_CODE_LENGTH))
    state = fields.StrField(required=True,
                            validate=validate.OneOf(GET_INVITE_CODE_STATE))
    created = fields.DateTimeField(missing=datetime.now())
示例#10
0
class Organization(Document):
    schema_version = StringField(validate=validate.Length(max=10), default='1')
    name = StringField(validate=validate.Length(max=50), required=True)
    fullname = StringField(validate=validate.Length(max=100))
    email = EmailField()
    registered_on = DateTimeField(default=datetime.datetime.utcnow)
    teams = ListField(ReferenceField('Team'), default=[])
    introduction = StringField(validate=validate.Length(max=500))
    website = URLField()
    owner = ReferenceField('User')
    members = ListField(ReferenceField('User'), default=[])
    editors = ListField(ReferenceField('User'), default=[])
    region = StringField()
    avatar = StringField(validate=validate.Length(max=100))
    path = StringField()
    personal = BooleanField(default=False)

    class Meta:
        collection_name = 'organizations'
示例#11
0
class RegisterUserSchema(UserSchema):
    phone = fields.StrField(required=True,
                            validate=validate.Regexp(r'[+][\w\d]+'))
    industry = marshmallow_fields.Nested(IndustryTagSchema, required=True)
    skills = fields.ListField(fields.StrField(),
                              required=True,
                              validate=validate.Length(min=1, max=10))
    interests = fields.ListField(fields.StrField(),
                                 validate=validate.Length(min=1, max=10))

    class Meta:
        fields = (
            'email',
            'password',
            'fullname',
            'nickname',
            'birthday',
            'phone',
            'current_location',
            'invited_type',
            'invited_by',
            'skills',
            'interests',
            'industry',
        )
        dateformat = DATE_FORMAT

    @post_load
    def make_user(self, data):
        data['phone_numbers'] = [data.pop('phone')]
        industry = data.pop('industry')
        skills = data.pop('skills')
        interests = data.pop('interests')
        user = User(**data)
        user.set_password(data['password'])
        return {
            'user': user,
            'industry': industry,
            'skills': skills,
            'interests': interests,
        }
示例#12
0
class UsersMixin(Document):
    password = fields.StrField(required=True, validate=validate.Length(min=5))

    class Meta:
        allow_inheritance = True
        abstract = True

    def set_password(self, password: str):
        self.password = get_hash(password)

    def check_password(self, password: str) -> bool:
        return safe_str_cmp(self.password, get_hash(password))
示例#13
0
class CafeEmployee(Document):
    username = fields.StringField(required=True,
                                  unique=True,
                                  validate=[
                                      validate.Length(min=6),
                                      validate.Length(max=60),
                                      validate.Regexp(r"[a-zA-Z ']+")
                                  ])
    password = fields.StringField(required=True,
                                  unique=True,
                                  validate=[
                                      validate.Length(min=8),
                                      validate.Length(max=100),
                                      validate.Regexp(r"[a-zA-Z0-9 ']+")
                                  ])
    id_cafe = fields.ReferenceField(Cafe)  #fields.ObjectIdField
    # group = fields.IntegerField()
    token = fields.StringField(required=True)

    class Meta:
        collection = db.employee
示例#14
0
class InviteGroup(Document):
    code = fields.StrField(unique=True,
                           required=True,
                           validate=validate.Length(equal=INVITE_CODE_LENGTH))
    limit = fields.IntField(required=True, validate=validate.Range(min=1))
    available_uses = fields.IntField(required=True,
                                     validate=validate.Range(min=0))

    # expiration_date = fields.DateTimeField()
    async def create_new_code(self, limit, code=None):
        from models.utils import create_new_invite_code

        self.code = code if code is not None else await create_new_invite_code(
        )
        self.limit = limit
        self.available_uses = limit
        await self.commit()
        return self
示例#15
0
class User(Document):  # pylint: disable=abstract-method
    """
    A user in the private database.
    """
    token = fields.StrField(required=True,
                            unique=True,
                            validate=validate.Length(equal=64))

    # The following 4 values could be unconfigured
    # Since the server only updates these after it validates credentials,
    # if both login and password exist, they're guaranteed to be valid credentials
    login = fields.StrField(required=False,
                            unique=True,
                            validate=validate.Regexp(r"\d+"))
    password = BinaryField(required=False)
    # Populated when credentials are set/updated
    # A value of null indicates either credentials are unset,
    # or the courses are in the process of being populated
    # An empty array indicates no courses found
    courses = fields.ListField(fields.ObjectIdField(),
                               required=False,
                               allow_none=True)
    # Should be set as soon as valid credentials are detected
    email = fields.EmailField(required=False, allow_none=True)

    active = fields.BoolField(default=True)
    errors = fields.ListField(fields.EmbeddedField(LockboxFailure), default=[])
    last_fill_form_result = fields.EmbeddedField(FillFormResult,
                                                 default=None,
                                                 allow_none=True)
    grade = fields.IntField(required=False, allow_none=True, default=None)
    first_name = fields.StrField(required=False,
                                 allow_none=True,
                                 default=None,
                                 validate=lambda s: s is None or len(s))
    last_name = fields.StrField(required=False,
                                allow_none=True,
                                default=None,
                                validate=lambda s: s is None or len(s))
示例#16
0
class BlacklistToken(Document):
    """
    Token Model for storing JWT tokens
    """
    token = StringField(validate=validate.Length(max=500),
                        required=True,
                        unique=True)
    blacklisted_on = DateTimeField(default=datetime.datetime.utcnow)

    class Meta:
        collection_name = 'blacklist_tokens'

    def __repr__(self):
        return '<id: token: {}'.format(self.token)

    @staticmethod
    async def check_blacklist(auth_token):
        # check whether auth token has been blacklisted
        res = await BlacklistToken.find_one({'token': str(auth_token)})
        if res is None:
            return False
        return True
示例#17
0
class InviteCodeSchema(Schema):
    invite_code = fields.StrField(
        required=True, validate=validate.Length(equal=INVITE_CODE_LENGTH))
示例#18
0
class Thread(Document):
    """
    We will mimic reddit, with votable threads. Each thread may have either
    a body text or a link, but not both.
    """
    # __tablename__ = 'threads_thread'

    title = fields.StrField(validate=validate.Length(max=THREAD.MAX_TITLE),
                            default=None)  # b.StringField(THREAD.MAX_TITLE)

    text = fields.StrField(default=None,
                           validate=validate.Length(max=THREAD.MAX_BODY))
    link = fields.StrField(default=None,
                           validate=validate.Length(max=THREAD.MAX_LINK))
    thumbnail = fields.StrField(default=None,
                                validate=validate.Length(max=THREAD.MAX_LINK))

    # NOTE: this should be ReferenceField
    user_id = fields.ObjectIdField()  # Integer?
    subreddit_id = fields.ObjectIdField()  #

    user = fields.ReferenceField("User")  # Integer?
    subreddit = fields.ReferenceField("Subreddit")

    comment_ids = fields.ListField(fields.ObjectIdField())
    comments = fields.ListField(fields.ReferenceField("Comment"))

    date_created = fields.DateTimeField(default=datetime.datetime.now(),
                                        missing=datetime.datetime.now())
    date_modified = fields.DateTimeField(
        default=datetime.datetime.now(),
        missing=datetime.datetime.now(),
    )

    status = fields.IntegerField(default=THREAD.ALIVE)

    num_votes = fields.IntegerField(default=0, missing=0)
    hotness = fields.IntegerField(default=0, missing=0)

    def update(self):
        if not self.date_created:
            self.date_created = datetime.datetime.now()
        self.date_modified = datetime.datetime.now()
        # self.subreddit = self.get_subreddit()
        # self.user = self.get_user()
        self.set_hotness()
        self.extract_thumbnail()
        return self

    class Meta:
        # collection = db.threads
        collection_name = "threads"
        indexes = ('username', '$text', 'title')

    # def get_subreddit(self):
    #     return subreddits_model.Subreddit.find({"id": self.subreddit_id})[0]

    # def get_user(self):
    #     return user_model.User.find({"id": self.user_id})[0]

    # def __init__(self, title, text, link, user_id, subreddit_id):
    #     self.title = title
    #     self.text = text
    #     self.link = link
    #     self.user_id = user_id
    #     self.subreddit_id = subreddit_id
    #     self.extract_thumbnail()
    #
    #     self.created_on = datetime.datetime.utcnow()
    #     self.updated_on = datetime.datetime.utcnow()
    #
    #     self.upvotes = 0
    #
    #     self.set_hotness()
    #     self.add_thread()
    #
    #
    # def get_thread(self):
    #     thread = {"title": self.title,
    #               "text" : self.text,
    #               "link": self.link,
    #               "user_id": self.user_id,
    #               "subreddit_id": self.subreddit_id,
    #               "created_on": self.created_on,
    #               "updated_on": self.updated_on,
    #               "upvotes": self.upvotes,
    #               "hotness": self.hotness}
    #     return thread
    #
    # def add_thread(self):
    #     thread = self.get_thread()
    #     id = db.threads.insert_one(thread).inserted_id
    #     self.set_id(id)
    #     return self
    #
    # def set_id(self, id):
    #     self.id = ObjectId(id)
    #
    # def __repr__(self):
    #     return '<Thread %r>' % (self.title)
    #
    # def get_comments(self, order_by='timestamp'):
    #     """
    #     default order by timestamp
    #     return only top levels!
    #     """
    #     if order_by == 'timestamp':
    #         return self.comments.filter_by(depth=1).\
    #             order_by(db.desc(Comment.created_on)).all()[:THREAD.MAX_COMMENTS]
    #     else:
    #         return self.comments.filter_by(depth=1).\
    #             order_by(db.desc(Comment.created_on)).all()[:THREAD.MAX_COMMENTS]
    #
    # def get_status(self):
    #     """
    #     returns string form of status, 0 = 'dead', 1 = 'alive'
    #     """
    #     return THREAD.STATUS[self.status]
    #
    def get_age(self):
        """
        returns the raw age of this thread in seconds
        """
        return (self.date_created -
                datetime.datetime(1970, 1, 1)).total_seconds()

    def get_hotness(self):
        """
        returns the reddit hotness algorithm (votes/(age^1.5))
        """
        order = math.log(max(abs(self.num_votes), 1),
                         10)  # Max/abs are not needed in our case
        seconds = self.get_age() - 1134028003
        return round(order + seconds / 45000, 6)

    def set_hotness(self):
        """
        returns the reddit hotness algorithm (votes/(age^1.5))
        """
        self.hotness = self.get_hotness()

    def pretty_date(self, typeof='created'):
        """
        returns a humanized version of the raw age of this thread,
        eg: 34 minutes ago versus 2040 seconds ago.
        """
        if typeof == 'created':
            return utils.pretty_date(self.date_created)
        elif typeof == 'updated':
            return utils.pretty_date(self.date_modified)

    def add_comment(self, comment_text, comment_parent_id, user_id):
        """
        add a comment to this particular thread
        """

        user = user_model.User.find_one({'id': ObjectId(user_id)})

        if comment_parent_id.strip().replace(" ", ""):
            # parent_comment = Comment.query.get_or_404(comment_parent_id)
            # if parent_comment.depth + 1 > THREAD.MAX_COMMENT_DEPTH:
            #    flash('You have exceeded the maximum comment depth')
            app.logger.error("have parent?: {}".format(comment_parent_id))
            app.logger.debug(type(comment_parent_id))
            comment_parent_id = ObjectId(comment_parent_id)
            comment = Comment(thread_id=ObjectId(self.id),
                              user_id=user.id,
                              text=comment_text,
                              parent_id=comment_parent_id,
                              parent=Comment.find_one(
                                  {"id": comment_parent_id}),
                              user=user,
                              thread=self,
                              date_created=datetime.datetime.now(),
                              date_modified=datetime.datetime.now())
        else:
            comment = Comment(thread_id=ObjectId(self.id),
                              user_id=ObjectId(user_id),
                              text=comment_text,
                              user=user,
                              thread=self,
                              date_created=datetime.datetime.now(),
                              date_modified=datetime.datetime.now())

        # db.session.add(comment)
        # db.session.commit()
        comment.commit()
        comment.set_depth()
        app.logger.debug("comment depth: {}".format(comment.depth))

        comment.commit()

        self.comments.append(comment)
        self.comment_ids.append(comment.id)
        return comment

    # def get_voter_ids(self):
    #     """
    #     return ids of users who voted this thread up
    #     """
    #     upvotes = ThreadUpvote.find({"thread_id":self.id})
    #     # rs = db.engine.execute(select)
    #     # ids = rs.fetchall() # list of tuples
    #     ids = [v.user_id for v in upvotes]
    #     return ids

    def has_voted(self, user_id):
        """
        did the user vote already
        """
        # select_votes = thread_upvotes.select(
        #         db.and_(
        #             thread_upvotes.c.user_id == user_id,
        #             thread_upvotes.c.thread_id == self.id
        #         )
        # )
        # rs = db.engine.execute(select_votes)

        select_votes = (ThreadUpvote.find(
            {"$and": [{
                "user_id": ObjectId(user_id)
            }, {
                "thread_id": self.id
            }]})).count()

        return False if select_votes == 0 else True

    def vote(self, user_id):
        """
        allow a user to vote on a thread. if we have voted already
        (and they are clicking again), this means that they are trying
        to unvote the thread, return status of the vote for that user
        """
        already_voted = self.has_voted(user_id)
        vote_status = None
        if not already_voted:
            # vote up the thread
            # db.engine.execute(
            #     thread_upvotes.insert(),
            #     user_id   = user_id,
            #     thread_id = self.id
            # )

            upvote_data = {"user_id": ObjectId(user_id), "thread_id": self.id}
            upvote = ThreadUpvote(**upvote_data)
            upvote.commit()

            self.num_votes = self.num_votes + 1
            vote_status = True
        else:

            query = {
                "$and": [{
                    "user_id": ObjectId(user_id)
                }, {
                    "thread_id": ObjectId(self.id)
                }]
            }
            app.logger.debug("thread_id: {}".format(self.id))
            app.logger.debug(ThreadUpvote.find(query).count())

            app.logger.debug(ThreadUpvote.__dict__)
            app.logger.debug(ThreadUpvote.opts.__dict__)

            # NOTE: Document.delete does not take query, but Document itself
            # upvote = ThreadUpvote.delete(query)

            upvote = ThreadUpvote.delete(ThreadUpvote.find_one(query))
            # upvote.commit()

            # NOTE: othe alternative is using pymongo api
            # upvote = db.thread_upvotes.remove(query)
            # NOTE: no need to do save:
            # db.thread_upvotes.save()

            app.logger.debug(upvote)

            self.num_votes = self.num_votes - 1
            vote_status = False

        app.logger.debug("vote_status: {}".format(vote_status))

        self.commit()
        # db.session.commit() # for the vote count
        return vote_status

    def extract_thumbnail(self):
        """
        ideally this type of heavy content fetching should be put on a
        celery background task manager or at least a crontab.. instead of
        setting it to run literally as someone posts a thread. but once again,
        this repo is just a simple example of a reddit-like crud application!
        """
        DEFAULT_THUMBNAIL = 'https://reddit.codelucas.com/static/imgs/reddit-camera.png'
        if self.link:
            thumbnail = media.get_top_img(self.link)
        if not thumbnail:
            thumbnail = DEFAULT_THUMBNAIL
        self.thumbnail = thumbnail
        self.commit()

    def get_comments(self):
        app.logger.debug(
            list(
                Comment.find({
                    "$and": [{
                        "thread_id": self.id
                    }, {
                        "parent": {
                            "$exists": True,
                            "$eq": None
                        }
                    }]
                })))

        comments = Comment.find({
            "$and": [{
                "thread_id": self.id
            }, {
                "parent": {
                    "$exists": True,
                    "$eq": None
                }
            }]
        })
        # return list(Comment.find({"thread_id":self.id}))
        return list(comments)

    def get_all_comments(self):
        app.logger.debug(list(Comment.find({"thread_id": self.id})))
        return list(Comment.find({"thread_id": self.id}))

    def get_comment_count(self):
        return Comment.find({"thread_id": self.id}).count()
示例#19
0
class Comment(Document):
    """
    This class is here because comments can only be made on threads,
    so it is contained completly in the threads module.

    Note the parent_id and children values. A comment can be commented
    on, so a comment has a one to many relationship with itself.

    Backrefs:
        A comment can refer to its parent thread with 'thread'
        A comment can refer to its parent comment (if exists) with 'parent'
    """
    # __tablename__ = 'threads_comment'

    text = fields.StringField(default=None,
                              validate=validate.Length(max=THREAD.MAX_BODY))

    user_id = fields.ObjectIdField()  # Integer?
    thread_id = fields.ObjectIdField()  # Integer?

    user = fields.ReferenceField("User")  # Integer?
    thread = fields.ReferenceField("Thread")  # Integer?

    parent_id = fields.ObjectIdField(missing=None)
    # children = fields.ReferenceField('Comment')
    parent = fields.ReferenceField('Comment', missing=None)

    depth = fields.IntField(default=1, missing=1)  # start at depth 1

    date_created = fields.DateTimeField(default=datetime.datetime.now(),
                                        missing=datetime.datetime.now())
    date_modified = fields.DateTimeField(default=datetime.datetime.now(),
                                         missing=datetime.datetime.now())

    num_votes = fields.IntegerField(default=0, missing=0)

    class Meta:
        collection_name = 'comments'

    def update(self):
        if not self.date_created:
            self.date_created = datetime.datetime.now()
        self.date_modified = datetime.datetime.now()
        # self.thread = self.get_thread()
        return self

    def __repr__(self):
        return '<Comment %r>' % (self.text[:25])

    # def __init__(self, thread_id, user_id, text, parent_id=None):
    #     self.thread_id = thread_id
    #     self.user_id = user_id
    #     self.text = text
    #     self.parent_id = parent_id
    #
    # def get_comment(self):
    #     comment = {"thread_id": self.thread_id,
    #               "user_id" : self.user_id,
    #               "text": self.text,
    #               "parent_id": self.parent_id,
    #               }
    #     return comment

    # def get_all_children(self):
    #     def get_children(parent_id, children=[]):
    #         children += Comment.find({"parent_id":parent_id})
    #         return children
    #
    #     def recursive_children(parent_id, children=[]):
    #         if children:
    #             for c in children:
    #                 return recursive_children(c.id)
    #
    #     for c in get_children():
    #         recursive_children(parent_id, children)
    #
    #     for c in Comment.find({"parent_id":parent_id}):
    #         children += get_children(c.id, children=children)
    #
    #     parent_id = copy.copy(self.id)
    #     Comment.find({"parent_id": self.id})
    #
    #     children = Comment.find({"parent_id":parent_id})
    #
    #     grandchildren = copy.copy(children)
    #     for child in copy.copy(children):
    #         grandchildren += get_recursive_children(child,

    def get_children(self):
        return Comment.find({"parent_id": self.id})

    def get_children_count(self):
        return self.get_children().count()

    def set_depth(self):
        """
        call after initializing
        """
        app.logger.debug("comments: {}".format([x for x in Comment.find()]))
        app.logger.debug("comments: {}".format(list(Comment.find())))
        for c in Comment.find():
            app.logger.debug("comment: {}".format(c))
            app.logger.debug("self.id, parent.id: {}".format(
                (self.id, self.parent_id)))

        num_children = self.get_children_count()
        app.logger.debug("num_children: {}".format(num_children))
        app.logger.debug("children: \n{}".format(
            [x for x in self.get_children()]))
        # if num_children > 0:
        if self.parent is not None:
            self.depth = self.parent.fetch().depth + 1
            self.commit()

    def get_comments(self, order_by='timestamp'):
        """
        default order by timestamp

        Note:
            Only getting depth = 1 comments for simplicity
        """
        app.logger.debug("in comments model.get_comments")
        if order_by == 'timestamp':
            # return self.children.order_by(db.desc(Comment.created_on)).\
            #     all()[:THREAD.MAX_COMMENTS]
            comments = (Comment.find({
                "parent_id": self.id
            }).sort([("date_created", pymongo.ASCENDING)
                     ])[:THREAD.MAX_COMMENTS])
            app.logger.debug("".join([
                "\n\t{}: child of {}".format(x.text,
                                             x.parent.fetch().text)
                for x in comments
            ]))
            comments = (Comment.find({
                "parent_id": self.id
            }).sort([("date_created", pymongo.ASCENDING)
                     ])[:THREAD.MAX_COMMENTS])
            app.logger.debug("returing: {}".format(comments))
            comments = (Comment.find({
                "parent_id": self.id
            }).sort([("date_created", pymongo.ASCENDING)
                     ])[:THREAD.MAX_COMMENTS])
            return list(comments)
        else:
            # return self.comments.order_by(db.desc(Comment.created_on)).\
            #     all()[:THREAD.MAX_COMMENTS]
            comments = (Comment.find({
                "parent_id": self.id
            }).sort([("date_created", pymongo.DESCENDING)
                     ])[:THREAD.MAX_COMMENTS])
            app.logger.debug(comments)
            return comments

    def get_margin_left(self):
        """
        nested comments are pushed right on a page
        -15px is our default margin for top level comments
        """
        margin_left = 15 + ((self.depth - 1) * 32)
        margin_left = min(margin_left, 680)
        return str(margin_left) + "px"

    def get_age(self):
        """
        returns the raw age of this thread in seconds
        """
        return (self.date_created -
                datetime.datetime(1970, 1, 1)).total_seconds()

    def pretty_date(self, typeof='created'):
        """
        returns a humanized version of the raw age of this thread,
        eg: 34 minutes ago versus 2040 seconds ago.
        """
        if typeof == 'created':
            return utils.pretty_date(self.date_created)
        elif typeof == 'updated':
            return utils.pretty_date(self.date_modified)

    def has_voted(self, user_id):
        """
        did the user vote already
        """

        select_votes = (CommentUpvote.find({
            "$and": [{
                "user_id": ObjectId(user_id)
            }, {
                "comment_id": self.id
            }]
        })).count()

        return False if select_votes == 0 else True

    def vote(self, user_id):
        """
        allow a user to vote on a thread. if we have voted already
        (and they are clicking again), this means that they are trying
        to unvote the thread, return status of the vote for that user
        """
        already_voted = self.has_voted(user_id)
        vote_status = None
        if not already_voted:
            # vote up the thread
            # db.engine.execute(
            #     thread_upvotes.insert(),
            #     user_id   = user_id,
            #     thread_id = self.id
            # )

            upvote_data = {"user_id": ObjectId(user_id), "comment_id": self.id}
            upvote = CommentUpvote(**upvote_data)
            upvote.commit()

            query = {
                "$and": [{
                    "user_id": ObjectId(user_id)
                }, {
                    "comment_id": ObjectId(self.id)
                }]
            }
            app.logger.debug("is created {}".format(
                CommentUpvote.find_one(query).is_created))

            self.num_votes = self.num_votes + 1
            vote_status = True
        else:

            query = {
                "$and": [{
                    "user_id": ObjectId(user_id)
                }, {
                    "comment_id": ObjectId(self.id)
                }]
            }
            app.logger.debug("comment_id: {}".format(self.id))
            app.logger.debug(CommentUpvote.find(query).count())

            app.logger.debug(CommentUpvote.__dict__)
            app.logger.debug(CommentUpvote.opts.__dict__)

            # NOTE: Document.delete does not take query, but Document itself
            # upvote = CommentUpvote.delete(query)

            upvoted_comment = CommentUpvote.find_one(query)
            if upvoted_comment:
                upvote = CommentUpvote.delete(upvoted_comment)

            app.logger.debug("upvoted_comment: {}".format(upvoted_comment))
            # upvote.commit()

            # NOTE: othe alternative is using pymongo api
            # upvote = db.thread_upvotes.remove(query)
            # NOTE: no need to do save:
            # db.thread_upvotes.save()

            # app.logger.debug(upvote)

            self.num_votes = self.num_votes - 1
            vote_status = False

        app.logger.debug("vote_status: {}".format(vote_status))

        self.commit()
        # db.session.commit() # for the vote count
        return vote_status

    def comment_on(self):
        """
        when someone comments on this particular comment
        """
        pass
示例#20
0
class User(Document):
    schema_version = StringField(validate=validate.Length(max=10), default='1')
    email = EmailField(required=True, unique=True)
    registered_on = DateTimeField(default=datetime.datetime.utcnow)
    name = StringField(validate=validate.Length(max=50))
    password_hash = StringField(validate=validate.Length(max=100))
    roles = ListField(StringField(validate=validate.Length(max=50)))
    avatar = StringField(validate=validate.Length(max=100))
    introduction = StringField(validate=validate.Length(max=500))
    organizations = ListField(ReferenceField('Organization'), default=[])
    teams = ListField(ReferenceField('Team'), default=[])
    region = StringField()

    class Meta:
        collection_name = 'users'

    @property
    def password(self):
        raise AttributeError('password: write-only field')

    @password.setter
    def password(self, password):
        self.password_hash = bcrypt.generate_password_hash(password).decode(
            'utf-8')

    def check_password(self, password):
        return bcrypt.check_password_hash(self.password_hash, password)

    @staticmethod
    def encode_auth_token(user_id):
        """
        Generates the Auth Token
        :return: string
        """
        try:
            payload = {
                'exp':
                datetime.datetime.utcnow() +
                datetime.timedelta(days=1, seconds=5),
                'iat':
                datetime.datetime.utcnow(),
                'sub':
                user_id
            }
            return jwt.encode(payload, key, algorithm='HS256')
        except Exception as e:
            logger.exception(e)
            return None

    @staticmethod
    async def decode_auth_token(auth_token):
        """
        Decodes the auth token
        :param auth_token:
        :return: dict|string
        """
        try:
            payload = jwt.decode(auth_token, key)
            is_blacklisted_token = await BlacklistToken.check_blacklist(
                auth_token)
            if is_blacklisted_token:
                return 'Token blacklisted. Please log in again.'
            else:
                return payload
        except jwt.ExpiredSignatureError:
            return 'Signature expired. Please log in again.'
        except jwt.InvalidTokenError:
            return 'Invalid token. Please log in again.'

    def is_collaborator(self):
        return 'collaborator' in self.roles

    def is_admin(self):
        return 'admin' in self.roles

    def __repr__(self):
        return "<User '{}'>".format(self.name)
示例#21
0
class Package(Document):
    schema_version = StringField(validate=validate.Length(max=10), default='1')
    package_type = StringField(required=True)
    name = StringField(required=True)
    index_url = URLField(default='http://127.0.0.1:5000/pypi')
    files = ListField(ReferenceField(PackageFile), default=[])
    proprietary = BooleanField(default=True)
    description = StringField()
    long_description = StringField()
    rating = FloatField(default=4)
    rating_times = IntField(default=1)
    download_times = IntField(default=0)
    organization = ReferenceField('Organization')
    team = ReferenceField('Team')
    uploader = ReferenceField('User')
    py_packages = ListField(
        StringField(),
        default=[])  # python packages defined by the test package
    upload_date = DateTimeField()
    modified = BooleanField(default=False)

    version_re = re.compile(r"^(?P<name>.+?)(-(?P<ver>\d.+?))-.*$").match

    class Meta:
        collection_name = 'packages'

    async def get_package_by_version(self, version=None):
        if version is None and len(self.files) > 0:
            return await self.files[0].fetch()
        for f in self.files:
            f = await f.fetch()
            if f.version == version:
                return f
        return None

    @async_property
    async def versions(self):
        return [(await f.fetch()).version for f in self.files]

    async def sort(self):
        files = [await f.fetch() for f in self.files]
        versions = [f.version for f in files]
        pairs = [(f, v) for f, v in zip(files, versions)]
        pairs.sort(key=lambda x: parse_version(x[1]), reverse=True)
        self.files = [f for f, v in pairs]
        await self.commit()

    @property
    def stars(self):
        return round(self.rating)

    @property
    def package_name(self):
        return self.name.replace('-', '_').replace(' ', '_')

    @property
    def latest_version(self):
        if len(self.files) > 0:
            return self.files[0].version
        return None

    def __hash__(self):
        return hash(str(self.pk))

    def __repr__(self):
        return self.package_name
示例#22
0
class TaskQueue(Document):
    '''
    Per endpoint per priority queue
    '''
    schema_version = StringField(validate=validate.Length(max=10), default='1')
    priority = IntField(validate=validate.Range(min=QUEUE_PRIORITY_MIN,
                                                max=QUEUE_PRIORITY_MAX),
                        default=QUEUE_PRIORITY_DEFAULT)
    tasks = ListField(ReferenceField('Task'), default=[])
    endpoint = ReferenceField('Endpoint')
    running_task = ReferenceField('Task', allow_none=True, default=missing)
    rw_lock = BooleanField(default=False)
    organization = ReferenceField('Organization')
    team = ReferenceField('Team')
    to_delete = BooleanField(default=False)

    class Meta:
        collection_name = 'task_queues'

    async def acquire_lock(self):
        for i in range(LOCK_TIMEOUT):
            if await self.collection.find_one_and_update(
                {
                    '_id': self.pk,
                    'rw_lock': False
                }, {'$set': {
                    'rw_lock': True
                }}):
                return True
            await asyncio.sleep(0.1)
        else:
            return False

    async def release_lock(self):
        await self.collection.find_one_and_update({'_id': self.pk},
                                                  {'$set': {
                                                      'rw_lock': False
                                                  }})

    async def pop(self):
        if not await self.acquire_lock():
            return None
        await self.reload()
        if len(self.tasks) == 0:
            await self.release_lock()
            return None
        task = self.tasks.pop(0)
        task = await task.fetch()
        self.running_task = task
        await self.commit()
        await self.release_lock()
        return task

    async def push(self, task):
        if not await self.acquire_lock():
            raise RuntimeError('failed to acquire queue lock')
        self.tasks.append(task)
        await self.commit()
        await self.release_lock()

    async def flush(self, cancelled=False):
        if not await self.acquire_lock():
            raise RuntimeError('failed to acquire queue lock')
        if cancelled:
            for task in self.tasks:
                task.status = 'cancelled'
                await task.commit()
        self.tasks = []
        await self.commit()
        await self.release_lock()
        return True