示例#1
0
def device_settings(study_id=None):
    study = Study.objects.get(pk=study_id)
    researcher = get_session_researcher()
    readonly = True if not researcher.check_study_admin(
        study_id) and not researcher.site_admin else False

    # if read only....
    if request.method == 'GET':
        return render_template(
            "device_settings.html",
            study=study.as_unpacked_native_python(),
            settings=study.device_settings.as_unpacked_native_python(),
            readonly=readonly,
        )

    if readonly:
        abort(403)

    params = {
        k: v
        for k, v in request.values.items()
        if not k.startswith("consent_section")
    }
    consent_sections = {
        k: v
        for k, v in request.values.items() if k.startswith("consent_section")
    }
    params = checkbox_to_boolean(CHECKBOX_TOGGLES, params)
    params = string_to_int(TIMER_VALUES, params)
    # the ios consent sections are a json field but the frontend returns something weird,
    # see the documentation in unflatten_consent_sections for details
    params["consent_sections"] = json.dumps(
        unflatten_consent_sections(consent_sections))
    study.device_settings.update(**params)
    return redirect('/edit_study/{:d}'.format(study.id))
示例#2
0
def inject_html_params():
    # these variables will be accessible to every template rendering attached to the blueprint
    return {
        "allowed_studies": get_researcher_allowed_studies(),
        "is_admin": researcher_is_an_admin(),
        "session_researcher": get_session_researcher(),
    }
示例#3
0
def interventions(study_id=None):
    study = Study.objects.get(pk=study_id)
    researcher = get_session_researcher()
    readonly = True if not researcher.check_study_admin(
        study_id) and not researcher.site_admin else False

    if request.method == 'GET':
        return render_template(
            'study_interventions.html',
            study=study,
            interventions=study.interventions.all(),
            readonly=readonly,
        )

    if readonly:
        abort(403)

    new_intervention = request.values.get('new_intervention', None)
    if new_intervention:
        intervention, _ = Intervention.objects.get_or_create(
            study=study, name=new_intervention)
        for participant in study.participants.all():
            InterventionDate.objects.get_or_create(participant=participant,
                                                   intervention=intervention)

    return redirect('/interventions/{:d}'.format(study.id))
示例#4
0
def manage_credentials():
    serializer = ApiKeySerializer(ApiKey.objects.filter(researcher=get_session_researcher()), many=True)
    return render_template(
        'manage_credentials.html',
        is_admin=researcher_is_an_admin(),
        api_keys=sorted(serializer.data, reverse=True, key=lambda x: x['created_on']),
    )
示例#5
0
def study_fields(study_id=None):
    study = Study.objects.get(pk=study_id)
    researcher = get_session_researcher()
    readonly = True if not researcher.check_study_admin(
        study_id) and not researcher.site_admin else False

    if request.method == 'GET':
        return render_template(
            'study_custom_fields.html',
            study=study,
            fields=study.fields.all(),
            readonly=readonly,
        )

    if readonly:
        return abort(403)

    new_field = request.values.get('new_field', None)
    if new_field:
        study_field, _ = StudyField.objects.get_or_create(study=study,
                                                          field_name=new_field)
        for participant in study.participants.all():
            ParticipantFieldValue.objects.create(participant=participant,
                                                 field=study_field)

    return redirect('/study_fields/{:d}'.format(study.id))
示例#6
0
def edit_researcher_page(researcher_pk):
    # Wow this got complex...
    session_researcher = get_session_researcher()
    edit_researcher = Researcher.objects.get(pk=researcher_pk)

    # site admins can edit study admins, but not other site admins.
    # (users do not edit their own passwords on this page.)
    editable_password = (
        not edit_researcher.username == session_researcher.username
        and not edit_researcher.site_admin)

    # if the session researcher is not a site admin then we need to restrict password editing
    # to only researchers that are not study_admins anywhere.
    if not session_researcher.site_admin:
        editable_password = editable_password and not edit_researcher.is_study_admin(
        )

    # edit_study_info is a list of tuples of (study relationship, whether that study is editable by
    # the current session admin, and the study itself.)
    visible_studies = session_researcher.get_visible_studies_by_name()
    if edit_researcher.site_admin:
        # if the session admin is a site admin then we can skip the complex logic
        edit_study_info = [(SITE_ADMIN, True, study)
                           for study in visible_studies]
    else:
        # When the session admin is just a study admin then we need to determine if the study that
        # the session admin can see is also one they are an admin on so we can display buttons.
        administerable_studies = set(
            get_administerable_studies_by_name().values_list("pk", flat=True))

        # We need the overlap of the edit_researcher studies with the studies visible to the session
        # admin, and we need those relationships for display purposes on the page.
        edit_study_relationship_map = {
            study_id: relationship.replace("_", " ").title()
            for study_id, relationship in edit_researcher.study_relations.
            filter(study__in=visible_studies).values_list(
                "study_id", "relationship")
        }

        # get the relevant studies, populate with relationship, editability, and the study.
        edit_study_info = []
        for study in visible_studies.filter(
                pk__in=edit_study_relationship_map.keys()):
            edit_study_info.append((
                edit_study_relationship_map[study.id],
                study.id in administerable_studies,
                study,
            ))

    return render_template(
        'edit_researcher.html',
        edit_researcher=edit_researcher,
        edit_study_info=edit_study_info,
        all_studies=get_administerable_studies_by_name(
        ),  # this is all the studies administerable by the user
        editable_password=editable_password,
        redirect_url='/edit_researcher/{:s}'.format(researcher_pk),
        is_self=edit_researcher.id == session_researcher.id,
    )
示例#7
0
def get_session_researcher_study_ids():
    """ Returns the appropriate study ids based on whether a user is a study or site admin """
    session_researcher = get_session_researcher()
    if session_researcher.site_admin:
        return Study.objects.exclude(deleted=True).values_list("id", flat=True)
    else:
        return session_researcher.study_relations.filter(
            study__deleted=False).values_list("study__id", flat=True)
示例#8
0
def get_administerable_studies_by_name():
    """ Site admins see all studies, study admins see only studies they are admins on. """
    researcher_admin = get_session_researcher()
    if researcher_admin.site_admin:
        studies = Study.get_all_studies_by_name()
    else:
        studies = researcher_admin.get_administered_studies_by_name()
    return studies
示例#9
0
def get_administerable_researchers():
    """ Site admins see all researchers, study admins see researchers on their studies. """
    researcher_admin = get_session_researcher()
    if researcher_admin.site_admin:
        relevant_researchers = Researcher.filter_alphabetical()
    else:
        relevant_researchers = researcher_admin.get_administered_researchers_by_username(
        )
    return relevant_researchers
示例#10
0
def delete_researcher(researcher_id):
    # only site admins can delete researchers from the system.
    session_researcher = get_session_researcher()
    if not session_researcher.site_admin:
        return abort(403)

    try:
        researcher = Researcher.objects.get(pk=researcher_id)
    except Researcher.DoesNotExist:
        return abort(404)

    StudyRelation.objects.filter(researcher=researcher).delete()
    researcher.delete()
    return redirect('/manage_researchers')
def pipeline_download_page():
    warn_researcher_if_hasnt_yet_generated_access_key(get_session_researcher())
    # FIXME clean this up.
    # it is a bit obnoxious to get this data, we need to deduplcate it and then turn it back into a list
    tags_by_study = {
        study['id']: list(
            set(
                PipelineUploadTags.objects.filter(
                    pipeline_upload__study__id=study['id']).values_list(
                        "tag", flat=True)))
        for study in get_researcher_allowed_studies()
    }
    return render_template(
        "data_pipeline_web_form.html",
        tags_by_study=tags_by_study,
        downloadable_studies=get_researcher_allowed_studies(),
    )
示例#12
0
def edit_custom_field(study_id=None):
    """Edits the name of a Custom field. Expects field_id anf edit_custom_field in request body"""

    study = Study.objects.get(pk=study_id)
    researcher = get_session_researcher()
    readonly = True if not researcher.check_study_admin(
        study_id) and not researcher.site_admin else False
    if readonly:
        return abort(403)

    field_id = request.values.get("field_id")
    new_field_name = request.values.get("edit_custom_field")
    if field_id:
        try:
            field = StudyField.objects.get(id=field_id)
        except StudyField.DoesNotExist:
            field = None
        if field and new_field_name:
            field.field_name = new_field_name
            field.save()

    return redirect('/study_fields/{:d}'.format(study.id))
示例#13
0
def create_study():
    # Only a SITE admin can create new studies.
    if not get_session_researcher().site_admin:
        return abort(403)

    if request.method == 'GET':
        studies = [
            study.as_unpacked_native_python()
            for study in Study.get_all_studies_by_name()
        ]
        return render_template('create_study.html', studies=studies)

    name = request.form.get('name', '')
    encryption_key = request.form.get('encryption_key', '')
    is_test = request.form.get(
        'is_test', "").lower() == 'true'  # 'true' -> True, 'false' -> False
    duplicate_existing_study = request.form.get('copy_existing_study',
                                                None) == 'true'

    if not (len(name) <= 2**16) or escape(name) != name:
        raise Exception("safety check on new study name failed")

    try:
        new_study = Study.create_with_object_id(name=name,
                                                encryption_key=encryption_key,
                                                is_test=is_test)
        if duplicate_existing_study:
            old_study = Study.objects.get(
                pk=request.form.get('existing_study_id', None))
            copy_existing_study(new_study, old_study)
        flash(f'Successfully created study {name}.', 'success')
        return redirect('/device_settings/{:d}'.format(new_study.pk))

    except ValidationError as ve:
        # display message describing failure based on the validation error (hacky, but works.)
        for field, message in ve.message_dict.items():
            flash(f'{field}: {message[0]}', 'danger')
        return redirect('/create_study')
示例#14
0
def delete_field(study_id=None):
    """Deletes the specified Custom Field. Expects field in the request body."""
    study = Study.objects.get(pk=study_id)
    researcher = get_session_researcher()
    readonly = True if not researcher.check_study_admin(
        study_id) and not researcher.site_admin else False
    if readonly:
        return abort(403)

    field = request.values.get('field', None)
    if field:
        try:
            study_field = StudyField.objects.get(study=study, id=field)
        except StudyField.DoesNotExist:
            study_field = None

        try:
            if study_field:
                study_field.delete()
        except ProtectedError:
            flash("This field can not be removed because it is already in use",
                  'danger')

    return redirect('/study_fields/{:d}'.format(study.id))
示例#15
0
def edit_intervention(study_id=None):
    """
    Edits the name of the intervention. Expects intervention_id and edit_intervention in the
    request body
    """
    study = Study.objects.get(pk=study_id)
    researcher = get_session_researcher()
    readonly = True if not researcher.check_study_admin(
        study_id) and not researcher.site_admin else False
    if readonly:
        return abort(403)

    intervention_id = request.values.get('intervention_id', None)
    new_name = request.values.get('edit_intervention', None)
    if intervention_id:
        try:
            intervention = Intervention.objects.get(id=intervention_id)
        except Intervention.DoesNotExist:
            intervention = None
        if intervention and new_name:
            intervention.name = new_name
            intervention.save()

    return redirect('/interventions/{:d}'.format(study.id))
示例#16
0
def delete_intervention(study_id=None):
    """Deletes the specified Intervention. Expects intervention in the request body."""
    study = Study.objects.get(pk=study_id)
    researcher = get_session_researcher()
    readonly = True if not researcher.check_study_admin(
        study_id) and not researcher.site_admin else False
    if readonly:
        return abort(403)

    intervention_id = request.values.get('intervention')
    if intervention_id:
        try:
            intervention = Intervention.objects.get(id=intervention_id)
        except Intervention.DoesNotExist:
            intervention = None
        try:
            if intervention:
                intervention.delete()
        except ProtectedError:
            flash(
                "This Intervention can not be removed because it is already in use",
                'danger')

    return redirect('/interventions/{:d}'.format(study.id))
def data_api_web_form_page():
    warn_researcher_if_hasnt_yet_generated_access_key(get_session_researcher())
    return render_template("data_api_web_form.html",
                           ALL_DATA_STREAMS=ALL_DATA_STREAMS)
示例#18
0
def disable_api_key():
    form = DisableApiKeyForm(request.values)
    if not form.is_valid():
        return redirect("/manage_credentials")

    api_key_id = request.values["api_key_id"]
    api_key_query = ApiKey.objects.filter(access_key_id=api_key_id).filter(researcher=get_session_researcher())
    if not api_key_query.exists():
        flash(Markup("No matching API key found to disable"), 'warning')
        return redirect("/manage_credentials")
    api_key = api_key_query[0]
    if not api_key.is_active:
        flash("That API key has already been disabled: %s" % api_key_id, 'warning')
        return redirect("/manage_credentials")
    api_key.is_active = False
    api_key.save()
    # flash("The API key %s is now disabled" % str(api_key.access_key_id), 'warning')
    return redirect("/manage_credentials")