Exemple #1
0
def read_survey_template(account_id, source_id, survey_template_id,
                         language_tag, token_info, survey_redirect_url=None):
    _validate_account_access(token_info, account_id)

    # TODO: can we get rid of source_id?  I don't have anything useful to do
    #  with it...  I guess I could check if the source is a dog before giving
    #  out a pet information survey?

    with Transaction() as t:
        survey_template_repo = SurveyTemplateRepo(t)
        info = survey_template_repo.get_survey_template_link_info(
            survey_template_id)

        # For external surveys, we generate links pointing out
        if survey_template_id == SurveyTemplateRepo.VIOSCREEN_ID:

            url = vioscreen.gen_survey_url(
                language_tag, survey_redirect_url
            )
            # TODO FIXME HACK: This field's contents are not specified!
            info.survey_template_text = {
                "url": url
            }
            return jsonify(info), 200

        # For local surveys, we generate the json representing the survey
        survey_template = survey_template_repo.get_survey_template(
            survey_template_id, language_tag)
        info.survey_template_text = vue_adapter.to_vue_schema(survey_template)

        # TODO FIXME HACK: We need a better way to enforce validation on fields
        #  that need it, can this be stored adjacent to the survey questions?
        client_side_validation = {
            "108": {
                # Height
                "inputType": "number",
                "validator": "number",
                "min": 0,
                "max": None
            },
            "113": {
                # Weight
                "inputType": "number",
                "validator": "number",
                "min": 0,
                "max": None
            }
        }
        for group in info.survey_template_text.groups:
            for field in group.fields:
                if field.id in client_side_validation:
                    field.set(**client_side_validation[field.id])

        return jsonify(info), 200
    def submit_answered_survey(self,
                               ag_login_id,
                               source_id,
                               language_tag,
                               survey_template_id,
                               survey_model,
                               survey_answers_id=None):
        # note that "ag_login_id" is the same as account_id

        # This is actually pretty complicated in the current schema:
        #   We need to filter the model down to questions that are in the
        #       template
        #   We need to ensure that the account has access to write the given
        #       participant
        #   We need to generate a survey_answer id
        #   We need to log that the user submitted this survey
        #   We need to write each answer to one or more rows

        # TODO: We need to ensure that the account has access to write the
        #  given participant!?!

        if survey_answers_id is None:
            survey_answers_id = str(uuid.uuid4())

        survey_template_repo = SurveyTemplateRepo(self._transaction)
        survey_template = survey_template_repo.get_survey_template(
            survey_template_id, language_tag)

        with self._transaction.cursor() as cur:

            # Log that the user submitted this survey
            cur.execute(
                "INSERT INTO ag_login_surveys "
                "(ag_login_id, survey_id, source_id) "
                "VALUES(%s, %s, %s)",
                (ag_login_id, survey_answers_id, source_id))

            # Write each answer
            for survey_template_group in survey_template.groups:
                for survey_question in survey_template_group.questions:
                    survey_question_id = survey_question.id
                    q_type = survey_question.response_type

                    # TODO FIXME HACK: Modify DB to make this unnecessary!
                    # We MUST record at least ONE answer for each survey
                    # (even if the user answered nothing)
                    #  or we can't properly track the survey template id later.
                    # Therefore, if the user answered NOTHING, store an empty
                    # string for the first string or text question in the
                    # survey, just so something is recorded.
                    if len(survey_model) == 0 and \
                            (q_type == "STRING" or q_type == "TEXT"):
                        survey_model[str(survey_question_id)] = ""

                    if str(survey_question_id) not in survey_model:
                        # TODO: Is this supposed to leave the question blank
                        #  or write Unspecified?
                        continue
                    answer = survey_model[str(survey_question_id)]

                    if q_type == "SINGLE":
                        # Normalize localized answer
                        normalized_answer = self._unlocalize(
                            answer, language_tag)

                        try:
                            cur.execute(
                                "INSERT INTO survey_answers "
                                "(survey_id, "
                                "survey_question_id, "
                                "response) "
                                "VALUES(%s, %s, %s)",
                                (survey_answers_id, survey_question_id,
                                 normalized_answer))
                        except psycopg2.errors.ForeignKeyViolation:
                            raise BadRequest("Invalid survey response: %s" %
                                             answer)

                    if q_type == "MULTIPLE":
                        for ans in answer:
                            normalized_answer = self._unlocalize(
                                ans, language_tag)
                            try:
                                cur.execute(
                                    "INSERT INTO survey_answers "
                                    "(survey_id, "
                                    "survey_question_id, "
                                    "response) "
                                    "VALUES(%s, %s, %s)",
                                    (survey_answers_id, survey_question_id,
                                     normalized_answer))
                            except psycopg2.errors.ForeignKeyViolation:
                                raise BadRequest(
                                    "Invalid survey response: %s" % ans)

                    if q_type == "STRING" or q_type == "TEXT":
                        # Note:  Can't convert language on free text...
                        cur.execute(
                            "INSERT INTO survey_answers_other "
                            "(survey_id, "
                            "survey_question_id, "
                            "response) "
                            "VALUES(%s, %s, %s)",
                            (survey_answers_id, survey_question_id, answer))

        if len(survey_model) == 0:
            # we should not have gotten to the end without recording at least
            # ONE answer (even an empty one) ... but it could happen if this
            # survey template includes NO text or string questions AND the
            # user doesn't answer any of the questions it does include. Not
            # worth making the code robust to this case, as this whole "include
            # one empty answer" is a temporary hack, but at least ensure we
            # know this problem occurred if it ever does
            raise RepoException("No answers provided for survey template %s "
                                "and not able to add an empty string default" %
                                survey_template_id)

        return survey_answers_id
Exemple #3
0
def read_survey_template(account_id,
                         source_id,
                         survey_template_id,
                         language_tag,
                         token_info,
                         survey_redirect_url=None,
                         vioscreen_ext_sample_id=None):
    _validate_account_access(token_info, account_id)

    # TODO: can we get rid of source_id?  I don't have anything useful to do
    #  with it...  I guess I could check if the source is a dog before giving
    #  out a pet information survey?

    with Transaction() as t:
        survey_template_repo = SurveyTemplateRepo(t)
        info = survey_template_repo.get_survey_template_link_info(
            survey_template_id)

        # For external surveys, we generate links pointing out
        if survey_template_id == SurveyTemplateRepo.VIOSCREEN_ID:
            if vioscreen_ext_sample_id:
                # User is about to start a vioscreen survey for this sample
                # record this in the database.
                db_vioscreen_id = survey_template_repo.create_vioscreen_id(
                    account_id, source_id, vioscreen_ext_sample_id)
            else:
                raise ValueError("Vioscreen Template requires "
                                 "vioscreen_ext_sample_id parameter.")
            (birth_year, gender
             ) = survey_template_repo.fetch_user_birth_year_gender(account_id)
            url = vioscreen.gen_survey_url(db_vioscreen_id,
                                           language_tag,
                                           survey_redirect_url,
                                           birth_year=birth_year,
                                           gender=gender)
            # TODO FIXME HACK: This field's contents are not specified!
            info.survey_template_text = {"url": url}
            t.commit()
            return jsonify(info), 200

        # For local surveys, we generate the json representing the survey
        survey_template = survey_template_repo.get_survey_template(
            survey_template_id, language_tag)
        info.survey_template_text = vue_adapter.to_vue_schema(survey_template)

        # TODO FIXME HACK: We need a better way to enforce validation on fields
        #  that need it, can this be stored adjacent to the survey questions?
        client_side_validation = {
            "108": {
                # Height
                "inputType": "number",
                "validator": "number",
                "min": 0,
                "max": None
            },
            "113": {
                # Weight
                "inputType": "number",
                "validator": "number",
                "min": 0,
                "max": None
            }
        }
        for group in info.survey_template_text.groups:
            for field in group.fields:
                if field.id in client_side_validation:
                    field.set(**client_side_validation[field.id])

        return jsonify(info), 200
def read_survey_template(account_id,
                         source_id,
                         survey_template_id,
                         language_tag,
                         token_info,
                         survey_redirect_url=None,
                         vioscreen_ext_sample_id=None):
    _validate_account_access(token_info, account_id)

    with Transaction() as t:
        survey_template_repo = SurveyTemplateRepo(t)
        info = survey_template_repo.get_survey_template_link_info(
            survey_template_id)
        remote_surveys = set(survey_template_repo.remote_surveys())

        # For external surveys, we generate links pointing out
        if survey_template_id in remote_surveys:
            if survey_template_id == SurveyTemplateRepo.VIOSCREEN_ID:
                url = _remote_survey_url_vioscreen(t, account_id, source_id,
                                                   language_tag,
                                                   survey_redirect_url,
                                                   vioscreen_ext_sample_id)
            elif survey_template_id == SurveyTemplateRepo.MYFOODREPO_ID:
                url = _remote_survey_url_myfoodrepo(t, account_id, source_id,
                                                    language_tag)
            elif survey_template_id == SurveyTemplateRepo.POLYPHENOL_FFQ_ID:
                url = _remote_survey_url_polyphenol_ffq(
                    t, account_id, source_id, language_tag)
            else:
                raise ValueError(f"Cannot generate URL for survey "
                                 f"{survey_template_id}")

            # TODO FIXME HACK: This field's contents are not specified!
            info.survey_template_text = {"url": url}
            t.commit()
            return jsonify(info), 200

        # For local surveys, we generate the json representing the survey
        survey_template = survey_template_repo.get_survey_template(
            survey_template_id, language_tag)
        info.survey_template_text = vue_adapter.to_vue_schema(survey_template)

        # TODO FIXME HACK: We need a better way to enforce validation on fields
        #  that need it, can this be stored adjacent to the survey questions?
        client_side_validation = {
            "108": {
                # Height
                "inputType": "number",
                "validator": "integer",
                "min": 0,
                "max": None
            },
            "113": {
                # Weight
                "inputType": "number",
                "validator": "integer",
                "min": 0,
                "max": None
            }
        }
        for group in info.survey_template_text.groups:
            for field in group.fields:
                if field.id in client_side_validation:
                    field.set(**client_side_validation[field.id])

        return jsonify(info), 200