def _call_fut(self, *args, **kw):
     from occams_forms.renderers import apply_data
     return apply_data(*args, **kw)
Exemple #2
0
def form(context, request):
    """
    XXX: Cannot merge into single view
        because of the way patient forms are handled
    """
    db_session = request.db_session

    patient = context.__parent__.__parent__
    schema = context.schema

    (is_phi, ) = (db_session.query(
        db_session.query(models.patient_schema_table).filter_by(
            schema_id=schema.id).exists()).one())

    if not is_phi:
        previous_url = request.current_route_path(
            _route_name='studies.patient_forms')
        show_metadata = True
        # We cannot determine which study this form will be applied to
        # so just use any version from active studies
        available_schemata = (db_session.query(datastore.Schema).join(
            models.study_schema_table).join(models.Study).filter(
                datastore.Schema.name == context.schema.name).filter(
                    datastore.Schema.publish_date != sa.null()).filter(
                        datastore.Schema.retract_date == sa.null()))
        allowed_versions = sorted(
            set(s.publish_date for s in available_schemata))
    else:
        previous_url = request.current_route_path(
            _route_name='studies.patient')
        show_metadata = False
        allowed_versions = None

    if request.has_permission('retract'):
        transition = modes.ALL
    elif request.has_permission('transition'):
        transition = modes.AVAILABLE
    else:
        transition = modes.AUTO

    Form = make_form(
        db_session,
        context.schema,
        entity=context,
        show_metadata=show_metadata,
        transition=transition,
        allowed_versions=allowed_versions,
    )

    form = Form(request.POST, data=entity_data(context))

    if request.method == 'POST':
        if not request.has_permission('edit', context):
            raise HTTPForbidden()
        if form.validate():
            upload_dir = request.registry.settings['studies.blob.dir']
            apply_data(db_session, context, form.data, upload_dir)
            db_session.flush()
            request.session.flash(
                _(u'Changes saved to: %s' % context.schema.title), 'success')
            return HTTPFound(location=previous_url)

    return {
        'phi':
        get_phi_entities(patient, request),
        'patient':
        view_json(patient, request),
        'form':
        render_form(form,
                    disabled=not request.has_permission('edit'),
                    cancel_url=previous_url,
                    attr={
                        'method': 'POST',
                        'action': request.current_route_path(),
                        'role': 'form'
                    }),
    }
 def _call_fut(self, *args, **kw):
     from occams_forms.renderers import apply_data
     return apply_data(*args, **kw)
def terminate_ajax(context, request):
    db_session = request.db_session
    try:
        entity = (
            db_session.query(datastore.Entity)
            .join(datastore.Entity.schema)
            .filter(datastore.Schema.name.in_(
                # Only search for forms being used as temrination forms
                db_session.query(datastore.Schema.name)
                .join(models.Study.termination_schema)
                .subquery()))
            .join(datastore.Context)
            .filter_by(external='enrollment', key=context.id)
            .one())
    except orm.exc.MultipleResultsFound:
        raise Exception('Should only have one...')
    except orm.exc.NoResultFound:
        schema = context.study.termination_schema
        entity = datastore.Entity(schema=schema)
        # XXX: This is really bad form as we're applying
        # side-effects to a GET request, but there is no time
        # to make this look prety...
        # If you remove this line you will be creating random termination
        # entries...
        context.entities.add(entity)
    else:
        schema = entity.schema

    if not entity.state:
        entity.state = (
            db_session.query(datastore.State)
            .filter_by(name='pending-entry')
            .one())

    if 'termination_date' not in schema.attributes:
        msg = 'There is no "termination_date" configured on: {}'
        log.warn(msg.format(schema.name))

    if request.has_permission('retract'):
        transition = modes.ALL
    elif request.has_permission('transition'):
        transition = modes.AVAILABLE
    else:
        transition = modes.AUTO

    Form = make_form(
        db_session, schema,
        entity=entity, transition=transition, show_metadata=False)

    form = Form(request.POST, data=entity_data(entity))

    def validate_termination_date(form, field):
        if not (field.data >= context.latest_consent_date):
            raise wtforms.ValidationError(request.localizer.translate(
                _(u'Termination must be on or after latest consent (${date})'),
                mapping={'date': context.latest_consent_date}
            ))

    # Inject a validator into the termination form so that we
    # ensure that the termination date provided is valid
    form.termination_date.validators.append(validate_termination_date)

    if request.method == 'POST':
        check_csrf_token(request)
        if form.validate():
            if not entity.id:
                # changing termination version *should* not be
                # allowed, just assign the schema that's already being used
                context.entities.add(entity)
            upload_dir = request.registry.settings['studies.blob.dir']
            apply_data(db_session, entity, form.data, upload_dir)
            context.termination_date = form.termination_date.data
            db_session.flush()
            return HTTPOk(json=view_json(context, request))
        else:
            return HTTPBadRequest(json={'errors': wtferrors(form)})

    return render_form(
        form,
        cancel_url=request.current_route_path(_route_name='studies.patient'),
        attr={
            'method': 'POST',
            'action': request.current_route_path(),
            'role': 'form',
            'data-bind': 'formentry: {}, submit: $root.terminateEnrollment'
        }
    )
Exemple #5
0
def apply_direct_mappings(task):
    # get all the direct mappings for processing
    mappings = (
        Session.query(models.Mapping)
        .filter_by(type=u'direct').all()
    )

    default_state = (
        Session.query(datastore.State)
        .filter_by(name='pending-entry')
        .one()
    )

    redis = app.redis
    total_mappings = len(mappings)

    count = 0

    mappings_id = six.text_type(str(uuid.uuid4()))

    redis.hmset(mappings_id, {
        'count': count,
        'total': total_mappings
    })

    for mapping in mappings:

        source_schema_name = mapping.logic['source_schema']
        source_schema_publish_date = mapping.logic['source_schema_publish_date']
        source_variable = mapping.logic['source_variable']

        target_schema_name = mapping.logic['target_schema']
        target_schema_publish_date = mapping.logic['target_schema_publish_date']
        target_variable = mapping.logic['target_variable']

        # get records that have a matching schema for source schema
        records = (
            Session.query(models.SiteData)
            .filter(
                models.SiteData.data['form_name'].astext == source_schema_name
            )
            .filter(
                models.SiteData.data['form_publish_date'].astext == source_schema_publish_date
            ).all()
        )

        for record in records:
            pid = record.data['pid']
            collect_date = record.data['collect_date']

            patient = (
                Session.query(studies.Patient)
                .filter_by(pid=pid)
                .one()
            )

            target_schema = (
                Session.query(datastore.Schema)
                .filter_by(name=target_schema_name)
                .filter_by(publish_date=target_schema_publish_date)
            ).one()

            # if the target schema already exists we want to add data
            # to the schema rather than creating a new entity
            entity_exists = False
            for item in patient.entities:
                if item.schema.name == target_schema_name and \
                   item.schema.publish_date.isoformat() == \
                   target_schema_publish_date:
                    entity = item
                    entity_exists = True
                    break

            if not entity_exists:
                entity = datastore.Entity(
                    schema=target_schema,
                    collect_date=collect_date,
                    state=default_state
                )

                patient.entities.add(entity)

            if mapping.logic['choices_mapping']:
                # add handling if there is no value to map
                source_key = record.data.get(source_variable)

                payload = {target_variable: source_key}
                upload_dir = tempfile.mkdtemp()
                apply_data(Session, entity, payload, upload_dir)
                shutil.rmtree(upload_dir)

            else:
                # non-choices processing
                source_key = record.data.get(source_variable)
                payload = {target_variable: source_key}
                upload_dir = tempfile.mkdtemp()
                apply_data(Session, entity, payload, upload_dir)
                shutil.rmtree(upload_dir)

        redis.hincrby(mappings_id, 'count')

        data = redis.hgetall(mappings_id)
        # redis-py returns everything as string, so we need to clean it
        for key in ('count', 'total'):
            data[key] = int(data[key])
        redis.publish('direct', json.dumps(data))
Exemple #6
0
def populate_project(
    db_session,
    project_name,
    consolidated_frame,
    pid_column=DEFAULT_PID_COLUMN,
    visit_column=DEFAULT_VISIT_COLUMN,
    collect_date_column=DEFAULT_COLLECT_DATE_COLUMN,
):
    """
    Processes a final dataframe (i.e. a frame after mappings have been applied)
    and creates entities for the target project.

    :param db_session: Current database transaction session
    :type db_session: sqlalchemy.orm.session.Session
    :param project_name: study where entities will be applied
    :type project_name: str
    :param consolidated_frame: dataframe populated with mapped variables
    :type consolidated_frame: pandas.DataFrame
    :returns: none
    """

    site = db_session.query(studies.Site).filter_by(name=project_name).one()
    project = (db_session.query(
        studies.Study).filter_by(name=project_name).one())
    default_state = (db_session.query(
        datastore.State).filter_by(name='pending-entry').one())

    for index, row in consolidated_frame.iterrows():
        pid = row['pid']

        try:
            patient = (db_session.query(
                studies.Patient).filter_by(pid=pid).one())
        except orm.exc.NoResultFound:
            patient = studies.Patient(site=site, pid=pid)
            db_session.add(patient)
            db_session.flush()

        for schema in project.schemata:

            payload = {}

            for attribute in schema.iterleafs():
                column_name = '_'.join(
                    [project.name, schema.name, attribute.name])

                if column_name not in row:
                    continue

                value = row[column_name]

                if isinstance(value, numbers.Number) and math.isnan(value):
                    continue

                payload[attribute.name] = value

            # Avoid creating empty records
            if not payload:
                continue

            calculated_collect_date_column = '_'.join(
                [project.name, schema.name, collect_date_column])
            collect_date = row[calculated_collect_date_column]

            entity = datastore.Entity(schema=schema,
                                      collect_date=collect_date,
                                      state=default_state)

            patient.entities.add(entity)

            upload_dir = tempfile.mkdtemp()
            apply_data(db_session, entity, payload, upload_dir)
            shutil.rmtree(upload_dir)
            db_session.flush()
Exemple #7
0
def form(context, request):
    """
    XXX: Cannot merge into single view
        because of the way patient forms are handled
    """
    db_session = request.db_session

    patient = context.__parent__.__parent__
    schema = context.schema

    (is_phi,) = (
        db_session.query(
            db_session.query(models.patient_schema_table)
            .filter_by(schema_id=schema.id)
            .exists())
        .one())

    if not is_phi:
        previous_url = request.current_route_path(
            _route_name='studies.patient_forms')
        show_metadata = True
        # We cannot determine which study this form will be applied to
        # so just use any version from active studies
        available_schemata = (
            db_session.query(datastore.Schema)
            .join(models.study_schema_table)
            .join(models.Study)
            .filter(datastore.Schema.name == context.schema.name)
            .filter(datastore.Schema.publish_date != sa.null())
            .filter(datastore.Schema.retract_date == sa.null()))
        allowed_versions = sorted(set(
            s.publish_date for s in available_schemata))
    else:
        previous_url = request.current_route_path(
            _route_name='studies.patient')
        show_metadata = False
        allowed_versions = None

    if request.has_permission('retract'):
        transition = modes.ALL
    elif request.has_permission('transition'):
        transition = modes.AVAILABLE
    else:
        transition = modes.AUTO

    Form = make_form(
        db_session,
        context.schema,
        entity=context,
        show_metadata=show_metadata,
        transition=transition,
        allowed_versions=allowed_versions,
    )

    form = Form(request.POST, data=entity_data(context))

    if request.method == 'POST':
        if not request.has_permission('edit', context):
            raise HTTPForbidden()
        if form.validate():
            upload_dir = request.registry.settings['studies.blob.dir']
            apply_data(db_session, context, form.data, upload_dir)
            db_session.flush()
            request.session.flash(
                _(u'Changes saved to: %s' % context.schema.title), 'success')
            return HTTPFound(location=previous_url)

    return {
        'phi': get_phi_entities(patient, request),
        'patient': view_json(patient, request),
        'form': render_form(
            form,
            disabled=not request.has_permission('edit'),
            cancel_url=previous_url,
            attr={
                'method': 'POST',
                'action': request.current_route_path(),
                'role': 'form'
            }
        ),
    }
Exemple #8
0
def populate_project(
        db_session,
        project_name,
        consolidated_frame,
        pid_column=DEFAULT_PID_COLUMN,
        visit_column=DEFAULT_VISIT_COLUMN,
        collect_date_column=DEFAULT_COLLECT_DATE_COLUMN,
        ):
    """
    Processes a final dataframe (i.e. a frame after mappings have been applied)
    and creates entities for the target project.

    :param db_session: Current database transaction session
    :type db_session: sqlalchemy.orm.session.Session
    :param project_name: study where entities will be applied
    :type project_name: str
    :param consolidated_frame: dataframe populated with mapped variables
    :type consolidated_frame: pandas.DataFrame
    :returns: none
    """

    site = db_session.query(studies.Site).filter_by(name=project_name).one()
    project = (
        db_session.query(studies.Study)
        .filter_by(name=project_name)
        .one()
    )
    default_state = (
        db_session.query(datastore.State)
        .filter_by(name='pending-entry')
        .one()
    )

    for index, row in consolidated_frame.iterrows():
        pid = row['pid']

        try:
            patient = (
                db_session.query(studies.Patient)
                .filter_by(pid=pid)
                .one()
            )
        except orm.exc.NoResultFound:
            patient = studies.Patient(site=site, pid=pid)
            db_session.add(patient)
            db_session.flush()

        for schema in project.schemata:

            payload = {}

            for attribute in schema.iterleafs():
                column_name = '_'.join([
                    project.name, schema.name, attribute.name
                ])

                if column_name not in row:
                    continue

                value = row[column_name]

                if isinstance(value, numbers.Number) and math.isnan(value):
                    continue

                payload[attribute.name] = value

            # Avoid creating empty records
            if not payload:
                continue

            calculated_collect_date_column = '_'.join([
                project.name, schema.name, collect_date_column
            ])
            collect_date = row[calculated_collect_date_column]

            entity = datastore.Entity(
                schema=schema,
                collect_date=collect_date,
                state=default_state
            )

            patient.entities.add(entity)

            upload_dir = tempfile.mkdtemp()
            apply_data(db_session, entity, payload, upload_dir)
            shutil.rmtree(upload_dir)
            db_session.flush()
Exemple #9
0
def form(context, request):
    """
    XXX: Cannot merge into single view
        because of the way patient forms are handled
    """

    db_session = request.db_session
    visit = context.__parent__.__parent__
    allowed_schemata = (db_session.query(datastore.Schema).join(
        models.study_schema_table).join(models.Study).join(
            models.Cycle).filter(
                datastore.Schema.name == context.schema.name).filter(
                    models.Cycle.id.in_([cycle.id for cycle in visit.cycles])))
    allowed_versions = [s.publish_date for s in allowed_schemata]

    if request.has_permission('retract'):
        transition = modes.ALL
    elif request.has_permission('transition'):
        transition = modes.AVAILABLE
    else:
        transition = modes.AUTO

    Form = make_form(
        db_session,
        context.schema,
        entity=context,
        show_metadata=True,
        transition=transition,
        allowed_versions=allowed_versions,
    )

    form = Form(request.POST, data=entity_data(context))

    if request.method == 'POST':

        if not request.has_permission('edit', context):
            raise HTTPForbidden()

        if form.validate():
            upload_dir = request.registry.settings['studies.blob.dir']
            apply_data(db_session, context, form.data, upload_dir)
            db_session.flush()
            request.session.flash(
                _(u'Changes saved for: ${form}',
                  mapping={'form': context.schema.title}), 'success')
            return HTTPFound(location=request.current_route_path(
                _route_name='studies.visit'))

    return {
        'visit':
        view_json(visit, request),
        'form':
        render_form(
            form,
            disabled=not request.has_permission('edit'),
            cancel_url=request.current_route_path(_route_name='studies.visit'),
            attr={
                'method': 'POST',
                'action': request.current_route_path(),
                'role': 'form'
            }),
    }
Exemple #10
0
def terminate_ajax(context, request):
    db_session = request.db_session
    try:
        entity = (
            db_session.query(datastore.Entity).join(
                datastore.Entity.schema).filter(
                    datastore.Schema.name.in_(
                        # Only search for forms being used as temrination forms
                        db_session.query(datastore.Schema.name).join(
                            models.Study.termination_schema
                        ).subquery())).join(datastore.Context).filter_by(
                            external='enrollment', key=context.id).one())
    except orm.exc.MultipleResultsFound:
        raise Exception('Should only have one...')
    except orm.exc.NoResultFound:
        schema = context.study.termination_schema
        entity = datastore.Entity(schema=schema)
        # XXX: This is really bad form as we're applying
        # side-effects to a GET request, but there is no time
        # to make this look prety...
        # If you remove this line you will be creating random termination
        # entries...
        context.entities.add(entity)
        context.patient.entities.add(entity)
    else:
        schema = entity.schema

    if not entity.state:
        entity.state = (db_session.query(
            datastore.State).filter_by(name='pending-entry').one())

    if 'termination_date' not in schema.attributes:
        msg = 'There is no "termination_date" configured on: {}'
        log.warn(msg.format(schema.name))

    if request.has_permission('retract'):
        transition = modes.ALL
    elif request.has_permission('transition'):
        transition = modes.AVAILABLE
    else:
        transition = modes.AUTO

    Form = make_form(db_session,
                     schema,
                     entity=entity,
                     transition=transition,
                     show_metadata=False)

    form = Form(request.POST, data=entity_data(entity))

    def validate_termination_date(form, field):
        if not (field.data >= context.latest_consent_date):
            raise wtforms.ValidationError(
                request.localizer.translate(_(
                    u'Termination must be on or after latest consent (${date})'
                ),
                                            mapping={
                                                'date':
                                                context.latest_consent_date
                                            }))

    # Inject a validator into the termination form so that we
    # ensure that the termination date provided is valid
    form.termination_date.validators.append(validate_termination_date)

    if request.method == 'POST':
        check_csrf_token(request)
        if form.validate():
            if not entity.id:
                # changing termination version *should* not be
                # allowed, just assign the schema that's already being used
                context.entities.add(entity)
            upload_dir = request.registry.settings['studies.blob.dir']
            apply_data(db_session, entity, form.data, upload_dir)
            context.termination_date = form.termination_date.data
            db_session.flush()
            return HTTPOk(json=view_json(context, request))
        else:
            return HTTPBadRequest(json={'errors': wtferrors(form)})

    return render_form(
        form,
        cancel_url=request.current_route_path(_route_name='studies.patient'),
        attr={
            'method': 'POST',
            'action': request.current_route_path(),
            'role': 'form',
            'data-bind': 'formentry: {}, submit: $root.terminateEnrollment'
        })
Exemple #11
0
def form(context, request):
    """
    XXX: Cannot merge into single view
        because of the way patient forms are handled
    """

    db_session = request.db_session
    visit = context.__parent__.__parent__
    allowed_schemata = (
        db_session.query(datastore.Schema)
        .join(models.study_schema_table)
        .join(models.Study)
        .join(models.Cycle)
        .filter(models.Cycle.id.in_([cycle.id for cycle in visit.cycles])))
    allowed_versions = [s.publish_date for s in allowed_schemata]

    if request.has_permission('retract'):
        transition = modes.ALL
    elif request.has_permission('transition'):
        transition = modes.AVAILABLE
    else:
        transition = modes.AUTO

    Form = make_form(
        db_session,
        context.schema,
        entity=context,
        show_metadata=True,
        transition=transition,
        allowed_versions=allowed_versions,
    )

    form = Form(request.POST, data=entity_data(context))

    if request.method == 'POST':

        if not request.has_permission('edit', context):
            raise HTTPForbidden()

        if form.validate():
            upload_dir = request.registry.settings['studies.blob.dir']
            apply_data(db_session, context, form.data, upload_dir)
            db_session.flush()
            request.session.flash(
                _(u'Changes saved for: ${form}', mapping={
                    'form': context.schema.title}),
                'success')
            return HTTPFound(location=request.current_route_path(
                _route_name='studies.visit'))

    return {
        'visit': view_json(visit, request),
        'form': render_form(
            form,
            disabled=not request.has_permission('edit'),
            cancel_url=request.current_route_path(_route_name='studies.visit'),
            attr={
                'method': 'POST',
                'action': request.current_route_path(),
                'role': 'form'
            }
        ),
    }