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))
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'
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'
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'
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
class Documentation(Document): schema_version = StringField(max_length=10, default='1') filename = StringField(required=True) path = StringField(required=True) uploader = ReferenceField(User) upload_date = DateTimeField(default=datetime.datetime.utcnow) last_modifier = ReferenceField(User) last_modified = DateTimeField(default=datetime.datetime.utcnow) organization = ReferenceField(Organization) team = ReferenceField(Team) view_times = IntField(default=0) proprietary = BooleanField(default=False) locked = BooleanField(default=False) language = StringField(default='en') class Meta: collection_name = 'documents'
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'
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'
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'
class PackageFile(Document): schema_version = StringField(max_length=10, default='1') filename = StringField(required=True) name = StringField(required=True) description = StringField() long_description = StringField() uploader = ReferenceField(User) upload_date = DateTimeField() download_times = IntField(default=0) version = StringField(default='0.0.1') class Meta: collection_name = 'package_files'
class Microservice(Document): name = StringField(unique=True, allow_none=False, required=True) version = StringField( unique=False, allow_none=False, required=True, validate=validate.Regexp( r'^\d+\.\d+\.\d+$', error="Field value must match the `major.minor.patch` version semantics." ) ) permissions = ListField(ReferenceField(Permission)) class Meta: indexes = ['$name', ]
class User(Document): username = StringField(unique=True, allow_none=False, required=True) password = StringField(allow_none=False, required=True) groups = ListField(ReferenceField(Group)) class Meta: indexes = [ '$username', ] def set_password(self, password): self.password = hash_password(password) def verify_password(self, password): return self.password and verify_password(password, self.password) async def pre_insert(self): self.set_password(self.password)
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
class Group(Document): name = StringField(allow_none=False, required=True) permissions = ListField(ReferenceField(Permission)) @classmethod async def synchronize_permissions(cls, old_permissions_ids, new_permissions_ids): deleted_permissions = list( set(old_permissions_ids) - set(new_permissions_ids)) if deleted_permissions: await Group.collection.update_many( {}, {"$pull": { "permissions": { "$in": deleted_permissions } }}) new_permissions = list( set(new_permissions_ids) - set(old_permissions_ids)) if not new_permissions_ids: return for group_name, config in app.config["DEFAULT_GROUPS"].items(): inserted_permissions = new_permissions[:] filter_expression = config.get('filter', None) if filter_expression: pipeline = [{ "$match": { "$and": [{ "_id": { "$in": inserted_permissions } }, filter_expression] } }, { '$group': { '_id': None, 'ids': { '$addToSet': '$_id' } } }] query_result = await Permission.collection.aggregate( pipeline).to_list(1) inserted_permissions = query_result[0][ 'ids'] if query_result else [] if inserted_permissions: await Group.collection.update_many({"name": group_name}, { "$addToSet": { "permissions": { "$each": inserted_permissions } } }) class Meta: indexes = { "keys": [ ('name', TEXT), ], "collation": Collation(locale="en", strength=2) }
class Users(Document): collection_name = "users" first_name = StringField(required=True) last_name = StringField(required=True) chats = ListField(ReferenceField('Chats'))
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
class Chats(Document): collection_name = "chats" title = StringField(required=True) users = ListField(ReferenceField('Users')) messages = ListField(ReferenceField('Messages'))
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)
class Task(Document): user = ReferenceField(User) title = StringField(required = True, max_length = 100) desc = StringField(required = True) mark_as = StringField(max_length = 8)
class Messages(Document): collection_name = "messages" sender = ReferenceField("Users") content = StringField(required=True) timestamp = DateTimeField(required=True)