class Task(db.Model): _registry = {} id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) account_id = db.Column(db.Integer, db.ForeignKey('account.id')) user = db.relationship('User', uselist=False) account = db.relationship('Account', uselist=False, back_populates='tasks') _type = db.Column(db.String) _value = db.Column(db.String) _prev_value = db.Column(db.String) last_update = db.Column(db.DateTime) has_changed = db.Column(db.Boolean) uses_webhook = db.Column(db.Boolean, default=False) def __init_subclass__(cls, **kwargs): idx = cls.__name__.index('Task') cls._registry[cls.__name__[:idx].lower] = cls @classmethod def descriptions(cls) -> List[Tuple[str, str]]: return [(key, val.description) for key, val in cls._registry.items()] @classmethod def by_id(cls, task_id: int) -> Optional[Task]: return cls.query.get(task_id) @property def type(self) -> str: return self.__class__.__name__ @property def name(self) -> str: return self.__class__.__name__ @property def value(self) -> str: return self._value @value.setter def value(self, new_value: str): if new_value != self._value: self.has_changed = True self._prev_value = self._value self._value = new_value @property def prev_value(self) -> str: return self._prev_value __mapper_args__ = {'polymorphic_identity': 'task', 'polymorphic_on': _type} def update(self, data: Mapping[str, Any]): pass
class DevOpsReleaseTask(Task, DevOpsTask, StatusTask): __tablename__ = 'devops_release_environment' task_id = db.Column(db.Integer, db.ForeignKey('task.id'), primary_key=True) environment = db.Column(db.String) environment_id = db.Column(db.Integer) @property def name(self) -> str: return '{} {}'.format(self.pipeline, self.environment) @property def type(self) -> str: return 'Azure DevOps Release Pipeline Environment' __mapper_args__ = { 'polymorphic_identity': 'devops_release_environment', } def __eq__(self, other: Any) -> bool: if not hasattr(other, 'project') or \ not hasattr(other, 'definition_id') or \ not hasattr(other, 'environment_id'): return False return self.project == other.project and \ self.definition_id == other.definition_id and \ self.environment_id == other.environment_id
class DevOpsBuildTask(Task, DevOpsTask, StatusTask): __tablename__ = 'devops_build_pipeline' task_id = db.Column(db.Integer, db.ForeignKey('task.id'), primary_key=True) branch = db.Column(db.String, default='master') @property def name(self) -> str: return self.pipeline @property def type(self) -> str: return 'Azure DevOps Build Pipeline' __mapper_args__ = { 'polymorphic_identity': 'devops_build_pipeline', } def __eq__(self, other: Any) -> bool: if not hasattr(other, 'project') or \ not hasattr(other, 'definition_id'): return False return self.project == other.project and \ self.definition_id == other.definition_id
class DevOpsAccount(Account): __tablename__ = 'devops_account' description = 'Azure DevOps' account_id = db.Column(db.Integer, db.ForeignKey('account.id'), primary_key=True) username = db.Column(db.String) organization = db.Column(db.String) token = db.Column(db.String) __mapper_args__ = {'polymorphic_identity': 'devops_account'} def remove_task(self, task: Any): if isinstance(task, Task): super(DevOpsAccount, self).remove_task(task) else: for t in self.tasks: if t == task: self.tasks.remove(t) @property def build_tasks(self) -> List[DevOpsBuildTask]: return [t for t in self.tasks if isinstance(t, DevOpsBuildTask)] @property def release_tasks(self) -> List[DevOpsReleaseTask]: return [t for t in self.tasks if isinstance(t, DevOpsReleaseTask)]
class GitHubAccount(Account): __tablename__ = 'github_account' __mapper_args__ = {'polymorphic_identity': 'github_account'} description = 'GitHub' account_id = db.Column(db.Integer, db.ForeignKey('account.id'), primary_key=True) token = db.Column(db.String)
class WebAccount(Account): __tablename__ = 'web_account' __mapper_args__ = {'polymorphic_identity': 'web_account'} description = 'Web API Account' account_id = db.Column(db.Integer, db.ForeignKey('account.id'), primary_key=True) base_url = db.Column(db.String)
class ApplicationInsightsAccount(Account): __tablename__ = 'application_insights_account' description = 'Application Insights' account_id = db.Column(db.Integer, db.ForeignKey('account.id'), primary_key=True) application_id = db.Column(db.String) api_key = db.Column(db.String) __mapper_args__ = { 'polymorphic_identity': 'application_insights_account' }
class Account(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) type = db.Column(db.String) nickname = db.Column(db.String) user = db.relationship('User', back_populates='accounts') tasks = db.relationship('Task', back_populates='account') __mapper_args__ = { 'polymorphic_identity': 'account', 'polymorphic_on': type } _registry = {} def __init_subclass__(cls, **kwargs): idx = cls.__name__.index('Account') cls._registry[cls.__name__[:idx].lower()] = cls @classmethod def descriptions(cls) -> List[Tuple[str, str]]: return [(key, val.description) for key, val in cls._registry.items()] @classmethod def by_id(cls, account_id: int) -> Optional[Account]: return cls.query.get(account_id) @classmethod def all(cls) -> List[Account]: return cls.query.all() @property def name(self) -> str: return self.nickname if self.nickname else self.type def add_task(self, task: Task): if isinstance(task, Task): task.user_id = self.user_id task.account_id = self.id self.tasks.append(task) def remove_task(self, task: Task): if isinstance(task, Task): self.tasks.remove(task)
class HealthcheckTask(Task, StatusTask): __tablename__ = 'healthcheck_task' __mapper_args__ = {'polymorphic_identity': 'healthcheck_task'} task_id = db.Column(db.Integer, db.ForeignKey('task.id'), primary_key=True) path = db.Column(db.String) @property def type(self) -> str: return 'Healthcheck' @property def name(self) -> str: return 'Healthcheck for {}'.format(self.account.base_url) def update(self, data: Mapping[str, Any]): super().update(data) self.url = data.get('url', self.url)
class ApplicationInsightsMetricTask(Task): __tablename__ = 'application_insight_metric' task_id = db.Column(db.Integer, db.ForeignKey('task.id'), primary_key=True) metric = db.Column(db.String) nickname = db.Column(db.String) start = db.Column(db.DateTime) end = db.Column(db.DateTime) aggregation = db.Column(db.String) timespan = db.Column(db.String) @property def type(self) -> str: return 'Application Insights metric' @property def name(self) -> str: return self.nickname if self.nickname else self.metric __mapper_args__ = { 'polymorphic_identity': 'application_insight_metric', } @classmethod def choices(cls): return [('requests/count', 'Request count'), ('requests/duration', 'Request duration'), ('requests/failed', 'Failed requests')] def update(self, data: Mapping[str, Any]): super().update(data) self.metric = data.get('metric', self.metric) self.nickname = data.get('nickname', self.nickname) self.aggregation = data.get('aggregation', self.aggregation) self.timespan = data.get('timespan', self.timespan)
class GitHubRepositoryStatusTask(Task, StatusTask): __tablename__ = 'github_repoistory_status' __mapper_args__ = { 'polymorphic_identity': 'github_repository_status', } task_id = db.Column(db.Integer, db.ForeignKey('task.id'), primary_key=True) owner = db.Column(db.String) repo_name = db.Column(db.String) pr_count = db.Column(db.Integer) @classmethod def by_repo(cls, repo_name): return cls.query.filter_by(repo_name=repo_name).first() @property def repo(self): return '{}/{}'.format(self.owner, self.repo_name) def update(self, data: Mapping[str, Any]): super().update(data) self.uses_webhook = data.get('uses_webhook', self.uses_webhook)