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 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 Recovery(InternalAPIMixin, db.Model): __tablename__ = 'recoveries' 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')) # TODO: ? backup_id = db.Column(db.Integer, db.ForeignKey('backups.id')) author_id = db.Column(db.Integer, nullable=False) # TODO: async def get_author(self): return await self.internal_request('login', 'get_user', user_id=self.author_id)
class ResultFormatter(db.Model): __tablename__ = 'formatters' id = db.Column(db.Integer, primary_key=True, autoincrement=True) template = db.Column(db.Text, nullable=False) action_id = db.Column(db.Integer, db.ForeignKey('actions.id')) enabled = db.Column(db.Boolean, nullable=False, default=True)
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 Bundle(db.Model): __tablename__ = 'bundles' STATUSES = ( ('created', _('Created')), ('uploaded', _('Uploaded')), ('delivering', _('Delivering')), ('delivered', _('Delivered')), ('error', _('Error')), ) id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(128), nullable=False) key = db.Column(db.String(64), nullable=False) filename = db.Column(db.String(128), nullable=False, unique=True) hash = db.Column(JSONType, nullable=False) filter = db.Column(JSONType, nullable=False) status = db.Column(ChoiceType(STATUSES), nullable=False, default='created') group_id = db.Column( db.Integer, db.ForeignKey('bundle_groups.id'), nullable=False, index=True) @property def application_version(self): return self.group.application_version @property def application(self): return self.application_version.application @property def deployment_method(self): return self.application.deployment_method @property def size(self): return default_storage.size(self.filename) @property def url(self): deployment_method = self.deployment_method.get_method() return deployment_method.url(self.filename) def make_hash(self, filename=None, group=None): newhash = {} group = group or self.group filename = filename or self.filename with default_storage.open(filename) as fd: hasher = Hasher(fd.read()) for hash_type, hash_is_active in group.hash_types.items(): if not hash_is_active: # hash type not active, so skip continue hash_type = hash_type.lower() hashing_method = getattr(hasher, hash_type, None) if callable(hashing_method): newhash[hash_type] = hashing_method() return newhash def update_hash(self): self.hash = self.make_hash()
class ApplicationVersion(db.Model): __tablename__ = 'application_versions' __table_args__ = (db.UniqueConstraint('value', 'application_id'), ) 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) environment_id = db.Column(db.Integer, db.ForeignKey('environments.id'), nullable=False) enabled = db.Column(db.Boolean, nullable=False, default=True) def __lt__(self, other): return self.value < other.value
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 Action(db.Model): __tablename__ = 'actions' TYPES = ( ('path', _('Path')), ('code', _('Code')), ) 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) value = db.Column(db.Text, nullable=False) type = db.Column(ChoiceType(TYPES)) enabled = db.Column(db.Boolean, nullable=False, default=True) formatter_id = db.Column(db.Integer, db.ForeignKey('formatters.id')) def __repr__(self): return "<Action(name=%s, description=%s)>" % (self.name, self.description) def __getattr__(self, item): return getattr(self.value_object, item) @cached_property def value_object(self) -> BaseAction: return import_string(self.value)()
class Post(db.Model): __tablename__ = 'posts' id = db.Column(db.Integer, primary_key=True, autoincrement=True) created = db.Column(db.DateTime, default=timezone.now) content = db.Column(db.Text, nullable=False) active = db.Column(db.Boolean, nullable=False, default=True) category_id = db.Column(db.Integer, db.ForeignKey('categories.id'))
class Item(db.Model): __tablename__ = 'items' __table_args__ = (db.UniqueConstraint('store_id', 'name'), ) id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(128), nullable=True) store_id = db.Column(db.Integer, db.ForeignKey('stores.id')) category_id = db.Column(db.Integer, db.ForeignKey('category.id')) payload = db.Column(JSONType, nullable=False, default={}) orders = db.relationship('Order', backref='item', lazy='dynamic') created = db.Column(db.DateTime, default=timezone.now) active = db.Column(db.Boolean, nullable=False, default=True) def description(self, lang): raise NotImplementedError def title(self, lang): raise NotImplementedError
class Message(InternalAPIMixin, db.Model): __tablename__ = 'messages' id = db.Column(db.Integer, primary_key=True, autoincrement=True) sender_id = db.Column(db.Integer) 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) group_id = db.Column(db.Integer, db.ForeignKey('groups.id')) 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): # TODO: message_id = self.id pass
class Credential(db.Model): __tablename__ = 'credential' id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.ForeignKey('user.id'), nullable=False, unique=False) credential = db.Column(db.String, nullable=False) credential_type_id = db.Column(db.ForeignKey('credential_type.id'), nullable=False) expiration_dt = db.Column(db.DateTime(timezone=True), nullable=False) user = db.relationship('User', backref='credential', cascade="all, delete-orphan", single_parent=True) def __repr__(self): return ("Credential(credential_type_id={0}, user_id={1})".format( self.credential_type_id, self.user_id))
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 URLMessage(Message): __tablename__ = 'url_messages' id = db.Column(db.Integer, db.ForeignKey('messages.id'), primary_key=True) content_type = db.Column(db.String(128), nullable=False) value = db.Column(URLType, nullable=False) __mapper_args__ = { 'polymorphic_identity': 'url_message', }
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) commit = db.Column(db.String(128), nullable=False, unique=True) application_id = db.Column(db.Integer, db.ForeignKey('applications.id'), nullable=False, index=True)
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 TextMessage(Message): __tablename__ = 'text_messages' id = db.Column(db.Integer, db.ForeignKey('messages.id'), primary_key=True) content_type = db.Column(db.String(128), nullable=False, default='text/plain') value = db.Column(db.Text, nullable=False) __mapper_args__ = { 'polymorphic_identity': 'text_message', }
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 Room(InternalAPIMixin, db.Model): __tablename__ = 'rooms' id = db.Column(db.Integer, primary_key=True) server_id = db.Column(db.Integer, db.ForeignKey('servers.id')) app_version_id = db.Column(db.Integer, db.ForeignKey('application_versions.id')) players = db.relationship('Player', backref='room', lazy='dynamic') settings = db.Column(JSONType, nullable=False, default={}) max_players_count = db.Column(db.Integer, nullable=False, default=0) async def check_moderations(self): # TODO: get moderations from moderation servce if True: raise UserBannedError async def join(self, player): players = await future_exec(self.players.all) if len(players) >= self.max_players_count: raise PlayersLimitPerRoomExceeded await self.check_moderations() player.room_id = self.id await future_exec(self.players.append, player) # TODO: make other players to know about new player player_data1 = {} for p in players: await RemoteUser.send_message_by_user_id( p.id, message=json.dumps(player_data1), content_type='application/json') # TODO: send some info to the new player player_data2 = {} await RemoteUser.send_message_by_user_id( player.user_id, message=json.dumps(player_data2), content_type='application/json')
class Order(InternalAPIMixin, db.Model): __tablename__ = 'orders' id = db.Column(db.Integer, primary_key=True, autoincrement=True) user_id = db.Column(db.Integer, nullable=False) item_id = db.Column(db.Integer, db.ForeignKey('items.id')) created = db.Column(db.DateTime, default=timezone.now) async def get_user(self) -> RemoteUser: data = await self.internal_request('login', 'get_user', user_id=self.user_id) return RemoteUser(**data)
class Seller(InternalAPIMixin, db.Model): __tablename__ = 'sellers' id = db.Column(db.Integer, primary_key=True, autoincrement=True) user_id = db.Column(db.Integer, nullable=False, unique=True) market_id = db.Column(db.Integer, db.ForeignKey('markets.id')) 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 Player(InternalAPIMixin, db.Model): __tablename__ = 'players' id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, nullable=False) room_id = db.Column(db.Integer, db.ForeignKey('rooms.id')) payload = db.Column(JSONType, nullable=False, default={}) async def get_user(self) -> RemoteUser: data = await self.internal_request('login', 'get_user', user_id=self.user_id) return RemoteUser(**data)
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 UserSocialAuth(_AppSession, SQLAlchemyUserMixin): """Social Auth association model.""" uid = db.Column(db.String(UID_LENGTH)) user_id = db.Column(User.id.type, db.ForeignKey(User.id), nullable=False, index=True) user = relationship(User, backref=backref('social_auth', lazy='dynamic')) @classmethod def username_max_length(cls): return User.__table__.columns.get('username').type.length @classmethod def user_model(cls): return User
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 VotingMember(InternalAPIMixin, db.Model): __tablename__ = 'voting_members' __table_args__ = ( db.UniqueConstraint('user_id', 'voting_id'), ) id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, nullable=False) voting_id = db.Column(db.Integer, db.ForeignKey('voting.id'), nullable=False) result = db.Column(ScalarListType(), nullable=False) created = db.Column(db.DateTime, default=timezone.now) updated = db.Column(db.DateTime, onupdate=timezone.now) voted = db.Column(db.Boolean, default=False) enabled = db.Column(db.Boolean, default=True) async def get_user(self) -> RemoteUser: data = await self.internal_request('login', 'get_user', user_id=self.user_id) return RemoteUser(**data) @as_future def vote(self, items: Optional[list] = None) -> None: items = self.result or items if not items: raise VotingError('No items to vote') if not self.voting.active: raise VotingError('Voting not active') if not self.enabled: raise VotingError('Voting member disabled') if self.voted: raise VotingError('Already voted') if len(items) != self.voting.select_count: raise VotingError('Voting items count: %s/%s' % (len(items), self.voting.select_count)) if not set(items).issubset(self.voting.items): raise VotingError('Voting items is %s. Must be a subset ' 'of %s' % (','.join(items), ','.join(self.voting.items))) self.result = items self.voted = True self.save() @as_future def discard(self) -> None: if self.voting.can_discard: self.delete() else: raise VotingError('Cannot discard')
class MessageStatus(InternalAPIMixin, db.Model): __tablename__ = 'message_statuses' id = db.Column(db.Integer, primary_key=True, autoincrement=True) value = db.Column(ChoiceType(MESSAGE_STATUSES), default='new') updated = db.Column(db.DateTime, onupdate=timezone.now) message_id = db.Column(db.Integer, db.ForeignKey('messages.id', ondelete='CASCADE')) receiver_id = db.Column(db.Integer) @property def request_user(self): return partial(self.internal_request, 'login', 'get_user') async def get_receiver(self) -> RemoteUser: data = await self.request_user(user_id=self.receiver_id) return RemoteUser(**data)
class Post(db.Model): __tablename__ = 'posts' id = db.Column(db.Integer, primary_key=True, autoincrement=True) created = db.Column(db.DateTime, default=timezone.now) content = db.Column(db.Text, nullable=False) enabled = db.Column(db.Boolean, nullable=False, default=True) category_id = db.Column(db.Integer, db.ForeignKey('categories.id')) image = db.Column(db.ImageType(width=None, height=None)) @hybrid_property def active(self): return self.enabled and self.created <= timezone.now() @active.expression def active(cls) -> bool: return db.and_(cls.created <= timezone.now(), cls.enabled)
class MessageReaction(InternalAPIMixin, db.Model): __tablename__ = 'message_reactions' __table_args__ = (db.UniqueConstraint('message_id', 'user_id', 'value'), ) id = db.Column(db.Integer, primary_key=True, autoincrement=True) value = db.Column(db.String(32)) message_id = db.Column(db.Integer, db.ForeignKey('messages.id', ondelete='CASCADE')) user_id = db.Column(db.Integer) @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)