def getAdminUserView(): #auto join user and fb_account User.fb_account = db.relationship("UserFacebookAccount", uselist=False, lazy='joined') #auto join circles User.circles = db.relationship("Circle", secondary="circle_user_rel", primaryjoin = "circle_user_rel.c.user_id == User.id", secondaryjoin = "circle_user_rel.c.circle_id == Circle.id", lazy = 'joined') return AdminUserView(User, db.session)
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, server_default=FetchedValue()) mine_region = db.Column(db.String(2), db.ForeignKey('mine_region_code.mine_region_code')) # Relationships #Almost always used and 1:1, so these are joined mine_location = db.relationship('MineLocation', backref='mine', uselist=False, 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') #Almost always used, but faster to use selectin to load related data mine_permit = db.relationship('Permit', backref='mine', order_by='desc(Permit.create_timestamp)', lazy='selectin') mine_type = db.relationship('MineType', backref='mine', order_by='desc(MineType.update_timestamp)', lazy='selectin') #Not always desired, set to lazy load using select mineral_tenure_xref = db.relationship('MineralTenureXref', backref='mine', lazy='select') 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='select') mine_party_appt = db.relationship('MinePartyAppointment', backref="mine", lazy='select') 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': self.mine_location.json() if self.mine_location else None, #Exploration permits must, always, and exclusively have an X as the second character, and we would like this to be returned last: 'mine_permit': [ item.json() for item in self.mine_permit if item.permit_no.lower()[1] != 'x' ] + [ item.json() for item in self.mine_permit if item.permit_no.lower()[1] == 'x' ], '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)], 'verified_status': self.verified_status.json() if self.verified_status else None, } 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_list() 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)], 'verified_status': self.verified_status.json() if self.verified_status else None, } 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': self.mine_location.json() if self.mine_location else None } 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): #this will get cleaned up when mine_location and mine are merged result = {'guid': str(self.mine_guid)} if self.mine_location: result['latitude'] = str(self.mine_location.latitude ) if self.mine_location.latitude else '' result['longitude'] = str(self.mine_location.longitude ) if self.mine_location.longitude else '' else: result['latitude'] = '' result['longitude'] = '' return result 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).filter_by( deleted_ind=False).first() except ValueError: return None @classmethod def find_by_mine_no(cls, _id): return cls.query.filter_by(mine_no=_id).filter_by( deleted_ind=False).first() @classmethod def find_by_mine_name(cls, term=None): MINE_LIST_RESULT_LIMIT = 50 if term: name_filter = Mine.mine_name.ilike('%{}%'.format(term)) mines_q = Mine.query.filter(name_filter).filter_by( deleted_ind=False) mines = mines_q.limit(MINE_LIST_RESULT_LIMIT).all() else: mines = Mine.query.limit(MINE_LIST_RESULT_LIMIT).all() return mines @classmethod def find_by_name_no_permit(cls, term=None): MINE_LIST_RESULT_LIMIT = 50 if term: name_filter = Mine.mine_name.ilike('%{}%'.format(term)) number_filter = Mine.mine_no.ilike('%{}%'.format(term)) permit_filter = Permit.permit_no.ilike('%{}%'.format(term)) mines_q = Mine.query.filter(name_filter | number_filter).filter_by( deleted_ind=False) permit_q = Mine.query.join(Permit).filter(permit_filter) mines = mines_q.union(permit_q).limit(MINE_LIST_RESULT_LIMIT).all() else: mines = Mine.query.limit(MINE_LIST_RESULT_LIMIT).all() return mines @classmethod def find_all_major_mines(cls): return cls.query.filter_by(major_mine_ind=True).filter_by( deleted_ind=False).all() @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): mine_note = mine_note if mine_note else '' 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): mine_no = mine_no if mine_no else '' if mine_no and len(mine_no) > 10: raise AssertionError('Mine number must not exceed 10 characters.') return mine_no
class MineIncident(AuditMixin, Base): __tablename__ = 'mine_incident' mine_incident_id = db.Column(db.Integer, primary_key=True, server_default=FetchedValue()) mine_incident_id_year = db.Column(db.Integer, nullable=False, default=datetime.datetime.now().year) mine_incident_guid = db.Column(UUID(as_uuid=True), nullable=False, server_default=FetchedValue()) mine_guid = db.Column(UUID(as_uuid=True), db.ForeignKey('mine.mine_guid'), nullable=False) incident_timestamp = db.Column(db.DateTime, nullable=False) incident_description = db.Column(db.String, nullable=False) reported_timestamp = db.Column(db.DateTime) reported_by_name = db.Column(db.String) reported_by_email = db.Column(db.String) reported_by_phone_no = db.Column(db.String) reported_by_phone_ext = db.Column(db.String) number_of_fatalities = db.Column(db.Integer) number_of_injuries = db.Column(db.Integer) emergency_services_called = db.Column(db.Boolean) followup_inspection = db.Column(db.Boolean) followup_inspection_date = db.Column(db.DateTime) mms_insp_cd = db.Column(db.String) reported_to_inspector_party_guid = db.Column( UUID(as_uuid=True), db.ForeignKey('party.party_guid'), nullable=False) responsible_inspector_party_guid = db.Column( UUID(as_uuid=True), db.ForeignKey('party.party_guid'), nullable=False) determination_inspector_party_guid = db.Column( UUID(as_uuid=True), db.ForeignKey('party.party_guid'), nullable=False) proponent_incident_no = db.Column(db.String) mine_incident_no = db.Column(db.String) determination_type_code = db.Column( db.String, db.ForeignKey( 'mine_incident_determination_type.mine_incident_determination_type_code' )) status_code = db.Column( db.String, db.ForeignKey('mine_incident_status_code.mine_incident_status_code')) followup_investigation_type_code = db.Column( db.String, db.ForeignKey( 'mine_incident_followup_investigation_type.mine_incident_followup_investigation_type_code' )) mine_determination_type_code = db.Column( db.String, db.ForeignKey( 'mine_incident_determination_type.mine_incident_determination_type_code' )) mine_determination_representative = db.Column(db.String) determination_type = db.relationship( 'MineIncidentDeterminationType', backref='mine_incidents', lazy='joined', uselist=False, foreign_keys=[determination_type_code]) dangerous_occurrence_subparagraphs = db.relationship( 'ComplianceArticle', backref='mine_incidents', lazy='joined', secondary='mine_incident_do_subparagraph') followup_investigation_type = db.relationship( 'MineIncidentFollowupInvestigationType', backref='mine_incidents', lazy='joined', uselist=False) recommendations = db.relationship( 'MineIncidentRecommendation', primaryjoin= "and_(MineIncidentRecommendation.mine_incident_id == MineIncident.mine_incident_id, MineIncidentRecommendation.deleted_ind==False)", lazy='selectin') documents = db.relationship('MineIncidentDocumentXref', lazy='joined') mine_documents = db.relationship('MineDocument', lazy='joined', secondary='mine_incident_document_xref') categories = db.relationship('MineIncidentCategory', lazy='joined', secondary='mine_incident_category_xref') mine_table = db.relationship('Mine', lazy='joined') mine_name = association_proxy('mine_table', 'mine_name') mine_region = association_proxy('mine_table', 'mine_region') major_mine_ind = association_proxy('mine_table', 'major_mine_ind') @hybrid_property def mine_incident_report_no(self): return str(self.mine_incident_id_year) + '-' + str( self.mine_incident_id) @hybrid_property def dangerous_occurrence_subparagraph_ids(self): return [ sub.compliance_article_id for sub in self.dangerous_occurrence_subparagraphs ] @classmethod def find_by_mine_incident_guid(cls, _id): try: uuid.UUID(_id, version=4) return cls.query.filter_by(mine_incident_guid=_id).first() except ValueError: return None @classmethod def create(cls, mine, incident_timestamp, incident_description, determination_type_code=None, mine_determination_type_code=None, mine_determination_representative=None, followup_investigation_type_code=None, reported_timestamp=None, reported_by_name=None, add_to_session=True): mine_incident = cls( incident_timestamp=incident_timestamp, incident_description=incident_description, reported_timestamp=reported_timestamp, reported_by_name=reported_by_name, determination_type_code=determination_type_code, mine_determination_type_code=mine_determination_type_code, mine_determination_representative=mine_determination_representative, followup_investigation_type_code=followup_investigation_type_code, ) mine.mine_incidents.append(mine_incident) if add_to_session: mine_incident.save(commit=False) return mine_incident @validates('reported_by') def validate_reported_by(self, key, reported_by): if reported_by: if len(reported_by) > 100: raise AssertionError( 'reported_by must not exceed 100 characters.') return reported_by @validates('reported_by_role') def validate_reported_by_role(self, key, reported_by_role): if reported_by_role: if len(reported_by_role) > 100: raise AssertionError( 'reported_by_role must not exceed 100 characters.') return reported_by_role @validates('followup_inspection_number') def validate_followup_inspection_number(self, key, followup_inspection_number): if followup_inspection_number: if len(followup_inspection_number) > 20: raise AssertionError( 'followup_inspection_number must not exceed 100 characters.' ) return followup_inspection_number @validates('incident_timestamp') def validate_incident_timestamp(self, key, incident_timestamp): if incident_timestamp: if incident_timestamp > datetime.datetime.utcnow(): raise AssertionError( 'incident_timestamp must not be in the future') return incident_timestamp @validates('reported_timestamp') def validate_reported_timestamp(self, key, reported_timestamp): if reported_timestamp: if reported_timestamp > datetime.datetime.utcnow(): raise AssertionError( 'reported_timestamp must not be in the future') return reported_timestamp
class User(db.Model, ModelMixin, UserMixin): __tablename__ = "users" email = db.Column(db.String(128), unique=True, nullable=False) salt = db.Column(db.String(128), nullable=False) password = db.Column(db.String(128), nullable=False) name = db.Column(db.String(128), nullable=False) is_admin = db.Column(db.Boolean, nullable=False, default=False) alias_generator = db.Column( db.Integer, nullable=False, default=AliasGeneratorEnum.word.value, server_default=str(AliasGeneratorEnum.word.value), ) notification = db.Column(db.Boolean, default=True, nullable=False, server_default="1") activated = db.Column(db.Boolean, default=False, nullable=False) profile_picture_id = db.Column(db.ForeignKey(File.id), nullable=True) otp_secret = db.Column(db.String(16), nullable=True) enable_otp = db.Column(db.Boolean, nullable=False, default=False, server_default="0") # some users could have lifetime premium lifetime = db.Column(db.Boolean, default=False, nullable=False, server_default="0") profile_picture = db.relationship(File) @classmethod def create(cls, email, name, password=None, **kwargs): user: User = super(User, cls).create(email=email, name=name, **kwargs) if not password: # set a random password password = random_string(20) user.set_password(password) db.session.flush() # create a first alias mail to show user how to use when they login GenEmail.create_new(user.id, prefix="my-first-alias") db.session.flush() return user def should_upgrade(self): return not self.is_premium() def is_premium(self): """user is premium if they have a active subscription""" if self.lifetime: return True sub: Subscription = self.get_subscription() if sub: return True return False def can_create_new_alias(self): if self.is_premium(): return True return GenEmail.filter_by( user_id=self.id).count() < MAX_NB_EMAIL_FREE_PLAN def set_password(self, password): salt = bcrypt.gensalt() password_hash = bcrypt.hashpw(password.encode(), salt).decode() self.salt = salt.decode() self.password = password_hash def check_password(self, password) -> bool: password_hash = bcrypt.hashpw(password.encode(), self.salt.encode()) return self.password.encode() == password_hash def profile_picture_url(self): if self.profile_picture_id: return self.profile_picture.get_url() else: return url_for("static", filename="default-avatar.png") def suggested_emails(self, website_name) -> (str, [str]): """return suggested email and other email choices """ website_name = convert_to_id(website_name) all_gen_emails = [ ge.email for ge in GenEmail.filter_by(user_id=self.id) ] if self.can_create_new_alias(): suggested_gen_email = GenEmail.create_new( self.id, prefix=website_name).email else: # pick an email from the list of gen emails suggested_gen_email = random.choice(all_gen_emails) return ( suggested_gen_email, list(set(all_gen_emails).difference({suggested_gen_email})), ) def suggested_names(self) -> (str, [str]): """return suggested name and other name choices """ other_name = convert_to_id(self.name) return self.name, [other_name, "Anonymous", "whoami"] def get_name_initial(self) -> str: names = self.name.split(" ") return "".join([n[0].upper() for n in names if n]) def plan_name(self) -> str: if self.is_premium(): sub = self.get_subscription() if sub.plan == PlanEnum.monthly: return "Monthly ($2.99/month)" else: return "Yearly ($29.99/year)" else: return "Free Plan" def get_subscription(self): """return *active* subscription TODO: support user unsubscribe and re-subscribe """ sub = Subscription.get_by(user_id=self.id) if sub and sub.cancelled: # sub is active until the next billing_date + 1 if sub.next_bill_date >= arrow.now().shift(days=-1).date(): return sub else: # past subscription, user is considered not having a subscription return None else: return sub def verified_custom_domains(self): return CustomDomain.query.filter_by(user_id=self.id, verified=True).all() def __repr__(self): return f"<User {self.id} {self.name} {self.email}>"
class Driver(db.Model): __tablename__ = "drivers" id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(254), nullable=False, unique=True) first_name = db.Column(db.String(40), nullable=False) last_name = db.Column(db.String(40), nullable=True) password = db.Column(db.LargeBinary(60), nullable=False) phone_number = db.Column(db.Integer, nullable=True) car_description = db.Column(db.Text, nullable=True) reward_points = db.Column(db.Integer, nullable=False, default=0) food_requests = db.relationship('FoodRequest', backref="driver", lazy=True) def __init__(self, **kwargs): super(Driver, self).__init__(**kwargs) self.email = self.email.strip() self.first_name = self.first_name.strip() self.password = bcrypt.hashpw( self.password.encode(), bcrypt.gensalt() ) def __repr__(self): return f"<Driver id: {self.id} {self.email}>" def verify_password(self, password): """Returns True if this password matches for this User.""" if isinstance(password, str): password = password.encode() if bcrypt.checkpw(password, self.password): return True return False def gen_access_token(self, exp=None): """Returns JWT token for this User""" if not exp: exp = settings.TOKEN_TYPES["session"]["expires_in"] payload = { "driver_id": self.id, "is_driver": True } token = generate_token(payload, "session", expires_in=exp) return { "access_token": token, "expires_in": exp } @staticmethod def verify_access_token(access_token): """Returns the User for this access_token if it passes verification""" try: payload = validate_token(access_token) except itsdangerous.BadSignature: abort(401, "Invalid token") return payload @staticmethod def identify(user_identity): """Returns a User object corresponding with this username or email or id""" if isinstance(user_identity, int): return Driver.query.get(user_identity) return Driver.query.filter( Driver.email.ilike(user_identity) ).first()
class Organization(db.Model): """Represent an orgnization. One to Many relationship to SampleGroups Many to Many relationship with Users Many to One realtionship with a User as a primary admin """ __tablename__ = 'organizations' uuid = db.Column(UUID(as_uuid=True), primary_key=True, server_default=db.text('uuid_generate_v4()')) name = db.Column(db.String(128), nullable=False, unique=True) primary_admin_uuid = db.Column(db.ForeignKey('users.uuid'), nullable=False) users = association_proxy("memberships", "users") sample_groups = db.relationship('SampleGroup', backref='organization', lazy=True) is_deleted = db.Column(db.Boolean, default=False, nullable=False) is_public = db.Column(db.Boolean, default=True, nullable=False) created_at = db.Column(db.DateTime, nullable=False) def __init__(self, primary_admin_uuid, name, is_deleted=False, is_public=True, created_at=datetime.datetime.utcnow()): """Initialize Pangea User model.""" self.primary_admin_uuid = primary_admin_uuid self.name = name self.is_deleted = is_deleted self.is_public = is_public self.created_at = created_at def serializable(self): out = { 'organization': { 'uuid': self.uuid, 'name': self.name, 'is_public': self.is_public, 'is_deleted': self.is_deleted, 'created_at': self.created_at, 'primary_admin_uuid': self.primary_admin_uuid, 'sample_group_uuids': [sg.uuid for sg in self.sample_groups], 'users': [user.uuid for user in self.users], }, } return out def serialize(self): return json.dumps(self.serializable()) def add_user(self, user, role_in_org='read'): OrganizationMembership(self.uuid, user.uuid, role=role_in_org).save() return self def admin_uuids(self): return [ membership.user_uuid for membership in self.memberships if membership.role == 'admin' ] def writer_uuids(self): return [ membership.user_uuid for membership in self.memberships if membership.role in ['admin', 'write'] ] def reader_uuids(self): return [ membership.user_uuid for membership in self.memberships if membership.role in ['admin', 'write', 'read'] ] def sample_group(self, name, description='', is_library=False, is_public=True): """Return a SampleGroup bound to this organization. Create and save the SampleGroup if it does not already exist. """ sample_groups = [sg for sg in self.sample_groups if sg.name == name] if sample_groups: sample_group = sample_groups[0] else: sample_group = SampleGroup(name, self.uuid, description=description, is_library=is_library, is_public=is_public).save() return sample_group def save(self): db.session.add(self) db.session.commit() return self @classmethod def from_user(cls, user, name, is_public=True): org = cls(user.uuid, name, is_public=is_public).save() org.add_user(user, role_in_org='admin') return org.save() @classmethod def from_uuid(cls, uuid): return cls.query.filter_by(uuid=uuid).one() @classmethod def from_name(cls, name): return cls.query.filter_by(name=name).one()
class Item(db.Model, BaseModel): body = db.Column(db.Text) done = db.Column(db.Boolean) author_id = db.Column(db.Integer, db.ForeignKey('user.id')) author = db.relationship('User', back_populates='items') order = db.Column(db.Integer, autoincrement=True)
class User(db.Model, FeatherModel, UserEDMMixin): """ User database model. TODO: * Upgrade to HoustonModel after full transition for Users out of EDM is complete """ def __init__(self, *args, **kwargs): if 'password' not in kwargs: raise ValueError('User must have a password') super().__init__(*args, **kwargs) guid = db.Column(db.GUID, default=uuid.uuid4, primary_key=True) # pylint: disable=invalid-name version = db.Column(db.Integer, default=None, nullable=True) email = db.Column(db.String(length=120), index=True, unique=True, nullable=False) password = db.Column( column_types.PasswordType(max_length=128, schemes=('bcrypt', )), nullable=False) # can me migrated from EDM field "password" full_name = db.Column( db.String(length=120), default='', nullable=False) # can be migrated from EDM field "fullName" website = db.Column( db.String(length=120), nullable=True) # can be migrated from EDM field "userURL" location = db.Column(db.String(length=120), nullable=True) affiliation = db.Column( db.String(length=120), nullable=True) # can be migrated from BE field "affiliation" forum_id = db.Column(db.String(length=120), nullable=True) locale = db.Column(db.String(length=20), default='EN', nullable=True) accepted_user_agreement = db.Column( db.Boolean, default=False, nullable=False ) # can be migrated from EDM field "acceptedUserAgreement" use_usa_date_format = db.Column(db.Boolean, default=True, nullable=False) show_email_in_profile = db.Column(db.Boolean, default=False, nullable=False) receive_notification_emails = db.Column( db.Boolean, default=True, nullable=False) # can be migrated from BE field "receiveEmails" receive_newsletter_emails = db.Column(db.Boolean, default=False, nullable=False) shares_data = db.Column( db.Boolean, default=True, nullable=False) # can be migrated from BE field "sharing" default_identification_catalogue = db.Column( db.GUID, nullable=True ) # this may just be a string, however EDM wants to do ID catalogues profile_asset_guid = db.Column( db.GUID, nullable=True) # should be reconciled with Jon's MediaAsset class footer_logo_asset_guid = db.Column( db.GUID, nullable=True) # should be reconciled with Jon's MediaAsset class organization_membership_enrollments = db.relationship( 'OrganizationUserMembershipEnrollment', back_populates='user') project_membership_enrollments = db.relationship( 'ProjectUserMembershipEnrollment', back_populates='user') class StaticRoles(enum.Enum): # pylint: disable=missing-docstring,unsubscriptable-object INTERNAL = (0x8000, 'Internal') ADMIN = (0x4000, 'Site Administrator') STAFF = (0x2000, 'Staff Member') ACTIVE = (0x1000, 'Active Account') SETUP = (0x0800, 'Account in Setup') RESET = (0x0400, 'Account in Password Reset') ALPHA = (0x0200, 'Enrolled in Alpha') BETA = (0x0100, 'Enrolled in Beta') @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_staff = _get_is_static_role_property('is_staff', StaticRoles.STAFF) is_active = _get_is_static_role_property('is_active', StaticRoles.ACTIVE) in_beta = _get_is_static_role_property('in_beta', StaticRoles.BETA) in_alpha = _get_is_static_role_property('in_alpha', StaticRoles.ALPHA) in_reset = _get_is_static_role_property('in_reset', StaticRoles.RESET) in_setup = _get_is_static_role_property('in_setup', StaticRoles.SETUP) def __repr__(self): return ('<{class_name}(' 'guid={self.guid}, ' 'email="{self.email}", ' 'name="{self.full_name}", ' 'is_internal={self.is_internal}, ' 'is_admin={self.is_admin}, ' 'is_staff={self.is_staff}, ' 'is_active={self.is_active}, ' ')>'.format(class_name=self.__class__.__name__, self=self)) @classmethod def get_admins(cls): # used for first run admin creation users = cls.query.all() # NOQA admin_users = [] for user in users: # TODO: Remove the check below at a later point after default admin create is removed if user.email.endswith('@localhost'): continue if user.is_admin: admin_users.append(user) return admin_users @classmethod def admin_user_initialized(cls): # used for first run admin creation return len(cls.get_admins()) > 0 @classmethod def ensure_user(cls, email, password, is_internal=False, is_admin=False, is_staff=False, is_active=True, in_beta=False, in_alpha=False, update=False, **kwargs): """ Create a new user. """ from app.extensions import db user = User.find(email=email) if user is None: user = User(password=password, email=email, is_internal=is_internal, is_admin=is_admin, is_staff=is_staff, is_active=is_active, in_beta=in_beta, in_alpha=in_alpha, **kwargs) with db.session.begin(): db.session.add(user) log.info('New user created: %r' % (user, )) elif update: user.password = password user.is_internal = is_internal user.is_admin = is_admin user.is_staff = is_staff user.is_active = is_active user.in_beta = in_beta user.in_alpha = in_alpha with db.session.begin(): db.session.merge(user) log.info('Updated user: %r' % (user, )) db.session.refresh(user) return user @classmethod def find(cls, email=None, password=None, edm_login_fallback=True): # Look-up via email if email is None: return None email_candidates = [ email, '%s@localhost' % (email, ), ] for email_candidate in email_candidates: user = cls.query.filter(User.email == email_candidate).first() if password is None: # If no password was provided to check, return any user account we find if user is not None: return user else: # Check local Houston password first if user is not None: # We found the user, check their provided password if user.password == password: return user # As a fallback, check all EDMs if the user can login if edm_login_fallback: # We want to check the EDM even if we don't have a local user record if current_app.edm.check_user_login( email_candidate, password): log.info('User authenticated via EDM: %r' % (email_candidate, )) if user is not None: # We authenticated a local user against an EDM (but the local password failed) if user.password != password: # The user passed the login with an EDM, update local password log.warning( "Updating user's local password: %r" % (user, )) user = user.set_password(password) return user else: log.critical( 'The user authenticated via EDM but has no local user record' ) # Try syncing all users from EDM cls.edm_sync_all() # If the user was just synced, go grab it (recursively) and return user = cls.find(email=email, edm_login_fallback=False) return user # If we have gotten here, one of these things happened: # 1) the user wasn't found # 2) the user's password was provided and was incorrect # 3) the user authenticated against the EDM but has no local user record return None @classmethod def query_search(cls, search=None): from sqlalchemy import or_, and_ from app.modules.auth.models import Code, CodeTypes if search is not None: search = search.strip().split(' ') search = [term.strip() for term in search] search = [term for term in search if len(term) > 0] or_terms = [] for term in search: codes = (Code.query.filter_by( code_type=CodeTypes.checkin).filter( Code.accept_code.contains(term), ).all()) code_users = set([]) for code in codes: if not code.is_expired: code_users.add(code.user.guid) or_term = or_( cls.guid.in_(code_users), cls.email.contains(term), cls.affiliation.contains(term), cls.forum_id.contains(term), cls.full_name.contains(term), ) or_terms.append(or_term) users = cls.query.filter(and_(*or_terms)) else: users = cls.query return users @property def is_authenticated(self): return True @property def is_anonymous(self): return False @property def is_email_confirmed(self): from app.modules.auth.models import Code, CodeTypes # Get any codes that fit this request code = (Code.query.filter_by(user=self, code_type=CodeTypes.email).order_by( Code.created.desc()).first()) if code is None: return False return code.is_resolved @property def picture(self): from app.modules.assets.models import Asset asset = Asset.query.filter_by(id=self.profile_asset_guid).first() if asset is None: placeholder_guid = (self.guid % 7) + 1 filename = 'images/placeholder_profile_%d.png' % ( placeholder_guid, ) return url_for('static', filename=filename) return url_for('backend.asset', code=asset.code) @property def memberships(self): return [ enrollment.organization for enrollment in self.organization_membership_enrollments ] @property def projects(self): return [ enrollment.project for enrollment in self.project_membership_enrollments ] def get_id(self): return self.guid 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 def check_supervisor(self, user): return self.check_owner(user) def get_codes(self, code_type, **kwargs): # This import for Code needs to be local from app.modules.auth.models import Code code = Code.get(self, code_type, **kwargs) return code def get_invite_code(self): # This import for Code needs to be local from app.modules.auth.models import CodeTypes return self.get_codes(CodeTypes.invite, replace=True) def get_email_confirmation_code(self): # This import for Code needs to be local from app.modules.auth.models import CodeTypes return self.get_codes(CodeTypes.email, replace=True) def get_account_recovery_code(self): # This import for Code needs to be local from app.modules.auth.models import CodeTypes return self.get_codes(CodeTypes.recover, replace=True, replace_ttl=None) def set_password(self, password): if password is None: # This function "sets" the password, it's the responsibility of the caller to ensure it's valid raise ValueError('Empty password not allowed') self.password = password with db.session.begin(): db.session.merge(self) db.session.refresh(self) return self def lockout(self): from app.modules.auth.models import OAuth2Client, OAuth2Grant, OAuth2Token, Code # Disable permissions self.is_staff = False self.is_admin = False self.is_active = False self.in_reset = False self.in_setup = False with db.session.begin(): db.session.merge(self) db.session.refresh(self) # Logout of sessions and API keys auth_list = [] auth_list += OAuth2Token.query.filter_by(user_guid=self.guid).all() auth_list += OAuth2Grant.query.filter_by(user_guid=self.guid).all() auth_list += OAuth2Client.query.filter_by(user_guid=self.guid).all() auth_list += Code.query.filter_by(user_guid=self.guid).all() for auth_ in auth_list: auth_.delete() return self def owns_object(self, obj): from app.modules.assets.models import Asset from app.modules.submissions.models import Submission from app.modules.encounters.models import Encounter from app.modules.sightings.models import Sighting from app.modules.projects.models import Project ret_val = False # Submission, Encounters and Projects all have an owner field, check that if (isinstance(obj, Submission) or isinstance(obj, Encounter) or isinstance(obj, Project)): ret_val = obj.owner is self elif isinstance(obj, Asset): # assets are not owned directly by the user but the submission they're in is. # todo, need to understand once assets become part of an encounter, do they still have a submission if obj.submission is not None: ret_val = obj.submission.owner is self elif isinstance(obj, Sighting): # up for consideration. old world allows control of a sighting if you own at least one encounter on it. for encounter in obj.get_encounters(): if encounter.get_owner() is self: ret_val = True break return ret_val
class Permit(AuditMixin, Base): __tablename__ = 'permit' _edit_groups = [PERMIT_EDIT_GROUP] _edit_key = PERMIT_EDIT_GROUP permit_id = db.Column(db.Integer, primary_key=True) permit_guid = db.Column(UUID(as_uuid=True), server_default=FetchedValue()) mine_guid = db.Column(UUID(as_uuid=True), db.ForeignKey('mine.mine_guid')) permit_no = db.Column(db.String(16), nullable=False) permit_status_code = db.Column( db.String(2), db.ForeignKey('permit_status_code.permit_status_code')) permit_amendments = db.relationship( 'PermitAmendment', backref='permit', primaryjoin= "and_(PermitAmendment.permit_id == Permit.permit_id, PermitAmendment.deleted_ind==False)", order_by= 'desc(PermitAmendment.issue_date), desc(PermitAmendment.permit_amendment_id)', lazy='select') permittee_appointments = db.relationship( 'MinePartyAppointment', lazy='select', order_by= 'desc(MinePartyAppointment.start_date), desc(MinePartyAppointment.mine_party_appt_id)' ) permit_status_code_relationship = db.relationship('PermitStatusCode', lazy='select') permit_status_code_description = association_proxy( 'permit_status_code_relationship', 'description') mine_name = association_proxy('mine', 'mine_name') @hybrid_property def current_permittee(self): if len(self.permittee_appointments) > 0: return self.permittee_appointments[0].party.name else: return "" def __repr__(self): return '<Permit %r>' % self.permit_guid @classmethod def find_by_permit_guid(cls, _id): return cls.query.filter_by(permit_guid=_id).first() @classmethod def find_by_mine_guid(cls, _id): return cls.query.filter_by(mine_guid=_id).all() @classmethod def find_by_permit_no(cls, _permit_no): return cls.query.filter_by(permit_no=_permit_no).first() @classmethod def find_by_permit_guid_or_no(cls, _permit_guid_or_no): result = cls.find_by_permit_guid(_permit_guid_or_no) if not result: result = cls.find_by_permit_no(_permit_guid_or_no) return result @classmethod def create(cls, mine_guid, permit_no, permit_status_code, add_to_session=True): mine_permit = cls(mine_guid=mine_guid, permit_no=permit_no, permit_status_code=permit_status_code) if add_to_session: mine_permit.save(commit=False) return mine_permit @validates('permit_status_code') def validate_status_code(self, key, permit_status_code): if not permit_status_code: raise AssertionError('Permit status code is not provided.') if len(permit_status_code) > 2: raise AssertionError('Permit status code is invalid.') return permit_status_code @validates('permit_no') def validate_permit_no(self, key, permit_no): if not permit_no: raise AssertionError('Permit number is not provided.') if len(permit_no) > 16: raise AssertionError( 'Permit number must not exceed 16 characters.') return permit_no
class User(PaginatedAPIMixin, db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), index=True, unique=True) email = db.Column(db.String(120), index=True, unique=True) password_hash = db.Column(db.String(128)) name = db.Column(db.String(64)) location = db.Column(db.String(64)) about_me = db.Column(db.Text()) member_since = db.Column(db.DateTime(), default=datetime.utcnow) last_seen = db.Column(db.DateTime(), default=datetime.utcnow) # 一对多 字段名,作者, # 反向引用,直接查询出当前用户的所有博客文章; 同时,Post实例中会有 author 属性 # cascade 用于级联删除,当删除user时,该user下面的所有posts都会被级联删除 posts = db.relationship('Post', backref='author', lazy='dynamic', cascade='all, delete-orphan') def __repr__(self): return '<User {}>'.format(self.username) # 添加打印对象 def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) def avatar(self, size): '''头像''' digest = md5(self.email.lower().encode('utf-8')).hexdigest() return 'https://www.gravatar.com/avatar/{}?d=identicon&s={}'.format( digest, size) def to_dict(self, include_email=False): # 默认参数为False data = { 'id': self.id, 'username': self.username, 'name': self.name, 'location': self.location, 'about_me': self.about_me, 'member_since': self.member_since.isoformat() + 'Z', 'last_seen': self.last_seen.isoformat() + 'Z', '_links': { 'self': url_for('api.get_user', id=self.id), 'avatar': self.avatar(128) } } if include_email: data['email'] = self.email return data # 将表单里填写的信息变成实例的属性 def from_dict(self, data, new_user=True): # 默认新用户为真 for field in ['username', 'email', 'name', 'location', 'about_me']: # 遍历表单中的username 和 email # 如果 data中 有存在得字段 if field in data: # 将值设置成实例对应的field属性 setattr(self, field, data[field]) # 如果还是新用户 且 有设置密码 if new_user and 'password' in data: # 将密码字段也设置成属性 self.set_password(data['password']) def ping(self): self.last_seen = datetime.utcnow() db.session.add(self) def get_jwt(self, expires_in=3600): # 将get_token方法修改为get_jwt()方法 now = datetime.utcnow() # 当前时间 payload = { 'user_id': self.id, 'name': self.name if self.name else self.username, # 如果用户的名字存在则放name,否则username 'exp': now + timedelta(seconds=expires_in), 'iat': now } return jwt.encode(payload, current_app.config['SECRET_KEY'], algorithm='HS256').decode( 'utf-8') # 返回一个字段payload,先进行编码再解码成utf-8格式 # 静态方法 @staticmethod def verify_jwt(token): # 使用jwt的decode解码 try: payload = jwt.decode(token, current_app.config['SECRET_KEY'], algorithm=['HS256']) except (jwt.exceptions.ExpiredSignatureError, jwt.exceptions.InvalidSignatureError) as e: # Token过期,或者被人修改,name签名验证也会失败 return None return User.query.get(payload.get('user_id')) # 返回user_id
class Permit(AuditMixin, Base): __tablename__ = 'permit' permit_id = db.Column(db.Integer, primary_key=True) permit_guid = db.Column(UUID(as_uuid=True), server_default=FetchedValue()) mine_guid = db.Column(UUID(as_uuid=True), db.ForeignKey('mine.mine_guid')) permit_no = db.Column(db.String(16), nullable=False) permit_status_code = db.Column( db.String(2), db.ForeignKey('permit_status_code.permit_status_code')) permit_amendments = db.relationship( 'PermitAmendment', backref='permit', primaryjoin= "and_(PermitAmendment.permit_id == Permit.permit_id, PermitAmendment.deleted_ind==False)", order_by= 'desc(PermitAmendment.issue_date), desc(PermitAmendment.permit_amendment_id)', lazy='select') def __repr__(self): return '<Permit %r>' % self.permit_guid def json(self): return { 'permit_id': str(self.permit_id), 'permit_guid': str(self.permit_guid), 'mine_guid': str(self.mine_guid), 'permit_no': self.permit_no, 'permit_status_code': self.permit_status_code, 'amendments': [x.json() for x in self.permit_amendments] } def json_for_list(self): return { 'permit_id': str(self.permit_id), 'permit_guid': str(self.permit_guid), 'mine_guid': str(self.mine_guid), 'permit_no': self.permit_no, 'permit_status_code': self.permit_status_code } @classmethod def find_by_permit_guid(cls, _id): return cls.query.filter_by(permit_guid=_id).first() @classmethod def find_by_mine_guid(cls, _id): return cls.query.filter_by(mine_guid=_id) @classmethod def find_by_permit_no(cls, _permit_no): return cls.query.filter_by(permit_no=_permit_no).first() @classmethod def create(cls, mine_guid, permit_no, permit_status_code, save=True): mine_permit = cls(mine_guid=mine_guid, permit_no=permit_no, permit_status_code=permit_status_code) if save: mine_permit.save(commit=False) return mine_permit @validates('permit_status_code') def validate_status_code(self, key, permit_status_code): if not permit_status_code: raise AssertionError('Permit status code is not provided.') if len(permit_status_code) > 2: raise AssertionError('Permit status code is invalid.') return permit_status_code @validates('permit_no') def validate_permit_no(self, key, permit_no): if not permit_no: raise AssertionError('Permit number is not provided.') if len(permit_no) > 16: raise AssertionError( 'Permit number must not exceed 16 characters.') return permit_no
class MinePartyAppointment(AuditMixin, Base): __tablename__ = "mine_party_appt" # Columns mine_party_appt_id = db.Column(db.Integer, primary_key=True, server_default=FetchedValue()) mine_party_appt_guid = db.Column(UUID(as_uuid=True), server_default=FetchedValue()) mine_guid = db.Column(UUID(as_uuid=True), db.ForeignKey('mine.mine_guid')) party_guid = db.Column(UUID(as_uuid=True), db.ForeignKey('party.party_guid')) mine_party_appt_type_code = db.Column( db.String(3), db.ForeignKey('mine_party_appt_type_code.mine_party_appt_type_code')) start_date = db.Column(db.DateTime) end_date = db.Column(db.DateTime) processed_by = db.Column(db.String(60), server_default=FetchedValue()) processed_on = db.Column(db.DateTime, nullable=False, server_default=FetchedValue()) #type specific foreign keys mine_tailings_storage_facility_guid = db.Column( UUID(as_uuid=True), db.ForeignKey('mine_tailings_storage_facility.mine_tailings_storage_facility_guid')) permit_guid = db.Column(UUID(as_uuid=True), db.ForeignKey('permit.permit_guid')) deleted_ind = db.Column(db.Boolean, server_default=FetchedValue()) # Relationships party = db.relationship('Party', lazy='joined') mine_party_appt_type = db.relationship( 'MinePartyAppointmentType', backref='mine_party_appt', order_by='desc(MinePartyAppointmentType.display_order)', lazy='joined') def assign_related_guid(self, related_guid): if self.mine_party_appt_type_code == "EOR": self.mine_tailings_storage_facility_guid = related_guid if self.mine_party_appt_type_code == "PMT": self.permit_guid = related_guid return # json def json(self, relationships=[]): result = { 'mine_party_appt_guid': str(self.mine_party_appt_guid), 'mine_guid': str(self.mine_guid), 'party_guid': str(self.party_guid), 'mine_party_appt_type_code': str(self.mine_party_appt_type_code), 'start_date': str(self.start_date) if self.start_date else None, 'end_date': str(self.end_date) if self.end_date else None, } if 'party' in relationships: result.update({'party': self.party.json(show_mgr=False) if self.party else str({})}) related_guid = "" if self.mine_party_appt_type_code == "EOR": related_guid = str(self.mine_tailings_storage_facility_guid) elif self.mine_party_appt_type_code == "PMT": related_guid = str(self.permit_guid) result["related_guid"] = related_guid return result # search methods @classmethod def find_by_mine_party_appt_guid(cls, _id): try: return cls.query.filter_by(mine_party_appt_guid=_id).filter_by( deleted_ind=False).first() except ValueError: return None @classmethod def find_all_by_mine_party_appt_guid(cls, _id): try: return cls.query.filter_by(mine_party_appt_guid=_id).filter_by( deleted_ind=False) except ValueError: return None @classmethod def find_by_mine_guid(cls, _id): try: return cls.find_by(mine_guid=_id) except ValueError: return None @classmethod def find_by_party_guid(cls, _id): try: return cls.find_by(party_guid=_id) except ValueError: return None @classmethod def find_parties_by_mine_party_appt_type_code(cls, code): try: return cls.find_by(mine_party_appt_type_codes=[code]) except ValueError: return None @classmethod def find_manager_history_by_mine_no(cls, mine_no): # send internal API call to fetch matching mine record mines_url = current_app.config['MINES_URL'] + '/mines/' + str(mine_no) auth_headers = request.headers.get('Authorization') if not auth_headers: return None, 401, 'Unauthorized' headers = {'Authorization': auth_headers} response = requests.get(url=mines_url, headers=headers) if not response: return None, 500, 'Server error' if response.status_code != 200: return None, response.status_code, response.reason # fetch mine history by mine_guid try: json_response = response.json() except: return None, 500, 'Server error' related_mine_guid = json_response.get('guid') if not related_mine_guid: return None, 404, 'Mine not found' records = cls.query.filter_by(mine_guid=related_mine_guid).all() if len(records) == 0: return None, 404, 'No Mine Manager history found' return records, 200, 'OK' @classmethod def find_by(cls, mine_guid=None, party_guid=None, mine_party_appt_type_codes=None): try: built_query = cls.query.filter_by(deleted_ind=False) if mine_guid: built_query = built_query.filter_by(mine_guid=mine_guid) if party_guid: built_query = built_query.filter_by(party_guid=party_guid) if mine_party_appt_type_codes: built_query = built_query.filter( cls.mine_party_appt_type_code.in_(mine_party_appt_type_codes)) return built_query.all() except ValueError: return None @classmethod def to_csv(cls, records, columns): rows = [','.join(columns)] for record in records: row = [] for column in columns: row.append(str(getattr(record, column))) rows.append(','.join(row)) return '\n'.join(rows) @classmethod def create(cls, mine_guid, party_guid, mine_party_appt_type_code, start_date=None, end_date=None, processed_by=processed_by, permit_guid=None, save=True): mpa = cls( mine_guid=mine_guid, party_guid=party_guid, permit_guid=permit_guid, mine_party_appt_type_code="PMT", start_date=start_date, end_date=end_date, processed_by=processed_by) if save: mpa.save(commit=False) return mpa # validators @validates('mine_guid') def validate_mine_guid(self, key, val): if not val: raise AssertionError('No mine guid provided.') return val @validates('party_guid') def validate_party_guid(self, key, val): if not val: raise AssertionError('No party guid provided.') return val @validates('mine_party_appt_type_code') def validate_mine_party_appt_type_code(self, key, val): if not val: raise AssertionError('No mine party appointment type code') if len(val) is not 3: raise AssertionError('invalid mine party appointment type code') return val @validates('mine_tailings_storage_facility_guid') def validate_mine_tailings_storage_facility_guid(self, key, val): if self.mine_party_appt_type_code == 'EOR': if not val: raise AssertionError( 'No mine_tailings_storage_facility_guid, but mine_party_appt_type_code is EOR.') return val @validates('permit_guid') def validate_permit_guid(self, key, val): if self.mine_party_appt_type_code == 'PMT': if not val: raise AssertionError('No permit_guid, but mine_party_appt_type_code is PMT.') return val
class User(UserMixin,db.Model): __tablename__ = 'user' id = db.Column('id',db.Integer,primary_key=True) username = db.Column(db.String(12),index=True) password_hash = db.Column(db.String(128)) sex = db.Column(db.Boolean,default=True) age = db.Column(db.Integer) email = db.Column(db.String(40)) icon = db.Column(db.String(70),default='default.jpg') #当期账户激活状态 confirm = db.Column(db.Boolean,default=False) #参数1模型名称 参数2反向引用的字段名 参数3 加载方式 提供对象 posts = db.relationship('Posts',backref='user',lazy='dynamic') #secondary在多对多关系中指定关联表的名称 favorite = db.relationship('Posts',secondary='collections',backref=db.backref('users',lazy='dynamic'),lazy='dynamic') #添加使用append 删除使用remove @property def password(self): raise ValueError @password.setter def password(self, password): self.password_hash = generate_password_hash(password) #生成token的方法 def generate_token(self): s = Seralize(current_app.config['SECRET_KEY']) return s.dumps({'id':self.id}) #检测token的方法 @staticmethod def check_token(token): s = Seralize(current_app.config['SECRET_KEY']) #从当前的token中拿出字典 try: id = s.loads(token)['id'] except: return False #根据用户id取出对应用户的对象 u = User.query.get(id) #判断 当期u对象是否存在 if not u: return False #判断当期用户的激活状态 如果没有激活 则激活 if not u.confirm: u.confirm = True db.session.add(u) return True #验证密码 def check_password_hash(self,password): return check_password_hash(self.password_hash,password) def is_favorite(self,postsId): all = self.favorite.all() for p in all: if p.id==postsId: return True #lambda表达式 if list(filter(lambda p:p.id==int(postsId),all)): return True return False #定义一个收藏与取消收藏方法 def add_favorite(self,pid): self.favorite.append(Posts.query.get(pid)) #定义一个取消收藏方法 def remove_favorite(self,pid): self.favorite.remove(Posts.query.get(pid))
class Item(db.Model): id = db.Column(db.Integer, primary_key=True) body = db.Column(db.Text) done = db.Column(db.Boolean, default=False) author_id = db.Column(db.Integer, db.ForeignKey('user.id')) author = db.relationship('User', back_populates='items')
class TowerDB(db.Model): tower_id = db.Column(db.Integer, primary_key=True) tower_name = db.Column(db.String(32), index=True) created_on = db.Column(db.Date, default=date.today) last_access = db.Column(db.Date, nullable=False, default=date.today, onupdate=date.today) users = db.relationship("UserTowerRelation", back_populates="tower") host_mode_enabled = db.Column(db.Boolean, default=False) additional_sizes_enabled = db.Column(db.Boolean, default=False) half_muffled = db.Column(db.Boolean, default=False) fully_muffled = db.Column(db.Boolean, default=False) wheatley_enabled = db.Column(db.Boolean, default=False) wheatley_settings_json = db.Column(db.String(), default="{}") anticlockwise = db.Column(db.Boolean, default=False) cowbell_enabled = db.Column(db.Boolean, default=False) def __repr__(self): return '<TowerDB {}: {}>'.format(self.tower_id, self.tower_name) def to_dict(self): data = { 'tower_id': self.tower_id, 'tower_name': self.tower_name, 'host_mode_enabled': self.host_mode_enabled, 'hosts': [u.to_dict() for u in self.hosts], } return data def to_Tower(self): has_changed_db = False # Parse Wheatley's settings from JSON (and initialise with '{}' if invalid or non-existent) wheatley_settings = None while wheatley_settings is None: try: wheatley_settings = json.loads(self.wheatley_settings_json) except TypeError: self.wheatley_settings_json = "{}" has_changed_db = True except Exception as e: self.log( f"Invalid Wheatley settings JSON {self.wheatley_settings_json}: {e}" ) self.wheatley_settings_json = "{}" has_changed_db = True # Read Wheatley's enabledness from the database, and initialise it if it's null if self.wheatley_enabled is None: self.wheatley_enabled = False has_changed_db = True # Commit the changes to the database if they've been made if has_changed_db: db.session.commit() return Tower( self.tower_name, tower_id=self.tower_id, host_mode_enabled=self.host_mode_enabled, # Force wheatley_enabled to be False if the Wheatley feature flag is not set wheatley_enabled=self.wheatley_enabled and app.wheatley.feature_flag(), wheatley_db_settings=wheatley_settings) def created_by(self, user): # Expects a User object # This should go through the user object, to avoid duplicating the # relation rel = user._get_relation_to_tower(self) rel.creator = True rel.host = True db.session.commit() @property def creator(self): rel = UserTowerRelation.query.filter( UserTowerRelation.tower == self, UserTowerRelation.creator == True).first() return rel.user if rel else None # We need to be able to get this from the TowerDB object for the User Menu @property def url_safe_name(self): out = re.sub(r'\s', '_', self.tower_name) out = re.sub(r'\W', '', out) return out.lower() @property def hosts(self): return [ rel.user for rel in UserTowerRelation.query.filter( UserTowerRelation.tower == self, UserTowerRelation.host == True).all() ] @property def host_ids(self): return [ rel.user.id for rel in UserTowerRelation.query.filter( UserTowerRelation.tower == self, UserTowerRelation.host == True).all() ]
class GroupSchedule(Schedule): user_group_id = reference_col('user_group') user_group = db.relationship("UserGroup", back_populates='schedules') __mapper_args__ = {'polymorphic_identity': 'group_schedule'}
class Lecture(db.Model): __tablename__ = 'lecture' id = db.Column(db.Integer, primary_key=True) dept = db.Column(db.String(10), nullable=False) course_num = db.Column(db.Integer, nullable=False) title = db.Column(db.String(50), nullable=False) section = db.Column(db.Integer, nullable=False) days = db.Column(db.String(10), nullable=False) start = db.Column(db.Integer, nullable=False) end = db.Column(db.Integer, nullable=False) professor = db.Column(db.String(50), nullable=True) hall_id = db.Column(db.Integer, db.ForeignKey('hall.id')) hall = db.relationship("Hall") discussion = db.relationship("Discussion", uselist=False, back_populates="lecture") user = db.relationship("User", secondary=UserLectureAssociation, back_populates="lecture") def __init__(self, dept, course_num, title, section, days, start, end, professor): self.dept = dept self.course_num = course_num self.title = title self.section = section self.days = days self.start = start self.end = end self.professor = professor def __repr__(self): return "<Lecture: {} {} {}>".format(self.dept, self.course_num, self.section) def get(id): return Lecture.query.get(id) def json_to_database(): classes = schedule.get_classes()['classes'] print('Writing {} lectures to database...'.format(len(classes))) for c in classes: try: lect = Lecture(c['dept'], c['course_num'], c['title'], c['section'], c['days'], c['start'], c['end'], c['professor']) lect.hall = Hall.query.filter( Hall.abbr == c['hall'].split(' ')[0]).first() print('Adding Lecture {} {} {}, starts at {}, taught by {}'. format(lect.dept, lect.course_num, lect.title, lect.start, lect.professor)) db.session.add(lect) except Exception as e: print('Error in writing lectures to table -- {}'.format(e)) print('Skipping...') continue db.session.commit()
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(20)) email = db.Column(db.String(64), unique=True) confirmed = db.Column(db.Boolean, default=False) # 添加保存头像文件名的字段 icon = db.Column(db.String(64), default='default.jpg') # 添加博客的反向引用 posts = db.relationship('Posts', lazy='dynamic', backref='user') # 添加收藏的反向引用 favorites = db.relationship('Posts', lazy='dynamic', secondary='collections', backref=db.backref('users', lazy='dynamic')) # 判断是否收藏 def is_favorite(self, pid): favorite = self.favorites.filter(Posts.id == pid).first() if favorite: return True return False # 添加收藏 def add_favorite(self, pid): p = Posts.query.get(pid) self.favorites.append(p) # 取消收藏 def del_favorite(self, pid): p = Posts.query.get(pid) self.favorites.remove(p) # 属性函数 @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 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) # 根据用户名查找数据库 u = User.query.get(data['id']) # 查看用户是否激活 if not u.confirmed: # 若没有激活,激活用户 u.confirmed = True db.session.add(u) return True except: return False
class User(UserMixin, db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True, index=True) email = db.Column(db.String(64), unique=True, index=True) password_hash = db.Column(db.String(128)) role_id = db.Column(db.Integer, db.ForeignKey('roles.id'), nullable=False) role = db.relationship('Role', back_populates='users') posts = db.relationship('Post', back_populates='author', lazy='dynamic') last_visit = db.Column(db.DateTime) is_confirmed = db.Column(db.Boolean, default=False) member_since = db.Column(db.DateTime, default=datetime.utcnow) image_hash = db.Column(db.String(128)) followings = db.relationship('Follow', foreign_keys=[Follow.follower_id], backref=db.backref('follower', lazy='joined'), lazy='dynamic') followers = db.relationship('Follow', foreign_keys=[Follow.followed_id], backref=db.backref('followed', lazy='joined'), lazy='dynamic') messages_sent = db.relationship('Message', foreign_keys=[Message.sender_id], backref='author', lazy='dynamic') messages_received = db.relationship('Message', foreign_keys=[Message.receiver_id], backref='receiver', lazy='dynamic') notifications = db.relationship('Notification', back_populates='receiver', lazy='dynamic') @property def password(self): raise AttributeError('password is not readable attribute') @password.setter def password(self, value): self.password_hash = generate_password_hash(value) def verify_password(self, value): return check_password_hash(self.password_hash, value) def ping(self): self.last_visit = datetime.utcnow() db.session.add(self) db.session.commit() def generate_confirmation_token(self): s = Serializer(current_app.config['SECRET_KEY'], expires_in=3600) return s.dumps({'id': self.id}).decode('utf-8') def confirm(self, token): s = Serializer(current_app.config['SECRET_KEY'], expires_in=3600) try: o = s.loads(token) return o['id'] == self.id except Exception: return False def gravatar(self, size=100, default='identicon', rating='g'): url = 'https://secure.gravatar.com/avatar' # hash = hashlib.md5(self.email.lower().encode('utf-8')).hexdigest() return '{url}/{hash}?s={size}&d={default}&r={rating}'.format( url=url, hash=self.image_hash, size=size, default=default, rating=rating) def follow(self, user): if user is not None: model = Follow(follower_id=self.id, followed_id=user.id) db.session.add(model) def unfollow(self, user): if user is not None: model = self.followings.filter_by(followed_id=user.id).first() # model = Follow.query.filter(Follow.follower_id == self.id, Follow.followed_id == user.id).first() db.session.delete(model) db.session.commit() def is_following(self, user): if user is None: return False return self.followings.filter_by( followed_id=user.id).first() is not None def is_followed_by(self, user): pass def can(self, permission_name): role = Role.query.filter_by(name=permission_name).first() if role and self.role.permissions & role.permissions: return True return False @property def is_admin(self): return self.role.name == 'Administrator' @staticmethod def on_email_change(target, value, oldvalue, initiator): if value != oldvalue: target.image_hash = hashlib.md5( value.lower().encode('utf-8')).hexdigest() def __repr__(self): return '<User %r>' % self.username
class EmailAddress(db.Model): __tablename__ = 'email_address' __versioned__ = {} __mapper_args__ = {'extension': BaseExtension()} id = db.Column(db.Integer, primary_key=True, index=True) email = db.Column("email", db.Text, index=True) primary = db.Column("primary", db.Boolean, default=False) active = db.Column("active", db.Boolean, default=False) patient_id = db.Column(db.Integer, db.ForeignKey('patient.id'), index=True) patient = db.relationship("Patient", back_populates="email_addresses") user_id = db.Column(db.Integer, db.ForeignKey('user.id'), index=True) user = db.relationship("User", back_populates="email_addresses") avatar_hash = db.Column(db.Text) created_at = db.Column(db.DateTime, default=datetime.utcnow()) updated_at = db.Column(db.DateTime) row_hash = db.Column(db.Text, index=True) def __init__(self, email=None, primary=False, active=True): self.email = email self.primary = primary self.active = active self._fhir = None def generate_avatar_hash(self): __doc__ = """ Generate an MD5 hash of the user's email. Stores the result in the user 'avatar_hash' attribute. This value is used when constructing the gravatar URL.""" if self.email and not re.search(r'(@EXAMPLE)+', self.email): email_lower = self.email.lower() self.avatar_hash = hashlib.md5( email_lower.encode('utf-8')).hexdigest() def gravatar_url(self, size=100, default='identicon', rating='g'): __doc__ = """ Generate a Gravatar url based on an MD5 hash of the user's email. URL output conforms to standards for Globally Recognized Avatar service. Defaults established as: Size: 100px Default: identicon (if gravatar not found, pattern unique to MD5 hash is displayed\ Rating: g """ url = 'https://secure.gravatar.com/avatar' if not self.avatar_hash: self.generate_avatar_hash() db.session.add(self) return '{url}/{hash}?s={size}&d={default}&r={rating}'.format( url=url, hash=self.avatar_hash, size=size, default=default, rating=rating) def dump(self): schema = EmailAddressSchema() return schema.dump(self).data @property def fhir(self): """ Returns fhir-client ContactPoint model object associated with SQLAlchemy Instance If no fhir-client object is initialized, one is created and stored in protected attrib _fhir :return: fhir-client ContactPoint object matching SQLAlchemy ORM object instance """ if not getattr(self, '_fhir', None): self.create_fhir_object() return self._fhir else: return self._fhir @fhir.setter def fhir(self, fhir_obj): """ Allows setting of the protected attribute _fhir Validates object is fhir-client model ContactPoint object :param fhir_obj: A fhir-client ContactPOint model object instance :return: None """ if not isinstance(fhir_obj, contactpoint.ContactPoint): raise TypeError('Object is not a fhirclient ContactPoint object') else: self._fhir = fhir_obj def create_fhir_object(self): fhir_contact = contactpoint.ContactPoint() fhir_contact.system = 'email' if self.active: fhir_contact.use = 'home' if self.primary: fhir_contact.rank = 1 else: fhir_contact.rank = 2 else: fhir_contact.use = 'old' fhir_contact.rank = 3 if self.email: fhir_contact.value = self.email self._fhir = fhir_contact def dump_fhir_json(self): self.create_fhir_object() return self.fhir.as_json() def generate_row_hash(self): data = { "email": self.email, "patient_id": self.patient_id, "user_id": self.user_id } data_str = json.dumps(data, sort_keys=True, default=json_serial) data_hash = hashlib.sha1(data_str.encode('utf-8')).hexdigest() return data_hash def before_insert(self): self.row_hash = self.generate_row_hash() if not self.avatar_hash: self.generate_avatar_hash() def before_update(self): self.row_hash = self.generate_row_hash() if not self.avatar_hash: self.generate_avatar_hash()
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') @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 Application(Base): __tablename__ = "application" __table_args__ = {"schema": "now_submissions"} messageid = db.Column(db.Integer, primary_key=True) application_guid = db.Column(UUID(as_uuid=True), nullable=False) mine_guid = db.Column(UUID(as_uuid=True), db.ForeignKey('mine.mine_guid')) trackingnumber = db.Column(db.Integer) applicationtype = db.Column(db.String) status = db.Column(db.String) submitteddate = db.Column(db.DateTime) receiveddate = db.Column(db.DateTime) applicantclientid = db.Column( db.Integer, db.ForeignKey('now_submissions.client.clientid')) submitterclientid = db.Column( db.Integer, db.ForeignKey('now_submissions.client.clientid')) noticeofworktype = db.Column(db.String) typeofpermit = db.Column(db.String) typeofapplication = db.Column(db.String) minenumber = db.Column(db.String) latitude = db.Column(db.Numeric(9, 7)) longitude = db.Column(db.Numeric(11, 7)) nameofproperty = db.Column(db.String) tenurenumbers = db.Column(db.String) crowngrantlotnumbers = db.Column(db.String) sitedirections = db.Column(db.String) firstaidequipmentonsite = db.Column(db.String) firstaidcertlevel = db.Column(db.String) descexplorationprogram = db.Column(db.String) proposedstartdate = db.Column(db.DateTime) proposedenddate = db.Column(db.DateTime) yearroundseasonal = db.Column(db.String) landcommunitywatershed = db.Column(db.String) landprivate = db.Column(db.String) landlegaldesc = db.Column(db.String) archsitesaffected = db.Column(db.String) sandgravelquarryoperations = db.Column(db.String) storeexplosivesonsite = db.Column(db.String) bcexplosivespermitissued = db.Column(db.String) bcexplosivespermitnumber = db.Column(db.String) bcexplosivespermitexpiry = db.Column(db.DateTime) campdisturbedarea = db.Column(db.Numeric(14, 2)) camptimbervolume = db.Column(db.Numeric(14, 2)) bldgdisturbedarea = db.Column(db.Numeric(14, 2)) bldgtimbervolume = db.Column(db.Numeric(14, 2)) stgedisturbedarea = db.Column(db.Numeric(14, 2)) stgetimbervolume = db.Column(db.Numeric(14, 2)) fuellubstoreonsite = db.Column(db.String) fuellubstored = db.Column(db.Integer) fuellubstoremethodbulk = db.Column(db.String) fuellubstoremethodbarrel = db.Column(db.String) cbsfreclamation = db.Column(db.String) cbsfreclamationcost = db.Column(db.Numeric(14, 2)) mechtrenchingreclamation = db.Column(db.String) mechtrenchingreclamationcost = db.Column(db.Numeric(14, 2)) expsurfacedrillreclamation = db.Column(db.String) expsurfacedrillreclcorestorage = db.Column(db.String) expsurfacedrillreclamationcost = db.Column(db.Numeric(14, 2)) expaccessreclamation = db.Column(db.String) expaccessreclamationcost = db.Column(db.Numeric(14, 2)) surfacebulksampleprocmethods = db.Column(db.String) surfacebulksamplereclamation = db.Column(db.String) surfacebulksamplereclsephandl = db.Column(db.String) surfacebulksamplerecldrainmiti = db.Column(db.String) surfacebulksamplereclcost = db.Column(db.Numeric(14, 2)) underexptotalore = db.Column(db.Integer) underexptotaloreunits = db.Column(db.String) underexptotalwaste = db.Column(db.Integer) underexptotalwasteunits = db.Column(db.String) underexpreclamation = db.Column(db.String) underexpreclamationcost = db.Column(db.Numeric(14, 2)) placerundergroundoperations = db.Column(db.String) placerhandoperations = db.Column(db.String) placerreclamationarea = db.Column(db.Numeric(14, 2)) placerreclamation = db.Column(db.String) placerreclamationcost = db.Column(db.Numeric(14, 2)) sandgrvqrydepthoverburden = db.Column(db.Numeric(14, 2)) sandgrvqrydepthtopsoil = db.Column(db.Numeric(14, 2)) sandgrvqrystabilizemeasures = db.Column(db.String) sandgrvqrywithinaglandres = db.Column(db.String) sandgrvqryalrpermitnumber = db.Column(db.String) sandgrvqrylocalgovsoilrembylaw = db.Column(db.String) sandgrvqryofficialcommplan = db.Column(db.String) sandgrvqrylandusezoning = db.Column(db.String) sandgrvqryendlanduse = db.Column(db.String) sandgrvqrytotalmineres = db.Column(db.Integer) sandgrvqrytotalmineresunits = db.Column(db.String) sandgrvqryannualextrest = db.Column(db.Integer) sandgrvqryannualextrestunits = db.Column(db.String) sandgrvqryreclamation = db.Column(db.String) sandgrvqryreclamationbackfill = db.Column(db.String) sandgrvqryreclamationcost = db.Column(db.Numeric(14, 2)) sandgrvqrygrdwtravgdepth = db.Column(db.Numeric(14, 1)) sandgrvqrygrdwtrexistingareas = db.Column(db.String) sandgrvqrygrdwtrtestpits = db.Column(db.String) sandgrvqrygrdwtrtestwells = db.Column(db.String) sandgrvqrygrdwtrother = db.Column(db.String) sandgrvqrygrdwtrmeasprotect = db.Column(db.String) sandgrvqryimpactdistres = db.Column(db.Integer) sandgrvqryimpactdistwater = db.Column(db.Integer) sandgrvqryimpactnoise = db.Column(db.String) sandgrvqryimpactprvtaccess = db.Column(db.String) sandgrvqryimpactprevtdust = db.Column(db.String) sandgrvqryimpactminvisual = db.Column(db.String) cutlinesexplgridtotallinekms = db.Column(db.Integer) cutlinesexplgridtimbervolume = db.Column(db.Numeric(14, 2)) cutlinesreclamation = db.Column(db.String) cutlinesreclamationcost = db.Column(db.Numeric(14, 2)) pondswastewatertreatfacility = db.Column(db.String) freeusepermit = db.Column(db.String) licencetocut = db.Column(db.String) timbertotalvolume = db.Column(db.Numeric(14, 2)) campbuildstgetotaldistarea = db.Column(db.Numeric(14, 2)) mechtrenchingtotaldistarea = db.Column(db.Numeric(14, 2)) expsurfacedrilltotaldistarea = db.Column(db.Numeric(14, 2)) expaccesstotaldistarea = db.Column(db.Numeric(14, 2)) surfacebulksampletotaldistarea = db.Column(db.Numeric(14, 2)) placertotaldistarea = db.Column(db.Numeric(14, 2)) underexptotaldistarea = db.Column(db.Numeric(14, 2)) sandgrvqrytotaldistarea = db.Column(db.Numeric(14, 2)) pondstotaldistarea = db.Column(db.Numeric(14, 2)) reclcostsubtotal = db.Column(db.Numeric(14, 2)) reclcostexist = db.Column(db.Numeric(14, 2)) reclcostrecl = db.Column(db.Numeric(14, 2)) reclcosttotal = db.Column(db.Numeric(14, 2)) reclareasubtotal = db.Column(db.Numeric(14, 2)) reclareaexist = db.Column(db.Numeric(14, 2)) reclarearecl = db.Column(db.Numeric(14, 2)) reclareatotal = db.Column(db.Numeric(14, 2)) anyotherinformation = db.Column(db.String) vfcbcapplicationurl = db.Column(db.String) messagecreateddate = db.Column(db.DateTime) processed = db.Column(db.String) processeddate = db.Column(db.DateTime) cutlinesexplgriddisturbedarea = db.Column(db.Numeric(14, 2)) pondsrecycled = db.Column(db.String) pondsexfiltratedtoground = db.Column(db.String) pondsdischargedtoenv = db.Column(db.String) pondsreclamation = db.Column(db.String) pondsreclamationcost = db.Column(db.Numeric(14, 2)) sandgrvqrytotalexistdistarea = db.Column(db.Numeric(14, 2)) nrsosapplicationid = db.Column(db.String) isblastselect = db.Column(db.String) istimberselect = db.Column(db.String) mine = db.relationship('Mine', lazy='joined') applicant = db.relationship('Client', lazy='joined', foreign_keys=[applicantclientid]) submitter = db.relationship('Client', lazy='joined', foreign_keys=[submitterclientid]) contacts = db.relationship('Contact', lazy='joined') documents = db.relationship('Document', lazy='joined') sand_grv_qry_activity = db.relationship('SandGrvQryActivity', lazy='joined') surface_bulk_sample_activity = db.relationship('SurfaceBulkSampleActivity', lazy='joined') under_exp_new_activity = db.relationship('UnderExpNewActivity', lazy='joined') under_exp_rehab_activity = db.relationship('UnderExpRehabActivity', lazy='joined') under_exp_surface_activity = db.relationship('UnderExpSurfaceActivity', lazy='joined') water_source_activity = db.relationship('WaterSourceActivity', lazy='joined') exp_access_activity = db.relationship('ExpAccessActivity', lazy='joined') mech_trenching_activity = db.relationship('MechTrenchingActivity', lazy='joined') existing_placer_activity = db.relationship( 'PlacerActivity', lazy='joined', secondary='now_submissions.existing_placer_activity_xref') existing_settling_pond = db.relationship( 'SettlingPond', lazy='joined', secondary='now_submissions.existing_settling_pond_xref') proposed_placer_activity = db.relationship( 'PlacerActivity', lazy='joined', secondary='now_submissions.proposed_placer_activity_xref') proposed_settling_pond = db.relationship( 'SettlingPond', lazy='joined', secondary='now_submissions.proposed_settling_pond_xref') mine_name = association_proxy('mine', 'mine_name') mine_region = association_proxy('mine', 'mine_region') def __repr__(self): return '<Application %r>' % self.messageid @classmethod def find_by_application_guid(cls, guid): cls.validate_guid(guid) return cls.query.filter_by(application_guid=guid).first() @classmethod def validate_guid(cls, guid, msg='Invalid guid.'): try: uuid.UUID(str(guid), version=4) except ValueError: raise AssertionError(msg)
class MineStatusXref(AuditMixin, Base): __tablename__ = 'mine_status_xref' mine_status_xref_guid = db.Column(UUID(as_uuid=True), primary_key=True) mine_operation_status_code = db.Column( db.String(3), db.ForeignKey('mine_operation_status_code.mine_operation_status_code')) mine_operation_status = db.relationship('MineOperationStatusCode', lazy='joined') mine_operation_status_reason_code = db.Column( db.String(3), db.ForeignKey( 'mine_operation_status_reason_code.mine_operation_status_reason_code' )) mine_operation_status_reason = db.relationship( 'MineOperationStatusReasonCode', lazy='joined') mine_operation_status_sub_reason_code = db.Column( db.String(3), db.ForeignKey( 'mine_operation_status_sub_reason_code.mine_operation_status_sub_reason_code' )) mine_operation_status_sub_reason = db.relationship( 'MineOperationStatusSubReasonCode', lazy='joined') description = db.Column(db.String(1024)) active_ind = db.Column(db.Boolean, nullable=False, server_default=FetchedValue()) def __repr__(self): return '<MineStatusXref %r>' % self.mine_status_xref_guid def json(self): return { 'mine_status_xref_guid': str(self.mine_status_xref_guid), 'mine_operation_status_code': self.mine_operation_status_code.json() if self.mine_operation_status_code else {}, 'mine_operation_status_reason_code': self.mine_operation_status_reason_code.json() if self.mine_operation_status_reason_code else {}, 'mine_operation_status_sub_reason_code': self.mine_operation_status_sub_reason_code.json() if self.mine_operation_status_sub_reason_code else {}, } @classmethod def active(cls): return cls.query.filter_by(active_ind=True).all() @classmethod def find_by_mine_status_xref_guid(cls, _id): return cls.query.filter_by(mine_status_xref_guid=_id).first() @classmethod def find_by_codes(cls, _mine_operation_status_code, _mine_operation_status_reason_code=None, _mine_operation_status_sub_reason_code=None): xref_query = cls.query \ .filter_by(mine_operation_status_code=_mine_operation_status_code) \ .order_by( cls.mine_operation_status_reason_code.desc(), cls.mine_operation_status_sub_reason_code.desc()) if _mine_operation_status_reason_code: xref_query = xref_query.filter_by( mine_operation_status_reason_code= _mine_operation_status_reason_code) if _mine_operation_status_sub_reason_code: xref_query = xref_query.filter_by( mine_operation_status_sub_reason_code= _mine_operation_status_sub_reason_code) return xref_query.first()
class ClientUser(db.Model, ModelMixin): __table_args__ = (db.UniqueConstraint("user_id", "client_id", name="uq_client_user"), ) user_id = db.Column(db.ForeignKey(User.id, ondelete="cascade"), nullable=False) client_id = db.Column(db.ForeignKey(Client.id, ondelete="cascade"), nullable=False) # Null means client has access to user original email gen_email_id = db.Column(db.ForeignKey(GenEmail.id, ondelete="cascade"), nullable=True) # user can decide to send to client another name name = db.Column(db.String(128), nullable=True, default=None, server_default=text("NULL")) # user can decide to send to client a default avatar default_avatar = db.Column(db.Boolean, nullable=False, default=False, server_default="0") gen_email = db.relationship(GenEmail, backref="client_users") user = db.relationship(User) client = db.relationship(Client) def get_email(self): return self.gen_email.email if self.gen_email_id else self.user.email def get_user_name(self): if self.name: return self.name else: return self.user.name def get_user_info(self) -> dict: """return user info according to client scope Return dict with key being scope name. For now all the fields are the same for all clients: { "client": "Demo", "email": "*****@*****.**", "email_verified": true, "id": 1, "name": "Son GM", "avatar_url": "http://s3..." } """ res = { "id": self.id, "client": self.client.name, "email_verified": True, "sub": str(self.id), } for scope in self.client.get_scopes(): if scope == Scope.NAME: if self.name: res[Scope.NAME.value] = self.name else: res[Scope.NAME.value] = self.user.name elif scope == Scope.AVATAR_URL: if self.user.profile_picture_id: if self.default_avatar: res[Scope.AVATAR_URL. value] = URL + "/static/default-avatar.png" else: res[Scope.AVATAR_URL. value] = self.user.profile_picture.get_url( AVATAR_URL_EXPIRATION) else: res[Scope.AVATAR_URL.value] = None elif scope == Scope.EMAIL: # Use generated email if self.gen_email_id: LOG.debug("Use gen email for user %s, client %s", self.user, self.client) res[Scope.EMAIL.value] = self.gen_email.email # Use user original email else: res[Scope.EMAIL.value] = self.user.email return res
class User(UserMixin, db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), index=True, unique=True, nullable=False) email = db.Column(db.String(120), index=True, unique=True, nullable=False) password = db.Column(db.Binary(128), nullable=True) about_me = db.Column(db.String(140)) last_seen = db.Column(db.DateTime, default=datetime.utcnow) last_message_read_time = db.Column(db.DateTime) posts = db.relationship('Post', backref='author', lazy='dynamic') followed = db.relationship('User', secondary=followers, primaryjoin=(followers.c.follower_id == id), secondaryjoin=(followers.c.followed_id == id), backref=db.backref('followers', lazy='dynamic'), lazy='dynamic') messages_sent = db.relationship('Message', foreign_keys='Message.sender_id', backref='author', lazy='dynamic') messages_received = db.relationship('Message', foreign_keys='Message.recipient_id', backref='recipient', lazy='dynamic') notifications = db.relationship('Notification', backref='user', lazy='dynamic') def __init__(self, username, email, password=None, **kwargs): db.Model.__init__(self, username=username, email=email, **kwargs) if password: self.set_password(password) else: self.password = None def set_password(self, password): self.password = bcrypt.generate_password_hash(password) def check_password(self, value): return bcrypt.check_password_hash(self.password, value) def follow(self, user): if not self.is_following(user): self.followed.append(user) def unfollow(self, user): if self.is_following(user): self.followed.remove(user) def is_following(self, user): return self.followed.filter( followers.c.followed_id == user.id).count() > 0 def followed_posts(self): followed = Post.query.join( followers, (followers.c.followed_id == Post.user_id)).filter( followers.c.follower_id == self.id) own = Post.query.filter_by(user_id=self.id) return followed.union(own).order_by(Post.timestamp.desc()) def get_reset_password_token(self, expires_in=600): return jwt.encode( { 'reset_password': self.id, 'exp': time() + expires_in }, current_app.config['SECRET_KEY'], algorithm='HS256').decode('utf-8') def avatar(self, size): digest = md5(self.email.lower().encode('utf-8')).hexdigest() return 'https://www.gravatar.com/avatar/{}?d=identicon&s={}'.format( digest, size) def new_messages(self): last_read_time = self.last_message_read_time or datetime(1900, 1, 1) return Message.query.filter_by(recipient=self).filter( Message.timestamp > last_read_time).count() def add_notification(self, name, data): self.notifications.filter_by(name=name).delete() n = Notification(name=name, payload_json=json.dumps(data), user=self) db.session.add(n) return n @staticmethod def verify_reset_password_token(token): try: id = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=['HS256'])['reset_password'] except: return return User.query.get(id)
class Project(db.Model, HoustonModel, Timestamp): """ Projects database model. """ guid = db.Column(db.GUID, default=uuid.uuid4, primary_key=True) # pylint: disable=invalid-name title = db.Column(db.String(length=50), nullable=False) user_membership_enrollments = db.relationship( 'ProjectUserMembershipEnrollment', back_populates='project') encounter_members = db.relationship('ProjectEncounter', back_populates='project') owner_guid = db.Column(db.GUID, db.ForeignKey('user.guid'), index=True, nullable=False) owner = db.relationship('User', backref=db.backref('owned_projects')) def __repr__(self): return ('<{class_name}(' 'guid={self.guid}, ' "title='{self.title}', " 'members={self.members} ' ')>'.format(class_name=self.__class__.__name__, self=self)) @property def members(self): return [ enrollment.user for enrollment in self.user_membership_enrollments ] @property def encounters(self): return [member.encounter for member in self.encounter_members] @db.validates('title') def validate_title(self, key, title): # pylint: disable=unused-argument,no-self-use if len(title) < 3: raise ValueError('Title has to be at least 3 characters long.') return title def add_user(self, user): with db.session.begin(): self.add_user_in_context(user) def add_encounter(self, encounter): with db.session.begin(): self.add_encounter_in_context(encounter) def add_user_in_context(self, user): enrollment = ProjectUserMembershipEnrollment( project=self, user=user, ) db.session.add(enrollment) self.user_membership_enrollments.append(enrollment) def add_encounter_in_context(self, encounter): enrollment = ProjectEncounter( project=self, encounter=encounter, ) db.session.add(enrollment) self.encounter_members.append(enrollment) def remove_user_in_context(self, user): for member in self.user_membership_enrollments: if member.user == user: db.session.delete(member) break def remove_encounter_in_context(self, encounter): for member in self.encounter_members: if member.encounter == encounter: db.session.delete(member) break def delete(self): with db.session.begin(): while self.user_membership_enrollments: db.session.delete(self.user_membership_enrollments.pop()) while self.encounter_members: db.session.delete(self.encounter_members.pop()) db.session.delete(self)
class NOWApplicationIdentity(Base, AuditMixin): __tablename__ = "now_application_identity" _edit_groups = [NOW_APPLICATION_EDIT_GROUP] _edit_key = NOW_APPLICATION_EDIT_GROUP now_application_guid = db.Column(UUID(as_uuid=True), primary_key=True, server_default=FetchedValue()) now_number = db.Column(db.String) now_application_id = db.Column( db.Integer, db.ForeignKey('now_application.now_application_id')) messageid = db.Column(db.Integer) mms_cid = db.Column(db.Integer) mine_guid = db.Column(UUID(as_uuid=True), db.ForeignKey('mine.mine_guid')) mine = db.relationship('Mine', lazy='joined') permit_id = db.Column(db.Integer, db.ForeignKey('permit.permit_id')) permit = db.relationship('Permit', lazy='select') now_application = db.relationship('NOWApplication') def __repr__(self): return '<NOWApplicationIdentity %r>' % self.now_application_guid @property def now_submission(self): return Application.query.get(self.messageid) @now_submission.setter def now_submission(self, now_submission): self.messageid = now_submission.messageid @hybrid_property def mms_now_submission(self): return MMSApplication.query.filter_by(mms_cid=self.mms_cid).first() @classmethod def find_by_guid(cls, _id): try: uuid.UUID(_id, version=4) return cls.query.filter_by(now_application_guid=_id).first() except ValueError: return None @classmethod def find_by_messageid(cls, messageid): return cls.query.filter_by(messageid=messageid).first() @classmethod def find_by_now_number(cls, now_number): return cls.query.filter_by(now_number=now_number).first() @classmethod def submission_count_ytd(cls, _mine_guid, _sub_year): try: return cls.query.filter_by(mine_guid=_mine_guid).filter( cls.now_number.ilike(f'%-{_sub_year}-%')).count() except ValueError: return None @classmethod def create_now_number(cls, mine): current_year = datetime.now().strftime("%Y") number_of_now = cls.submission_count_ytd(mine.mine_guid, current_year) return f'{mine.mine_no}-{current_year}-{str(number_of_now + 1).zfill(2)}'
class Mine(AuditMixin, Base): __tablename__ = 'mine' mine_guid = db.Column(UUID(as_uuid=True), primary_key=True, server_default=FetchedValue()) mine_no = db.Column(db.String(10)) mine_name = db.Column(db.String(60), nullable=False) mine_note = db.Column(db.String(300), default='') legacy_mms_mine_status = db.Column(db.String(50)) major_mine_ind = db.Column(db.Boolean, nullable=False, default=False) deleted_ind = db.Column(db.Boolean, nullable=False, server_default=FetchedValue()) mine_region = db.Column(db.String(2), db.ForeignKey('mine_region_code.mine_region_code')) ohsc_ind = db.Column(db.Boolean, nullable=False, server_default=FetchedValue()) union_ind = db.Column(db.Boolean, nullable=False, server_default=FetchedValue()) latitude = db.Column(db.Numeric(9, 7)) longitude = db.Column(db.Numeric(11, 7)) geom = db.Column(Geometry('POINT', 3005)) mine_location_description = db.Column(db.String) # Relationships #Almost always used and 1:1, so these are 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') #Almost always used, but faster to use selectin to load related data mine_permit = db.relationship('Permit', backref='mine', order_by='desc(Permit.create_timestamp)', lazy='selectin') mine_type = db.relationship( 'MineType', backref='mine', order_by='desc(MineType.update_timestamp)', primaryjoin= "and_(MineType.mine_guid == Mine.mine_guid, MineType.active_ind==True)", lazy='selectin') mine_documents = db.relationship( 'MineDocument', backref='mine', primaryjoin= "and_(MineDocument.mine_guid == Mine.mine_guid, MineDocument.active_ind==True)", lazy='select') mine_party_appt = db.relationship('MinePartyAppointment', backref="mine", lazy='select') mine_incidents = db.relationship('MineIncident', backref="mine", lazy='select') mine_reports = db.relationship('MineReport', backref="mine", lazy='select') def __repr__(self): return '<Mine %r>' % self.mine_guid @reconstructor def init_on_load(self): if self.latitude and self.longitude: try: self.utm_values = utm.from_latlon(self.latitude, self.longitude) except utm.error.OutOfRangeError: self.utm_values = () @hybrid_property def utm_easting(self): return self.utm_values[0] if self.utm_values else None @hybrid_property def utm_northing(self): return self.utm_values[1] if self.utm_values else None @hybrid_property def utm_zone_number(self): return self.utm_values[2] if self.utm_values else None @hybrid_property def utm_zone_letter(self): return self.utm_values[3] if self.utm_values else None @hybrid_property def mine_location(self): return { 'latitude': self.latitude, 'longitude': self.longitude, 'utm_easting': self.utm_easting, 'utm_northing': self.utm_northing, 'utm_zone_number': self.utm_zone_number, 'utm_zone_letter': self.utm_zone_letter, 'mine_location_description': self.mine_location_description } @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).filter_by( deleted_ind=False).first() except ValueError: return None @classmethod def find_by_mine_no(cls, _id): return cls.query.filter_by(mine_no=_id).filter_by( deleted_ind=False).first() @classmethod def find_by_mine_name(cls, term=None): MINE_LIST_RESULT_LIMIT = 50 if term: name_filter = Mine.mine_name.ilike('%{}%'.format(term)) mines_q = Mine.query.filter(name_filter).filter_by( deleted_ind=False) mines = mines_q.limit(MINE_LIST_RESULT_LIMIT).all() else: mines = Mine.query.limit(MINE_LIST_RESULT_LIMIT).all() return mines @classmethod def find_by_name_no_permit(cls, term=None): MINE_LIST_RESULT_LIMIT = 50 if term: name_filter = Mine.mine_name.ilike('%{}%'.format(term)) number_filter = Mine.mine_no.ilike('%{}%'.format(term)) permit_filter = Permit.permit_no.ilike('%{}%'.format(term)) mines_q = Mine.query.filter(name_filter | number_filter).filter_by( deleted_ind=False) permit_q = Mine.query.join(Permit).filter(permit_filter) mines = mines_q.union(permit_q).limit(MINE_LIST_RESULT_LIMIT).all() else: mines = Mine.query.limit(MINE_LIST_RESULT_LIMIT).all() return mines @classmethod def find_all_major_mines(cls): return cls.query.filter_by(major_mine_ind=True).filter_by( deleted_ind=False).all() @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, add_to_session=True, ohsc_ind=None, union_ind=None): mine = cls(mine_guid=uuid.uuid4(), mine_no=mine_no, mine_name=mine_name, major_mine_ind=mine_category, mine_region=mine_region, ohsc_ind=ohsc_ind, union_ind=union_ind) if add_to_session: 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): mine_note = mine_note if mine_note else '' 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): mine_no = mine_no if mine_no else '' if mine_no and len(mine_no) > 10: raise AssertionError('Mine number must not exceed 10 characters.') return mine_no @validates('mine_region') def validate_mine_region(self, key, mine_region): if not mine_region: raise AssertionError('No mine region code provided.') if len(mine_region) > 2: raise AssertionError('Invalid region code') return mine_region
class User(AppModel): __tablename__ = 'auth_users' description = None username = db.Column(db.String(64), unique=True, index=True) password_hash = db.Column(db.String(128)) email = db.Column(db.String(64), unique=True, index=True) active = db.Column(db.Boolean, default=True) confirmed = db.Column(db.Boolean, default=False) confirmed_at = db.Column(db.DateTime()) last_login_at = db.Column(db.DateTime()) last_login_ip = db.Column(INET) login_count = db.Column(db.Integer, default=0) roles = db.relationship('Role', secondary='auth_users_roles', backref=db.backref('users', lazy='dynamic')) @classmethod def create_with_role(cls, username, password, email, role, **kwargs): new_user = cls(username=username, password=password, email=email, **kwargs) role = Role.get_by(name=role) new_user.roles.append(role) db.session.add(new_user) db.session.commit() return new_user @property def password(self): raise AttributeError('password is not a readable attribute') @password.setter def password(self, password): self.password_hash = pwd_ctx.encrypt(password) def verify_password(self, password): return pwd_ctx.verify(password, self.password_hash) def generate_auth_token(self, expiration): s = Serializer(current_app.config.get('SECRET_KEY'), expires_in=int(expiration)) return s.dumps({'id': self.id}) @staticmethod def verify_auth_token(token): s = Serializer(current_app.config.get('SECRET_KEY')) try: data = s.loads(token) except SignatureExpired: return None # valid token, but expired except BadSignature: return None # invalid token user_id = data.get('id') if not user_id: return None return User.query.get(user_id) def generate_email_token(self, expiration): s = Serializer(current_app.config.get('SECRET_KEY'), expires_in=int(expiration)) return s.dumps({'email': self.email}) @staticmethod def confirm(token): s = Serializer(current_app.config.get('SECRET_KEY')) try: data = s.loads(token) except (BadSignature, SignatureExpired): return False user = db.session.query(User).filter_by( email=data.get('email')).first() if not user or user.confirmed: return False user.confirmed = True user.confirmed_at = datetime.now() db.session.add(user) db.session.commit() return True def generate_reset_token(self, expiration=3600): s = Serializer(current_app.config.get('SECRET_KEY'), int(expiration)) return s.dumps({'reset': self.id}) @staticmethod def verify_reset_password_token(token): s = Serializer(current_app.config.get('SECRET_KEY')) try: data = s.loads(token) except (BadSignature, SignatureExpired): return False return db.session.query(User).filter_by(id=data.get('reset')).first() def generate_email_change_token(self, new_email, expiration=3600): s = Serializer(current_app.config.get('SECRET_KEY'), int(expiration)) return s.dumps({'change_email': self.id, 'new_email': new_email}) @staticmethod def change_email(token): s = Serializer(current_app.config.get('SECRET_KEY')) try: data = s.loads(token) except (BadSignature, SignatureExpired): return False user = db.session.query(User).filter_by( email=data.get('new_email')).first() if not user or user.confirmed: return False user.confirmed = True user.confirmed_at = datetime.now() db.session.add(user) db.session.commit() return True def can(self, permissions): return self.role is not None and \ (self.role.permissions & permissions) == permissions def is_administrator(self): return self.can(Permission.ADMINISTER) def logged_in(self, commit=True): self.last_login_at = datetime.now() self.last_login_ip = request.remote_addr self.login_count += 1 if commit: db.session.commit() def list_roles_names(self): return [role.name for role in self.roles] def add_role(self, role_name, commit=True): new_role = Role.get_by(name=role_name) if new_role: self.roles.append(new_role) if commit: db.session.commit() return True return False def remove_role(self, role_name, commit=True): if role_name not in self.list_roles_names(): return False if len(self.roles) == 1: return False for i, role in enumerate(self.roles): if role.name == role_name: self.roles.pop(i) break if commit: db.session.commit() return True def export_data(self, exclude=None): response = super().export_data(exclude=exclude) roles = list() for role in self.roles: roles.append(role.export_data(exclude=exclude)) response.update({'roles': roles}) return response def set_active(self, commit=True): self.active = True if commit: db.session.commit() def set_inactive(self, commit=True): self.active = False if commit: db.session.commit() def set_confirmed(self, commit=True): self.confirmed = True if commit: db.session.commit() def set_not_confirmed(self, commit=True): self.confirmed = False if commit: db.session.commit() @classmethod def is_valid_username(cls, username): return User.get_by(username=username) is None @classmethod def is_valid_email(cls, email): return User.get_by(email=email) is None @classmethod def remove_fake(cls, item): max_user_role_id = UserRole.get_max_id() count = len(item.roles) super().remove_fake(item) UserRole.set_sequence_value(value=max_user_role_id - count)
class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(64), index=True) email = db.Column(db.String(120), index=True, unique=True) password_hash = db.Column(db.String(128)) towers = db.relationship("UserTowerRelation", back_populates="user") joined = db.Column(db.Date, default=date.today) token = db.Column(db.String(32), index=True, unique=True) token_expiration = db.Column(db.DateTime) donation_thank_you = db.Column(db.String(64), index=True) donation_badge = db.Column(db.Integer) user_settings_json = db.Column(db.String(), default="{}") def to_dict(self): data = { 'username': self.username, 'email': self.email, } return data def get_token(self, expires_in=86400): now = datetime.utcnow() if self.token and self.token_expiration > now + timedelta(seconds=60): return self.token self.token = base64.b64encode(os.urandom(24)).decode('utf-8') self.token_expiration = now + timedelta(seconds=expires_in) db.session.commit() return self.token def revoke_token(self): self.token_expiration = datetime.utcnow() - timedelta(seconds=1) @staticmethod def check_token(token): user = User.query.filter_by(token=token).first() if user is None or user.token_expiration < datetime.utcnow(): return None return user @property def badge(self): try: return { 0: 'badge-tower.png', 1: 'badge-hand.png' }[self.donation_badge] except KeyError: return None def __repr__(self): return '<User {}>'.format(self.username) def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) def _clean_recent_towers(self, cutoff=10): # delete all but the cuttoff most recent towers old_rels = sorted([tower for tower in self.towers if tower.recent], key=lambda x: x.visited, reverse=True)[cutoff:] for rel in old_rels: db.session.delete(rel) def get_reset_password_token(self, expires_in=86400): return jwt.encode( { 'reset_password': self.id, 'exp': time() + expires_in }, Config.SECRET_KEY, algorithm='HS256').decode('utf-8') @staticmethod def verify_reset_password_token(token): try: id = jwt.decode(token, Config.SECRET_KEY, algorithms=['HS256'])['reset_password'] except BaseException: return return User.query.get(id) def _get_relation_to_tower(self, tower): # Helper function: returns a relation between the user and the tower. # Creates the relation if none existed before. if isinstance(tower, Tower): # cast to TowerDB tower = tower.to_TowerDB() # See if a relation already exists rel = UserTowerRelation.query.filter( UserTowerRelation.user == self, UserTowerRelation.tower == tower).first() if not rel: # Just creating this is enough to add it to the database with # relevant relations rel = UserTowerRelation(user=self, tower=tower) return rel def clear_all_towers(self): for rel in self.towers: db.session.delete(rel) def add_recent_tower(self, tower): rel = self._get_relation_to_tower(tower) # Update the timestamp (and recent, if necessary) rel.recent = True rel.visited = datetime.now() # self._clean_recent_towers() # no reason to do this now that the # my_towers page exists db.session.commit() def remove_recent_tower(self, tower): rel = self._get_relation_to_tower(tower) rel.recent = False db.session.commit() def toggle_bookmark(self, tower): rel = self._get_relation_to_tower(tower) rel.bookmark = not rel.bookmark db.session.commit() def recent_towers(self, n=0): # Allows you to limit to n items; returns all by default # This returns a list of TowerDB objects — if we want to convert them # to memory, that should # happen by looking them up in the TowerDict instance n = n or len(self.towers) return [ rel.tower for rel in sorted( self.towers, key=lambda r: r.visited, reverse=True) if rel.recent ][:n] def bookmarked_towers(self, n=0): # Allows you to limit to n items; returns all by default # This returns a list of TowerDB objects — if we want to convert them # to memory, that should # happen by looking them up in the TowerDict instance n = n or len(self.towers) return [rel.tower for rel in self.towers if rel.bookmark][:n] def bookmarked(self, tower_id): # checks if a tower_id is bookmarked return tower_id in [ rel.tower.tower_id for rel in self.towers if rel.bookmark ] @property def tower_properties(self): # For the my_towers page, we need the tower relations as a list of # dictionaries, which each include the tower info + the relation info tower_properties = [] for rel in sorted(self.towers, key=lambda x: x.visited, reverse=True): tower_properties.append( dict( { 'tower_id': rel.tower.tower_id, 'tower_url': rel.tower.url_safe_name, 'tower_name': rel.tower.tower_name }, **rel.relation_dict)) return tower_properties def check_permissions(self, tower_id, permission): # Given a tower_id: check if the user has relevant permissions # 'creator': can edit settings # 'host': can manage practices in host mode if permission not in ['creator', 'host']: raise KeyError('The requested permission type does not exist.') return tower_id in [ int(t.tower_id) for t in self.towers if getattr(t, permission) ] def make_host(self, tower): rel = self._get_relation_to_tower(tower) rel.host = True if not isinstance(tower, Tower): tower = tower.to_Tower() tower.add_host_id(self.id) db.session.commit() def remove_host(self, tower): rel = self._get_relation_to_tower(tower) rel.host = False if not isinstance(tower, Tower): tower = tower.to_Tower() try: tower.remove_host_id(self.id) except ValueError: pass db.session.commit() @property def user_settings(self): # Parse user settings from json to dict user_settings = defaultdict(dict) try: user_settings.update(json.loads(self.user_settings_json)) except TypeError: pass return user_settings def get_settings_with_defaults(self): try: user_settings = json.loads(self.user_settings_json) except TypeError: user_settings = {} merged_dict = {} for key, val in Config.DEFAULT_SETTINGS.items(): merged_dict[key] = val.copy() if key in user_settings: merged_dict[key].update(user_settings[key]) return merged_dict @user_settings.setter def user_settings(self, update): self.user_settings_json = json.dumps(update) db.session.commit() def reset_category(self, category): user_settings = json.loads(self.user_settings_json) user_settings[category] = {} self.user_settings_json = json.dumps(user_settings) db.session.commit() def reset_keybinding(self, setting): user_settings = json.loads(self.user_settings_json) if setting in user_settings['keybindings']: del user_settings['keybindings'][setting] for keybinding in Config.DEFAULT_SETTINGS['keybindings'][setting]: for val in user_settings['keybindings'].values(): if keybinding in val: val.remove(keybinding) self.user_settings_json = json.dumps(user_settings) db.session.commit()
class ApplicationNDA(Base): __tablename__ = "application_nda" __table_args__ = {"schema": "now_submissions"} class _ModelSchema(Base._ModelSchema): application_nda_guid = fields.String(dump_only=True) mine_guid = fields.String(dump_only=True) status = FieldTemplate(field=fields.String, one_of='NOWApplicationStatus_description') messageid = db.Column(db.Integer, primary_key=True) application_nda_guid = db.Column(UUID(as_uuid=True), nullable=False, server_default=FetchedValue()) mine_guid = db.Column(UUID(as_uuid=True), db.ForeignKey('mine.mine_guid')) trackingnumber = db.Column(db.Integer) applicationtype = db.Column(db.String) status = db.Column(db.String) submitteddate = db.Column(db.DateTime) receiveddate = db.Column(db.DateTime) applicantclientid = db.Column( db.Integer, db.ForeignKey('now_submissions.client.clientid')) submitterclientid = db.Column( db.Integer, db.ForeignKey('now_submissions.client.clientid')) typedeemedauthorization = db.Column(db.String) permitnumber = db.Column(db.String) minenumber = db.Column(db.String) nownumber = db.Column(db.String) planactivitiesdrillprogram = db.Column(db.String) planactivitiesipsurvey = db.Column(db.String) proposedstartdate = db.Column(db.DateTime) proposedenddate = db.Column(db.DateTime) totallinekilometers = db.Column(db.Integer) descplannedactivities = db.Column(db.String) proposednewenddate = db.Column(db.DateTime) reasonforextension = db.Column(db.String) anyotherinformation = db.Column(db.String) vfcbcapplicationurl = db.Column(db.String) messagecreateddate = db.Column(db.DateTime) processed = db.Column(db.String) processeddate = db.Column(db.DateTime) nrsosapplicationid = db.Column(db.String) originating_system = db.Column(db.String) mine = db.relationship( 'Mine', lazy='joined', uselist=False, primaryjoin='Mine.mine_guid==ApplicationNDA.mine_guid', foreign_keys=mine_guid) applicant = db.relationship('Client', uselist=False, lazy='select', foreign_keys=[applicantclientid]) submitter = db.relationship('Client', uselist=False, lazy='select', foreign_keys=[submitterclientid]) documents = db.relationship('DocumentNDA', lazy='select') def __repr__(self): return '<ApplicationNDA %r>' % self.messageid @classmethod def find_by_messageid(cls, messageid): return cls.query.filter_by(messageid=messageid).first()
def getAdminBugPostView(): #auto join user BugPost.user = db.relationship("User", uselist=False, lazy='joined') return AdminBugPostView(BugPost, db.session)
def getAdminEmailView(): # auto join user Email.user = db.relationship("User", uselist=False, lazy="joined") return AdminEmailView(Email, db.session)