def wrapper(*args, **kwargs):
            event = args[0]
            correlation_id = event["correlation_id"]
            logger = event["logger"]
            parameters = event[parameter_type]
            if parameter_type == "body":
                parameters = json.loads(parameters)

            default_parameter = parameters.get(default_parameter_name)
            anon_id = parameters.get("anon_project_specific_user_id")

            if default_parameter and anon_id:
                errorjson = {
                    parameter_type: parameters,
                    "correlation_id": str(correlation_id),
                }
                raise utils.DetailedValueError(
                    f"This endpoint requires {parameter_type} parameter {default_parameter_name} or anon_project_specific_user_id, not both",
                    errorjson,
                )
            elif default_parameter:
                logger.info(
                    "API call",
                    extra={
                        default_parameter_name: default_parameter,
                        "anon_project_specific_user_id": anon_id,
                        "correlation_id": correlation_id,
                        "event": args[0],
                    },
                )
            elif anon_id:
                logger.info(
                    "API call",
                    extra={
                        default_parameter_name: default_parameter,
                        "anon_project_specific_user_id": anon_id,
                        "correlation_id": correlation_id,
                        "event": args[0],
                    },
                )
                parameters[default_parameter_name] = lookup_func(
                    anon_id, correlation_id
                )
                if parameter_type == "body":
                    event[parameter_type] = json.dumps(parameters)
            else:  # e.g. parameters is None or an empty dict
                errorjson = {
                    parameter_type: parameters,
                    "correlation_id": str(correlation_id),
                }
                raise utils.DetailedValueError(
                    f"This endpoint requires {parameter_type} parameter user_task_id or anon_project_specific_user_id; none were given",
                    errorjson,
                )

            updated_args = (event, *args[1:])
            result = func(*updated_args, **kwargs)
            return result
Example #2
0
def patch_user_api(event, context):
    logger = event["logger"]
    correlation_id = event["correlation_id"]

    # get info supplied to api call
    user_id = event["pathParameters"]["id"]
    try:
        user_jsonpatch = JsonPatch.from_string(event["body"])
    except InvalidJsonPatch:
        raise utils.DetailedValueError(
            "invalid jsonpatch",
            details={
                "traceback": traceback.format_exc(),
                "correlation_id": correlation_id,
            },
        )

    # convert email to lowercase
    for p in user_jsonpatch:
        if p.get("path") == "/email":
            p["value"] = p["value"].lower()
        # strip leading and trailing spaces
        try:
            p["value"] = p["value"].strip()
        except KeyError:
            raise utils.DetailedValueError(
                "invalid jsonpatch",
                details={
                    "traceback": traceback.format_exc(),
                    "correlation_id": correlation_id,
                },
            )

    logger.info(
        "API call",
        extra={
            "user_id": user_id,
            "user_jsonpatch": user_jsonpatch,
            "correlation_id": correlation_id,
            "event": event,
        },
    )

    modified_time = utils.now_with_tz()

    # create an audit record of update, inc 'undo' patch
    entity_update = create_user_entity_update(user_id, user_jsonpatch,
                                              modified_time, correlation_id)
    patch_user(user_id, user_jsonpatch, modified_time, correlation_id)
    # on successful update save audit record
    entity_update.save()
    return {"statusCode": HTTPStatus.NO_CONTENT, "body": json.dumps("")}
 def __init__(self, response_dict, correlation_id=None):
     self.survey_id = response_dict.pop("survey_id", None)
     self.response_id = response_dict.pop("response_id", None)
     self.project_task_id = str(
         utils.validate_uuid(response_dict.pop("project_task_id", None)))
     self.anon_project_specific_user_id = str(
         utils.validate_uuid(
             response_dict.pop("anon_project_specific_user_id", None)))
     self.anon_user_task_id = str(
         utils.validate_uuid(response_dict.pop("anon_user_task_id", None)))
     for required_parameter_name, value in [
         ("survey_id", self.survey_id),
         ("response_id", self.response_id),
     ]:
         if not value:
             raise utils.DetailedValueError(
                 f"Required parameter {required_parameter_name} not present in body of call",
                 details={
                     "response_dict": response_dict,
                     "correlation_id": correlation_id,
                 },
             )
     self.response_dict = response_dict
     self.ddb_client = Dynamodb(
         stack_name=const.STACK_NAME,
         correlation_id=correlation_id,
     )
     self.correlation_id = correlation_id
Example #4
0
 def _validate_status(status):
     if status in STATUS_CHOICES:
         return status
     else:
         errorjson = {"status": status}
         raise utils.DetailedValueError("invalid user_task status",
                                        errorjson)
Example #5
0
def user_task_completed_handler(event, context):
    """
    Handles user_task_completed events posted to EB bus.
    Note that the standard way to do this would be create a json patch entity and implement full patch functionality in
    user_task as in other patchable entities.
    """
    detail_type = event["detail-type"]
    assert (detail_type == "user_task_completed"
            ), f"Unexpected detail-type: {detail_type}"
    correlation_id = event["correlation_id"]
    event_detail = event["detail"]
    try:
        user_task_id = event_detail["user_task_id"]
    except KeyError:
        try:
            anon_ut_id = event_detail["anon_user_task_id"]
        except KeyError:
            raise utils.DetailedValueError(
                "Mandatory data (user_task_id or anon_user_task_id) not found in event detail",
                details={
                    "event_detail": event_detail,
                },
            )
        user_task_id = anon_user_task_id_2_user_task_id(
            anon_ut_id, correlation_id)
    set_user_task_completed(user_task_id, correlation_id)
    return {"statusCode": HTTPStatus.NO_CONTENT}
Example #6
0
    def post_block(self, calendar_id, start, end, notes="automated block"):
        """

        Args:
            calendar_id (int): acuity calendar id
            start (datetime.datetime): start time of block
            end (datetime.datetime): end time of block
            notes (str): any notes to include for the blocked off time

        Returns:

        """
        body_params = {
            "calendarID": calendar_id,
            "start": start.strftime(self.strftime_format_str),
            "end": end.strftime(self.strftime_format_str),
            "notes": notes,
        }
        body_json = json.dumps(body_params)
        self.logger.debug(
            "Acuity API call",
            extra={
                "body_params": body_params,
                "correlation_id": self.correlation_id,
            },
        )
        response = self.session.post(f"{self.base_url}blocks", data=body_json)
        if response.ok:
            return response.json()
        else:
            raise utils.DetailedValueError(
                f"Acuity post block call failed with response: {response.status_code}, {response.text}",
                details={},
            )
Example #7
0
 def _format_consent_statements(self):
     counter = 0
     custom_properties_dict = dict()
     for statement_dict in self.consent.consent_statements:
         counter += 1
         key = list(statement_dict.keys())[0]
         custom_properties_dict[f"consent_row_{counter:02}"] = key
         custom_properties_dict[
             f"consent_value_{counter:02}"] = statement_dict[key]
     if counter > CONSENT_ROWS_IN_TEMPLATE:
         raise utils.DetailedValueError(
             "Number of consent statements exceeds maximum supported by template",
             details={
                 "len_consent_statements":
                 len(self.consent.consent_statements),
                 "consent_statements": self.consent.consent_statements,
                 "rows_in_template": CONSENT_ROWS_IN_TEMPLATE,
                 "correlation_id": self.correlation_id,
             },
         )
     while counter < CONSENT_ROWS_IN_TEMPLATE:
         counter += 1
         custom_properties_dict[f"consent_row_{counter:02}"] = str()
         custom_properties_dict[f"consent_value_{counter:02}"] = str()
     return custom_properties_dict
    def from_json(cls, ugm_json, correlation_id):
        """
        Creates new object as specified by JSON.
        Checks that attributes are present but does not check for referential integrity (ie that user and group exist)
        :param ugm_json: MUST contain: user_id, user_group_id, may OPTIONALLY include: id, created, modified
        :param correlation_id:
        :return: new ugm object
        """
        try:
            user_id = utils.validate_uuid(ugm_json["user_id"])
            user_group_id = utils.validate_uuid(ugm_json["user_group_id"])
        except utils.DetailedValueError as err:  # uuids are not valid
            err.add_correlation_id(correlation_id)
            raise err
        except KeyError as err:  # mandatory data not present
            error_json = {
                "parameter": err.args[0],
                "correlation_id": str(correlation_id),
            }
            raise utils.DetailedValueError(
                "mandatory data missing", error_json
            ) from err

        ugm = cls(user_id, user_group_id, ugm_json, correlation_id)

        return ugm
def validate_status(s):
    if s in STATUS_CHOICES:
        return s
    else:
        errorjson = {"status": s}
        raise utils.DetailedValueError("invalid user_project status",
                                       errorjson)
Example #10
0
 def _notify_participant(self):
     custom_properties_dict = self._format_consent_statements()
     custom_properties_dict["consent_info_url"] = self.consent_info_url
     custom_properties_dict[
         "project_short_name"] = self.consent.project_short_name
     (
         custom_properties_dict["current_date"],
         custom_properties_dict["current_time"],
     ) = self._split_consent_datetime()
     email_dict = dict()
     email_dict["custom_properties"] = custom_properties_dict
     self.logger.info(
         "API call",
         extra={
             "email_dict": email_dict,
             "correlation_id": self.correlation_id,
         },
     )
     template_name = self.template_name
     if self.consent.anon_project_specific_user_id:
         email_dict[
             "to_recipient_id"] = self.consent.anon_project_specific_user_id
     elif self.to_recipient_email:
         email_dict["to_recipient_email"] = self.to_recipient_email
     else:
         raise utils.DetailedValueError(
             "Input consent event does not contain recipient info",
             details={
                 "consent_dict": self.consent_dict,
             },
         )
     return self.core_api_client.send_transactional_email(
         template_name=template_name, **email_dict)
 def from_eb_event(cls, event):
     detail_type = event["detail-type"]
     assert (
         detail_type == "user_interview_task"
     ), f"Unexpected detail-type: {detail_type}"
     task_response = super().from_eb_event(event=event)
     try:
         interview_task_id = task_response._detail.pop("interview_task_id")
     except KeyError:
         raise utils.DetailedValueError(
             "Mandatory interview_task_id data not found in user_interview_task event",
             details={
                 "event": event,
             },
         )
     return cls(
         response_id=task_response._response_id,
         event_time=task_response._event_time,
         anon_project_specific_user_id=task_response.anon_project_specific_user_id,
         anon_user_task_id=task_response.anon_user_task_id,
         detail_type=detail_type,
         detail=task_response._detail,
         correlation_id=task_response._correlation_id,
         interview_task_id=interview_task_id,
     )
 def from_eb_event(cls, event):
     event_detail = event["detail"]
     response_id = event_detail.pop("response_id")
     event_time = event["time"]
     try:
         anon_project_specific_user_id = event_detail.pop(
             "anon_project_specific_user_id")
         anon_user_task_id = event_detail.pop("anon_user_task_id")
     except KeyError as exc:
         raise utils.DetailedValueError(
             f"Mandatory {exc} data not found in source event",
             details={
                 "event": event,
             },
         )
     return cls(
         response_id=response_id,
         event_time=event_time,
         anon_project_specific_user_id=anon_project_specific_user_id,
         anon_user_task_id=anon_user_task_id,
         detail_type=event["detail-type"],
         detail=event_detail,
         correlation_id=event["id"],
         account=event_detail.pop("account", "cambridge"),
     )
Example #13
0
    def create_user_task(self, ut_dict):
        """
        Inserts new UserTask row in thiscovery db

        Args:
            ut_dict: must contain user_id, project_task_id and consented; may optionally include id, created,
                    status, anon_user_task_id, first_name, last_name, email

        Returns:
            Dictionary representation of new user task
        """
        self.from_dict(ut_dict=ut_dict)
        self._create_user_task_validate_mandatory_data()
        self._create_user_task_process_optional_data(ut_dict=ut_dict)
        self._get_project_task()
        user_project = create_user_project_if_not_exists(
            self.user_id, self.project_id, self._correlation_id)
        self.user_project_id = user_project["id"]
        self.anon_project_specific_user_id = user_project[
            "anon_project_specific_user_id"]
        self._create_user_task_abort_if_exists()
        self._get_user_info()

        if self.project_task_status not in ["active", "testing"]:
            raise utils.DetailedValueError(
                f"Project task is not active or testing", {"event": ut_dict})
        if self.user_specific_url and (self.project_task_status
                                       in ["active", "complete"]):
            self.user_task_url = self._get_survey_personal_link()
        else:
            self.user_task_url = self.base_url
        self.thiscovery_db_dump()
        url = self.calculate_url()

        new_user_task = {
            "id": self.id,
            "created": self.created,
            "modified": self.created,
            "user_id": self.user_id,
            "user_project_id": self.user_project_id,
            "project_task_id": self.project_task_id,
            "task_provider_name": self.task_provider_name,
            "url": url,
            "status": self.status,
            "consented": self.consented,
            "anon_user_task_id": self.anon_user_task_id,
        }

        extra_data_for_crm = self.get_task_signup_data_for_crm()
        task_signup_event = ThiscoveryEvent({
            "detail-type": "task_signup",
            "detail": {
                **new_user_task, "extra_data": extra_data_for_crm
            },
        })
        task_signup_event.put_event()

        return new_user_task
Example #14
0
 def delete_block(self, block_id):
     response = self.session.delete(f"{self.base_url}blocks/{block_id}")
     if response.ok:
         return response.status_code
     else:
         error_message = f"Acuity delete block call failed with status code: {response.status_code}"
         error_dict = {"block_id": block_id}
         self.logger.error(error_message, extra=error_dict)
         raise utils.DetailedValueError(error_message, details=error_dict)
Example #15
0
    def get_interview_question_list_from_Qualtrics(self):
        def parse_question_html(s):
            text_m = PROMPT_RE.search(s)
            text = text_m.group(1)

            description_m = DESCRIPTION_RE.search(s)
            try:
                description = description_m.group(1)
            except AttributeError:
                description = None
            return text, description

        interview_question_list = list()
        question_counter = 1
        block_ids_flow = [
            x["ID"] for x in self.flow if x["Type"] not in ["Branch"]
        ]  # flow items of Branch type represent survey branching logic
        for block_id in block_ids_flow:
            block = self.blocks[block_id]
            block_name = block["Description"]
            question_ids = [x["QuestionID"] for x in block["BlockElements"]]
            for question_id in question_ids:
                q = self.questions[question_id]
                question_name = q["DataExportTag"]
                question_text_raw = q["QuestionText"]
                try:
                    question_text, question_description = parse_question_html(
                        question_text_raw)
                except AttributeError:  # no match found for PROMPT_RE
                    if SYSTEM_RE.findall(question_text_raw):
                        continue  # this is a system config question; skip
                    else:
                        raise utils.DetailedValueError(
                            "Mandatory prompt div could not be found in interview question",
                            details={
                                "question": question_text_raw,
                                "survey_id": self.survey_id,
                                "question_id": question_id,
                                "question_export_tag": question_name,
                            },
                        )
                question = InterviewQuestion(
                    survey_id=self.survey_id,
                    survey_modified=self.modified,
                    question_id=question_id,
                    question_name=question_name,
                    sequence_no=str(question_counter),
                    block_name=block_name,
                    block_id=block_id,
                    question_text=question_text,
                    question_description=question_description,
                )
                interview_question_list.append(question)
                question_counter += 1
        return interview_question_list
Example #16
0
 def get_calendars(self):
     response = self.session.get(f"{self.base_url}calendars")
     if response.ok:
         calendars = response.json()
         self.calendars = {x["id"]: x for x in calendars}
         return response.json()
     else:
         raise utils.DetailedValueError(
             f"Acuity get calendars call failed with response: {response}",
             details={},
         )
 def _parse_properties(self, properties_list, properties_map):
     try:
         return {k: properties_map[k] for k in properties_list}
     except KeyError as err:
         raise utils.DetailedValueError(
             f"Custom property {err} not found in properties_map",
             details={
                 "properties_list": properties_list,
                 "properties_map": properties_map,
                 "correlation_id": self.correlation_id,
             },
         )
Example #18
0
 def get_task_signup_data_for_crm(self):
     extra_data = execute_query(sql_q.SIGNUP_DETAILS_SELECT_SQL,
                                (str(self.id), ), self._correlation_id)
     if len(extra_data) == 1:
         return extra_data[0]
     else:
         errorjson = {
             "user_task_id": self.id,
             "correlation_id": str(self._correlation_id),
         }
         raise utils.DetailedValueError(
             "could not load details for user task", errorjson)
Example #19
0
def get_personal_link_api(event, context):
    valid_accounts = ["cambridge", "thisinstitute"]
    logger = event["logger"]
    correlation_id = event["correlation_id"]
    params = event["queryStringParameters"]
    project_task_id = params.get('project_task_id')

    # validate params
    try:
        survey_id = params["survey_id"]
        anon_project_specific_user_id = str(
            utils.validate_uuid(params["anon_project_specific_user_id"]))
        if (account := params["account"]) not in valid_accounts:
            raise utils.DetailedValueError(
                f'Account {account} is not supported. Valid values are {",".join(valid_accounts)}',
                details={"params": params},
            )
    except KeyError as err:
        raise utils.DetailedValueError(f"Mandatory {err} data not provided",
                                       details={"params": params})

    logger.info(
        "API call",
        extra={
            "anon_project_specific_user_id": anon_project_specific_user_id,
            "correlation_id": correlation_id,
            "survey_id": survey_id,
            "project_task_id": project_task_id,
        },
    )
    plm = PersonalLinkManager(
        survey_id=survey_id,
        anon_project_specific_user_id=anon_project_specific_user_id,
        account=account,
        project_task_id=project_task_id,
    )
    return {
        "statusCode": HTTPStatus.OK,
        "body": json.dumps({"personal_link": plm.get_personal_link()}),
    }
Example #20
0
def cochrane_get(url):
    full_url = utils.get_secret("cochrane-connection")["base_url"] + url
    headers = dict()
    headers["Content-Type"] = "application/json"
    logger = utils.get_logger()
    response = requests.get(full_url, headers=headers)
    if response.ok:
        data = response.json()
        logger.info("API response", extra={"body": data})
        return data
    else:
        raise utils.DetailedValueError("Cochrane API call failed",
                                       details={"response": response.content})
 def appointment_date_check(self, now):
     tomorrow = now + datetime.timedelta(days=1)
     tomorrow_string = tomorrow.strftime("%Y-%m-%d")
     if self.appointment.appointment_date != tomorrow_string:
         err_message = (
             f"Appointment {self.appointment.appointment_id} is on "
             f"{self.appointment.appointment_date}, not tomorrow; aborting reminder"
         )
         details = {
             "appointment": self.appointment.as_dict(),
         }
         self.logger.debug(err_message, extra=details)
         raise utils.DetailedValueError(err_message, details=details)
Example #22
0
 def _create_user_task_validate_mandatory_data(self):
     for param in ["user_id", "project_task_id", "consented"]:
         if self.__dict__[param] is None:
             errorjson = {
                 "parameter": param,
                 "correlation_id": str(self._correlation_id),
             }
             raise utils.DetailedValueError("mandatory data missing",
                                            details=errorjson)
     try:
         utils.validate_uuid(self.user_id)
         utils.validate_uuid(self.project_task_id)
         utils.validate_utc_datetime(self.consented)
     except utils.DetailedValueError as err:
         err.add_correlation_id(self._correlation_id)
         raise err
Example #23
0
 def reschedule_appointment(self, appointment_id, new_datetime, **kwargs):
     response = self.session.put(
         url=f"{self.base_url}appointments/{appointment_id}/reschedule",
         data=json.dumps({
             **kwargs, "datetime":
             new_datetime.strftime("%Y-%m-%dT%H:%M:%S%Z")
         }),
     )
     if response.ok:
         return response.status_code
     else:
         error_message = (
             f"Acuity call failed with status code: {response.status_code}")
         error_dict = {"response": response.content}
         self.logger.error(error_message, extra=error_dict)
         raise utils.DetailedValueError(error_message, details=error_dict)
Example #24
0
 def wrapper(*args, **kwargs):
     response = func(*args, **kwargs)
     if response.ok:
         try:
             return response.json()
         except JSONDecodeError:
             return response
     else:
         logger = utils.get_logger()
         logger.error(
             f"Acuity API call failed with response: {response}",
             extra={"response.content": response.content},
         )
         raise utils.DetailedValueError(
             f"Acuity API call failed with response: {response}",
             details={"response": response.content},
         )
Example #25
0
def redirect_to_user_interview_task(event, context):
    """
    Updates user task url in response to
    user_interview_task events posted by Qualtrics
    """
    detail_type = event["detail-type"]
    assert (detail_type == "user_interview_task"
            ), f"Unexpected detail-type: {detail_type}"
    event_detail = event["detail"]
    correlation_id = event["id"]
    try:
        anon_user_task_id = utils.validate_uuid(
            event_detail.pop("anon_user_task_id"))
    except KeyError as exc:
        raise utils.DetailedValueError(
            f"Mandatory {exc} data not found in source event",
            details={
                "event": event,
            },
        )

    ssm_client = SsmClient()
    vcs_param = ssm_client.get_parameter(name="video-call-system")
    ut_base_url = vcs_param["base-url"]
    user_task_url = f"{ut_base_url}?response_id={event_detail['response_id']}"

    ut_id = anon_user_task_id_2_user_task_id(anon_user_task_id,
                                             correlation_id=correlation_id)
    updated_rows_count = execute_non_query(
        sql_q.UPDATE_USER_TASK_URL,
        (
            user_task_url,
            str(utils.now_with_tz()),
            str(ut_id),
        ),
        correlation_id,
    )
    assert (
        updated_rows_count == 1
    ), f"Failed to update url of user task {ut_id}; updated_rows_count: {updated_rows_count}"

    body = {
        "user_task_id": ut_id,
        "user_task_url": user_task_url,
    }
    return {"statusCode": HTTPStatus.OK, "body": json.dumps(body)}
Example #26
0
def list_user_tasks_api(event, context):
    logger = event["logger"]
    correlation_id = event["correlation_id"]

    parameters = event["queryStringParameters"]
    user_id = parameters.get("user_id")

    if not user_id:  # e.g. parameters is None or an empty dict
        errorjson = {
            "queryStringParameters": parameters,
            "correlation_id": str(correlation_id),
        }
        raise utils.DetailedValueError(
            "This endpoint requires parameter user_id", errorjson)

    project_task_id = parameters.get("project_task_id")

    if project_task_id:
        logger.info(
            "API call",
            extra={
                "user_id": user_id,
                "project_task_id": project_task_id,
                "correlation_id": correlation_id,
                "event": event,
            },
        )
        result = filter_user_tasks_by_project_task_id(user_id, project_task_id,
                                                      correlation_id)
    else:
        logger.info(
            "API call",
            extra={
                "user_id": user_id,
                "correlation_id": correlation_id,
                "event": event,
            },
        )
        result = list_user_tasks_by_user(user_id, correlation_id)

    # todo: this was added here as a way of quickly fixing an issue with the thiscovery frontend; review what to do for the longer term
    if len(result) == 1:
        result = result[0]

    return {"statusCode": HTTPStatus.OK, "body": json.dumps(result)}
Example #27
0
def post_event(event, context):
    ssm_client = SsmClient()
    allowed_detail_types = ssm_client.get_parameter("thiscovery-events")[
        "allowed_detail_types"
    ]
    event_dict = json.loads(event["body"])
    alarm_test = event_dict.get("brew_coffee")
    if alarm_test:
        raise utils.DeliberateError("Coffee is not available", details={})
    detail_type = event_dict.get("detail-type")
    if detail_type not in allowed_detail_types:
        raise utils.DetailedValueError(
            f"Unsupported event type: {detail_type}", details={"event": event_dict}
        )
    thiscovery_event = eb.ThiscoveryEvent(event_dict)
    eb_client = eb.EventbridgeClient()
    eb_client.put_event(thiscovery_event=thiscovery_event)
    return {"statusCode": HTTPStatus.OK, "body": ""}
def user_group_membership_handler(event, context):
    """
    Handles user_group_membership events posted to EB bus
    """
    logger = event["logger"]
    detail_type = event["detail-type"]
    assert (
        detail_type == "user_group_membership"
    ), f"Unexpected detail-type: {detail_type}"
    correlation_id = event["correlation_id"]
    event_detail = event["detail"]
    try:
        user_id = event_detail["user_id"]
    except KeyError:
        try:
            anon_ut_id = event_detail["anon_user_task_id"]
        except KeyError:
            raise utils.DetailedValueError(
                "Mandatory data (user_id or anon_user_task_id) not found in event detail",
                details={
                    "event_detail": event_detail,
                },
            )
        user_id = anon_user_task_id_2_user_id(anon_ut_id, correlation_id)
    event_detail["user_id"] = user_id

    try:
        ugm = UserGroupMembership.new_from_json(event_detail, correlation_id)
        return {"statusCode": HTTPStatus.CREATED, "body": json.dumps(ugm.to_dict())}

    except utils.DuplicateInsertError:
        return {"statusCode": HTTPStatus.NO_CONTENT, "body": json.dumps({})}
    except utils.ObjectDoesNotExistError as err:
        return utils.log_exception_and_return_edited_api_response(
            err, HTTPStatus.NOT_FOUND, logger, correlation_id
        )
    except utils.DetailedValueError as err:
        return utils.log_exception_and_return_edited_api_response(
            err, HTTPStatus.BAD_REQUEST, logger, correlation_id
        )
    except Exception as err:
        return utils.log_exception_and_return_edited_api_response(
            err, HTTPStatus.INTERNAL_SERVER_ERROR, logger, correlation_id
        )
Example #29
0
 def from_eb_event(cls, event: dict):
     event_detail = event["detail"]
     try:
         account = event_detail["account"]
         return cls(
             account=account,
             survey_id=event_detail["survey_id"],
             contact_list_id=event_detail.get(
                 "contact_list_id",
                 const.DISTRIBUTION_LISTS[account]["id"]),
             correlation_id=event["id"],
             project_task_id=event_detail["project_task_id"],
         )
     except KeyError as exc:
         raise utils.DetailedValueError(
             f"Mandatory {exc} data not found in source event",
             details={
                 "event": event,
             },
         )
Example #30
0
def put_interview_questions(event, context):
    """
    Handles interview_questions_update events posted by Qualtrics
    """
    try:
        event_for_interview_system = {
            "detail-type": event["detail-type"],
            "detail": {
                "survey_id": event["detail"]["survey_id"],
            },
        }
    except KeyError as err:
        raise utils.DetailedValueError(
            f"interview_questions_update event missing mandatory data {err}",
            details={})
    sd = SurveyDefinition.from_eb_event(event=event)
    body = sd.ddb_update_interview_questions()
    eac = EventsApiClient()
    eac.post_event(event_for_interview_system)
    return {"statusCode": HTTPStatus.OK, "body": json.dumps(body)}