class WorkflowLibraryModel(db.Model): __tablename__ = 'workflow_library' id = db.Column(db.Integer, primary_key=True) workflow_spec_id = db.Column(db.String, db.ForeignKey('workflow_spec.id'), nullable=True) library_spec_id = db.Column(db.String, db.ForeignKey('workflow_spec.id'), nullable=True) parent = db.relationship(WorkflowSpecModel, primaryjoin=workflow_spec_id==WorkflowSpecModel.id, backref=backref('libraries',cascade='all, delete')) library = db.relationship(WorkflowSpecModel,primaryjoin=library_spec_id==WorkflowSpecModel.id, backref=backref('parents',cascade='all, delete'))
class ApprovalFile(db.Model): file_data_id = db.Column(db.Integer, db.ForeignKey(FileDataModel.id), primary_key=True) approval_id = db.Column(db.Integer, db.ForeignKey("approval.id"), primary_key=True) approval = db.relationship("ApprovalModel") file_data = db.relationship(FileDataModel)
class WorkflowModel(db.Model): __tablename__ = 'workflow' id = db.Column(db.Integer, primary_key=True) bpmn_workflow_json = db.Column(db.JSON) status = db.Column(db.Enum(WorkflowStatus)) study_id = db.Column(db.Integer, db.ForeignKey('study.id')) study = db.relationship("StudyModel", backref='workflow') workflow_spec_id = db.Column(db.String, db.ForeignKey('workflow_spec.id')) workflow_spec = db.relationship("WorkflowSpecModel") total_tasks = db.Column(db.Integer, default=0) completed_tasks = db.Column(db.Integer, default=0) last_updated = db.Column(db.DateTime(timezone=True), server_default=func.now()) user_id = db.Column(db.String, default=None)
class StudyModel(db.Model): __tablename__ = 'study' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String) short_title = db.Column(db.String, nullable=True) last_updated = db.Column(db.DateTime(timezone=True), server_default=func.now()) status = db.Column(db.Enum(StudyStatus)) progress_status = db.Column(db.Enum(ProgressStatus)) irb_status = db.Column(db.Enum(IrbStatus)) primary_investigator_id = db.Column(db.String, nullable=True) sponsor = db.Column(db.String, nullable=True) ind_number = db.Column(db.String, nullable=True) user_uid = db.Column(db.String, db.ForeignKey('user.uid'), nullable=False) investigator_uids = db.Column(db.ARRAY(db.String), nullable=True) requirements = db.Column(db.ARRAY(db.Integer), nullable=True) on_hold = db.Column(db.Boolean, default=False) enrollment_date = db.Column(db.DateTime(timezone=True), nullable=True) #events = db.relationship("TaskEventModel") events_history = db.relationship("StudyEvent", cascade="all, delete, delete-orphan") short_name = db.Column(db.String, nullable=True) proposal_name = db.Column(db.String, nullable=True) def update_from_protocol_builder(self, study: ProtocolBuilderCreatorStudy, user_id): self.title = study.TITLE self.user_uid = user_id self.last_updated = study.DATELASTMODIFIED self.irb_status = IrbStatus.incomplete_in_protocol_builder
class LookupFileModel(db.Model): """Gives us a quick way to tell what kind of lookup is set on a form field. Connected to the file data model, so that if a new version of the same file is created, we can update the listing.""" __tablename__ = 'lookup_file' id = db.Column(db.Integer, primary_key=True) workflow_spec_id = db.Column(db.String) task_spec_id = db.Column(db.String) field_id = db.Column(db.String) is_ldap = db.Column( db.Boolean) # Allows us to run an ldap query instead of a db lookup. file_model_id = db.Column(db.Integer, db.ForeignKey('file.id')) last_updated = db.Column(db.DateTime(timezone=True)) dependencies = db.relationship("LookupDataModel", lazy="select", backref="lookup_file_model", cascade="all, delete, delete-orphan") file_model = db.relationship("FileModel")
class WorkflowSpecDependencyFile(db.Model): """Connects a workflow to the version of the specification files it depends on to execute""" file_data_id = db.Column(db.Integer, db.ForeignKey(FileDataModel.id), primary_key=True) workflow_id = db.Column(db.Integer, db.ForeignKey("workflow.id"), primary_key=True) file_data = db.relationship(FileDataModel)
class StudyEvent(db.Model): __tablename__ = 'study_event' id = db.Column(db.Integer, primary_key=True) study_id = db.Column(db.Integer, db.ForeignKey(StudyModel.id), nullable=False) study = db.relationship(StudyModel, back_populates='events_history') create_date = db.Column(db.DateTime(timezone=True), server_default=func.now()) status = db.Column(db.Enum(StudyStatus)) comment = db.Column(db.String, default='') event_type = db.Column(db.Enum(StudyEventType)) user_uid = db.Column(db.String, db.ForeignKey('user.uid'), nullable=True)
class FileDataModel(db.Model): __tablename__ = 'file_data' id = db.Column(db.Integer, primary_key=True) md5_hash = db.Column(UUID(as_uuid=True), unique=False, nullable=False) data = deferred(db.Column( db.LargeBinary)) # Don't load it unless you have to. version = db.Column(db.Integer, default=0) date_created = db.Column(db.DateTime(timezone=True), default=func.now()) file_model_id = db.Column(db.Integer, db.ForeignKey('file.id')) file_model = db.relationship("FileModel", foreign_keys=[file_model_id])
class WorkflowSpecModel(db.Model): __tablename__ = 'workflow_spec' id = db.Column(db.String, primary_key=True) display_name = db.Column(db.String) display_order = db.Column(db.Integer, nullable=True) description = db.Column(db.Text) category_id = db.Column(db.Integer, db.ForeignKey('workflow_spec_category.id'), nullable=True) category = db.relationship("WorkflowSpecCategoryModel") is_master_spec = db.Column(db.Boolean, default=False) standalone = db.Column(db.Boolean, default=False) library = db.Column(db.Boolean, default=False)
class WorkflowModel(db.Model): __tablename__ = 'workflow' id = db.Column(db.Integer, primary_key=True) bpmn_workflow_json = db.Column(db.JSON) status = db.Column(db.Enum(WorkflowStatus)) study_id = db.Column(db.Integer, db.ForeignKey('study.id')) study = db.relationship("StudyModel", backref='workflow') workflow_spec_id = db.Column(db.String, db.ForeignKey('workflow_spec.id')) workflow_spec = db.relationship("WorkflowSpecModel") total_tasks = db.Column(db.Integer, default=0) completed_tasks = db.Column(db.Integer, default=0) last_updated = db.Column(db.DateTime) # Order By is important or generating hashes on reviews. dependencies = db.relationship( WorkflowSpecDependencyFile, cascade="all, delete, delete-orphan", order_by="WorkflowSpecDependencyFile.file_data_id") def spec_version(self): dep_ids = list(dep.file_data_id for dep in self.dependencies) return "-".join(str(dep_ids))
class StudyAssociated(db.Model): """ This model allows us to associate people with a study, and optionally give them edit access. This allows us to create a table with PI, D_CH, etc. and give access to people other than the study owner. Task_Events will still work as they have previously """ __tablename__ = 'study_associated_user' id = db.Column(db.Integer, primary_key=True) study_id = db.Column(db.Integer, db.ForeignKey(StudyModel.id), nullable=False) uid = db.Column(db.String, db.ForeignKey('ldap_model.uid'), nullable=False) role = db.Column(db.String, nullable=True) send_email = db.Column(db.Boolean, nullable=True) access = db.Column(db.Boolean, nullable=True) ldap_info = db.relationship(LdapModel)
class ApprovalModel(db.Model): __tablename__ = 'approval' id = db.Column(db.Integer, primary_key=True) study_id = db.Column(db.Integer, db.ForeignKey(StudyModel.id), nullable=False) study = db.relationship(StudyModel) workflow_id = db.Column(db.Integer, db.ForeignKey(WorkflowModel.id), nullable=False) workflow = db.relationship(WorkflowModel) approver_uid = db.Column( db.String ) # Not linked to user model, as they may not have logged in yet. status = db.Column(db.String) message = db.Column(db.String, default='') date_created = db.Column(db.DateTime(timezone=True), default=func.now()) date_approved = db.Column(db.DateTime(timezone=True), default=None) version = db.Column( db.Integer) # Incremented integer, so 1,2,3 as requests are made. approval_files = db.relationship(ApprovalFile, back_populates="approval", cascade="all, delete, delete-orphan", order_by=ApprovalFile.file_data_id)
class EmailModel(db.Model): __tablename__ = 'email' id = db.Column(db.Integer, primary_key=True) subject = db.Column(db.String) sender = db.Column(db.String) recipients = db.Column(db.String) cc = db.Column(db.String, nullable=True) bcc = db.Column(db.String, nullable=True) content = db.Column(db.String) content_html = db.Column(db.String) study_id = db.Column(db.Integer, db.ForeignKey(StudyModel.id), nullable=True) timestamp = db.Column(db.DateTime(timezone=True), default=func.now()) workflow_spec_id = db.Column(db.String, nullable=True) study = db.relationship(StudyModel)
class UserModel(db.Model): __tablename__ = 'user' id = db.Column(db.Integer, primary_key=True) uid = db.Column(db.String, db.ForeignKey('ldap_model.uid'), unique=True) ldap_info = db.relationship("LdapModel") def is_admin(self): # Currently admin abilities are set in the configuration, but this # may change in the future. return self.uid in app.config['ADMIN_UIDS'] def encode_auth_token(self): """ Generates the Auth Token :return: string """ hours = float(app.config['TOKEN_AUTH_TTL_HOURS']) payload = { # 'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=hours, minutes=0, seconds=0), # 'iat': datetime.datetime.utcnow(), 'sub': self.uid } return jwt.encode( payload, app.config.get('SECRET_KEY'), algorithm='HS256', ) @staticmethod def decode_auth_token(auth_token): """ Decodes the auth token :param auth_token: :return: integer|string """ try: payload = jwt.decode(auth_token, app.config.get('SECRET_KEY'), algorithms='HS256') return payload except jwt.ExpiredSignatureError: raise ApiError('token_expired', 'The Authentication token you provided expired and must be renewed.') except jwt.InvalidTokenError: raise ApiError('token_invalid', 'The Authentication token you provided is invalid. You need a new token. ')