class Group(DB.Model): __tablename__ = 'group' id = DB.Column(DB.Integer, primary_key=True, autoincrement=True) name = DB.Column(DB.DateTime) order = DB.Column(DB.String(255)) comment = DB.Column(DB.DateTime) showNotice = DB.Column(DB.Integer, default=1) multiAccount = DB.Column(DB.Integer, default=0)
class Product(DB.Model): __tablename__ = 'product' id = DB.Column(DB.Integer, primary_key=True, autoincrement=True) # name = DB.Column( DB.String( 255 ) ) type = DB.Column(DB.Integer) # 0 or none stands by enabled flow = DB.Column(DB.Integer) # unit: Mn price = DB.Column(DB.Float) # unit: ¥ enable = DB.Column(DB.Boolean, default=True) duration = DB.Column(DB.Integer) # unit: seconds buffer_period = DB.Column(DB.Integer) # unit: seconds @staticmethod def add_type(price: float, flow: int, duration: timedelta, buffer_period: timedelta): dseconds = duration.total_seconds() bseconds = buffer_period.total_seconds() ot = Product(price=price, flow=flow, duration=dseconds, buffer_period=bseconds) return ot def to_dict(self): return { "id": self.id, "flow": self.flow, "price": self.price, "enable": self.enable, "duration": self.duration, "bufferPeriod": self.buffer_period } def to_dict(self): di = { "id": self.id, "flow": self.flow, "price": self.price, "enable": self.enable, "duration": self.duration, "bufferPeriod": self.buffer_period } return di def __repr__(self): return '<Product %d %s>' % (self.id, self.enable)
class WebguiSetting(DB.Model): """ TODO reconstruct this model Type (can be ignored, just used as utility): String: Value type by default, should be processed by other logic Image: Value are encoded with base64 format Number: Treat value as number( use float builtin function), Boolean: are stored in number with only two candicates (0 or 1) Json: Value are encoded with json format Hidden: Not visible for even manager """ __tablename__ = 'webguiSetting' id = DB.Column(DB.Integer, primary_key=True, autoincrement=True) key = DB.Column(DB.String(255), unique=True) value = DB.Column(DB.Text) type = DB.Column(DB.String(32), default='String') def getTypedValue(self): if not self.type: return self.value if self.type == 'Boolean': return self.value == '1' if self.type == 'Number': try: return int(self.value) except Exception: return float(self.value) return self.value @staticmethod def getSetting(key, default_value=None, default_type="String"): setting = WebguiSetting.query.filter_by(key=key).first() if setting is None and default_value is not None: setting = WebguiSetting(key=key, value=default_value, type=default_type) db.session.add(setting) db.session.commit() return setting def to_dict(self): di = { 'id': self.id, 'key': self.key, 'value': self.value if type(self.value) is str else self.value.decode(), 'type': self.type, } return di
class Announcement(DB.Model): """公告数据模型 """ __tablename__ = 'announcement' id = DB.Column(DB.Integer, primary_key=True) title = DB.Column(DB.String(255), nullable=False) variant = DB.Column(DB.String(32)) # primary, success, warn content = DB.Column(DB.BLOB) createtime = DB.Column(DB.DateTime, default=datetime.now) top = DB.Column(DB.Integer, default=0) def to_dict(self): content = self.content.decode( 'utf-8') if self.content is not None else '' di = { 'id': self.id, 'title': self.title, 'variant': self.variant, 'content': content, 'createTime': self.createtime.timestamp(), 'top': self.top, } return di
class Email(DB.Model): __tablename__ = 'email' id = DB.Column(DB.Integer, primary_key=True, autoincrement=True) to = DB.Column(DB.String(255), nullable=False) content = DB.Column(DB.Text) time = DB.Column(DB.DateTime, default=datetime.now) subject = DB.Column(DB.String(255)) ip = DB.Column(DB.String(255)) type = DB.Column(DB.String(255)) remark = DB.Column(DB.String(255)) session = DB.Column(DB.String(255)) def to_dict(self): di = { 'id': self.id, 'to': self.to, 'content': self.content, 'time': self.time.timestamp(), 'subject': self.subject, 'ip': self.ip, 'type': self.type, 'remark': self.remark, 'session': self.session, } return di def __repr__(self): return "<Email to: {}, subject: {}, content: {}, time: {}>"\ .format(self.to, self.subject, self.content, self.time)
class Order(DB.Model): __tablename__ = 'order' id = DB.Column(DB.Integer, primary_key=True, autoincrement=True) uid = DB.Column(DB.Integer, nullable=False) pid = DB.Column(DB.Integer, nullable=False) server = DB.Column(DB.String(255)) code = DB.Column(DB.String(32)) alipay = DB.Column(DB.Float) wechatpay = DB.Column(DB.Float) orderTime = DB.Column(DB.DateTime) commentByUser = DB.Column(DB.Text, default='') # whether the Manager has confirmed this order checked = DB.Column(DB.Boolean, default=False) # buffer period bufferPeriodExpire = DB.Column(DB.DateTime) expire = DB.Column(DB.DateTime) @staticmethod def place_order(uid: int, product: Product, **kwargs): od = Order(uid=uid, pid=product.id) # od.code = getRandomCode( 32 ) od.code = '{:%Y%m%d%H%M%S}{:1}'.format(datetime.now(), getRandomCode(18)) od.commentByUser = kwargs.get('comment', '') now = datetime.now() od.orderTime = now od.checked = kwargs.get('checked', False) od.bufferPeriodExpire = timedelta(seconds=product.buffer_period) + now od.expire = timedelta(seconds=product.duration) + now app.m_db.session.add(od) app.m_db.session.commit() # return od def is_valid(self): now = datetime.now() if not self.checked: return now < self.bufferPeriodExpire return now < self.expire def check_it(self, alipay=0, wechatpay=0): # if not alipay self.checked = True self.alipay = alipay self.wechatpay = wechatpay def relateProduct(self): return Product.query.filter_by(id=self.productId).first() def to_dict(self): di = { 'id': self.id, 'uid': self.uid, 'pid': self.pid, 'server': self.server, 'code': self.code, 'alipay': self.alipay, 'wechatpay': self.wechatpay, 'orderTime': self.orderTime.timestamp(), 'commentByUser': self.commentByUser, 'checked': self.checked, 'bufferPeriodExpire': self.bufferPeriodExpire.timestamp(), 'expire': self.expire.timestamp(), } return di
class ProductQrcode(DB.Model): __tablename__ = 'productQrcode' id = DB.Column(DB.Integer, primary_key=True) pid = DB.Column(DB.Integer, nullable=False) # product Id category = DB.Column(DB.String(32), nullable=True) # such as alipay or wechatpay qrcode = DB.Column(DB.TEXT) # base64 encoded image desc = DB.Column(DB.String(255)) path = DB.Column(DB.String(255)) # if save image as files, path to find it remark = DB.Column(DB.String(32)) # reserved def to_dict(self): di = { "id": self.id, "pid": self.pid, "category": self.category, "qrcode": self.qrcode, "desc": self.desc, "path": self.path, "remark": self.remark, } return di
class User(DB.Model): """The life cycle of an webserver user is not clear now. So the user type may be confusing. TODO reconstruct this model """ __tablename__ = 'user' id = DB.Column(DB.Integer, primary_key=True, autoincrement=True) type = DB.Column(DB.String(255)) salt = DB.Column(DB.String(8), nullable=False) email = DB.Column(DB.String(255), nullable=False) group = DB.Column(DB.Integer, default=0) level = DB.Column(DB.Integer, default=1) comment = DB.Column(DB.String(255), default='') password = DB.Column(DB.String(255), nullable=False) telegram = DB.Column(DB.String(255)) username = DB.Column(DB.String(255)) lastLogin = DB.Column(DB.DateTime) createTime = DB.Column(DB.DateTime) resetPasswordId = DB.Column(DB.String(255)) resetPasswordTime = DB.Column(DB.DateTime) TypeTrial = 'trial' TypeActive = "active" TypeBanned = 'banned' TypeInvalid = 'invalid' TypeNotified = 'notified' TypeDefault = 'default' TypeTest = 'test' def __init__(self, **kwargs): super(User, self).__init__(**kwargs) # self.password = password self.salt = getRandomCode(8) self.password = self.__gen_passwd(self.password) self.createTime = datetime.now() def __repr__(self): return '<User %s %s %s>' % (self.email, self.salt, self.password) def __gen_passwd(self, password): """Just generate secure password, but not modify object's password attribute, parameter password can't be None or self.password, otherwise the method which checks whether password is valid will return a Fake result """ return hashlib.sha256((self.salt + password).encode()).hexdigest() def updatePassword(self, new_passwd): self.password = self.__gen_passwd(new_passwd) def is_password_valid(self, password): """check whether the password (will be encrypted) passed in is the same as the encrypted password stored in the database records """ password = str(password) password = self.__gen_passwd(password) return password == self.password def request_reset_passwd(self): self.resetPasswordId = getRandomCode(24) self.resetPasswordTime = datetime.now() def do_reset_passwd(self, passwdId, new_passwd): """reset password and clear requestId @returns True if succesfully reset, False otherwise """ if not self.resetPasswordId or not self.resetPasswordTime: return False now = datetime.now() diff = now - self.resetPasswordTime if diff > timedelta(hours=3): # overtime, invalid return False if passwdId != self.resetPasswordId: return False self.password = self.__gen_passwd(new_passwd) self.resetPasswordId = '' return True def to_dict(self): lastLogin = self.lastLogin.timestamp( ) if self.lastLogin is not None else None di = { 'id': self.id, 'email': self.email, 'type': self.type, 'group': self.group, 'comment': self.comment, 'telegram': self.telegram, 'username': self.username, 'lastLogin': lastLogin, 'createTime': self.createTime.timestamp(), } return di