class Order(BaseModel): uuid = UUIDField(unique=True) total_price = DecimalField() user = ForeignKeyField(User, related_name="orders") def json(self): return { 'uuid': str(self.uuid), 'total_price': float(self.total_price), 'user': str(self.user.uuid), 'items': self._get_order_items() } def _get_order_items(self): data = [] for order_item in self.order_items: item = order_item.item data.append({ 'uuid': str(item.uuid), 'name': item.name, 'quantity': order_item.quantity, 'subtotal': float(order_item.subtotal) }) return data
class Secret(Model): id = UUIDField(primary_key=True, default=uuid.uuid4) data = CharField() expiration = DateTimeField() reads = IntegerField() token = TokenField(id) def serialize(self): return { 'data': self.data, 'expiration': (self.expiration - datetime.now()).seconds // 3600, 'reads': self.reads, } @classmethod def deserialize(cls, data): secret = Secret( data=data.get('data'), expiration=datetime.now() + timedelta(hours=int(data.get('expiration'))), reads=data.get('reads'), ) secret.validate() return secret def validate(self): if not all(( 0 < len(self.data) <= settings.MAX_DATA_LENGTH, self.expiration <= datetime.now() + timedelta(hours=settings.MAX_EXPIRATION), 0 < int(self.reads) <= settings.MAX_READS, )): raise ValueError() class Meta: database = db_url.connect(settings.DATABASE_URL)
class Token(Model): """Выданные токены авторизации""" id = UUIDField(primary_key=True, help_text='Токен') user = ForeignKeyField(User, help_text='Пользователь, которому был выдан токен') revoked = BooleanField(index=True, help_text='Был ли токен отозван') authoraize_date = DateTimeField(index=True, help_text='Дата создания токена') revoke_date = DateTimeField(index=True, help_text='Дата отзыва токена') @staticmethod def create_token(user, revoke_in): id = uuid.uuid4() auth_date = datetime.utcnow() revoke_date = auth_date + revoke_in Token.insert(id=id, user=user, revoked=False, authoraize_date=auth_date, revoke_date=revoke_date).execute() return id, revoke_date @staticmethod def validate(token): with Token.atomic() as txn: try: token_record = Token[token] if not token_record: return False if token_record.revoked: return False now = datetime.utcnow() if token_record.revoke_date < now: token_record.revoked = True token_record.revoke_date = now token_record.save() return True except DoesNotExist: return False @staticmethod def get_user(token): with Token.atomic() as txn: try: token_record = Token[token] if not token_record: return return token_record.user except DoesNotExist: return @staticmethod def get_info(token): with Token.atomic() as txn: try: token_record = Token[token] if not token_record: return return token_record except DoesNotExist: return @staticmethod def revoke(token): with Token.atomic() as txn: try: token_record = Token[token] if not token_record: return False token_record.revoked = True token_record.revoke_date = datetime.utcnow() token_record.save() return True except DoesNotExist: return False
class TestingID(BaseModel): uniq = UUIDField()
class Format(Model): """Формат отображения единицы измерения""" id = UUIDField(primary_key = True, help_text = '') description = TextField(help_text = '')
class Standard(Model): """Стандарт единицы измерения""" id = UUIDField(primary_key=True, help_text='')
class MessageArchive(BaseModel): FORMATS = ['txt', 'csv', 'json'] archive_id = UUIDField(primary_key=True, default=uuid.uuid4) message_ids = BinaryJSONField() created_at = DateTimeField(default=datetime.utcnow) expires_at = DateTimeField( default=lambda: datetime.utcnow() + timedelta(days=7)) class Meta: db_table = 'message_archives' indexes = ((('created_at', ), False), (('expires_at', ), False)) @classmethod def create_from_message_ids(cls, message_ids): return cls.create(message_ids=message_ids) @property def url(self): # TODO: use web endpoint here return 'https://dashboard.rowboat.party/archive/{}.txt'.format( self.archive_id) def encode(self, fmt='txt'): from rowboat.models.user import User if fmt not in self.FORMATS: raise Exception('Invalid format {}'.format(fmt)) q = Message.select(Message.id, Message.channel_id, Message.timestamp, Message.content, Message.deleted, Message.attachments, User).join(User).where( (Message.id << self.message_ids)) if fmt == 'txt': return u'\n'.join(map(self.encode_message_text, q)) elif fmt == 'csv': return u'\n'.join([ 'id,channel_id,timestamp,author_id,author,content,deleted,attachments' ] + map(self.encode_message_csv, q)) elif fmt == 'json': return json.dumps({'messages': map(self.encode_message_json, q)}) @staticmethod def encode_message_text(msg): return u'{m.timestamp} ({m.id} / {m.channel_id} / {m.author.id}) {m.author}: {m.content} ({attach})'.format( m=msg, attach=', '.join(map(unicode, msg.attachments or []))) @staticmethod def encode_message_csv(msg): def wrap(i): return u'"{}"'.format(six.text_type(i).replace('"', '""')) return ','.join( map(wrap, [ msg.id, msg.timestamp, msg.author.id, msg.author, msg.content, str(msg.deleted).lower(), ' '.join(msg.attachments or []) ])) @staticmethod def encode_message_json(msg): return dict(id=str(msg.id), timestamp=str(msg.timestamp), author_id=str(msg.author.id), username=msg.author.username, discriminator=msg.author.discriminator, content=msg.content, deleted=msg.deleted, attachments=msg.attachments)
class DbCardPack(BaseModel): uuid = UUIDField(unique=True) name = CharField(max_length=64) watermark = CharField(max_length=10)
class Favorite(BaseModel): """ Many to many table to relate an item with a user.""" uuid = UUIDField(unique=True) user = ForeignKeyField(User, related_name="favorites") item = ForeignKeyField(Item, related_name="favorites") _schema = FavoriteSchema
class Order(BaseModel): """ Orders represent an order placed by a `User`, containing one or more `Item` that have to be delivered to one of the user's `Address`. Attributes: uuid (UUID): Order's unique id total_price (:any:`decimal.Decimal`): Total price for the order delivery_address (:any:`Address`): Address specified for delivery user (:any:`User`): User that created the order """ uuid = UUIDField(unique=True, default=uuid4) total_price = DecimalField(default=0) delivery_address = ForeignKeyField(Address, related_name="orders") user = ForeignKeyField(User, related_name="orders") _schema = OrderSchema class Meta: order_by = ('created_at', ) @property def order_items(self): """ Property that execute a cross-table query against :class:`models.OrderItem` to get a list of all OrderItem related to the callee order. Returns: list: :class:`models.OrderItem` related to the order. """ query = (OrderItem.select( OrderItem, Order).join(Order).where(Order.uuid == self.uuid)) return [orderitem for orderitem in query] def empty_order(self): """ Remove all the items from the order deleting all OrderItem related to this order and resetting the order's total_price value to 0. Returns: models.Order: The updated order """ self.total_price = 0 OrderItem.delete().where(OrderItem.order == self).execute() self.save() return self @staticmethod def create_order(user, address, items): """ Create an Order and respective OrderItems. OrderItems are created in a single query as well as the Order. It also updates Items' availability. Args: user (models.User): order owner address (models.Address): order address items (dict): item updates entries as a dictionary, keys are items and values are new quantities to set. Example of argument: ..code-block:: python items = { Item.get(pk=1): 3, Item.get(pk=2): 1, } Returns: models.Order: The new order """ total_price = sum(item.price * quantity for item, quantity in items.items()) with database.atomic(): order = Order.create( delivery_address=address, user=user, total_price=total_price, ) order.update_items(items, update_total=False) return order def update_items(self, items, update_total=True, new_address=None): """ Update Order and respective OrderItems by splitting in creation, deletion and updating queries, minimizing the interactions with the database. It also updates Items' availability. Args: items (dict): item updates entries as a dictionary, keys are items and values are new quantities to set. Example of argument: ..code-block:: python items = { Item.get(pk=1): 3, Item.get(pk=2): 0, Item.get(pk=3): 1, } update_total (bool): if True the procedure updates order's total price. Default to True. new_address (models.Address): if not None the procedure updates the order with the given address. Default to None. Returns: models.Order: The new/updated order """ to_create = {} to_remove = {} to_edit = {} total_price_difference = 0 orderitems = self.order_items # split items in insert, delete and update sets for item, quantity in items.items(): for orderitem in orderitems: if orderitem.item == item: difference = quantity - orderitem.quantity if quantity == 0: to_remove[item] = orderitem.quantity elif difference > item.availability: raise InsufficientAvailabilityException(item, quantity) elif quantity < 0: raise WrongQuantity() else: to_edit[item] = difference total_price_difference += item.price * difference break else: if quantity <= 0: raise WrongQuantity() elif quantity > item.availability: raise InsufficientAvailabilityException(item, quantity) else: to_create[item] = quantity total_price_difference += item.price * quantity with database.atomic(): self.edit_items_quantity(to_edit) self.create_items(to_create) self.delete_items(to_remove) if update_total: self.total_price += total_price_difference if new_address: self.address = new_address if update_total or new_address: self.save() return self @database.atomic() def edit_items_quantity(self, items): """ Update orderitems using a query for each item, and updates items' availability. Args: items (dict): item updates entries as a dictionary, keys are items and values are new quantities to set. Example of argument: ..code-block:: python items = { Item.get(pk=1): 3, Item.get(pk=3): 1, } Returns: Order: callee instance """ if not items: return orderitems = OrderItem.select().where( OrderItem.item << [k for k in items.keys()], OrderItem.order == self) for orderitem in orderitems: for item, difference in items.items(): if orderitem.item == item: item.availability -= difference item.save() orderitem.quantity += difference orderitem._calculate_subtotal() orderitem.save() break def delete_items(self, items): """ Delete orderitems in a single query and updates items' availability. Args: items (dict): item entries as a dictionary, keys are items to delete and values are previously reserved quantities. Example of argument: ..code-block:: python items = { Item.get(pk=1): 3, Item.get(pk=2): 2, } """ if not items: return with database.atomic(): for item, quantity in items.items(): item.availability += quantity item.save() OrderItem.delete().where(OrderItem.order == self).where( OrderItem.item << [k for k in items.keys()]).execute() def create_items(self, items): """ Creates orderitems in a single query and updates items' availability. Args: items (dict): item entries as a dictionary, keys are items to create and values are new quantities to set. Example of argument: ..code-block:: python items = { Item.get(pk=1): 3, Item.get(pk=2): 1, } """ if not items: return with database.atomic(): for item, quantity in items.items(): item.availability -= quantity item.save() OrderItem.insert_many([{ 'order': self, 'item': item, 'quantity': quantity, 'subtotal': item.price * quantity, } for item, quantity in items.items()]).execute() def add_item(self, item, quantity=1): """ Add items to the order. It updates item availability. Args: item (models.Item): the Item to add quantity (int): how many items to add Returns: order (models.Order): the updated order """ return self.update_items({item: quantity}) def remove_item(self, item, quantity=1): """ Remove the given item from the order, reducing quantity of the relative OrderItem entity or deleting it if removing the last item ``(OrderItem.quantity == 0)``. It also restores the item availability. Args: item (models.Item): the Item to remove quantity (int): how many items to remove Returns: order (models.Order): the updated order """ return self.update_items({item: -quantity})
class User(BaseModel, UserMixin): """ User represents an user for the application. Attributes: first_name (str): User's first name last_name (str): User's last name email (str): User's **valid** email password (str): User's password admin (bool): User's admin status. Defaults to ``False`` .. NOTE:: Each User resource must have an unique `email` field, meaning that there cannot be two user's registered with the same email. For this reason, when checking for user's existence, the server requires either the `uuid` of the user or its `email`. """ uuid = UUIDField(unique=True) first_name = CharField() last_name = CharField() email = CharField(unique=True) password = CharField() admin = BooleanField(default=False) _schema = UserSchema @staticmethod def exists(email): """ Check that an user exists by checking the email field. Args: email (str): User's email to check """ try: User.get(User.email == email) except User.DoesNotExist: return False return True @staticmethod def hash_password(password): """ Use passlib to get a crypted password. Args: password (str): password to hash Returns: str: hashed password """ return pbkdf2_sha256.hash(password) def verify_password(self, password): """ Verify a clear password against the stored hashed password of the user using passlib. Args: password (str): Password to verify against the hashed stored password Returns: bool: wether the given email matches the stored one """ return pbkdf2_sha256.verify(password, self.password) def add_favorite(user, item): """Link the favorite item to user.""" return Favorite.create( uuid=uuid4(), item=item, user=user, ) def delete_favorite(self, obj): obj.delete_instance()
class Clicks(BaseModel): id = UUIDField() x_pos = DecimalField() y_pos = DecimalField() image_url = TextField()
class UserAccess: """ """ id = UUIDField(primary_key = True, help_text = '') class Meta: table_name = 'user_access'
class InstrumentUser(CherryPyAPI): """ Relates users and instrument objects. Attributes: +--------------+--------------------------------------------+ | Name | Description | +==============+============================================+ | instrument | Link to the Instrument model | +--------------+--------------------------------------------+ | relationship | Link to the Relationship model | +--------------+--------------------------------------------+ | user | User who is responsible for the instrument | +--------------+--------------------------------------------+ """ uuid = UUIDField(primary_key=True, default=uuid.uuid4, index=True) instrument = ForeignKeyField(Instruments, backref='custodians') user = ForeignKeyField(Users, backref='instruments') relationship = ForeignKeyField(Relationships, backref='instrument_user') # pylint: disable=too-few-public-methods class Meta(object): """PeeWee meta class contains the database and the primary key.""" database = DB indexes = ( (('user', 'instrument', 'relationship'), True), ) # pylint: enable=too-few-public-methods def to_hash(self, **flags): """Convert the object to a hash.""" obj = super(InstrumentUser, self).to_hash(**flags) obj['uuid'] = str(self.__data__['uuid']) obj['instrument'] = int(self.__data__['instrument']) obj['user'] = int(self.__data__['user']) obj['relationship'] = str(self.__data__['relationship']) return obj def from_hash(self, obj): """Convert the hash into the object.""" super(InstrumentUser, self).from_hash(obj) self._set_only_if('uuid', obj, 'uuid', lambda: uuid.UUID(obj['uuid'])) self._set_only_if_by_name('relationship', obj, Relationships) self._set_only_if( 'instrument', obj, 'instrument', lambda: Instruments.get(Instruments.id == obj['instrument']) ) self._set_only_if( 'user', obj, 'user', lambda: Users.get(Users.id == obj['user']) ) @classmethod def where_clause(cls, kwargs): """Where clause for the various elements.""" where_clause = super(InstrumentUser, cls).where_clause(kwargs) attrs = ['uuid', 'instrument', 'user', 'relationship'] return cls._where_attr_clause(where_clause, kwargs, attrs)
class SymptomLocation(DatabaseModel): id = UUIDField(primary_key=True, default=uuid.uuid4) name = TextField(null=False)
class WalletGroupAddressMerge(BaseModel): wallet = UUIDField(index=True) address = TextField(index=True, unique=True)
class Module_Type(BaseModel): id = PrimaryKeyField() uuid = UUIDField(constraints=[SQL('DEFAULT uuid_generate_v4()')], unique=True) type = CharField()
class Relationships(CherryPyAPI): """ Relationships model class for metadata. Attributes: +-------------------+-------------------------------------+ | Name | Description | +===================+=====================================+ | uuid | relationship unique ID | +-------------------+-------------------------------------+ | name | relationship name | +-------------------+-------------------------------------+ | display_name | relationship display name | +-------------------+-------------------------------------+ | description | relationship long description | +-------------------+-------------------------------------+ | encoding | encoding for the name | +-------------------+-------------------------------------+ """ uuid = UUIDField(primary_key=True, default=uuid.uuid4, index=True) name = CharField(default='', unique=True, index=True) display_name = CharField(default='', index=True) description = TextField(default='') encoding = CharField(default='UTF8') @classmethod def create_table(cls, safe=True, **options): """Create the table and populate it with initial relationships.""" super(Relationships, cls).create_table() static_relationships = [{ 'name': 'upload_required', 'display_name': 'Required for Upload', 'description': 'This relationship means that the objects are required for upload to be asserted.' }, { 'name': 'search_required', 'display_name': 'Required for Search', 'description': 'This relationship means that the objects are required for search to be asserted.' }, { 'name': 'member_of', 'display_name': 'Member of', 'description': 'subject is a member of the object' }, { 'name': 'co_principal_investigator', 'display_name': 'Co-Principal Investigator', 'description': 'subject is the co-principal investigator of the object' }, { 'name': 'principal_investigator', 'display_name': 'Principal Investigator', 'description': 'subject is the principal investigator of the object' }, { 'name': 'custodian', 'display_name': 'Custodian', 'description': 'subject is the custodian of the object' }, { 'name': 'point_of_contact', 'display_name': 'Point of Contact', 'description': 'subject is the point of contact for the object' }, { 'name': 'authorized_releaser', 'display_name': 'Authorized Releaser', 'description': 'subject is the authorized releaser of the object' }] for static_rel in static_relationships: Relationships.get_or_create(**static_rel) def to_hash(self, **flags): """Convert the object to a hash.""" obj = super(Relationships, self).to_hash(**flags) obj['uuid'] = str(self.uuid) for attr in ['name', 'display_name', 'description']: obj[attr] = unicode_type(getattr(self, attr)) obj['encoding'] = str(self.encoding) return obj def from_hash(self, obj): """Convert the hash to the object.""" super(Relationships, self).from_hash(obj) self._set_only_if('uuid', obj, 'uuid', lambda: uuid.UUID(obj['uuid'])) for attr in ['name', 'display_name', 'description']: self._set_only_if(attr, obj, attr, lambda o=obj, a=attr: unicode_type(o[a])) self._set_only_if('encoding', obj, 'encoding', lambda: str(obj['encoding'])) @classmethod def where_clause(cls, kwargs): """PeeWee specific where clause used for search.""" where_clause = super(Relationships, cls).where_clause(kwargs) return cls._where_attr_clause( where_clause, kwargs, ['uuid', 'name', 'description', 'display_name', 'encoding'])
class Corridor(BaseModel): id = PrimaryKeyField() uuid = UUIDField(default=uuid.uuid4(), unique=True) # location = ForeignKeyField(Location, related_name='related_corridors') corridor = CharField()
class Order(BaseModel): user = UUIDField(index=True, verbose_name="用户")
class Prefix(Model): """Приставка к единицам измерения""" id = UUIDField(primary_key = True, help_text = 'Идентификатор приставки')
class OrderItem(BaseModel): order = UUIDField(index=True, verbose_name="订单id") goods = UUIDField(index=True, verbose_name="商品id") price = DecimalField(verbose_name="成交价格") amount = IntegerField(verbose_name="购买数量")
class File(BaseModel): id = UUIDField(default=uuid4(), unique=True, primary_key=True) f_name = TextField() fc_datetime = DateTimeField(default=dt.now)
class Contract_Type(BaseModel): id = PrimaryKeyField() uuid = UUIDField(default=uuid.uuid4(), unique=True) type = CharField()
class MessageArchive(BaseModel): FORMATS = ['txt', 'csv', 'json'] archive_id = UUIDField(primary_key=True, default=uuid.uuid4) message_ids = BinaryJSONField() created_at = DateTimeField(default=datetime.utcnow) expires_at = DateTimeField(default=lambda: datetime.utcnow() + timedelta(days=7)) class Meta: db_table = 'message_archives' indexes = ( (('created_at', ), False), (('expires_at', ), False) ) @classmethod def create_from_message_ids(cls, message_ids): return cls.create(message_ids=message_ids) @property def url(self): with open('config.yaml', 'r') as f: config = safe_load(f) return '{}/api/archive/{}.html'.format(config['web']['DOMAIN'], self.archive_id) def encode(self, fmt='txt'): from rowboat.models.user import User if fmt not in self.FORMATS: raise Exception('Invalid format {}'.format(fmt)) q = Message.select( Message.id, Message.channel_id, Message.timestamp, Message.content, Message.deleted, Message.attachments, User ).join( User ).where( (Message.id << self.message_ids) ).order_by( Message.id ) if fmt == 'txt': return u'\n'.join(map(self.encode_message_text, q)) elif fmt == 'csv': return u'\n'.join([ 'id,channel_id,timestamp,author_id,author,content,deleted,attachments' ] + map(self.encode_message_csv, q)) elif fmt == 'json': return json.dumps({ 'messages': map(self.encode_message_json, q) }) elif fmt == 'html': return q @staticmethod def encode_message_text(msg): attachments = msg.attachments or [] return u'{m.timestamp} ({m.id} / {m.channel_id} / {m.author.id}) {m.author}: {m.content}{attach}'.format( m=msg, attach=' ({})'.format(', '.join(unicode(i).replace('cdn.discordapp.com', 'media.discordapp.net', 1) for i in attachments)) if len(attachments) > 0 else '' ) @staticmethod def encode_message_csv(msg): def wrap(i): return u'"{}"'.format(six.text_type(i).replace('"', '""')) return ','.join(map(wrap, [ msg.id, msg.timestamp, msg.author.id, msg.author, msg.content, str(msg.deleted).lower(), ' '.join(msg.attachments or []) ])) @staticmethod def encode_message_json(msg): conn = database.obj.get_conn() channel_name = None with conn.cursor() as cur: cur.execute('SELECT name FROM channels WHERE channel_id = {};'.format(int(msg.channel_id))) row = cur.fetchone() channel_name = row[0] if row else None return dict( id=str(msg.id), timestamp=str(msg.timestamp), author_id=str(msg.author.id), channel=channel_name, channel_id=str(msg.channel_id), username=msg.author.username, discriminator=str(msg.author.discriminator).zfill(4), content=msg.content, deleted=msg.deleted, attachments=msg.attachments)
class Module(BaseModel): id = PrimaryKeyField() uuid = UUIDField(constraints=[SQL('DEFAULT uuid_generate_v4()')], unique=True) type = ForeignKeyField(Module_Type, related_name='related_modules') build_on = DateField(default=datetime.datetime.now().date())
class UUIDData(BaseModel): id = UUIDField(primary_key=True) data = CharField()
class Servers(BaseModel): id = UUIDField(primary_key=True, default=uuid4) server_id = IntegerField() city = CharField() country = CharField() provider = CharField()
class Master(Model): """Модель со значениями корневых прав доступа для узла""" id = UUIDField(primary_key=True, help_text='') revoked = BooleanField(index=True, help_text='') authoraize_date = DateTimeField(index=True, help_text='') revoke_date = DateTimeField(index=True, null=True, help_text='')
class WalletGroup(BaseModel): uid = UUIDField(unique=True)