class Role(PaginatedAPIMixin, db.Model): """角色表""" __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True) slug = db.Column(db.String(255), unique=True) name = db.Column(db.String(255)) # 角色表 default = db.Column(db.Boolean, default=False, index=True) # 是否是默认角色 permissions = db.Column( db.Integer) # 角色拥有的权限,各操作对应一个二进制位,能执行某项操作的角色,其位会被设为 1 users = db.relationship('User', backref='role', lazy='dynamic') def __init__(self, **kwargs): super(Role, self).__init__(**kwargs) if self.permissions is None: self.permissions = 0 @staticmethod def insert_roles(): roles = { 'shutup': ('小黑屋', ()), 'reader': ('读者', (Permission.FOLLOW, Permission.COMMENT)), 'author': ('作者', (Permission.FOLLOW, Permission.COMMENT, Permission.WRITE)), 'administrator': ('管理员', (Permission.FOLLOW, Permission.COMMENT, Permission.WRITE, Permission.ADMIN)) } default_role = 'reader' for r in roles: role = Role.query.filter_by(slug=r).first() if role is None: role = Role(slug=r, name=roles[r][0]) role.reset_permission() for perm in roles[r][1]: role.add_permission(perm) role.default = (role.slug == default_role) db.session.add(role) db.session.commit() def reset_permission(self): """重置权限""" self.permissions = 0 def has_permission(self, perm) -> bool: """是否存在此权限""" return self.permissions & perm == perm def add_permission(self, perm): """添加权限""" if not self.has_permission(perm): self.permissions += perm def remove_permission(self, perm): """删除权限""" if self.has_permission(perm): self.permissions -= perm def get_permissions(self): """获取角色具体权限操作""" p = [(Permission.FOLLOW, 'follow'), (Permission.ADMIN, 'administrator'), (Permission.WRITE, 'author'), (Permission.COMMENT, 'reader')] new_p = (i[1] for i in p if self.has_permission(i[0])) return ",".join(new_p) def to_dict(self): """序列化输出""" data = { 'id': self.id, 'slug': self.slug, 'name': self.name, 'default': self.default, 'permissions': self.permissions, '_links': { 'self': url_for('api.get_role', id=self.id) } } return data def from_dict(self, data): for field in ['slug', 'name', 'permissions']: if field in data: setattr(self, field, data[field]) def __str__(self): return self.name def __repr__(self): return '<Role {}>'.format(self.name)
class User(UserMixin, db.Model): __tablename__ ='users' id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(32), nullable=False, unique=True) student_id = db.Column(db.Integer, nullable=False) true_name = db.Column(db.String(32), nullable=False) phone_number = db.Column(db.String(32), nullable=False) email = db.Column(db.String(64), nullable=False, unique=False) password_hash = db.Column(db.String(128), nullable=False) group_id = db.Column(db.Integer, db.ForeignKey('group.id'), default=2) group = db.relationship('Group', backref=db.backref('users', lazy='dynamic')) storage_id = db.Column(db.Integer, db.ForeignKey('store_location.id'), nullable=True) storage = db.relationship('Storage', backref=db.backref('users', lazy='dynamic')) last_login = db.Column(db.DateTime, default=datetime.now) icon = db.Column(db.String(64), default='img/a3.jpg') # Add a backreference to another model # Parameter 1: the associated model name # backref:Dynamically added fields in the associated model # Load mode: dynamic, no load, but provide record query # if use one to one,add uselist=Flase # posts = db.relationship('Post', backref='user', lazy=True) def __repr__(self): return self.username # Password field protection @property def password(self): raise AttributeError('keyword is Unreadable attribute') # Set the password and encrypt the storage @password.setter def password(self, password): #Equivalent to execution user.password_hash=password self.password_hash = generate_password_hash(password) # Password check def verify_password(self, password): return check_password_hash(self.password_hash, password)
class UserBindInfo(ModelBase): id = db.Column(db.Integer, primary_key=True, autoincrement=False, comment='用户ID', nullable=False) name = db.Column(db.String(64), comment="名称", nullable=False) account = db.Column(db.String(32), comment="账号", nullable=False, index=True) _bind_type = db.Column('bind_type', db.SmallInteger, comment="绑定类型", nullable=False) _merchant = db.Column('merchant', db.Integer, comment="商户ID", nullable=False) __table_args__ = ( # 联合唯一索引 db.UniqueConstraint('name', 'bind_type', 'merchant', name='uix_user_bind_name_bind_type_merchant'), ) @property def uid(self): return self.id @uid.setter def uid(self, value): self.id = value @property def merchant(self) -> MerchantEnum: return MerchantEnum(self._merchant) @merchant.setter def merchant(self, merchant: MerchantEnum): self._merchant = merchant.value @property def bind_type(self): """ 返回账户枚举类型 :return: """ return AccountTypeEnum(self._bind_type) @bind_type.setter def bind_type(self, e_value): """ 传入账户的类型 :param e_value: :return: """ self._bind_type = e_value.value @classmethod def query_bind_by_uid(cls, uid): """ 根据用户ID查询绑定信息 :param uid: :return: """ return cls.query_one(query_fields=dict(id=uid)) @classmethod def query_bind(cls, merchant: MerchantEnum, name, bind_type: AccountTypeEnum = AccountTypeEnum.ACCOUNT): return cls.query_one(query_fields=dict( _merchant=merchant.value, name=name, _bind_type=bind_type.value, )) @classmethod def bind_account(cls, uid, merchant: MerchantEnum, account, name, bind_type: AccountTypeEnum = AccountTypeEnum.ACCOUNT): obj = cls() obj.uid = uid obj.merchant = merchant obj.name = name obj.account = account obj.bind_type = bind_type cls.commit_models(obj) return obj @classmethod def unbind_account(cls, uid): obj = cls.query_bind_by_uid(uid) if not obj: return False cls.commit_models(obj, delete=True) return True
class Despesas(db.Model): __tablename__ = 'Despesas' id = db.Column(db.INT(), primary_key=True) ano_mes_lancamento = db.Column(db.NVARCHAR(500)) codigo_orgao_superior = db.Column(db.NVARCHAR(500)) nome_orgao_superior = db.Column(db.NVARCHAR(500)) codigo_orgao_subordinado = db.Column(db.NVARCHAR(500)) nome_orgao_subordinado = db.Column(db.NVARCHAR(500)) codigo_unidade_gestora = db.Column(db.NVARCHAR(500)) nome_unidade_gestora = db.Column(db.NVARCHAR(500)) codigo_gestao = db.Column(db.NVARCHAR(500)) nome_gestao = db.Column(db.NVARCHAR(500)) codigo_unidade_orcamentaria = db.Column(db.NVARCHAR(500)) nome_unidade_orcamentaria = db.Column(db.NVARCHAR(500)) codigo_funcao = db.Column(db.NVARCHAR(500)) nome_funcao = db.Column(db.NVARCHAR(500)) codigo_subfuncao = db.Column(db.NVARCHAR(500)) nome_subfuncao = db.Column(db.NVARCHAR(500)) codigo_programa_orcamentario = db.Column(db.NVARCHAR(500)) nome_programa_orcamentario = db.Column(db.NVARCHAR(500)) codigo_acao = db.Column(db.NVARCHAR(500)) nome_acao = db.Column(db.NVARCHAR(500)) idTipoDespesa = db.Column(db.NVARCHAR(500)) idRubrica = db.Column(db.INT()) idIes = db.Column(db.INT())
class ActivityDetailBase(AuditMixin, Base): __tablename__ = 'activity_detail' activity_detail_id = db.Column(db.Integer, primary_key=True, server_default=FetchedValue()) activity_type_description = db.Column(db.String) disturbed_area = db.Column(db.Numeric(14, 2)) timber_volume = db.Column(db.Numeric(14, 2)) number_of_sites = db.Column(db.Integer) width = db.Column(db.Integer) length = db.Column(db.Integer) depth = db.Column(db.Integer) quantity = db.Column(db.Integer) incline = db.Column(db.Numeric(14, 2)) incline_unit_type_code = db.Column( db.String, db.ForeignKey('unit_type.unit_type_code')) cut_line_length = db.Column(db.Integer) water_quantity = db.Column(db.Integer) water_quantity_unit_type_code = db.Column( db.String, db.ForeignKey('unit_type.unit_type_code')) activity_summaries = db.relationship( 'ActivitySummaryBase', secondary='activity_summary_detail_xref') activity_type_code = db.column_property( db.select([ActivitySummaryBase.activity_type_code], and_( ActivitySummaryDetailXref.activity_summary_id == ActivitySummaryBase.activity_summary_id, ActivitySummaryDetailXref.activity_detail_id == activity_detail_id)).as_scalar()) __mapper_args__ = {'polymorphic_on': activity_type_code}
class UserExchangeAuth(db.Model): id = db.Column(db.Integer, nullable=False, unique=True, primary_key=True) exchange = db.Column(db.String(), nullable=False, unique=False) user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
class CircleTaskBlock(db.Model): """ This represents meta information about 1 block in the circle task. """ __tablename__ = 'circletask_blocks' __table_args__ = { 'comment': "This table holds in each row information about a block in the Circle Task study. " "Blocks can be associated with one another as belonging to the same session. " "A session is a single run through the study with all its consecutive blocks. " "Each block is comprised of trials." } # The combination of user_id and hash should* be unique and could be used as a composite key (and drop id). # time column can't be used, as it may not be unique, even though it's unlikely. # *It's highly unlikely that someone produces the exact same dataset, but not impossible. id = db.Column(db.Integer, primary_key=True, comment="Unique identifier for a block.") user_id = db.Column(db.String(32), db.ForeignKey('users.id'), nullable=False, comment="User who performed the task.") session_uid = db.Column( db.String(32), unique=False, nullable=False, comment= "The session a block belongs to. Sessions consist of consecutive blocks in a " "single run through the study.") nth_session = db.Column( db.Integer, unique=False, nullable=False, default=1, comment= "Chronological order of a session per user. How many times did a user upload data?" ) nth_block = db.Column( db.Integer, unique=False, nullable=True, default=1, comment="Chronological order of a block within a session.") treatment = db.Column( db.String(120), unique=False, nullable=True, comment= "Which degree of freedom had a constraint on it during a block. Independent variable." ) warm_up = db.Column( db.Float, unique=False, nullable=False, default=0.5, comment="Time before each trial to prepare, in seconds.") trial_duration = db.Column( db.Float, unique=False, nullable=False, default=2.0, comment="Time given for performing the task for each trial, in seconds." ) cool_down = db.Column( db.Float, unique=False, nullable=False, default=0.5, comment="Time after each trial to give feedback, in seconds.") time = db.Column( db.Float, unique=False, nullable=True, comment="Time at which a block was finished, in seconds since epoch.") time_iso = db.Column( db.DateTime, unique=False, nullable=False, default=datetime.utcnow, comment="Time at which a block was finished, in ISO format.") rating = db.Column( db.Integer, unique=False, nullable=True, comment= "The user's perceived difficulty of the block on a Likert Scale. " "Very easy - 0, Easy - 1, Neutral - 2, Difficult - 3, Very difficult - 4" ) hash = db.Column( db.String(32), unique=True, nullable=False, comment= "MD5 hash value for all the trials of a block. Used to check integrity of submitted data." ) trials = db.relationship('CircleTaskTrial', backref='block') def __repr__(self): return f"CircleTaskBlock(user_id='{self.user_id}', session_uid={self.session_uid}, " \ f"nth_session={self.nth_session}, nth_block={self.nth_block}, treatment='{self.treatment}', "\ f"time={self.time}, time_iso='{self.time_iso}', rating='{self.rating}', hash='{self.hash}')"
class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(20), unique=True) password_hash = db.Column(db.String(128)) email = db.Column(db.String(64), unique=True) confirmed = db.Column(db.Boolean, default=False) # 头像 icon = db.Column(db.String(40), default='default.jpg') # 添加博客的反向引用 posts = db.relationship('Posts', backref='user', lazy='dynamic') # 添加收藏的反向引用 favorites = db.relationship('Posts', secondary='collections', backref=db.backref('users', lazy='dynamic'), lazy='dynamic') @property def password(self): raise AttributeError('不能访问密码属性') @password.setter def password(self, password): self.password_hash = generate_password_hash(password) # 密码校验 def vierify_password(self, password): return check_password_hash(self.password_hash, password) # 封装方法生成用于账户激活的token def generate_activate_token(self, expires_in=3600): s = Serializer(current_app.config['SECRET_KEY'], expires_in=expires_in) return s.dumps({'id': self.id}) # 校验激活的token @staticmethod def check_activate_token(token): s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token) # 判断是否有token这个值 except: return False u = User.query.get(data['id']) if not u: return False # 如果用户没有激活 if not u.confirmed: u.confirmed = True db.session.add(u) return True # 校验找回密码的token @staticmethod def check_find_token(token): s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token) # 判断是否有token这个值 except: return False u = User.query.get(data['id']) if u: return u # 封装修改邮箱的方法 # 封装方法生成用于账户激活的token def generate_email_token(self, email, expires_in=3600): self.email = email s = Serializer(current_app.config['SECRET_KEY'], expires_in=expires_in) return s.dumps({'id': self.id, 'email': self.email}) # 校验新邮箱 @staticmethod def check_email_token(token): s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token) # 判断是否有token这个值 except: return False u = User.query.get(data['id']) if not u: return False # 如果用户没有激活 if u: u.email = data['email'] db.session.add(u) return True # 判断用户是否收藏指定模型 def is_favorite(self, pid): # 所有收藏的博客 favorite = self.favorites.filter(Posts.id == pid).first() if favorite: return True else: return False # 添加收藏 def add_favorite(self, pid): p = Posts.query.get(pid) # favorite = self.favorites.all() # favorite.append(p) self.favorites.append(p) # 删除收藏 def del_favorite(self, pid): p = Posts.query.get(pid) favorite = self.favorites.all() favorite.remove(p)
class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(32), nullable=False, unique=True) email = db.Column(db.String(255), unique=True) activation_key = db.Column(db.String(36)) created_time = db.Column(db.DateTime, default=get_current_time) # ================================================================ # Password _password = db.Column('password', db.String(20), nullable=False) def _get_password(self): return self._password def _set_password(self, password): self._password = sha256_crypt.encrypt(password, rounds=12345) # Hide password encryption by exposing password field only. password = db.synonym('_password', descriptor=property(_get_password, _set_password)) def check_password(self, password): if self._password is None: return False return sha256_crypt.verify(password, self._password) # ================================================================ # One-to-many relationship between users and roles. role_id = db.Column(db.SmallInteger, default=USER) def get_role(self): return USER_ROLE[self.role_id] # ================================================================ # One-to-many relationship between users and user_statuses. status_id = db.Column(db.SmallInteger, default=INACTIVE) def get_status(self): return USER_STATUS[self.status_id] # ================================================================ # One-to-one (uselist=False) relationship between users and user_details. user_detail_id = db.Column(db.Integer, db.ForeignKey("user_details.id")) user_detail = db.relationship("UserDetail", uselist=False, backref="users") # ================================================================ # Class methods @classmethod # TODO: What does this do? def authenticate(cls, login, password): user = cls.query.filter( db.or_(User.username == login, User.email == login)).first() authenticated = user.check_password(password) if user else False return user, authenticated def __repr__(self): return '<User %r>' % (self.username) def get_dob(self): return self.user_detail.dob.isoformat( ) if self.user_detail.dob is not None else None def as_dict(self): return { "id": self.id, "username": self.username, "email": self.email, "created_time": format_date(self.created_time), "first_name": self.user_detail.first_name, "last_name": self.user_detail.last_name, "gender": self.user_detail.gender, "dob": self.get_dob(), "phone": self.user_detail.phone, "bio": self.user_detail.bio, "url": self.user_detail.url } def session_as_dict(self): is_authenticated = self.is_authenticated() if (is_authenticated): return { "id": self.id, "username": self.username, "email": self.email, "status": self.get_status(), "auth": is_authenticated } else: return {"auth": is_authenticated} # ================================================================ # Required by Flask-Login def is_authenticated(self): # Should just return True unless the object represents a user that should not be allowed to authenticate for some reason return True def is_active(self): return True if self.status_id == ACTIVE else False def is_anonymous(self): # Should return True only for fake users that are not supposed to log in to the system. return False def get_id(self): return unicode(self.id)
class Goods(db.Model, HasImagesMixin): __tablename__ = 'goods' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(255))
class StatusUpdate(Base): __tablename__ = "status_update" __table_args__ = { "schema": "now_submissions" } id = db.Column(db.Integer, primary_key=True) businessareanumber = db.Column(db.String) status = db.Column(db.String) statusupdatedate = db.Column(db.DateTime) processed = db.Column(db.String) processeddate = db.Column(db.DateTime) requeststatus = db.Column(db.String) requestmessage = db.Column(db.String) seqnum = db.Column(db.Integer) statusreason = db.Column(db.String) applicationtype = db.Column(db.String) def __repr__(self): return '<Client %r>' % self.clientid
""" app.users.models.followers ~~~~~~~~~~~~~~~~~~~~~~~~~~ Followers model. """ from datetime import datetime from app.extensions import db followers = db.Table( 'followers', db.Column('follower_id', db.Integer, db.ForeignKey('user.id')), db.Column('followed_id', db.Integer, db.ForeignKey('user.id')), db.Column('created', db.DateTime, default=datetime.utcnow))
class User(db.Model, Timestamp): """ User database model. """ id = db.Column(db.Integer, primary_key=True) # pylint: disable=invalid-name username = db.Column(db.String(length=80), unique=True, nullable=False) password = db.Column( column_types.PasswordType( max_length=128, schemes=('bcrypt', ) ), nullable=False ) email = db.Column(db.String(length=120), unique=True, nullable=False) first_name = db.Column(db.String(length=30), default='', nullable=False) middle_name = db.Column(db.String(length=30), default='', nullable=False) last_name = db.Column(db.String(length=30), default='', nullable=False) class StaticRoles(enum.Enum): # pylint: disable=missing-docstring,unsubscriptable-object INTERNAL = (0x8000, "Internal") ADMIN = (0x4000, "Admin") REGULAR_USER = (0x2000, "Regular User") ACTIVE = (0x1000, "Active Account") @property def mask(self): return self.value[0] @property def title(self): return self.value[1] static_roles = db.Column(db.Integer, default=0, nullable=False) is_internal = _get_is_static_role_property('is_internal', StaticRoles.INTERNAL) is_admin = _get_is_static_role_property('is_admin', StaticRoles.ADMIN) is_regular_user = _get_is_static_role_property('is_regular_user', StaticRoles.REGULAR_USER) is_active = _get_is_static_role_property('is_active', StaticRoles.ACTIVE) def __repr__(self): return ( "<{class_name}(" "id={self.id}, " "username=\"{self.username}\", " "email=\"{self.email}\", " "is_internal={self.is_internal}, " "is_admin={self.is_admin}, " "is_regular_user={self.is_regular_user}, " "is_active={self.is_active}, " ")>".format( class_name=self.__class__.__name__, self=self ) ) def has_static_role(self, role): return (self.static_roles & role.mask) != 0 def set_static_role(self, role): if self.has_static_role(role): return self.static_roles |= role.mask def unset_static_role(self, role): if not self.has_static_role(role): return self.static_roles ^= role.mask def check_owner(self, user): return self == user @property def is_authenticated(self): return True @property def is_anonymous(self): return False @classmethod def find_with_password(cls, username, password): """ Args: username (str) password (str) - plain-text password Returns: user (User) - if there is a user with a specified username and password, None otherwise. """ user = cls.query.filter_by(username=username).first() if not user: return None if user.password == password: return user return None
class Mine(AuditMixin, Base): __tablename__ = 'mine' mine_guid = db.Column(UUID(as_uuid=True), primary_key=True) mine_no = db.Column(db.String(10)) mine_name = db.Column(db.String(60), nullable=False) mine_note = db.Column(db.String(300), default='') major_mine_ind = db.Column(db.Boolean, nullable=False, default=False) deleted_ind = db.Column(db.Boolean, nullable=False, default=True) mine_region = db.Column(db.String(2), db.ForeignKey('mine_region_code.mine_region_code')) mine_region = db.Column(db.String(2), db.ForeignKey('mine_region_code.mine_region_code')) # Relationships mineral_tenure_xref = db.relationship('MineralTenureXref', backref='mine', lazy='joined') mine_location = db.relationship( 'MineLocation', backref='mine=', order_by='desc(MineLocation.update_timestamp)', lazy='joined') mine_permit = db.relationship('Permit', backref='mine', order_by='desc(Permit.issue_date)', lazy='joined') mine_status = db.relationship('MineStatus', backref='mine', order_by='desc(MineStatus.update_timestamp)', lazy='joined') mine_tailings_storage_facilities = db.relationship( 'MineTailingsStorageFacility', backref='mine', order_by= 'desc(MineTailingsStorageFacility.mine_tailings_storage_facility_name)', lazy='joined') mine_expected_documents = db.relationship( 'MineExpectedDocument', primaryjoin= "and_(MineExpectedDocument.mine_guid == Mine.mine_guid, MineExpectedDocument.active_ind==True)", backref='mine', order_by='desc(MineExpectedDocument.due_date)', lazy='joined') mine_type = db.relationship('MineType', backref='mine', order_by='desc(MineType.update_timestamp)', lazy='joined') def __repr__(self): return '<Mine %r>' % self.mine_guid def json(self): return { 'guid': str(self.mine_guid), 'mine_name': self.mine_name, 'mine_no': self.mine_no, 'mine_note': self.mine_note, 'major_mine_ind': self.major_mine_ind, 'region_code': self.mine_region, 'mineral_tenure_xref': [item.json() for item in self.mineral_tenure_xref], 'mine_location': [item.json() for item in self.mine_location], 'mine_permit': [item.json() for item in self.mine_permit], 'mine_status': [item.json() for item in self.mine_status], 'mine_tailings_storage_facility': [item.json() for item in self.mine_tailings_storage_facilities], 'mine_expected_documents': [item.json() for item in self.mine_expected_documents], 'mine_type': [item.json() for item in self.active(self.mine_type)] } def json_for_list(self): return { 'guid': str(self.mine_guid), 'mine_name': self.mine_name, 'mine_no': self.mine_no, 'mine_note': self.mine_note, 'major_mine_ind': self.major_mine_ind, 'region_code': self.mine_region, 'mine_permit': [item.json() for item in self.mine_permit], 'mine_status': [item.json() for item in self.mine_status], 'mine_tailings_storage_facility': [item.json() for item in self.mine_tailings_storage_facilities], 'mine_type': [item.json() for item in self.active(self.mine_type)] } def json_for_map(self): return { 'guid': str(self.mine_guid), 'mine_name': self.mine_name, 'mine_no': self.mine_no, 'mine_note': self.mine_note, 'major_mine_ind': self.major_mine_ind, 'region_code': self.mine_region, 'mine_location': [item.json() for item in self.mine_location] } def json_by_name(self): return { 'guid': str(self.mine_guid), 'mine_name': self.mine_name, 'mine_no': self.mine_no } def json_by_location(self): mine_location = self.mine_location[0] if self.mine_location else None return { 'guid': str(self.mine_guid), 'latitude': str(mine_location.latitude) if mine_location else '', 'longitude': str(mine_location.longitude) if mine_location else '' } def json_by_permit(self): return { 'guid': str(self.mine_guid), 'mine_permit': [item.json() for item in self.mine_permit] } @staticmethod def active(records): return list(filter(lambda x: x.active_ind, records)) @classmethod def find_by_mine_guid(cls, _id): try: uuid.UUID(_id, version=4) return cls.query.filter_by(mine_guid=_id).first() except ValueError: return None @classmethod def find_by_mine_no(cls, _id): return cls.query.filter_by(mine_no=_id).first() @classmethod def find_by_mine_no_or_guid(cls, _id): result = cls.find_by_mine_guid(_id) if result is None: result = cls.find_by_mine_no(_id) return result @classmethod def create_mine(cls, mine_no, mine_name, mine_category, mine_region, user_kwargs, save=True): mine = cls(mine_guid=uuid.uuid4(), mine_no=mine_no, mine_name=mine_name, major_mine_ind=mine_category, mine_region=mine_region, **user_kwargs) if save: mine.save(commit=False) return mine @validates('mine_name') def validate_mine_name(self, key, mine_name): if not mine_name: raise AssertionError('No mine name provided.') if len(mine_name) > 60: raise AssertionError('Mine name must not exceed 60 characters.') return mine_name @validates('mine_note') def validate_mine_note(self, key, mine_note): if len(mine_note) > 300: raise AssertionError('Mine note must not exceed 300 characters.') return mine_note @validates('mine_no') def validate_mine_no(self, key, mine_no): if len(mine_no) > 10: raise AssertionError('Mine number must not exceed 10 characters.') return mine_no
class User(UserMixin, db.Model): __tablename__ = 'user' userid = db.Column(db.String(64), primary_key=True, default=str(uuid1())) username = db.Column(db.String(64), nullable=False) realname = db.Column(db.String(64), default='') mobile = db.Column(db.String(32), nullable=False) password_hash = db.Column(db.String(128), nullable=False) level = db.Column(db.String(2), default='1') score = db.Column(db.String(10), default='0') role = db.Column(db.String(2), default='1') email = db.Column(db.String(128), nullable=False) blackflag = db.Column(db.String(2), default='0') delflag = db.Column(db.String(2), default='0') createtime = db.Column(db.DateTime, default=str(datetime.now())) def db2json(self): data = to_json(self) return data @property def password(self): raise AttributeError('密码是不可读属性') @password.setter def password(self, password): self.password_hash = generate_password_hash(password) # 密码校验 def verify_password(self, password): return check_password_hash(self.password_hash, password) # 生成token作为校验 def encode_auth_token(self, user_id): try: payload = { 'exp': datetime.utcnow() + timedelta(days=1, seconds=0), 'iat': datetime.utcnow(), 'sub': user_id } return jwt.encode(payload, Config.SECRET_KEY, algorithm='HS256') except Exception as e: return e # 对token解码 # 用静态方法,使其与class实例无关 @staticmethod def decode_auth_token(auth_token): try: payload = jwt.decode(auth_token, Config.SECRET_KEY) return payload['sub'], 200 except jwt.ExpiredSignatureError: return '签名已过期,请再次登录', 401 except jwt.InvalidTokenError: return '令牌无效,请再次登录', 403
from .user import User from .posts import Posts from app.extensions import db # 创建多对多的中间关联表,ORM自动维护 collections = db.Table( 'collections', db.Column('user_id', db.Integer, db.ForeignKey('users.id')), db.Column('posts_id', db.Integer, db.ForeignKey('posts.id')))
#-*-coding=utf-8-*- # project: workspace # createtime: 2018/4/12 9:09 # IDE: PyCharm # anthor: ZT@gufan from app.extensions import db #定义多对多关系 注意定义一个中间表 posts_tags = db.Table( "posts_tags", db.Column('post_id', db.Integer, db.ForeignKey("posts.id")), db.Column('tag_id', db.Integer, db.ForeignKey('tags.id'))) class User(db.Model): __tablename__ = "users" id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(255), nullable=False) password = db.Column(db.String(255), nullable=False) posts = db.relationship('Post', backref="users", lazy="dynamic") def __repr__(self): return "<Model User {}>".format(self.username) class Post(db.Model): __tablename__ = "posts" id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(255)) text = db.Column(db.Text())
class Udcontent(db.Model): __tablename__ = 'udcontent' id = db.Column(db.Integer, primary_key=True) content = db.Column(db.String(32)) ud_id = db.Column(db.Integer) pid = db.Column(db.Integer)
class StrategyModel(db.Model): __tablename__ = "strategies" id = db.Column(db.Integer, nullable=False, unique=True, primary_key=True) uuid = db.Column(db.String(), unique=True, default=shortuuid.uuid()) name = db.Column(db.String(), nullable=False, unique=False) created_at = db.Column(db.DateTime(), default=datetime.datetime.now()) trading_config = db.Column(db.JSON(), nullable=False, unique=False) dataset_config = db.Column(db.JSON(), nullable=False, unique=False) indicators_config = db.Column(db.JSON(), nullable=False, unique=False) signals_config = db.Column(db.JSON(), nullable=False, unique=False) status = db.Column(db.String(), nullable=True, unique=False, primary_key=False) result_json = db.Column(db.JSON(), nullable=True, unique=False) user_id = db.Column(db.Integer, db.ForeignKey("users.id")) @classmethod def from_json(cls, strat_json, user_id=None): d = json.loads(strat_json) instance = cls() instance.uuid = shortuuid.uuid() instance.name = d.get("name") instance.trading_config = d.get("trading") instance.dataset_config = d.get("datasets") instance.indicators_config = d.get("indicators") instance.signals_config = d.get("signals") if user_id is not None: instance.user_id = user_id return instance def update_from_job(self, job): self.status = job.status current_app.logger.debug( f"Updating strategy {self.id} status: {self.status}") if job.result: current_app.logger.debug(f"Strategy {self.id} job has finished") self.result_json = job.result db.session.commit() def config_to_json(self): d = { "id": self.id, "name": self.name, "trading": self.trading_config, "datasets": self.dataset_config, "indicator": self.indicators_config, "signals_config": self.signals_config, } return json.dumps(d) @property def parsed_result_json(self): if self.result_json is None: return {} d = json.loads(self.result_json) clean_result = {} for k, v in d.items(): # nested dict with trading type as key metric, val = k, v.get("Backtest", v) clean_result[metric] = val return clean_result def pretty_result(self): string = "" if self.result_json is None: return None result_dict = json.loads(self.result_json) for k, v in result_dict.items(): # nested dict with trading type as key metric, val = k, v["Backtest"] string += f"{metric}: {val}\n" return string
class Application(Base, AuditMixin): __tablename__ = 'application' class _ModelSchema(Base._ModelSchema): id = fields.Integer(dump_only=True) guid = fields.String(dump_only=True) submission_date = fields.String(dump_only=True) status_changes = fields.Raw(dump_only=True) ##DO NOT INGEST ON POST id = db.Column(db.Integer, primary_key=True, server_default=FetchedValue()) guid = db.Column(UUID(as_uuid=True), nullable=False, unique=True, server_default=FetchedValue()) submission_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) json = db.Column(JSONB, nullable=False) review_json = db.Column(JSONB) submitter_ip = db.Column(db.String) edit_note = db.Column(db.String) application_phase_code = db.Column( db.String, db.ForeignKey('application_phase_type.application_phase_code'), nullable=False) documents = db.relationship('ApplicationDocument', lazy='select') payment_documents = db.relationship( 'PaymentDocument', lazy='select', primaryjoin= 'and_(PaymentDocument.application_guid == Application.guid, PaymentDocument.active_ind == True)' ) status_changes = db.relationship( 'ApplicationStatusChange', lazy='select', order_by='desc(ApplicationStatusChange.change_date)', ) def __repr__(self): return f'<{self.__class__.__name__} {self.guid}>' @classmethod def get_all(cls): return cls.query.all() @classmethod def find_by_guid(cls, guid): return cls.query.filter_by(guid=guid).one_or_none() @validates('json') def validate_json(self, key, json): well_sites = json.get('well_sites') for site in well_sites: contracted_work = site.get('contracted_work') work = list( set(list(WELL_SITE_CONTRACTED_WORK.keys())).intersection( contracted_work)) if len(work) == 0: raise AssertionError( 'Application must contain at least one piece of contracted work.' ) for i in work: work_item = contracted_work.get(i) total = [ value for key, value in work_item.items() if key in WELL_SITE_CONTRACTED_WORK.get(i) ] if sum(total) == 0: raise AssertionError( 'Contracted works must have an amount greater than $0') for key, value in APPLICATION_JSON.items(): k = json.get(key, None) if k: for item in value: if item == 'company_name': company_name = k.get(item, None) if company_name: for i in COMPANY_NAME_JSON_KEYS: if not company_name.get(i, None): raise AssertionError( f'{i} must not be None') else: raise AssertionError(f'{item} must not be None') if not k.get(item, None): raise AssertionError(f'{item} must not be None') else: raise AssertionError(f'{key} must not be None') return json @hybrid_property def company_name(self): return self.json.get('company_details', {}).get('company_name', {}).get('label') @company_name.expression def company_name(self): return Application.json['company_details']['company_name'][ 'label'].astext @hybrid_property def agreement_number(self): return str(self.id).zfill(4) @hybrid_property def well_sites_with_review_data(self): """Merges well sites with their corresponding review data and provides extra information.""" well_sites = self.json.get('well_sites') # Merge well sites with their corresponding review data. if self.review_json: ws_reviews = self.review_json.get('well_sites') for i, ws_review in enumerate(ws_reviews): if not ws_review: continue for wan, review_data in ws_review.items(): for k, v in review_data.items(): if k != 'contracted_work': continue for cw_type, cw_data in v.items(): well_sites[i]['contracted_work'][cw_type].update( cw_data) # Calculate the sum for each contracted work item for i, well_site in enumerate(well_sites): for cw_type, cw_data in well_site.get('contracted_work', {}).items(): cw_total = 0 for k, v in cw_data.items(): if k in WELL_SITE_CONTRACTED_WORK[cw_type]: cw_total += v well_sites[i]['contracted_work'][cw_type][ 'contracted_work_total'] = round(cw_total, 2) return well_sites @hybrid_method def contracted_work(self, status, include_payment): contracted_work = [] contracted_work_payments = None if include_payment: contracted_work_payments = marshal( ContractedWorkPayment.find_by_application_guid(self.guid), CONTRACTED_WORK_PAYMENT) for ws in self.well_sites_with_review_data: for cw_type, cw_data in ws.get('contracted_work', {}).items(): if cw_data.get('contracted_work_status_code', None) != status: continue cw_item = {} cw_item['application_id'] = self.id cw_item['application_guid'] = str(self.guid) cw_item['company_name'] = self.company_name cw_item['contracted_work_type'] = cw_type cw_item['well_authorization_number'] = ws['details'][ 'well_authorization_number'] cw_item['estimated_shared_cost'] = self.calc_est_shared_cost( cw_data) cw_item.update(cw_data) if include_payment: cw_payment = next( (cwp for cwp in contracted_work_payments if cwp['work_id'] == cw_item['work_id']), None) cw_item['contracted_work_payment'] = cw_payment contracted_work.append(cw_item) return contracted_work @classmethod def all_approved_contracted_work(self, application_id=None, application_guid=None, company_name=None): contracted_work_payments = [] approved_applications = [] if application_id or application_guid or company_name: if application_id and not application_guid: application = Application.query.filter_by( id=application_id).one_or_none() application_guid = application.guid if application else None approved_applications = Application.query.filter( and_( Application.application_status_code == 'FIRST_PAY_APPROVED', Application.id == application_id if application_id != None else True, Application.guid == application_guid if application_guid != None else True, Application.company_name == company_name if company_name != None else True)).order_by( Application.id).all() approved_application_guids = [ x.guid for x in approved_applications ] contracted_work_payments = ContractedWorkPayment.query.filter( Application.guid.in_(approved_application_guids)).all() else: approved_applications = Application.query.filter_by( application_status_code='FIRST_PAY_APPROVED').order_by( Application.id).all() contracted_work_payments = ContractedWorkPayment.query.all() contracted_work_payments_lookup = {} for cwp in contracted_work_payments: contracted_work_payments_lookup[cwp.work_id] = marshal( cwp, CONTRACTED_WORK_PAYMENT) approved_applications_approved_contracted_work = [] for application in approved_applications: for approved_work in application.contracted_work( 'APPROVED', False): approved_work[ 'contracted_work_payment'] = contracted_work_payments_lookup.get( approved_work['work_id'], None) approved_work[ 'application_phase_code'] = application.application_phase_code approved_applications_approved_contracted_work.append( approved_work) return approved_applications_approved_contracted_work def find_contracted_work_by_id(self, work_id): for ws in self.well_sites_with_review_data: for cw_type, cw_data in ws.get('contracted_work', {}).items(): if cw_data['work_id'] == work_id: return cw_data def find_contracted_work_type_by_work_id(self, work_id): for ws in self.well_sites_with_review_data: for cw_type, cw_data in ws.get('contracted_work', {}).items(): if cw_data['work_id'] == work_id: return cw_type def calc_est_shared_cost(self, contracted_work): """Calculates the contracted work item's Estimated Shared Cost, which is half of the estimated cost \ unless that value is $100,000 or more, then it is $100,000. """ half_est_cost = round(contracted_work['contracted_work_total'] / 2.0, 2) est_shared_cost = half_est_cost if half_est_cost <= 100000 else 100000 return est_shared_cost def calc_total_est_shared_cost(self): """Calculates this application's contribution (sum of all contracted work Estimated Shared Cost) to the Provincial Financial Contribution total.""" total_est_shared_cost = 0 for ws in self.well_sites_with_review_data: for cw_type, cw_data in ws.get('contracted_work', {}).items(): if cw_data.get('contracted_work_status_code', None) != 'APPROVED': continue total_est_shared_cost += self.calc_est_shared_cost(cw_data) return total_est_shared_cost def calc_first_prf_amount(self): """Calculates this application's payment phase one amount, which is 10% of the total estimated shared cost.""" return round(self.calc_total_est_shared_cost() * 0.10, 2) @hybrid_property def shared_cost_agreement_template_json(self): """Generates the JSON used to generate this application's Shared Cost Agreement document.""" result = self.json # Create general document info result['agreement_no'] = self.agreement_number result['application_guid'] = str(self.guid) result['agreement_date'] = datetime.now().strftime("%d, %b, %Y") # Create company info _company_details = self.json.get('company_details') _company_name = _company_details['company_name']['label'] addr1 = _company_details.get('address_line_1') addr2 = _company_details.get( 'address_line_2') + '\n' if _company_details.get( 'address_line_2') else "" city = _company_details.get('city') post_cd = _company_details.get('postal_code') prov = _company_details.get('province') # Create applicant info _applicant_name = self.applicant_name result['applicant_name'] = _applicant_name result[ 'applicant_address'] = f'{addr1}\n{addr2}{post_cd}\n{city}, {prov}' result['applicant_company_name'] = _company_name result['funding_amount'] = '${:,.2f}'.format( self.calc_total_est_shared_cost()) result[ 'recipient_contact_details'] = f'{_applicant_name},\n{_company_name},\n{addr1} {post_cd} {city} {prov},\n{self.applicant_email},\n{self.submitter_phone_1}' # Create detailed info for each well site's contracted work items result['formatted_well_sites'] = "" for ws in self.well_sites_with_review_data: site_details = ws.get('details', {}) wan = site_details.get('well_authorization_number') for worktype, wt_details in ws.get('contracted_work', {}).items(): if wt_details.get('contracted_work_status_code', None) != 'APPROVED': continue site = f'\nWell Authorization Number: {wan}\n' site += f' Eligible Activities as described in Application: {worktype.replace("_"," ").capitalize()}\n' site += f' Applicant\'s Estimated Cost: {"${:,.2f}".format(wt_details.get("contracted_work_total"))}\n' site += f' Provincial Financial Contribution: {"${:,.2f}".format(self.calc_est_shared_cost(wt_details))}\n' site += f' Planned Start Date: {wt_details["planned_start_date"]}\n' site += f' Planned End Date: {wt_details["planned_end_date"]}\n' result['formatted_well_sites'] += site return result @hybrid_property def applicant_name(self): return f"{self.json['company_contact']['first_name']} {self.json['company_contact']['last_name']}" @hybrid_property def applicant_email(self): return self.json.get('company_contact', {}).get('email') @hybrid_property def submitter_phone_1(self): ph1 = self.json.get('company_contact', {}).get('phone_number_1') ph1_ext = self.json.get('company_contact', {}).get('phone_number_1_ext') return ph1 if not ph1_ext else f'{ph1} ext.{ph1_ext}' @hybrid_property def application_status_code(self): if self.status_changes: return self.status_changes[0].application_status_code else: return 'NOT_STARTED' @application_status_code.expression def application_status_code(self): return func.coalesce( select([ApplicationStatusChange.application_status_code]).where( ApplicationStatusChange.application_guid == self.guid).order_by(desc( ApplicationStatusChange.change_date)).limit(1).as_scalar(), 'NOT_STARTED') def send_confirmation_email(self): html_content = f""" <p> We have successfully received your application in the British Columbia Dormant Sites Reclamation Program. Please keep your reference number safe as you will need it to carry your application forward in this process. You can view the contents of your application below. <br /> <br /> <a href='{Config.URL}/view-application-status/{self.guid}'>Click here to view the status of your application.</a> <br/> <br/> <br/> <br/> <br/> </p> {self.get_application_html()} """ with EmailService() as es: es.send_email_to_applicant(self, 'Application Confirmation', html_content) def get_application_html(self): def create_company_details(company_details): indigenous_content = '' if self.application_phase_code == 'INITIAL': indigenous_participation_ind = company_details.get( 'indigenous_participation_ind', False) == True indigenous_content = f""" <h2>Indigenous Participation</h2> <p>{"Yes" if indigenous_participation_ind else "No"}</p> {f'<p>{company_details["indigenous_participation_description"]}</p>' if indigenous_participation_ind else ""} """ elif self.application_phase_code == 'NOMINATION': indigenous_affiliation = company_details.get( 'indigenous_affiliation') indigenous_communities = company_details.get( 'indigenous_communities', []) has_indigenous_affiliation = indigenous_affiliation and indigenous_communities and indigenous_affiliation != 'NONE' and indigenous_affiliation in INDIGENOUS_APPLICANT_AFFILIATION indigenous_affiliation_label = INDIGENOUS_APPLICANT_AFFILIATION[ indigenous_affiliation] if has_indigenous_affiliation else INDIGENOUS_APPLICANT_AFFILIATION[ "NONE"] indigenous_content = f""" <h2>Indigenous Affiliation</h2> <p>{indigenous_affiliation_label}</p> """ if has_indigenous_affiliation: def create_indigenous_community(community): return f'<li>{community}</li>' indigenous_content += f""" <h3>Indigenous Peoples</h3> <ul> {''.join([create_indigenous_community(community) for community in indigenous_communities])} </ul> """ return f""" <h1>Company Details</h1> <h2>Company Name</h2> <p>{company_details["company_name"]["label"]}</p> <h2>Company Address</h2> <p> {company_details["city"]} {company_details["province"]} Canada <br /> {company_details["address_line_1"]} <br /> {f'{company_details["address_line_2"]}<br />' if company_details.get("address_line_2") else ""} {company_details["postal_code"]} </p> <h2>Business Number</h2> <p>{company_details["business_number"]}</p> {indigenous_content} """ def create_company_contact(company_contact): return f""" <h1>Company Contact</h1> <p>{company_contact["first_name"]} {company_contact["last_name"]}</p> <p>{company_contact["email"]}</p> <p> Phone: {company_contact["phone_number_1"]}<br /> {f'Ext.: {company_contact["phone_ext_1"]}<br />' if company_contact.get("phone_ext_1") else ""} {f'Phone 2.: {company_contact["phone_number_2"]}<br />' if company_contact.get("phone_number_2") else ""} {f'Ext. 2: {company_contact["phone_ext_2"]}<br />' if company_contact.get("phone_ext_2") else ""} {f'Fax: {company_contact["fax"]}<br />' if company_contact.get("fax") else ""} </p> """ def create_contract_details(contract_details): try: permit_holder = PermitHolderResource.get( self, operator_id=contract_details["operator_id"])["records"][0] except: current_app.logger.warning( 'Failed to find the permit holder. Displaying operator ID instead.' ) return f""" <h1>Contract Details</h1> <h2>Permit Holder</h2> <p>{permit_holder["organization_name"] if permit_holder else f'Operator ID: {contract_details["operator_id"]}'}</p> """ def create_well_sites(well_sites): def create_well_site(well_site, index): def create_site_condition(condition, site_conditions): return f"<li><b>{condition['label']}</b>: {'Yes' if condition['name'] in site_conditions and site_conditions[condition['name']] == True else 'No'}</li>" def create_contracted_work_section(section, contracted_work): def create_indigenous_subcontractors( section, contracted_work): if self.application_phase_code == 'INITIAL': return '' def create_indigenous_subcontractor( number, subcontractor): return f""" Subcontractor {number}:<br /> <p> Subcontractor Name: {subcontractor['indigenous_subcontractor_name']}<br /> Indigenous Affiliation: {INDIGENOUS_SUBCONTRACTOR_AFFILIATION[subcontractor['indigenous_affiliation']]}<br /> Indigenous Peoples:<br /> <ul> {''.join([f'<li>{community}</li>' for community in subcontractor['indigenous_communities']])} </ul> </p> """ indigenous_subcontractors = contracted_work.get( section['section_name'], {}).get('indigenous_subcontractors', []) indigenous_subcontractors_content = 'N/A' if not indigenous_subcontractors else ''.join( [ create_indigenous_subcontractor( i + 1, subcontractor) for i, subcontractor in enumerate(indigenous_subcontractors) ]) return f""" <p><u>Indigenous Subcontractors</u></p> {indigenous_subcontractors_content} """ def create_sub_section(sub_section, section, contracted_work): def create_amount_field(amount_field, section, contracted_work): return f""" <tr> <td style="padding-left: 10px;">{amount_field["label"]}:</td> <td style="padding-left: 10px;">{'$0.00' if not (section["section_name"] in contracted_work and (amount_field["name"] in contracted_work[section["section_name"]])) else f'${contracted_work[section["section_name"]][amount_field["name"]] or "0.00"}'}</td> </tr> """ return f""" <p><u>{sub_section["sub_section_header"]}</u></p> <table class="contracted_work_amount"> {''.join([create_amount_field(amount_field, section, contracted_work) for amount_field in sub_section["amount_fields"]])} </table> """ return f""" <h4>{section["section_header"]}</h4> <p>Planned Start Date: {contracted_work[section["section_name"]]["planned_start_date"] if contracted_work.get(section["section_name"]) and contracted_work.get(section["section_name"]).get("planned_start_date") else "N/A"}</p> <p>Planned End Date: {contracted_work[section["section_name"]]["planned_end_date"] if contracted_work.get(section["section_name"]) and contracted_work.get(section["section_name"]).get("planned_end_date") else "N/A"}</p> {''.join([create_sub_section(sub_section, section, contracted_work) for sub_section in section["sub_sections"]])} <br /> {create_indigenous_subcontractors(section, contracted_work)} """ def create_site_condition(site_conditions): site_conditions_section = "" if self.application_phase_code == 'NOMINATION' else f""" h3>Site Conditions</h3> {''.join()} <ul> {''.join([create_site_condition(condition, well_site["site_conditions"]) for condition in SITE_CONDITIONS])} </ul> """ return f""" <h2>Well Site {index + 1}</h2> <h3>Well Authorization Number</h3> <p>{well_site["details"]["well_authorization_number"]}</p> {create_site_condition(well_site)} <h3>Contracted Work</h3> {''.join([create_contracted_work_section(section, well_site["contracted_work"]) for section in CONTRACTED_WORK])} <hr /> """ return f""" <h1>Well Sites</h1> {''.join([create_well_site(well_site, index) for index, well_site in enumerate(well_sites)])} """ html = f""" {create_company_details(self.json["company_details"])} {create_company_contact(self.json["company_contact"])} {create_contract_details(self.json["contract_details"])} {create_well_sites(self.json["well_sites"])} """ return html def save_application_history(self): application_json = marshal(self, APPLICATION) application_json["application_id"] = self.id application_history = ApplicationHistory._schema().load( application_json) application_history.save() return application_history def process_well_sites_work_items(self, well_sites_json, func, **args): def perform(self, fun, **args): fun(**args) for site in well_sites_json: contracted_work = site.get('contracted_work') works = list( set(list(WELL_SITE_CONTRACTED_WORK.keys())).intersection( contracted_work)) for i in works: work_item = contracted_work.get(i) if args is not None: args["work_item"] = work_item perform(self, func, **args) def update_work_item_action(self, work_item, id, planned_start_date, planned_end_date): if work_item["work_id"] == id: work_item["planned_start_date"] = planned_start_date work_item["planned_end_date"] = planned_end_date def iterate_application_work_items_action(self, work_item): application_json = marshal(self, APPLICATION) json = application_json["json"]["well_sites"] args = { "id": work_item["work_id"], "planned_start_date": work_item["planned_start_date"], "planned_end_date": work_item["planned_end_date"] } self.process_well_sites_work_items(json, self.update_work_item_action, **args)
class CircleTaskTrial(db.Model): """ Variables specific to circle task. """ __tablename__ = 'circletask_trials' __table_args__ = { 'comment': "This table holds in each row information about the outcome of a single trial from " "the Circle Task study. Trials belong to a block, which are part of a complete run " "through the study." } # Can't use ForeignKeyConstraint as composite key, # because user_id, session and block are not unique keys in reference table. id = db.Column(db.Integer, primary_key=True, comment="Unique identifier of a trial.") # ToDo: user_id rly necessary? -> self.block_id.user_id or get-method user_id = db.Column(db.String(32), db.ForeignKey('users.id'), nullable=False, comment="User who performed the task.") block_id = db.Column(db.Integer, db.ForeignKey('circletask_blocks.id'), nullable=False, comment="The block a trial belongs to.") # Since nth_block is a non-unique property in CircleTaskBlock we cannot place its value here, # but have to go through block_id. trial = db.Column(db.Integer, unique=False, nullable=False, comment="Chronological order of trial within a block.") df1 = db.Column( db.Float, unique=False, nullable=True, comment= "Value of degree of freedom 1 at end of trial. Dependent variable.") df2 = db.Column( db.Float, unique=False, nullable=True, comment= "Value of degree of freedom 2 at end of trial. Dependent variable.") df1_grab = db.Column( db.Float, unique=False, nullable=True, comment= "Delta time in seconds after trial onset at which df1 slider was grabbed." ) df1_release = db.Column( db.Float, unique=False, nullable=True, comment= "Delta time in seconds after trial onset at which df1 slider was released, either " "by the user or by the end of the countdown.") df1_duration = db.Column(db.Float, unique=False, nullable=True, comment="Duration of the df1 grab, in seconds.") df2_grab = db.Column( db.Float, unique=False, nullable=True, comment= "Delta time in seconds after trial onset at which df2 slider was grabbed." ) df2_release = db.Column( db.Float, unique=False, nullable=True, comment= "Delta time in seconds after trial onset at which df2 slider was released, either " "by the user or by the end of the countdown.") df2_duration = db.Column(db.Float, unique=False, nullable=True, comment="Duration of the df2 grab, in seconds.") sum = db.Column( db.Float, unique=False, nullable=True, comment= "Sum of values for df1 and df2 at end of trial. Dependent variable.") def __init__(self, **kwargs): super(CircleTaskTrial, self).__init__(**kwargs) self.df1_duration = kwargs['df1_release'] - kwargs['df1_grab'] self.df2_duration = kwargs['df2_release'] - kwargs['df2_grab'] self.sum = kwargs['df1'] + kwargs['df2'] def __repr__(self): return f"CircleTaskTrial(user_id='{self.user_id}', block_id={self.block_id}, trial={self.trial}, " \ f"df1={self.df1}, df1_grab={self.df1_grab}, df1_release={self.df1_release}, " \ f"df2={self.df2}, df2_grab={self.df2_grab}, df2_release={self.df2_release})"
class CreditCard(ResourceMixin, db.Model): IS_EXPIRING_THRESHOLD_MONTHS = 2 __tablename__ = 'credit_cards' id = db.Column(db.Integer, primary_key=True) # Relationships. user_id = db.Column(db.Integer, db.ForeignKey('users.id', onupdate='CASCADE', ondelete='CASCADE'), index=True, nullable=False) # Card details. brand = db.Column(db.String(32)) last4 = db.Column(db.Integer) exp_date = db.Column(db.Date, index=True) is_expiring = db.Column(db.Boolean(), nullable=False, server_default='0') def __init__(self, **kwargs): # Call Flask-SQLAlchemy's constructor. super(CreditCard, self).__init__(**kwargs) @classmethod def is_expiring_soon(cls, compare_date=None, exp_date=None): """ Determine whether or not this credit card is expiring soon. :param compare_date: Date to compare at :type compare_date: date :param exp_date: Expiration date :type exp_date: date :return: bool """ return exp_date <= timedelta_months( CreditCard.IS_EXPIRING_THRESHOLD_MONTHS, compare_date=compare_date) @classmethod def mark_old_credit_cards(cls, compare_date=None): """ Mark credit cards that are going to expire soon or have expired. :param compare_date: Date to compare at :type compare_date: date :return: Result of updating the records """ today_with_delta = timedelta_months( CreditCard.IS_EXPIRING_THRESHOLD_MONTHS, compare_date) CreditCard.query.filter(CreditCard.exp_date <= today_with_delta) \ .update({CreditCard.is_expiring: True}) return db.session.commit() @classmethod def extract_card_params(cls, customer): """ Extract the credit card info from a payment customer object. :param customer: Payment customer :type customer: Payment customer :return: dict """ card_data = customer.sources.data[0] exp_date = datetime.date(card_data.exp_year, card_data.exp_month, 1) card = { 'brand': card_data.brand, 'last4': card_data.last4, 'exp_date': exp_date, 'is_expiring': CreditCard.is_expiring_soon(exp_date=exp_date) } return card
return pwd_context.verify(password, self.password) def to_json(self): json_user = { 'id': str(self.id), 'username': self.username, 'avator': self.avator, 'email': self.email, # 'pictures':self.pictures } return json_user # 关联表tag_picture relation = db.Table('tag_pic_relation', db.Column('id', db.Integer, primary_key=True), db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')), db.Column('picture_id', db.Integer, db.ForeignKey('pictures.id')) ) class Picture(db.Model): __tablename__ = 'pictures' id = db.Column(db.Integer, primary_key=True) despriction = db.Column(db.String(500)) address = db.Column(db.String(200), unique=True) userId = db.Column(db.Integer, db.ForeignKey('user.id')) tags = db.relationship( 'Tag', secondary=relation, backref=db.backref('pictures', lazy='dynamic')) comments = db.relationship( 'Comment', backref='pictures', lazy='dynamic')
make_searchable() class NoteQuery(BaseQuery, SearchQueryMixin): pass def sanitize(content): soup = BeautifulSoup(content, 'html.parser') nodes = soup.recursiveChildGenerator() text_nodes = [e for e in nodes if isinstance(e, str)] return ''.join(text_nodes) tags = db.Table('note_tag', db.Column('tag.id', db.Integer, db.ForeignKey('tag.id')), db.Column('note.id', db.Integer, db.ForeignKey('note.id'))) class Note(db.Model, GetOr404Mixin, GetOrCreateMixin): query_class = NoteQuery id = db.Column(db.Integer, primary_key=True) content = db.Column(db.Text) created = db.Column(db.DateTime) updated = db.Column(db.DateTime) is_email = db.Column(db.Boolean) history = db.relationship('NoteHistory', backref='note', cascade='delete') user_id = db.Column(db.Integer, db.ForeignKey('user.id')) author = db.relationship('User', backref='notes') search_vector = db.Column(TSVectorType('content'))
class Party(AuditMixin, Base): __tablename__ = 'party' party_guid = db.Column(UUID(as_uuid=True), primary_key=True, server_default=FetchedValue()) first_name = db.Column(db.String, nullable=True) middle_name = db.Column(db.String, nullable=True) party_name = db.Column(db.String, nullable=False) phone_no = db.Column(db.String, nullable=False) phone_ext = db.Column(db.String, nullable=True) email = db.Column(db.String, nullable=True) effective_date = db.Column(db.DateTime, nullable=False, server_default=FetchedValue()) expiry_date = db.Column(db.DateTime) party_type_code = db.Column( db.String, db.ForeignKey('party_type_code.party_type_code')) deleted_ind = db.Column(db.Boolean, nullable=False, server_default=FetchedValue()) mine_party_appt = db.relationship('MinePartyAppointment', lazy='joined') address = db.relationship('Address', lazy='joined') job_title = db.Column(db.String, nullable=True) postnominal_letters = db.Column(db.String, nullable=True) idir_username = db.Column(db.String, nullable=True) business_role_appts = db.relationship('PartyBusinessRoleAppointment', lazy='joined') party_orgbook_entity = db.relationship('PartyOrgBookEntity', backref='party_orgbook_entity', uselist=False, lazy='select') @hybrid_property def name(self): return self.first_name + ' ' + self.party_name if self.first_name else self.party_name @hybrid_property def business_roles_codes(self): return [ x.party_business_role_code for x in self.business_role_appts if (not x.end_date or x.end_date > datetime.utcnow()) ] @name.expression def name(cls): return func.concat(cls.first_name, ' ', cls.party_name) def __repr__(self): return '<Party %r>' % self.party_guid # TODO: Remove this once mine_party_appt has been refactored def json(self, show_mgr=True, relationships=[]): context = { 'party_guid': str(self.party_guid), 'party_type_code': self.party_type_code, 'phone_no': self.phone_no, 'phone_ext': self.phone_ext, 'email': self.email, 'effective_date': self.effective_date.isoformat(), 'expiry_date': self.expiry_date.isoformat() if self.expiry_date is not None else None, 'party_name': self.party_name, 'name': self.name, 'address': self.address[0].json() if len(self.address) > 0 else [{}], 'job_title': self.job_title, 'postnominal_letters': self.postnominal_letters, 'idir_username': self.idir_username } if self.party_type_code == 'PER': context.update({ 'first_name': self.first_name, }) if 'mine_party_appt' in relationships: context.update({ 'mine_party_appt': [item.json() for item in self.mine_party_appt], }) return context @classmethod def find_by_party_guid(cls, _id): try: uuid.UUID(_id) except ValueError: raise BadRequest('Invalid Party guid') return cls.query.filter_by(party_guid=_id, deleted_ind=False).first() @classmethod def find_by_name(cls, party_name, first_name=None): party_type_code = 'PER' if first_name else 'ORG' filters = [ func.lower(cls.party_name) == func.lower(party_name), cls.party_type_code == party_type_code, cls.deleted_ind == False ] if first_name: filters.append( func.lower(cls.first_name) == func.lower(first_name)) return cls.query.filter(*filters).first() @classmethod def search_by_name(cls, search_term, party_type=None, query_limit=50): _filter_by_name = func.upper(cls.name).contains( func.upper(search_term)) if party_type: return cls.query.filter(cls.party_type_code == party_type).filter( _filter_by_name).filter( cls.deleted_ind == False).limit(query_limit) else: return cls.query.filter(_filter_by_name).filter( cls.deleted_ind == False).limit(query_limit) @classmethod def create( cls, # Required fields party_name, phone_no, party_type_code, # Optional fields address_type_code=None, # Nullable fields email=None, first_name=None, phone_ext=None, suite_no=None, address_line_1=None, address_line_2=None, city=None, sub_division_code=None, post_code=None, add_to_session=True): party = cls( # Required fields party_name=party_name, phone_no=phone_no, party_type_code=party_type_code, # Optional fields email=email, first_name=first_name, phone_ext=phone_ext) if add_to_session: party.save(commit=False) return party @validates('party_type_code') def validate_party_type_code(self, key, party_type_code): if not party_type_code: raise AssertionError('Party type is not provided.') if party_type_code not in ['PER', 'ORG']: raise AssertionError('Invalid party type.') return party_type_code @validates('first_name') def validate_first_name(self, key, first_name): if self.party_type_code == 'PER' and not first_name: raise AssertionError('Person first name is not provided.') if first_name and len(first_name) > 100: raise AssertionError( 'Person first name must not exceed 100 characters.') return first_name @validates('party_name') def validate_party_name(self, key, party_name): if not party_name: raise AssertionError('Party name is not provided.') if len(party_name) > 100: raise AssertionError('Party name must not exceed 100 characters.') return party_name @validates('phone_no') def validate_phone_no(self, key, phone_no): if not phone_no: raise AssertionError('Party phone number is not provided.') if not re.match(r'[0-9]{3}-[0-9]{3}-[0-9]{4}', phone_no): raise AssertionError( 'Invalid phone number format, must be of XXX-XXX-XXXX.') return phone_no @validates('email') def validate_email(self, key, email): if email and not re.match(r'[^@]+@[^@]+\.[^@]+', email): raise AssertionError(f'Invalid email format. {email}') return email
class Note(db.Model, GetOr404Mixin, GetOrCreateMixin): query_class = NoteQuery id = db.Column(db.Integer, primary_key=True) content = db.Column(db.Text) created = db.Column(db.DateTime) updated = db.Column(db.DateTime) is_email = db.Column(db.Boolean) history = db.relationship('NoteHistory', backref='note', cascade='delete') user_id = db.Column(db.Integer, db.ForeignKey('user.id')) author = db.relationship('User', backref='notes') search_vector = db.Column(TSVectorType('content')) tags = db.relationship('Tag', backref='notes', secondary=tags) class VersionDoesNotExist(Exception): def __init__(self, note, version): super(Note.VersionDoesNotExist, self).__init__( 'Note version {} not found in history of note {}'.format( version, note.id)) @classmethod def create(cls, content, author, is_email=False): note = Note(content=sanitize(content), author=author, is_email=is_email) note.created = datetime.datetime.utcnow() note.updated = note.created db.session.add(note) db.session.commit() return note def update(self, content): now = datetime.datetime.utcnow() version = NoteHistory(self, now) db.session.add(version) self.history.append(version) self.content = sanitize(content) self.updated = now db.session.add(self) db.session.commit() def revert(self, version=None): if version is None: version = len(self.history) - 1 versions = {rev.version: rev for rev in self.history} if version not in versions: raise Note.VersionDoesNotExist(self, version) self.update(versions[version].content) def delete(self): db.session.delete(self) db.session.commit() def add_tag(self, tag_name): if tag_name and not self.has_tag(tag_name): self.tags.append(Tag(name=sanitize(tag_name), author=self.author)) db.session.add(self) db.session.commit() def has_tag(self, tag_name): return Note.query.join(tags).filter(Note.id == self.id, Tag.author == self.author, Tag.name == tag_name).count() > 0 def remove_tag(self, tag_name): if self.has_tag(tag_name): tag = [tag for tag in self.tags if tag.name == tag_name] self.tags.remove(tag[0]) db.session.add(self) db.session.commit() @classmethod def search(cls, term, user): return Note.query.filter(Note.author == user).search(term, sort=True) @property def rendered(self): markdown = current_app.jinja_env.filters['markdown'] return markdown(self.content) @property def truncated(self): truncate = current_app.jinja_env.filters['truncate_html'] return truncate(self.rendered, 250, end=" \u2026") @property def edit_url(self): return url_for('notes.edit', id=self.id) @property def just_updated(self): undo_timeout = (datetime.datetime.utcnow() - datetime.timedelta(minutes=2)) return bool(self.history and self.updated > undo_timeout) @property def undo_url(self): return url_for('notes.undo', id=self.id) @property def timestamp(self): return self.updated.strftime('%Y%m%d%H%M%S.%f') @property def friendly_updated(self): humanize = current_app.jinja_env.filters['humanize'] return humanize(self.updated) def json(self): return { 'id': self.id, 'truncated': self.truncated, 'edit_url': self.edit_url, 'content': self.content, 'just_updated': self.just_updated, 'undo_url': self.undo_url, 'timestamp': self.timestamp, 'friendly_updated': self.friendly_updated, 'is_email': self.is_email, 'tags': [{ 'name': tag.name, 'url': tag.url } for tag in self.tags] }
class User(MerchantBase): """ 用户,按商户分库 """ id = db.Column(db.Integer, primary_key=True, autoincrement=False, comment='用户ID,主键但不自增,由全局表生成id') _create_time = db.Column('create_time', db.Integer, nullable=False, comment="创建时间", index=True) account = db.Column(db.String(32), comment="账号,手机号码/邮箱", nullable=False) _ac_type = db.Column('ac_type', db.SmallInteger, default=AccountTypeEnum.NONE.value, comment="账号类型,手机号码/邮箱") _state = db.Column('state', db.SmallInteger, default=AccountStateEnum.ACTIVE.value, comment="账号状态") _login_pwd = db.Column('login_pwd', db.String(100), comment="登录密码,已加密存储") _trade_pwd = db.Column('trade_pwd', db.String(100), comment="支付密码,已加密存储") _flag = db.Column('flag', db.SmallInteger, comment="账号状态", nullable=True) _permissions = db.Column('permissions', db.SmallInteger, comment="账号权限", nullable=True) __table_args__ = ( # 联合唯一索引 db.UniqueConstraint('account', 'merchant', name='uix_user_account_mch_name'), # 联合索引 # db.Index('ix_user_account_mch_name', 'account', 'merchant'), ) _merchant = db.Column('merchant', db.Integer, comment="商户ID", nullable=False) @property def merchant(self) -> MerchantEnum: return MerchantEnum(self._merchant) @merchant.setter def merchant(self, merchant: MerchantEnum): self._merchant = merchant.value @property def permissions(self) -> List[UserPermissionEnum]: if not self._permissions: return UserPermissionEnum.get_all_enums() return UserPermissionEnum.parse_permissions(self._permissions) @permissions.setter def permissions(self, values: List[UserPermissionEnum]): self._permissions = UserPermissionEnum.join_permissions(values) @property def permission_names(self): return [x.name for x in self.permissions] def has_permission(self, perm: UserPermissionEnum): """ 判断用户是否有权限 :param perm: :return: """ if not self._permissions: # 未设置权限,拥有所有权限 return True return perm.has_permission(self._permissions) @property def flag(self) -> AccountFlagEnum: if not self._flag: return AccountFlagEnum.NORMAL return AccountFlagEnum(self._flag) @flag.setter def flag(self, value: AccountFlagEnum): if value: self._flag = value.value @property def is_official_auth(self): return self.flag == AccountFlagEnum.VIP @property def is_test_user(self): """ 是否是测试用户 :return: """ return self.merchant.is_test @property def uid(self): return self.id @property def is_active(self): return self._state == AccountStateEnum.ACTIVE.value @property def state(self) -> AccountStateEnum: return AccountStateEnum(self._state) @state.setter def state(self, value: AccountStateEnum): self._state = value.value @property def ac_type(self): """ 返回账户枚举类型 :return: """ return AccountTypeEnum(self._ac_type) @ac_type.setter def ac_type(self, e_value): """ 传入账户的类型 :param e_value: :return: """ if e_value: self._ac_type = e_value.value @property def login_pwd(self): """ 登录密码 :return: """ return self._login_pwd @login_pwd.setter def login_pwd(self, raw_pwd): """ 设置密码时要进行加密 :param raw_pwd: :return: """ if raw_pwd: self._login_pwd = generate_password_hash(raw_pwd) @property def trade_pwd(self): """ 交易密码 :return: """ return self._trade_pwd @trade_pwd.setter def trade_pwd(self, raw_pwd): """ 设置交易密码 :param raw_pwd: :return: """ if raw_pwd: self._trade_pwd = generate_password_hash(raw_pwd) def has_trade_pwd(self): return bool(self.trade_pwd) @classmethod def generate_model(cls, merchant, account, ac_type: AccountTypeEnum = None, login_pwd=None): """ 生成用户模型 :param merchant: :param account: :param ac_type: :param login_pwd: :return: """ user = cls.get_model_obj(merchant=merchant) user.account = account user.ac_type = ac_type user.login_pwd = login_pwd user.merchant = merchant user.id = 0 return user @classmethod def register_account(cls, merchant, account, ac_type: AccountTypeEnum = None, login_pwd=None): """ 注册账号 :param merchant: :param account: :param ac_type: :param login_pwd: :return: """ uid = GlobalUid.make_uid(merchant) with db.auto_commit(): user = cls.generate_model(merchant, account, ac_type, login_pwd) user.id = uid db.session.add(user) balance = UserBalance.generate_model(user.uid, merchant) db.session.add(balance) return user @classmethod def delete_account(cls, merchant, uid=None, account=None): """ 删除账号 :param uid: :param account: :param merchant: :return: """ with db.auto_commit(): user = cls.query_user(merchant, uid=uid, account=account) db.session.delete(user) @classmethod def update_user_state(cls, merchant, account=None, uid=None, state=None): """ 修改用户状态 :param merchant: :param account: :param uid: :param state: :return: """ with db.auto_commit(): if not account: user = cls.query_user(merchant=merchant, uid=uid) else: user = cls.query_user(merchant=merchant, account=account) if user is not None: user.state = state db.session.add(user) return True else: return False @classmethod def update_user_flag(cls, merchant, flag: AccountFlagEnum, account=None, uid=None): """ 修改用户标签 """ if account: user = cls.query_user(merchant=merchant, account=account) else: user = cls.query_user(merchant=merchant, uid=uid) if user is not None: user.flag = flag cls.commit_models(user) UserFlagCache(user.uid).set_flag(flag) return True return False @classmethod def update_user_permission(cls, merchant, permissions: List[UserPermissionEnum], account=None, uid=None): """ 修改用户权限 """ if account: user = cls.query_user(merchant=merchant, account=account) else: user = cls.query_user(merchant=merchant, uid=uid) if user is not None: user.permissions = permissions cls.commit_models(user) return True return False @classmethod def reset_password(cls, merchant, account=None, uid=None, login_pwd=None): """ 修改密码 :param merchant: :param account: :param uid: :param login_pwd: :return: """ with db.auto_commit(): if not account: user = cls.query_user(merchant=merchant, uid=uid) else: user = cls.query_user(merchant=merchant, account=account) if user is not None: user.login_pwd = login_pwd db.session.add(user) return True else: return False @classmethod def verify_login(cls, merchant, account, password): """ 账号密码鉴权 :param merchant: :param account: :param password: :return: """ user = cls.query_user(merchant, account=account) if not user: return False return user.check_login_pwd(password) @classmethod def verify_password(cls, merchant, uid, password): """ 账号密码鉴权 :param merchant: :param uid: :param password: :return: """ user = cls.query_user(merchant, uid=uid) if not user: return False return user.check_login_pwd(password) def check_login_pwd(self, raw_pwd): return check_password_hash(self._login_pwd, raw_pwd) @classmethod def query_user(cls, merchant, uid=None, account=None): """ 查询用户 :param merchant: :param uid: :param account: :return: """ if uid: kwargs = dict(id=int(uid)) elif account: kwargs = dict(account=account, ) else: raise ValueError('parameter error') kwargs['_merchant'] = merchant.value return cls.query_one(query_fields=kwargs) @classmethod def set_payment_password(cls, merchant, account=None, uid=None, trade_pwd=None): """ 修改密码 :param merchant: :param account: :param uid: :param trade_pwd: :return: """ with db.auto_commit(): if not account: user = cls.query_user(merchant=merchant, uid=uid) else: user = cls.query_user(merchant=merchant, account=account) if user is not None: user.trade_pwd = trade_pwd db.session.add(user) return True else: return False @classmethod def verify_payment_password(cls, merchant, uid, password): """ 支付密码鉴权 :param merchant: :param uid: :param password: :return: """ user = cls.query_user(merchant, uid=uid) if not user: return False return user.check_trade_pwd(password) def check_trade_pwd(self, raw_pwd): """ 验证交易密码 :param raw_pwd: :return: """ if not self._trade_pwd: return False return check_password_hash(self._trade_pwd, raw_pwd)
class ContractedWorkPayment(Base, AuditMixin): __tablename__ = 'contracted_work_payment' def __init__(self, application, contracted_work_payment_status_code, contracted_work_payment_code, **kwargs): super(ContractedWorkPayment, self).__init__(**kwargs) initial_status = ContractedWorkPaymentStatusChange( contracted_work_payment=self, application=application, contracted_work_payment_status_code= contracted_work_payment_status_code, contracted_work_payment_code=contracted_work_payment_code) self.status_changes.append(initial_status) contracted_work_payment_id = db.Column(db.Integer, primary_key=True) application_guid = db.Column(UUID(as_uuid=True), db.ForeignKey('application.guid'), nullable=False) work_id = db.Column(db.String, unique=True, nullable=False) interim_actual_cost = db.Column(db.Numeric(14, 2)) final_actual_cost = db.Column(db.Numeric(14, 2)) interim_paid_amount = db.Column(db.Numeric(14, 2)) final_paid_amount = db.Column(db.Numeric(14, 2)) interim_total_hours_worked_to_date = db.Column(db.Numeric(14, 2)) final_total_hours_worked_to_date = db.Column(db.Numeric(14, 2)) interim_number_of_workers = db.Column(db.Integer) final_number_of_workers = db.Column(db.Integer) work_completion_date = db.Column(db.Date) interim_submitter_name = db.Column(db.String) final_submitter_name = db.Column(db.String) interim_eoc_application_document_guid = db.Column( UUID(as_uuid=True), db.ForeignKey('application_document.application_document_guid'), unique=True) final_eoc_application_document_guid = db.Column( UUID(as_uuid=True), db.ForeignKey('application_document.application_document_guid'), unique=True) final_report_application_document_guid = db.Column( UUID(as_uuid=True), db.ForeignKey('application_document.application_document_guid'), unique=True) interim_eoc_document = db.relationship( 'ApplicationDocument', lazy='selectin', foreign_keys=[interim_eoc_application_document_guid]) final_eoc_document = db.relationship( 'ApplicationDocument', lazy='selectin', foreign_keys=[final_eoc_application_document_guid]) interim_report = db.Column(db.String) final_report_document = db.relationship( 'ApplicationDocument', lazy='selectin', foreign_keys=[final_report_application_document_guid]) status_changes = db.relationship( 'ContractedWorkPaymentStatusChange', lazy='selectin', order_by='desc(ContractedWorkPaymentStatusChange.change_timestamp)') payment_documents = db.relationship( 'PaymentDocument', lazy='selectin', secondary='payment_document_contracted_work_payment_xref') # Auditing audit_ind = db.Column(db.Boolean) audit_user = db.Column(db.String) audit_timestamp = db.Column(db.DateTime) # General Reporting surface_landowner = db.Column(db.String) reclamation_was_achieved = db.Column(db.Boolean) # Abandonment Reporting abandonment_cut_and_capped_completed = db.Column(db.Boolean) abandonment_notice_of_operations_submitted = db.Column(db.Boolean) abandonment_was_pipeline_abandoned = db.Column(db.Boolean) abandonment_metres_of_pipeline_abandoned = db.Column(db.Integer) # PSI and DSI Reporting site_investigation_type_of_document_submitted = db.Column(db.String) site_investigation_concerns_identified = db.Column(db.Boolean) # Remediation Reporting remediation_identified_contamination_meets_standards = db.Column( db.Boolean) remediation_type_of_document_submitted = db.Column(db.String) remediation_reclaimed_to_meet_cor_p1_requirements = db.Column(db.Boolean) # Reclamation Reporting reclamation_reclaimed_to_meet_cor_p2_requirements = db.Column(db.Boolean) reclamation_surface_reclamation_criteria_met = db.Column(db.Boolean) @hybrid_property def has_interim_prfs(self): if self.payment_documents: return any( doc.active_ind and doc.payment_document_code == 'INTERIM_PRF' for doc in self.payment_documents) return False @hybrid_property def has_final_prfs(self): if self.payment_documents: return any( doc.active_ind and doc.payment_document_code == 'FINAL_PRF' for doc in self.payment_documents) return False @hybrid_property def interim_payment_status_code(self): if self.interim_payment_status: return self.interim_payment_status.contracted_work_payment_status_code else: return 'INFORMATION_REQUIRED' @hybrid_property def interim_payment_status(self): if self.interim_payment_status_changes: return self.interim_payment_status_changes[0] @hybrid_property def interim_payment_status_changes(self): return [ status for status in self.status_changes if status.contracted_work_payment_code == 'INTERIM' ] @hybrid_property def interim_payment_submission_date(self): if self.interim_payment_status_changes: return self.interim_payment_status_changes[-1].change_timestamp @hybrid_property def final_payment_status_code(self): if self.final_payment_status: return self.final_payment_status.contracted_work_payment_status_code else: return 'INFORMATION_REQUIRED' @hybrid_property def final_payment_status(self): if self.final_payment_status_changes: return self.final_payment_status_changes[0] @hybrid_property def final_payment_status_changes(self): return [ status for status in self.status_changes if status.contracted_work_payment_code == 'FINAL' ] @hybrid_property def final_payment_submission_date(self): if self.final_payment_status_changes: return self.final_payment_status_changes[-1].change_timestamp @hybrid_property def review_deadlines(self): review_deadlines = { 'interim': REVIEW_DEADLINE_NOT_APPLICABLE, 'final': REVIEW_DEADLINE_NOT_APPLICABLE } interim_payment_submission_date = self.interim_payment_submission_date final_payment_submission_date = self.final_payment_submission_date # No payment information has been submitted if interim_payment_submission_date is None and final_payment_submission_date is None: return review_deadlines # We don't need to review payments that have already had at least one PRF issued if interim_payment_submission_date and self.has_interim_prfs: interim_payment_submission_date = None review_deadlines['interim'] = REVIEW_DEADLINE_PAID if final_payment_submission_date and self.has_final_prfs: final_payment_submission_date = None review_deadlines['final'] = REVIEW_DEADLINE_PAID # Both interim and final have been submitted and have completed the payment process if interim_payment_submission_date is None and final_payment_submission_date is None: return review_deadlines days_to_review = timedelta(days=90) if interim_payment_submission_date: interim_deadline = interim_payment_submission_date + days_to_review review_deadlines['interim'] = interim_deadline if final_payment_submission_date: final_deadline = final_payment_submission_date + days_to_review review_deadlines['final'] = final_deadline return review_deadlines def __repr__(self): return f'<{self.__class__.__name__} {self.contracted_work_payment_id} {self.application_guid} {self.work_id}>' @classmethod def find_by_application_guid(cls, application_guid): return cls.query.filter_by(application_guid=application_guid).all() @classmethod def find_by_work_id(cls, work_id): return cls.query.filter_by(work_id=work_id).one_or_none()
# -*- coding: utf-8 -*- """ Base models """ from flask_security import RoleMixin, UserMixin from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound from app.extensions import db from lib.model_utils import GetOr404Mixin, GetOrCreateMixin user_roles = db.Table( 'user_roles', db.Column('user_id', db.Integer, db.ForeignKey('user.id')), db.Column('role_id', db.Integer, db.ForeignKey('role.id'))) class Role(db.Model, RoleMixin): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), unique=True) description = db.Column(db.String(255)) class User(db.Model, UserMixin, GetOrCreateMixin, GetOr404Mixin): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(255), unique=True) password = db.Column(db.String) full_name = db.Column(db.String) inbox_email = db.Column(db.String(255), unique=True) active = db.Column(db.Boolean) confirmed_at = db.Column(db.DateTime) roles = db.relationship('Role',
class Comment(PaginatedAPIMixin, db.Model): """评论模型类""" __tablename__ = 'comments' id = db.Column(db.Integer, primary_key=True) body = db.Column(db.TEXT) timestamp = db.Column(db.DateTime, index=True) mark_read = db.Column(db.Boolean, default=False) # 是否已读 disabled = db.Column(db.Boolean, default=False) # 屏蔽显示 # 评论者的id author_id = db.Column(db.Integer, db.ForeignKey('users.id')) # 评论博文的id post_id = db.Column(db.Integer, db.ForeignKey('posts.id')) # 父评论id parent_id = db.Column(db.Integer, db.ForeignKey('comments.id', ondelete='CASCADE')) parent = db.relationship('Comment', backref= \ db.backref('children', cascade='all,delete-orphan'), remote_side=[id]) likers = db.relationship('User', secondary=comments_likes, backref=db.backref('liked_comments', lazy='dynamic')) def __repr__(self): """控制台输出""" return "<Comment {}>".format(self.id) def get_descendants(self): '''获取一级评论的所有子孙''' data = set() def descendants(comment): if comment.children: data.update(comment.children) for child in comment.children: descendants(child) descendants(self) return data def get_ancestors(self): """获取评论的所有爸爸们""" data = [] def ancestors(comment): if comment.parent: data.append(comment.parent) ancestors(comment.parent) ancestors(self) return data def from_dict(self, data: dict): """填充数据至当前模型类""" for filed in [ 'body', 'timestamp', 'mark_read', 'disabled', 'post_id', 'parent_id' ]: setattr(self, filed, data[filed]) def to_dict(self) -> dict: """序列化评论模型""" data = { 'id': self.id, 'body': self.body, 'timestamp': self.timestamp, 'mark_read': self.mark_read, 'disabled': self.disabled, 'author': { 'id': self.author.id, 'username': self.author.username, 'name': self.author.name, 'avatar': self.author.avatar(128) }, 'post': { 'id': self.post.id, 'title': self.post.title, 'author_id': self.post.author.id }, 'parent_id': self.parent_id if self.parent else None, '_links': { 'self': url_for('api.get_comment', id=self.id), 'author_url': url_for('api.get_user', id=self.author_id), 'post_url': url_for('api.get_post', id=self.post_id), 'parent_url': url_for('api.get_comment', id=self.parent_id) if self.parent else None, 'children_url': [ url_for('api.get_comment', id=child.id) for child in self.children ] if self.childeren else None } } return data def is_liked_by(self, user): """用户是否点赞""" return user in self.likers def liked_by(self, user): """点赞评论""" if not self.is_liked_by(user): self.likers.append(user) def un_liked_by(self, user): """取消点赞""" if self.is_liked_by(user): self.likers.remove(user)