Ejemplo n.º 1
0
def list_user_tasks_by_user(user_id, correlation_id=None):
    try:
        user_id = utils.validate_uuid(user_id)
    except utils.DetailedValueError:
        raise

    # check that user exists
    try:
        user_result = get_user_by_id(user_id, correlation_id)[0]
    except IndexError:
        errorjson = {"user_id": user_id, "correlation_id": str(correlation_id)}
        raise utils.ObjectDoesNotExistError("user does not exist", errorjson)

    result = execute_query(sql_q.LIST_USER_TASKS_SQL, (str(user_id), ),
                           correlation_id)

    # add url field to each user_task in result
    edited_result = list()
    for ut in result:
        user_task = UserTask(correlation_id=correlation_id)
        user_task.from_dict(ut_dict=ut)
        user_task.id = ut["user_task_id"]
        user_task.first_name = user_result["first_name"]
        user_task.last_name = user_result["last_name"]
        user_task.email = user_result["email"]
        ut["url"] = user_task.calculate_url()
        del ut["base_url"]
        del ut["external_task_id"]
        del ut["user_specific_url"]
        del ut["user_task_url"]
        del ut["anon_project_specific_user_id"]
        del ut["anonymise_url"]
        edited_result.append(ut)

    return edited_result
Ejemplo n.º 2
0
def raise_error(event, context):
    logger = event['logger']
    correlation_id = event['correlation_id']

    params = event['queryStringParameters']
    error_id = params['error_id']
    logger.info('Event info',
                extra={
                    'error_id': error_id,
                    'correlation_id': correlation_id,
                    'event': event
                })

    errorjson = {'error_id': error_id, 'correlation_id': str(correlation_id)}
    msg = 'no error'

    if error_id == '4xx':
        msg = 'error triggered for testing purposes'
        raise utils.ObjectDoesNotExistError(msg, errorjson)
    elif error_id == '5xx':
        msg = 'error triggered for testing purposes'
        raise Exception(msg)
    elif error_id == 'slow':
        msg = 'slow response triggered for testing purposes'
        time.sleep(2)  # this should trigger lambda duration alarm
    elif error_id == 'timeout':
        msg = 'timeout response triggered for testing purposes'
        time.sleep(10)  # this should trigger lambda timeout

    return {"statusCode": HTTPStatus.OK, "body": json.dumps(msg)}
Ejemplo n.º 3
0
def raise_error_api(event, context):
    logger = event["logger"]
    correlation_id = event["correlation_id"]

    params = event["queryStringParameters"]
    error_id = params["error_id"]
    logger.info(
        "API call",
        extra={
            "error_id": error_id,
            "correlation_id": correlation_id,
            "event": event
        },
    )

    errorjson = {"error_id": error_id, "correlation_id": str(correlation_id)}
    msg = "no error"

    if error_id == "4xx":
        msg = "error triggered for testing purposes"
        raise utils.ObjectDoesNotExistError(msg, errorjson)
    elif error_id == "5xx":
        msg = "error triggered for testing purposes"
        raise Exception(msg)
    elif error_id == "slow":
        msg = "slow response triggered for testing purposes"
        time.sleep(2)  # this should trigger lambda duration alarm
    elif error_id == "timeout":
        msg = "timeout response triggered for testing purposes"
        time.sleep(10)  # this should trigger lambda timeout

    return {"statusCode": HTTPStatus.OK, "body": json.dumps(msg)}
Ejemplo n.º 4
0
def get_project_api(event, context):
    logger = event["logger"]
    correlation_id = event["correlation_id"]

    project_id = event["pathParameters"]["id"]
    logger.info(
        "API call",
        extra={
            "project_id": project_id,
            "correlation_id": correlation_id,
            "event": event,
        },
    )

    result = get_project_with_tasks(project_id, correlation_id)

    if len(result) > 0:
        return {"statusCode": HTTPStatus.OK, "body": json.dumps(result)}
    else:
        errorjson = {
            "project_id": project_id,
            "correlation_id": str(correlation_id)
        }
        raise utils.ObjectDoesNotExistError(
            "project is planned or does not exist", errorjson)
Ejemplo n.º 5
0
def set_user_task_completed(ut_id, correlation_id=None):
    utils.validate_uuid(ut_id)
    # check that user_task exists
    result = get_user_task(ut_id, correlation_id)
    if len(result) == 0:
        errorjson = {
            "user_task_id": ut_id,
            "correlation_id": str(correlation_id)
        }
        raise utils.ObjectDoesNotExistError("user task does not exist",
                                            errorjson)

    if result[0]["project_task_status"] not in ["planned", "testing"]:
        updated_rows_count = execute_non_query(
            sql_q.UPDATE_USER_TASK_STATUS,
            (
                "complete",
                str(utils.now_with_tz()),
                str(ut_id),
            ),
            correlation_id,
        )
        assert (
            updated_rows_count == 1
        ), f"Failed to update status of user task {ut_id}; updated_rows_count: {updated_rows_count}"
 def new_from_json(cls, ugm_json, correlation_id):
     """
     Full process of creating validating and persisting new membership record.
     Creates new object as specified by JSON, checks that user and group exist and that membership does not currently exist in database
     :param ugm_json: MUST contain: user_id, user_group_id, may OPTIONALLY include: id, created, modified
     :param correlation_id:
     :return: new ugm object, will raise errors for invalid data
     """
     if ("user_group_id" not in ugm_json) and ("url_code" in ugm_json):
         url_code = ugm_json["url_code"]
         user_group = UserGroup.get_by_url_code(url_code, correlation_id)
         if user_group is not None:
             ugm_json["user_group_id"] = user_group.id
             if (user_group.testing is False) and user_group.sister_testing_group_id:
                 tasks_statuses = [x["status"] for x in user_group.tasks]
                 if tasks_statuses == ["testing"] * len(
                     tasks_statuses
                 ):  # if all statuses are testing
                     ugm_json["user_group_id"] = user_group.sister_testing_group_id
         else:  # url_code not found
             errorjson = {
                 "url_code": url_code,
                 "correlation_id": str(correlation_id),
             }
             raise utils.ObjectDoesNotExistError(
                 "user group url_code does not exist", errorjson
             )
     try:
         ugm = UserGroupMembership.from_json(ugm_json, correlation_id)
         ugm.validate(correlation_id)
         ugm.insert_to_db(correlation_id)
         return ugm
     except Exception as err:
         raise err
 def check_project_task_exists(self):
     env_name = utils.get_environment_name()
     if env_name == "prod":
         core_api_url = "https://api.thiscovery.org/"
     else:
         core_api_url = f"https://{env_name}-api.thiscovery.org/"
     result = utils.aws_get(
         endpoint_url="v1/project",
         base_url=core_api_url,
     )
     assert (result["statusCode"] == HTTPStatus.OK
             ), f"Call to core API returned error: {result}"
     projects = json.loads(result["body"])
     project_task_ids = list()
     for p in projects:
         tasks = p["tasks"]
         for t in tasks:
             project_task_ids.append(t["id"])
     if self.project_task_id not in project_task_ids:
         raise utils.ObjectDoesNotExistError(
             f"Project tasks id {self.project_task_id} not found in Thiscovery database",
             details={
                 "project_task_ids": project_task_ids,
                 "correlation_id": self.correlation_id,
             },
         )
     return True
Ejemplo n.º 8
0
def put_task_response(event, context):
    """
    Handles user_task_completed and survey_response EB events
    # todo: extend this to handle user_interview_task events
    """
    logger = event["logger"]
    detail_type = event["detail-type"]
    try:
        tr = TaskResponse.from_eb_event(event=event)
    except KeyError as err:
        if detail_type == "user_task_completed":
            err_message = f"Task response not saved. Missing {err} data in user_task_completed event"
            logger.error(err_message, extra={"event": event})
            return {"statusCode": HTTPStatus.BAD_REQUEST, "body": err_message}
        else:
            raise
    if detail_type in ["user_task_completed", "survey_response"]:
        tr.get_project_task_id()
        tr.user_id = tr.get_user_id()
        survey_client = SurveyClient(
            survey_id=tr.survey_id,
            correlation_id=tr._correlation_id,
            account=tr.account,
        )

        response_query_counter = 0
        while response_query_counter < 6:
            try:
                tr.participant_responses = survey_client.get_response(
                    response_id=tr.qualtrics_response_id, )
            except utils.DetailedValueError as err:
                logger.debug(
                    f"survey_client.get_response error: {err}",
                    extra={
                        "event": event,
                        "response_query_counter": response_query_counter,
                    },
                )
                response_query_counter += 1
                time.sleep(0.5)
            else:
                break
        else:
            raise utils.ObjectDoesNotExistError(
                f"Qualtrics response not found after {response_query_counter} attempts",
                details={
                    "account": tr.account,
                    "survey_id": tr.survey_id,
                    "response_id": tr.qualtrics_response_id,
                },
            )

        for k, v in tr.participant_responses.items():
            if isinstance(v, float):
                tr.participant_responses[k] = str(
                    v
                )  # Dynamodb does not support float types (another option: decimal.Decimal(str(v))
        tr._detail_type = "survey_response"
    tr.ddb_dump(unpack_detail=True)
    return {"statusCode": HTTPStatus.OK, "body": ""}
 def query_ddb_by_response_id_alone(self):
     user_interview_task_events = self._ddb_client.query(
         table_name=const.TASK_RESPONSES_TABLE["name"],
         filter_attr_name="type",
         filter_attr_values=["user_interview_task"],
         KeyConditionExpression="response_id = :response_id",
         ExpressionAttributeValues={
             ":response_id": self._response_id,
         },
     )
     events_n = len(user_interview_task_events)
     if events_n > 1:
         self._logger.error(
             f'Found {events_n} user_interview_tasks in {const.TASK_RESPONSES_TABLE["name"]} ddb table; expected 1',
             extra={
                 "user_interview_task": self.as_dict(),
             },
         )
     try:
         return user_interview_task_events[0]
     except (IndexError, TypeError):
         raise utils.ObjectDoesNotExistError(
             f"user_interview_task could not be found in Dynamodb",
             details={
                 "user_interview_task": self.as_dict(),
             },
         )
Ejemplo n.º 10
0
def anon_user_task_id_2_parameter(anon_ut_id, parameter_name, correlation_id=None):
    try:
        return execute_query(
            sql_q.ANON_USER_TASK_ID_2_ID_SQL,
            [anon_ut_id],
            correlation_id,
        )[0][parameter_name]
    except IndexError:
        errorjson = {"anon_ut_id": anon_ut_id, "correlation_id": str(correlation_id)}
        raise utils.ObjectDoesNotExistError("user task does not exist", errorjson)
 def _get_project_short_name(self):
     project_list = self.appointment._core_api_client.get_projects()
     for p in project_list:
         for t in p["tasks"]:
             if t["id"] == self.appointment.appointment_type.project_task_id:
                 self.project_id = p["id"]
                 self.project_name = p["name"]
                 return self.project_name
     raise utils.ObjectDoesNotExistError(
         f"Project task {self.appointment.appointment_type.project_task_id} not found",
         details={},
     )
Ejemplo n.º 12
0
def apsuid_2_user_id(anon_project_specific_user_id, correlation_id=None):
    try:
        return execute_query(
            sql_q.GET_USER_BY_ANON_PROJECT_SPECIFIC_USER_ID_SQL,
            [anon_project_specific_user_id],
            correlation_id,
        )[0]["id"]
    except IndexError:
        errorjson = {
            "anon_project_specific_user_id": anon_project_specific_user_id,
            "correlation_id": str(correlation_id),
        }
        raise utils.ObjectDoesNotExistError("user project does not exist", errorjson)
 def _get_interviewer_myinterview_link(self):
     if self.interviewer_calendar_ddb_item is None:
         self._get_calendar_ddb_item()
     try:
         return self.interviewer_calendar_ddb_item["myinterview_link"]
     except KeyError:
         raise utils.ObjectDoesNotExistError(
             f"Calendar {self.appointment.calendar_id} Dynamodb item does not contain a myinterview_link column",
             details={
                 "appointment": self.appointment.as_dict(),
                 "correlation_id": self.correlation_id,
             },
         )
 def _get_original_booking(self):
     original_booking_info = self.appointment.get_appointment_item_from_ddb(
     )
     try:
         self.appointment.latest_participant_notification = (
             original_booking_info.get("latest_participant_notification",
                                       "0000-00-00 00:00:00+00:00"))
     except AttributeError:
         raise utils.ObjectDoesNotExistError(
             f"Original booking of appointment {self.appointment.appointment_id} not found in Dynamodb",
             details={"appointment": self.appointment.as_dict()},
         )
     return original_booking_info
 def _get_researcher_email_address(self):
     if self.interviewer_calendar_ddb_item is None:
         self._get_calendar_ddb_item()
     try:
         return self.interviewer_calendar_ddb_item["emails_to_notify"]
     except KeyError:
         raise utils.ObjectDoesNotExistError(
             f"Calendar {self.appointment.calendar_id} Dynamodb item does not contain an emails_to_notify column",
             details={
                 "appointment": self.appointment.as_dict(),
                 "correlation_id": self.correlation_id,
             },
         )
    def validate(self, correlation_id):
        """
        Checks that the ids in self actually exist in database and that self does not already exist
        :return: nothing, but raises errors if not valid
        """
        results = execute_query_multiple(
            base_sql_tuple=(SQL_USER, SQL_USER_GROUP, SQL_USER_GROUP_MEMBERSHIP),
            params_tuple=(
                (self.user_id,),
                (self.user_group_id,),
                (self.user_id, self.user_group_id),
            ),
            correlation_id=correlation_id,
        )

        user_data = results[0]
        user_group_data = results[1]
        user_group_membership_data = results[2]

        if len(user_data) == 0:
            errorjson = {"user_id": self.user_id, "correlation_id": str(correlation_id)}
            raise utils.ObjectDoesNotExistError("user does not exist", errorjson)

        if len(user_group_data) == 0:
            errorjson = {
                "user_group_id": self.user_group_id,
                "correlation_id": str(correlation_id),
            }
            raise utils.ObjectDoesNotExistError("user group does not exist", errorjson)

        if len(user_group_membership_data) > 0:
            errorjson = {
                "user_id": self.user_id,
                "user_group_id": self.user_group_id,
                "correlation_id": str(correlation_id),
            }
            raise utils.DuplicateInsertError(
                "user group membership already exists", errorjson
            )
 def _get_calendar_ddb_item(self):
     if self.appointment.calendar_id is None:
         self.appointment.get_appointment_info_from_acuity()
     self.interviewer_calendar_ddb_item = self.ddb_client.get_item(
         table_name=self.calendar_table, key=self.appointment.calendar_id)
     if not self.interviewer_calendar_ddb_item:
         raise utils.ObjectDoesNotExistError(
             f"Calendar {self.appointment.calendar_id} not found in Dynamodb",
             details={
                 "appointment": self.appointment.as_dict(),
                 "correlation_id": self.correlation_id,
             },
         )
     return self.interviewer_calendar_ddb_item
Ejemplo n.º 18
0
def list_user_projects(user_id, correlation_id):

    try:
        user_id = utils.validate_uuid(user_id)
    except utils.DetailedValueError:
        raise

    # check that user exists
    result = get_user_by_id(user_id, correlation_id)
    if len(result) == 0:
        errorjson = {"user_id": user_id, "correlation_id": str(correlation_id)}
        raise utils.ObjectDoesNotExistError("user does not exist", errorjson)

    return execute_query(LIST_USER_PROJECTS_SQL, (str(user_id), ),
                         correlation_id)
 def ddb_load(self):
     item = self.get_appointment_item_from_ddb()
     try:
         item_app_type = item["appointment_type"]
     except TypeError:
         raise utils.ObjectDoesNotExistError(
             f"Appointment {self.appointment_id} could not be found in Dynamodb",
             details={
                 "appointment": self.as_dict(),
                 "correlation_id": self._correlation_id,
             },
         )
     del item["appointment_type"]
     self.__dict__.update(item)
     self.appointment_type.from_dict(item_app_type)
Ejemplo n.º 20
0
def create_user_entity_update(user_id, user_jsonpatch, modified,
                              correlation_id):
    try:
        original_user_list = get_user_by_id(user_id, correlation_id)
        original_user = original_user_list[0]
        return EntityUpdate("user", original_user, user_jsonpatch, modified,
                            correlation_id)
    except IndexError as ex:
        errorjson = {"user_id": user_id, "correlation_id": str(correlation_id)}
        raise utils.ObjectDoesNotExistError("user does not exist", errorjson)
    except JsonPatchException as ex:
        errorjson = {
            "user_jsonpatch": user_jsonpatch.to_string(),
            "correlation_id": str(correlation_id),
        }
        raise utils.PatchInvalidJsonError("invalid jsonpatch", errorjson)
Ejemplo n.º 21
0
 def _get_user_info(self):
     # get user info if not received from calling process
     if None in [self.first_name, self.last_name, self.email]:
         try:
             user = get_user_by_id(self.user_id,
                                   correlation_id=self._correlation_id)[0]
         except IndexError:
             errorjson = {
                 "user_id": self.user_id,
                 "correlation_id": str(self._correlation_id),
             }
             return utils.ObjectDoesNotExistError("User does not exist",
                                                  errorjson)
         self.first_name = user["first_name"]
         self.last_name = user["last_name"]
         self.email = user["email"]
Ejemplo n.º 22
0
    def __init__(self,
                 user_id,
                 correlation_id=None,
                 demo=None,
                 include_non_visible_data=False):
        self.user_id = user_id
        self.correlation_id = correlation_id
        self.include_non_visible_data = include_non_visible_data
        project_list_sql = sql_q.PROJECT_USER_SELECT_SQL_NON_DEMO_ONLY
        if demo:
            project_list_sql = sql_q.PROJECT_USER_SELECT_SQL_DEMO_ONLY

        results = execute_query_multiple(
            base_sql_tuple=(
                sql_q.get_project_status_for_user_sql["sql0"],
                sql_q.get_project_status_for_user_sql["sql1"],
                sql_q.get_project_status_for_user_sql["sql2"],
                sql_q.get_project_status_for_user_sql["sql3"],
                sql_q.get_project_status_for_user_sql["sql4"],
                sql_q.get_project_status_for_user_sql["sql5"],
                project_list_sql,
            ),
            params_tuple=((user_id, ), ) * 6 + ((None, ), ),
            correlation_id=correlation_id,
        )
        self.project_group_users_dict = dict_from_dataset(
            results[0], "project_id")
        self.project_testgroup_users_dict = dict_from_dataset(
            results[1], "project_id")
        self.projecttask_group_users_dict = dict_from_dataset(
            results[2], "project_task_id")
        self.projecttask_testgroup_users_dict = dict_from_dataset(
            results[3], "project_task_id")
        self.projects_usertasks_dict = dict_from_dataset(
            results[4], "project_task_id")
        try:
            self.user_first_name = results[5][0]["first_name"]
            self.user_last_name = results[5][0]["last_name"]
            self.user_email = results[5][0]["email"]
        except IndexError:
            errorjson = {
                "user_id": user_id,
                "correlation_id": str(correlation_id)
            }
            raise utils.ObjectDoesNotExistError(
                f"User {user_id} could not be found", errorjson)
        self.project_list = results[6]
 def ddb_load(self):
     if self.modified is None:
         item = self._ddb_client.get_item(
             table_name=APPOINTMENT_TYPES_TABLE,
             key=str(self.type_id),
             correlation_id=self._correlation_id,
         )
         try:
             self.__dict__.update(item)
         except TypeError:
             raise utils.ObjectDoesNotExistError(
                 f"Appointment type {self.type_id} could not be found in Dynamodb",
                 details={
                     "appointment_type": self.as_dict(),
                     "correlation_id": self._correlation_id,
                 },
             )
Ejemplo n.º 24
0
    def __init__(self, **kwargs):
        self._logger = utils.get_logger()
        self._correlation_id = kwargs.get("correlation_id")
        self.destination_survey_id = kwargs.get("survey_id")
        self.destination_response_id = kwargs.get("response_id")
        err_message = "Call to initialise_survey missing mandatory data: {}"
        assert self.destination_survey_id, err_message.format("survey_id")
        assert self.destination_survey_id, err_message.format("response_id")

        self.survey_init_config = SurveyInitConfig(
            destination_survey_id=self.destination_survey_id,
            correlation_id=self._correlation_id,
        )
        self.survey_init_config.get()
        try:
            self.survey_init_config.details
        except AttributeError:
            raise utils.ObjectDoesNotExistError(
                f"Initialisation config not found for survey {self.destination_survey_id}",
                details={},
            )

        self.destination_account = kwargs.get("account", "cambridge")
        self.anon_project_specific_user_id = kwargs.get(
            "anon_project_specific_user_id")
        assert self.anon_project_specific_user_id, err_message.format(
            "anon_project_specific_user_id")
        self._core_client = CoreApiClient(correlation_id=self._correlation_id)
        user = self._core_client.get_user_by_anon_project_specific_user_id(
            self.anon_project_specific_user_id)
        self.user_id = user["id"]
        self.ddb_client = Dynamodb(stack_name=const.STACK_NAME,
                                   correlation_id=self._correlation_id)
        self.cached_responses = dict()
        self.missing_responses = list()
        self.target_embedded_data = dict()
        self.responses_client = ResponsesClient(
            survey_id=self.destination_survey_id,
            qualtrics_account_name=self.destination_account,
            correlation_id=self._correlation_id,
        )
Ejemplo n.º 25
0
 def ddb_load(self):
     if self.modified is None:
         self._get_project_task_id()
         item = self._ddb_client.get_item(
             table_name=CONSENT_DATA_TABLE,
             key=self.project_task_id,
             key_name="project_task_id",
             sort_key={"consent_id": self.consent_id},
             correlation_id=self._correlation_id,
         )
         try:
             self.__dict__.update(item)
         except TypeError:
             raise utils.ObjectDoesNotExistError(
                 f"Consent item {self.project_task_id}, {self.consent_id} could not be found in Dynamodb",
                 details={
                     "consent_dict": self.as_dict(),
                     "correlation_id": self._correlation_id,
                 },
             )
         else:
             return HTTPStatus.OK
Ejemplo n.º 26
0
def get_user_by_id_api(event, context):
    logger = event["logger"]
    correlation_id = event["correlation_id"]

    user_id = event["pathParameters"]["id"]
    logger.info(
        "API call",
        extra={
            "user_id": user_id,
            "correlation_id": correlation_id,
            "event": event
        },
    )

    result = get_user_by_id(user_id, correlation_id)

    if len(result) > 0:
        user_json = result[0]
        return {"statusCode": HTTPStatus.OK, "body": json.dumps(user_json)}

    else:
        errorjson = {"user_id": user_id, "correlation_id": str(correlation_id)}
        raise utils.ObjectDoesNotExistError("user does not exist", errorjson)
    def ddb_load(self):
        if self.modified is None:
            if self._project_task_id:
                item = self._ddb_client.get_item(
                    table_name=const.INTERVIEW_TASKS_TABLE["name"],
                    key=str(self._project_task_id),
                    key_name=const.INTERVIEW_TASKS_TABLE["partition_key"],
                    sort_key={
                        const.INTERVIEW_TASKS_TABLE["sort_key"]: self._interview_task_id
                    },
                )
                items = [item]
            else:
                items = self._ddb_client.query(
                    table_name=const.INTERVIEW_TASKS_TABLE["name"],
                    IndexName="interview-task-id-index",
                    KeyConditionExpression="interview_task_id = :interview_task_id",
                    ExpressionAttributeValues={
                        ":interview_task_id": self._interview_task_id,
                    },
                )
                items_n = len(items)
                assert (
                    items_n <= 1
                ), f'Found {items_n} interview_tasks in {const.INTERVIEW_TASKS_TABLE["name"]} ddb table; expected 1'

            try:
                self.__dict__.update(items[0])
            except (IndexError, TypeError):
                raise utils.ObjectDoesNotExistError(
                    f"InterviewTask could not be found in Dynamodb",
                    details={
                        "project_task_id": self._project_task_id,
                        "interview_task_id": self._interview_task_id,
                        "InterviewTask": self.as_dict(),
                    },
                )
def main():
    calendar_name = input(
        "Please input the name of the calendar you want to add to Dynamodb, as shown in Acuity's UI:"
    )
    if not calendar_name:
        sys.exit()
    acuity_client = AcuityClient()
    ddb_client = Dynamodb(stack_name=STACK_NAME)
    acuity_calendars = acuity_client.get_calendars()
    pprint(acuity_calendars)
    target_calendar = None
    for c in acuity_calendars:
        if c["name"] == calendar_name:
            target_calendar = c
            continue
    if target_calendar:
        response = ddb_client.put_item(
            "Calendars",
            target_calendar["id"],
            item_type="acuity-calendar",
            item_details=target_calendar,
            item={
                "label": target_calendar["name"],
                "block_monday_morning": True,
                "emails_to_notify": list(),
                "myinterview_link": None,
            },
        )
        assert (
            response["ResponseMetadata"]["HTTPStatusCode"] == HTTPStatus.OK
        ), f"Dynamodb client put_item operation failed with response: {response}"
        print(
            f'Calendar "{calendar_name}" successfully added to Dynamodb table')
    else:
        raise utils.ObjectDoesNotExistError(
            f'Calendar "{calendar_name}" not found in Acuity')
Ejemplo n.º 29
0
def create_user_project(up_json, correlation_id, do_nothing_if_exists=False):
    """
    Inserts new UserProject row in thiscovery db

    Args:
        up_json: must contain user_id and project_id; may optionally include id, created, status, anon_project_specific_user_id
        correlation_id:
        do_nothing_if_exists:

    Returns:
    """
    # extract mandatory data from json
    try:
        user_id = utils.validate_uuid(
            up_json["user_id"])  # all public id are uuids
        project_id = utils.validate_uuid(up_json["project_id"])
    except utils.DetailedValueError as err:
        err.add_correlation_id(correlation_id)
        raise err
    except KeyError as err:
        errorjson = {
            "parameter": err.args[0],
            "correlation_id": str(correlation_id)
        }
        raise utils.DetailedValueError("mandatory data missing",
                                       errorjson) from err

    # now process optional json data
    optional_fields_name_default_and_validator = [
        ("anon_project_specific_user_id", str(uuid.uuid4()),
         utils.validate_uuid),
        ("created", str(utils.now_with_tz()), utils.validate_utc_datetime),
        ("status", DEFAULT_STATUS, validate_status),
    ]
    for (
            variable_name,
            default_value,
            validating_func,
    ) in optional_fields_name_default_and_validator:
        if variable_name in up_json:
            try:
                globals()[variable_name] = validating_func(
                    up_json[variable_name]
                )  # https://stackoverflow.com/a/4687672
            except utils.DetailedValueError as err:
                err.add_correlation_id(correlation_id)
                raise err
        else:
            globals()[variable_name] = default_value

    # id shadows builtin function, so treat if separately (using globals() approach above would overwrite that function)
    if "id" in up_json:
        try:
            id = utils.validate_uuid(up_json["id"])
        except utils.DetailedValueError as err:
            err.add_correlation_id(correlation_id)
            raise err
    else:
        id = str(uuid.uuid4())

    # check external account does not already exist
    existing = get_existing_user_project_id(user_id, project_id,
                                            correlation_id)
    if len(existing) > 0:
        if do_nothing_if_exists:
            return existing[0]
        else:
            errorjson = {
                "user_id": user_id,
                "project_id": project_id,
                "correlation_id": str(correlation_id),
            }
            raise utils.DuplicateInsertError("user_project already exists",
                                             errorjson)

    # lookup user id (needed for insert) for user uuid (supplied in json)
    result = get_user_by_id(user_id, correlation_id)
    if len(result) == 0:
        errorjson = {"user_id": user_id, "correlation_id": str(correlation_id)}
        raise utils.ObjectDoesNotExistError("user does not exist", errorjson)

    execute_non_query(
        CREATE_USER_PROJECT_SQL,
        (
            id,
            created,
            created,
            user_id,
            project_id,
            status,
            anon_project_specific_user_id,
        ),
        correlation_id,
    )

    new_user_project = {
        "id": id,
        "created": created,
        "modified": created,
        "user_id": user_id,
        "project_id": project_id,
        "status": status,
        "anon_project_specific_user_id": anon_project_specific_user_id,
    }

    return new_user_project
Ejemplo n.º 30
0
def get_user_by_email_api(event, context):
    """
    Handler for Lambda function supporting the /v1/user API endpoint. Supports retrieval of user info by email or anon_project_specific_user_id

    Args:
        event (dict): event['queryStringParameters'] may contain either an 'email' or 'anon_project_specific_user_id' parameter, but not both.
        context:

    Returns:
    """
    logger = event["logger"]
    correlation_id = event["correlation_id"]

    parameters = event["queryStringParameters"]

    if not parameters:  # e.g. parameters is None or an empty dict
        errorjson = {
            "queryStringParameters": parameters,
            "correlation_id": str(correlation_id),
        }
        raise utils.DetailedValueError(
            "This endpoint requires one query parameter (email or anon_project_specific_user_id); none were found",
            errorjson,
        )
    else:
        user_email = parameters.get("email")
        anon_project_specific_user_id = parameters.get(
            "anon_project_specific_user_id")

    if user_email and anon_project_specific_user_id:
        errorjson = {
            "user_email": user_email,
            "anon_project_specific_user_id": anon_project_specific_user_id,
            "correlation_id": str(correlation_id),
        }
        raise utils.DetailedValueError(
            "Please query by either email or anon_project_specific_user_id, but not both",
            errorjson,
        )
    elif user_email:
        user_email = user_email.lower()
        logger.info(
            "API call",
            extra={
                "user_email": user_email,
                "correlation_id": correlation_id,
                "event": event,
            },
        )
        result = get_user_by_email(user_email, correlation_id)
    elif anon_project_specific_user_id:
        logger.info(
            "API call",
            extra={
                "anon_project_specific_user_id": anon_project_specific_user_id,
                "correlation_id": correlation_id,
                "event": event,
            },
        )
        result = get_user_by_anon_project_specific_user_id(
            anon_project_specific_user_id, correlation_id)
    else:
        errorjson = {
            "queryStringParameters": parameters,
            "correlation_id": str(correlation_id),
        }
        raise utils.DetailedValueError("Query parameters invalid", errorjson)

    if len(result) > 0:
        return {"statusCode": HTTPStatus.OK, "body": json.dumps(result[0])}
    else:
        errorjson = {
            "user_email": user_email,
            "anon_project_specific_user_id": anon_project_specific_user_id,
            "correlation_id": str(correlation_id),
        }
        raise utils.ObjectDoesNotExistError("user does not exist", errorjson)