class PeriodicTask(Model): __tablename__ = "periodic_task" id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(length=120), unique=True) task = db.Column(db.String(length=120)) crontab_id = db.Column(db.Integer, db.ForeignKey('crontab_schedule.id')) crontab = db.relationship("CrontabSchedule", back_populates="periodic_tasks") interval_id = db.Column(db.Integer, db.ForeignKey('interval_schedule.id')) interval = db.relationship("IntervalSchedule", back_populates="periodic_tasks") args = db.Column(db.String(length=120)) kwargs = db.Column(db.String(length=120)) last_run_at = db.Column(db.DateTime, default=timezone.now) total_run_count = db.Column(db.Integer, default=0) enabled = db.Column(db.Boolean, default=True) no_changes = False def __str__(self): fmt = '{0.name}: {0.crontab}' return fmt.format(self) @property def schedule(self): if self.crontab: return self.crontab.schedule if self.interval: return self.interval.schedule
class Message(InternalAPIMixin, db.Model): __tablename__ = 'messages' id = db.Column(db.Integer, primary_key=True, autoincrement=True) sender_id = db.Column(db.Integer, nullable=False) group_id = db.Column(db.Integer, nullable=False) created = db.Column(db.DateTime, default=timezone.now) updated = db.Column(db.DateTime, onupdate=timezone.now) active = db.Column(db.Boolean, nullable=False, default=True) draft = db.Column(db.Boolean, nullable=False, default=False) statuses = db.relationship('MessageStatus', backref='message', lazy='dynamic') reactions = db.relationship('MessageReaction', backref='message', lazy='dynamic') discriminator = db.Column(db.String) __mapper_args__ = { 'polymorphic_on': discriminator, 'polymorphic_identity': 'message', } @property def request_user(self): return partial(self.internal_request, 'login', 'get_user') async def get_sender(self) -> RemoteUser: data = await self.request_user(user_id=self.sender_id) return RemoteUser(**data) @classmethod @as_future def outgoing_messages(cls, sender_id, **kwargs): return cls.query.filter_by(active=True, sender_id=sender_id, **kwargs) @classmethod @as_future def incoming_messages(cls, receiver_id, **kwargs): return cls.query.filter_by(active=True, **kwargs).join(MessageStatus) \ .filter(MessageStatus.receiver_id == receiver_id) @classmethod async def draft_messages(cls, sender_id, **kwargs): return await cls.outgoing_messages(sender_id).filter_by(draft=True, **kwargs) @classmethod @as_future def new_messages(cls, receiver_id, **kwargs): return cls.query.filter_by(active=True, **kwargs).join(MessageStatus) \ .filter(MessageStatus.receiver_id == receiver_id, MessageStatus.value == 'new') @as_future def add_reaction(self, user_id, value): return MessageReaction.create(value=value, user_id=user_id, message_id=self.id)
class Store(db.Model): __tablename__ = 'stores' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(128), nullable=True, unique=True) payload = db.Column(JSONType, nullable=False, default={}) orders = db.relationship('Order', backref='store', lazy='dynamic') items = db.relationship('Item', backref='store', lazy='dynamic') active = db.Column(db.Boolean, nullable=False, default=True)
class Market(db.Model): __tablename__ = 'markets' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(128), nullable=True) title = db.Column(db.String(512), nullable=True) enabled = db.Column(db.Boolean, nullable=False, default=True) sellers = db.relationship('Seller', backref='market', lazy='dynamic') items = db.relationship('Item', backref='market', lazy='dynamic')
class Group(db.Model): __tablename__ = 'groups' id = db.Column(db.Integer, primary_key=True, autoincrement=True) active = db.Column(db.Boolean, nullable=False, default=True) backups = db.relationship('Backup', backref='group', lazy='dynamic') recoveries = db.relationship('Recovery', backref='group', lazy='dynamic') # TODO: ? color = db.Column(ColorType)
class Group(db.Model): __tablename__ = 'groups' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(128), nullable=False) description = db.Column(db.String(512), nullable=False) recoveries = db.relationship('Recovery', backref='group', lazy='dynamic') backups = db.relationship('Backup', backref='group', lazy='dynamic') def __repr__(self): return '<Group(name=%s)>' % self.name
class PartySession(InternalAPIMixin, db.Model): __tablename__ = 'party_sessions' class Roles(enum.Enum): ADMIN = 1000 USER = 0 class Permissions(enum.Enum): ADMIN = 1000 CAN_CLOSE = ADMIN CAN_START = 500 USER = 0 id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, nullable=False) party_id = db.Column(db.Integer, db.ForeignKey('parties.id')) party = db.relationship('Party', backref=db.backref('sessions', lazy='dynamic')) role = db.Column(db.Enum(Roles), default=Roles.USER) settings = db.Column(JSONType, nullable=False, default={}) app_version_id = db.Column(db.Integer, db.ForeignKey('application_versions.id')) app_version = db.relationship( 'ApplicationVersion', backref=db.backref('sessions', lazy='dynamic')) def has_permission(self, perm: Permissions) -> bool: return self.role.value >= perm.value @property def request_user(self): return partial(self.internal_request, 'login', 'get_user') async def get_user(self) -> RemoteUser: data = await self.request_user(user_id=self.user_id) return RemoteUser(**data) @hybrid_property def members(self): return self.party.members @_check_permission(Permissions.CAN_START) async def start_party(self) -> None: await self.party.start(self) async def join_server(self) -> None: await self.party.join_server(self) async def close(self, code=None, reason=None) -> None: # TODO: all party members want to know that await future_exec(self.delete) leave_party = close
class GeoLocation(db.Model): __tablename__ = 'geo_locations' id = db.Column(db.Integer, primary_key=True) point = db.Column(Geometry(geometry_type='POINT', srid=4326)) region_id = db.Column(db.Integer, db.ForeignKey('geo_location_regions.id')) servers = db.relationship('Server', backref='geo_location', lazy='dynamic') default = db.Column(db.Boolean, nullable=False, default=False) @classmethod async def get_nearest(cls, lat, lon): """ Find the nearest point to the input coordinates. Convert the input coordinates to a WKT point and query for nearest point. """ pt = WKTElement('POINT({0} {1})'.format(lon, lat), srid=4326) return cls.query.order_by(cls.point.distance_box(pt)).first() @classmethod async def get_default(cls): return cls.query.filter_by(default=True).order_by(cls.id).first() @staticmethod async def from_point_to_xy(pt): """Extract x and y coordinates from a point geometry.""" # noinspection PyUnresolvedReferences point_json = json.loads(db.session.scalar(func.ST_AsGeoJSON(pt.point))) return point_json['coordinates']
class ResultFormatter(db.Model): __tablename__ = 'formatters' id = db.Column(db.Integer, primary_key=True, autoincrement=True) template = db.Column(db.Text, nullable=False) action = db.relationship('Action', backref='formatter', lazy='dynamic') enabled = db.Column(db.Boolean, nullable=False, default=True)
class Group(db.Model): __tablename__ = 'groups' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(128), nullable=False, unique=True) type = db.Column(ChoiceType(GROUP_TYPES)) created = db.Column(db.DateTime, default=timezone.now) updated = db.Column(db.DateTime, onupdate=timezone.now) active = db.Column(db.Boolean, nullable=False, default=True) messages = db.relationship('Message', backref='group', lazy='dynamic') @as_future def get_messages(self, user_id=None, **kwargs): default_kwargs = dict(active=True) if user_id is not None: default_kwargs.update(sender_id=user_id) default_kwargs.update(kwargs) return self.messages.filter_by(**default_kwargs) @as_future def get_memberships(self, user_id=None, **kwargs): default_kwargs = dict(active=True) if user_id is not None: default_kwargs.update(user_id=user_id) default_kwargs.update(kwargs) return self.memberships.filter_by(**default_kwargs)
class IntervalSchedule(Model): __tablename__ = "interval_schedule" PERIOD_CHOICES = (('days', _('Days')), ('hours', _('Hours')), ('minutes', _('Minutes')), ('seconds', _('Seconds')), ('microseconds', _('Microseconds'))) id = db.Column(db.Integer, primary_key=True, autoincrement=True) every = db.Column(db.Integer, nullable=False) period = db.Column(ChoiceType(PERIOD_CHOICES)) periodic_tasks = db.relationship('PeriodicTask') @property def schedule(self): return schedules.schedule( datetime.timedelta(**{self.period.code: self.every})) @classmethod def from_schedule(cls, session, schedule, period='seconds'): every = max(schedule.run_every.total_seconds(), 0) obj = cls.filter_by(session, every=every, period=period).first() if obj is None: return cls(every=every, period=period) else: return obj def __str__(self): if self.every == 1: return _('every {0.period_singular}').format(self) return _('every {0.every} {0.period}').format(self) @property def period_singular(self): return self.period[:-1]
class Backup(db.Model): __tablename__ = 'backups' id = db.Column(db.Integer, primary_key=True, autoincrement=True) created = db.Column(db.DateTime, default=timezone.now) group_id = db.Column(db.Integer, db.ForeignKey('groups.id')) recoveries = db.relationship('Recovery', backref='backup', lazy='dynamic')
class GeoLocationRegion(db.Model): __tablename__ = 'geo_location_regions' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) locations = db.relationship('GeoLocation', backref='region', lazy='dynamic')
class Category(db.Model): __tablename__ = 'category' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(128), nullable=True, unique=True) scheme = db.Column(JSONType, nullable=False, default={}) items = db.relationship('Item', backref='category', lazy='dynamic') active = db.Column(db.Boolean, nullable=False, default=True)
class ApplicationVersion(db.Model): __tablename__ = 'application_versions' __table_args__ = (db.UniqueConstraint('app_name', 'app_version'), ) id = db.Column(db.Integer, primary_key=True, autoincrement=True) app_name = db.Column(db.String(128), nullable=False) app_version = db.Column(db.String(128), nullable=False) build_id = db.Column(db.Integer, db.ForeignKey('builds.id')) build = db.relationship('Build')
class Category(db.Model): __tablename__ = 'categories' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(128), nullable=False, unique=True) description = db.Column(db.String(512), nullable=False) posts = db.relationship('Post', backref='category', lazy='dynamic') def __repr__(self): return '<Category(name=%s)>' % self.name
class Category(db.Model): __tablename__ = 'categories' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(128), nullable=False, unique=True) description = db.Column(db.String(512), nullable=False) posts = db.relationship('Post', backref='category', lazy='dynamic') def get_posts(self): return self.posts.filter_by(active=True).all()
class ApplicationVersion(db.Model): __tablename__ = 'application_versions' id = db.Column(db.Integer, primary_key=True, autoincrement=True) value = db.Column(db.String(128), nullable=False) application_id = db.Column( db.Integer, db.ForeignKey('applications.id'), nullable=False, index=True) groups = db.relationship( 'BundlesGroup', backref=db.backref('application_version'), lazy='dynamic', cascade='all, delete-orphan')
class CrontabSchedule(Model): """ Task result/status. """ __tablename__ = "crontab_schedule" __table_args__ = (db.UniqueConstraint('minute', 'hour', 'day_of_week', 'day_of_month', 'month_of_year'), ) id = db.Column(db.Integer, primary_key=True, autoincrement=True) minute = db.Column(db.String(length=120), default="*") hour = db.Column(db.String(length=120), default="*") day_of_week = db.Column(db.String(length=120), default="*") day_of_month = db.Column(db.String(length=120), default="*") month_of_year = db.Column(db.String(length=120), default="*") periodic_tasks = db.relationship('PeriodicTask') def __str__(self): rfield = lambda f: f and str(f).replace(' ', '') or '*' return '{0} {1} {2} {3} {4} (m/h/d/dM/MY)'.format( rfield(self.minute), rfield(self.hour), rfield(self.day_of_week), rfield(self.day_of_month), rfield(self.month_of_year), ) @property def schedule(self): spec = { 'minute': self.minute, 'hour': self.hour, 'day_of_week': self.day_of_week, 'day_of_month': self.day_of_month, 'month_of_year': self.month_of_year } return schedules.crontab(**spec) # noinspection PyProtectedMember @classmethod def from_schedule(cls, session, schedule): spec = { 'minute': schedule._orig_minute, 'hour': schedule._orig_hour, 'day_of_week': schedule._orig_day_of_week, 'day_of_month': schedule._orig_day_of_month, 'month_of_year': schedule._orig_month_of_year } obj = cls.filter_by(session, **spec).first() if obj is None: return cls(**spec) else: return obj
class Bot(db.Model): """ Automation format: { "connect": [ { "group": "name_1" }, { "group": "name_2" }, ... { "group": "name_N" } ] } """ __tablename__ = 'bots' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(128), nullable=False, unique=True) description = db.Column(db.String(512), nullable=False) payload = db.Column(JSONType, nullable=False, default={}) automation = db.Column(JSONType, nullable=False, default={}) last_login = db.Column(db.DateTime, nullable=True, default=None) created = db.Column(db.DateTime, default=timezone.now) enabled = db.Column(db.Boolean, nullable=False, default=True) actions = db.relationship('Action', secondary=bot_action_association, backref='bots', lazy='dynamic') @property def connect_groups(self) -> List[str]: return [item['group'] for item in self.automation['connect']] def __str__(self): return self.name def __repr__(self): return "<Bot(name=%s, description=%s)>" % (self.name, self.description) @hybrid_property def photo(self): return self.payload.get('avatar') @hybrid_property def first_name(self): return self.payload.get('first_name') @hybrid_property def last_name(self): return self.payload.get('last_name')
class Application(db.Model): __tablename__ = 'applications' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(256), nullable=False) repo_url = db.Column(db.String(512), nullable=False) repo_branch = db.Column(db.String(128), default='master') repo_ssh_key = db.Column(db.Text) versions = db.relationship('ApplicationVersion', backref='application', lazy='dynamic', cascade='all, delete-orphan')
class Environment(db.Model): __tablename__ = 'environments' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) description = db.Column(db.String(512), nullable=False) discovery = db.Column(URLType, nullable=False) scheme_id = db.Column(db.Integer, db.ForeignKey('payload_scheme.id'), nullable=False) payload = db.Column(JSONType, nullable=False, default={}) # defined by ``scheme`` color = db.Column(ColorType) enabled = db.Column(db.Boolean, nullable=False, default=True) app_versions = db.relationship('ApplicationVersion', backref='environment', lazy='dynamic') scheme = db.relationship('PayloadScheme')
class Application(db.Model): __tablename__ = 'applications' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(256), nullable=False) deployment_method_id = db.Column( db.Integer, db.ForeignKey('deployment_methods.id'), nullable=False, index=True) filters_scheme = db.Column(JSONType, nullable=False) payload_scheme = db.Column(JSONType, nullable=False) versions = db.relationship( 'ApplicationVersion', backref=db.backref('application'), lazy='dynamic', cascade='all, delete-orphan')
class Environment(db.Model): __tablename__ = 'environments' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) description = db.Column(db.String(512), nullable=False) discovery = db.Column(URLType, nullable=False) payload = db.Column(JSONType, nullable=False, default={}) color = db.Column(ColorType) active = db.Column(db.Boolean, nullable=False, default=True) app_versions = db.relationship('ApplicationVersion', backref='environment', lazy='dynamic')
class EventCategory(db.Model): __tablename__ = 'event_categories' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(128), nullable=False) description = db.Column(db.String(512), nullable=False) payload = db.Column(JSONType, nullable=False, default={}) events = db.relationship('Event', backref='category', lazy='dynamic') generators = db.relationship('EventGenerator', backref='category', lazy='dynamic') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.Schema = self.get_schema_class() @classmethod def get_schema_class(cls): class _Schema(ma.Schema): class Meta: model = cls fields = ('id', 'name', 'description', 'payload') return _Schema
class Permission(db.Model): __tablename__ = 'permission' id = db.Column(db.Integer, primary_key=True) domain_id = db.Column(db.ForeignKey('domain.id'), nullable=True) action_id = db.Column(db.ForeignKey('action.id'), nullable=True) resource_id = db.Column(db.ForeignKey('resource.id'), nullable=True) domain = db.relationship('Domain', backref='permission') action = db.relationship('Action', backref='permission') resource = db.relationship('Resource', backref='permission') roles = db.relationship('Role', secondary=role_permission, backref='permissions') users = association_proxy('roles', 'users') def __repr__(self): return ( "Permission(domain_id={0},action_id={1},resource_id={2})".format( self.domain_id, self.action_id, self.resource_id))
class Application(db.Model): __tablename__ = 'applications' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(128), nullable=False, unique=True) title = db.Column(db.String(512), nullable=False, unique=True) enabled = db.Column(db.Boolean, nullable=False, default=True) versions = db.relationship('ApplicationVersion', backref='application', lazy='dynamic') @as_future def latest_version(self): return self.versions.last()
class DeploymentMethod(db.Model): __tablename__ = 'deployment_methods' # noinspection PyArgumentList Names = enum.Enum('Names', list(Deployment().methods_dict)) id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(ChoiceType(Names, impl=db.Integer()), nullable=False) data = db.Column(JSONType, nullable=False) applications = db.relationship( 'Application', backref=db.backref('deployment_method'), lazy='dynamic', cascade='all, delete-orphan') def get_method(self): cls = Deployment().get_method(self.name) return cls(**self.data)
class Item(InternalAPIMixin, db.Model): __tablename__ = 'items' id = db.Column(db.Integer, primary_key=True, autoincrement=True) user_id = db.Column(db.Integer, nullable=False) market_id = db.Column(db.Integer, db.ForeignKey('markets.id')) orders = db.relationship('Order', backref='item', lazy='dynamic') created = db.Column(db.DateTime, default=timezone.now) payload = db.Column(JSONType, nullable=False, default={}) price = db.Column(JSONType, nullable=False, default={}) enabled = db.Column(db.Boolean, nullable=False, default=True) async def get_user(self) -> RemoteUser: data = await self.internal_request('login', 'get_user', user_id=self.user_id) return RemoteUser(**data)
class BundlesGroup(db.Model): __tablename__ = 'bundle_groups' STATUSES = ( ('created', _('Created')), ('publishing', _('Publishing')), ('published', _('Published')), ('error', _('Error')), ) id = db.Column(db.Integer, primary_key=True, autoincrement=True) status = db.Column(ChoiceType(STATUSES), nullable=False, default='created') hash_types = db.Column(JSONType, nullable=False) bundles = db.relationship( 'Bundle', backref=db.backref('group'), lazy='dynamic', cascade='all, delete-orphan') version_id = db.Column( db.Integer, db.ForeignKey('application_versions.id'), nullable=False, index=True)