class ClientAskForLeaveSubFlow(StateMachineModel): id = db.Column(db.Integer, primary_key=True) client_id = db.Column(db.Integer, db.ForeignKey('state_machine_client.id'), unique=True) user = db.relationship(StateMachineClient, backref=db.backref("client_ask_for_leave_sub_flow", uselist=False)) __states__ = ( (0, "initial"), (1001, "processing"), (1002, "success"), (1003, "failed"), ) __transitions__ = [ { "trigger": "ask_for_leave", "source": "initial", "dest": "processing", }, { "trigger": "approve", "source": "processing", "dest": "success", }, { "trigger": "reject", "source": "processing", "dest": "failed", }, ]
class OAuth2AuthorizationCode(db.Model, OAuth2AuthorizationCodeMixin): __tablename__ = 'oauth2_code' id = db.Column(db.Integer, primary_key=True) user_id = db.Column( db.Integer, db.ForeignKey('user.id', ondelete='CASCADE')) user = db.relationship('User')
class TransactionRecord(db.Model): __table__ = "transaction_record" id = db.Column(db.Integer, primary_key=True) transaction_id = db.Column(UUIDType(), db.ForeignKey("transaction.id")) field = db.Column(db.String(32), doc=_("Field")) before = db.Column(db.PickleType, doc=_('Original Value')) after = db.Column(db.PickleType, doc=_('New Value')) transactions = db.relationship(Transaction, )
class OAuth2Token(db.Model, OAuth2TokenMixin): __tablename__ = 'oauth2_token' id = db.Column(db.Integer, primary_key=True) user_id = db.Column( db.Integer, db.ForeignKey('user.id', ondelete='CASCADE')) user = db.relationship('User', backref=db.backref("oauth2_token",uselist=False)) def is_refresh_token_expired(self): expires_at = self.issued_at + self.expires_in * 2 return expires_at < time.time()
class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) user_name = db.Column(db.String(40), unique=True) password = db.Column(db.Binary(70)) email = db.Column(db.String(64), unique=True) def __str__(self): return self.username def get_user_id(self): return self.id def set_password(self, password): self.password = hashpw(password.encode("utf-8"), gensalt()) @classmethod def find_by_password(cls, email, password, *args, **kwargs): email = email.strip() password = password.strip() if email and password: user = cls.query.filter( cls.email == email ).first() if user and user.check_password(password): return user def check_password(self, password): pw_hash = hashpw(password=password.encode("utf-8"), salt=self.password) return pw_hash == self.password @classmethod def login(cls, email, password, *args, **kwargs): user = cls.find_by_password(email=email, password=password) if not user: raise exceptions.InvalidEmailOrPassword() login_user(user) user.last_login_time = time.time() object_session(user).commit() return jsonify({"code": 1000, "message": 'success'})
class StateMachineClient(StateMachineModel): id = db.Column(db.Integer, primary_key=True) __states__ = ( (0, "initial"), (1000, "pending"), (1001, "active"), (1002, "good"), (1003, "fraud"), (1004, "deleted"), ) __transitions__ = [ { "trigger": "initialize", "source": "initial", "dest": "pending", }, { "trigger": "activate", "source": "pending", "dest": "active", }, { "trigger": "mark_as_good", "source": "active", "dest": "good", }, { "trigger": "mark_as_fraud", "source": "active", "dest": "fraud", }, { "trigger": "delete_state", "source": "*", "dest": "deleted" }, { "trigger": "do_nothing", "source": "pending", "dest": "pending" } ] __state_children_mapping__ = { "good": 'client_ask_for_leave_sub_flow' } def after_activate(self, *args, **kwargs): print("a huge improvement! We have another customer") def after_fraud(self, *args, **kwargs): print("suspend app!!!")
class Transaction(db.Model): __table__ = "transaction" id = db.Column(UUIDType(), primary_key=True) object_uuid = db.Column(UUIDType(), nullable=False, ) object_id = db.Column(db.Integer) object_table = db.Column(db.String(100), null=True) created = db.Column(db.DateTime, default=datetime.datetime.utcnow) utime = db.Column(db.DateTime, default=datetime.datetime.utcnow)
class Client(db.Model, OAuth2ClientMixin): id = db.Column(db.Integer, primary_key=True) user_id = db.Column( db.Integer, db.ForeignKey('user.id', ondelete='CASCADE') ) user = db.relationship('User')
class Parent(TransactionEnabled, db.Model): __tablename__ = 'parent' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(length=255)) children = db.relationship("Child")
class Child(TransactionEnabled, db.Model): __tablename__ = 'child' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(length=255)) parent_id = db.Column(db.Integer, db.ForeignKey('parent.id')) parent = db.relationship("Parent")
class StateMachineModel(db.Model): __abstract__ = True __states__ = [] __transitions__ = [] __state_children_mapping__ = {} status = db.Column(db.SmallInteger, index=True, default=0, nullable=False) @property def state(self): return self.status @state.setter def state(self, value): self.status = value def __init__(self,*args, **kwargs): super(StateMachineModel, self).__init__(*args,**kwargs) initial = self._get_initial() machine = Machine(model=self, states=self._get_states(), transitions=self.get_transitions(), auto_transitions=False, initial=initial, send_event=True) self.fsm = machine def get_states(self): return self.__states__[:] def _get_initial(self): if self.status is None: self.status = 0 initial = dict(self.get_states()).get(self.status) if initial in self.__state_children_mapping__: rel_obj = getattr(self, self.__state_children_mapping__[initial]) initial = '%s_%s' % (initial, rel_obj.state) return initial def _get_states(self): states_dict = dict(self.get_states()) for key, value in self.__state_children_mapping__.items(): child_obj = getattr(self, value) state_key = dict((y, x) for (x, y) in self.get_states())[key] if child_obj: # 当子状态机已存在, 整合子状态机状态 states_dict[state_key] = { 'name': key, 'children': child_obj.fsm, } else: # 当子状态机不存在,生成一个空对象,表示初始状态 child_relation = getattr(self.__class__, value) assert isinstance(child_relation, InstrumentedAttribute) target_class = child_relation.prop.mapper.class_ assert issubclass(target_class, StateMachineModel) states_dict[state_key] = { 'name': key, 'children': target_class().fsm, } print(states_dict) states = states_dict.values() return list(states) @classmethod def get_transitions(cls): return cls.__transitions__[:] def _init_obj_for_state(self, rel): if not getattr(self, rel, None): class_ = getattr(self.__class__, rel).prop.mapper.class_ obj = class_() db.session.add(obj) setattr(self, rel, obj)