Exemple #1
0
    def iam_role(self) -> SafeDict:
        if self._iam_role is None:
            try:
                self._iam_role = SafeDict(self.iam.get_role(RoleName=self.role_name)["Role"])
            except botocore.exceptions.ClientError:
                # If a ClientError happened while getting the role, it means he do not exist.
                logging.debug(f"Creating {self.role_name} IAM Role..")

                attach_policy_obj = json.loads(self.attach_policy)
                assume_policy_obj = json.loads(self.assume_policy)

                self._iam_role = SafeDict(self.iam.create_role(RoleName=self.role_name, AssumeRolePolicyDocument=self.assume_policy)["Role"])

                # create or update the role's policies if needed
                policy = self.iam_resource.RolePolicy(self.role_name, "inoft-vocal-permissions")
                try:
                    if policy.policy_document != attach_policy_obj:
                        logging.debug(f"Updating inoft-vocal-permissions policy on {self.role_name} IAM Role.")
                        policy.put(PolicyDocument=self.attach_policy)

                except botocore.exceptions.ClientError:
                    logging.debug(f"Creating inoft-vocal-permissions policy on {self.role_name} IAM Role.")
                    policy.put(PolicyDocument=self.attach_policy)

                role_policy_dict = self._iam_role.get("AssumeRolePolicyDocument").to_dict()
                if role_policy_dict != assume_policy_obj:
                    if (SafeDict(role_policy_dict["Statement"][0]).get("Principal").get("Service").to_any()
                            != assume_policy_obj["Statement"][0]["Principal"]["Service"]):

                        logging.debug(f"Updating assume role policy on {self.role_name} IAM Role.")
                        self.iam_client.update_assume_role_policy(RoleName=self.role_name, PolicyDocument=self.assume_policy)

        return self._iam_role
Exemple #2
0
    def create_and_setup_api_routes(self, api_id: str, lambda_arn: str):
        integration_creation_response = SafeDict(self.api_gateway_client.create_integration(ApiId=api_id,
            IntegrationType="AWS_PROXY", PayloadFormatVersion="2.0", IntegrationUri=lambda_arn, TimeoutInMillis=10000))

        integration_id = integration_creation_response.get("IntegrationId").to_str(default=None)
        if integration_id is None:
            raise Exception(f"Error while creating the route integration of the api towards the lambda_function."
                            f"The integration_id was not found in the integration creation response."
                            f"Please delete the api and redo the deployment."
                            f"If the issue persist, create an Issue topic on the github page of the framework.")

        route_names = ["amazonAlexaV1", "googleAssistantDialogflowV1", "samsungBixbyV1", "appleSiriV1"]
        route_names_to_settings_keys = {"amazonAlexaV1": "alexaApiEndpointUrlNotRecommendedToUse",
                                        "googleAssistantDialogflowV1": "googleAssistantApiEndointUrl",
                                        "samsungBixbyV1": "samsungBixbyApiEndointUrl",
                                        "appleSiriV1": "siriApiEndointUrl"}

        api_gateway_root_url = self.api_gateway_v2_url(api_id=api_id)
        for route_name in route_names:
            self.boto_session.get_credentials()
            response = self.api_gateway_client.create_route(
                ApiId=api_id,
                AuthorizationType="None",
                RouteKey=f"ANY /{route_name}",
                # A space is required between the HTTP method and the /
                Target=f"integrations/{integration_id}",
            )
            self.add_lambda_permission_to_call_api_resource(lambda_arn=lambda_arn, api_id=api_id, route_key=route_name)
            api_route_url = f"{api_gateway_root_url}/{route_name}"
            click.echo(f"Api route {click.style(route_name, fg='green')} creation complete accessible on {api_route_url}")
            self.settings.settings.get_set("deployment", {}).get_set("endpoints", {}).put(
                route_names_to_settings_keys[route_name], api_route_url).reset_navigated_dict()
Exemple #3
0
 def session_attributes(self) -> SafeDict:
     if not isinstance(self._session_attributes, SafeDict):
         if isinstance(self.session.attributes, dict):
             self._session_attributes = SafeDict(self.session.attributes)
         else:
             self._session_attributes = SafeDict()
     return self._session_attributes
Exemple #4
0
    def create_api_gateway(self, lambda_arn: str, lambda_name: str, description: str = None) -> str:
        # todo: fix bug if id of api gateway is present in file, but the api has been deleted, it will not try to recreate it
        api_name = lambda_name or lambda_arn.split(":")[-1]

        api_creation_response = SafeDict(self.api_gateway_client.create_api(Name=api_name,
            Description=description or self.default_description, Target=lambda_arn, ProtocolType="HTTP"))
        api_id = api_creation_response.get("ApiId").to_str()

        self.create_and_setup_api_routes(api_id=api_id, lambda_arn=lambda_arn)
        return api_id
    def _load_smart_session_user_data(self):
        # We use a separate function to load the smart session user data, and we do not include it in the property itself,
        # because this function can be called by the smart_session_user_data property or the session_been_resumed property.
        if self._smart_session_user_data is None:
            if self.sessions_users_data_disable_database is False:
                self._smart_session_user_data, self._session_been_resumed = self.dynamodb_adapter.get_smart_session_attributes(
                    user_id=self.persistent_user_id, session_id=self.session_id, timeout_seconds=self.default_session_data_timeout)

                if not isinstance(self._smart_session_user_data, SafeDict):
                    self._smart_session_user_data = SafeDict()
            else:
                self._smart_session_user_data = SafeDict()
        logging.debug(f"_smart_session_user_data = {self._smart_session_user_data}")
 def persistent_user_data(self) -> SafeDict:
     if self._persistent_user_data is None:
         if self.sessions_users_data_disable_database is False:
             self._persistent_user_data = self.dynamodb_adapter.get_persistent_attributes(user_id=self.persistent_user_id)
         if not isinstance(self._persistent_user_data, SafeDict):
             self._persistent_user_data = SafeDict()
         logging.debug(f"_persistent_user_data = {self._persistent_user_data}")
     return self._persistent_user_data
 def settings(self) -> SafeDict:
     if Settings.settings_loaded is not True:
         if self.raise_if_not_loaded is True:
             raise Exception(
                 f"The settings have not yet been loaded and are : {Settings.settings}"
             )
         else:
             Settings._settings = SafeDict()
     return Settings._settings
Exemple #8
0
    def simple_session_user_data(self) -> SafeDict:
        for output_context in self.request.queryResult.outputContexts:
            if isinstance(output_context,
                          dict) and "name" in output_context.keys(
                          ) and "parameters" in output_context.keys():
                all_texts_after_slash = output_context["name"].split("/")
                last_text_after_slash = all_texts_after_slash[
                    len(all_texts_after_slash) - 1]
                if str(last_text_after_slash).lower() == "sessiondata":
                    # We lower the text, to make sure that it will work even if the cases have been lowered. Because for some reasons,
                    # google is lowering the keys, so even if the key in the framework os sessionData, google might return sessiondata.
                    parameters_stringed_dict_or_dict = output_context[
                        "parameters"]
                    if parameters_stringed_dict_or_dict is not None:
                        if isinstance(parameters_stringed_dict_or_dict, str):
                            parameters_stringed_dict_or_dict = json_loads(
                                parameters_stringed_dict_or_dict)
                        if isinstance(parameters_stringed_dict_or_dict, dict):
                            # The data key contains an stringed dictionary of the data we are interested by.
                            if "data" in parameters_stringed_dict_or_dict.keys(
                            ):
                                parameters_stringed_dict_or_dict = parameters_stringed_dict_or_dict[
                                    "data"]

                            if isinstance(parameters_stringed_dict_or_dict,
                                          str):
                                parameters_stringed_dict_or_dict = json_loads(
                                    parameters_stringed_dict_or_dict)
                            if isinstance(parameters_stringed_dict_or_dict,
                                          dict):
                                self._simple_session_user_data = SafeDict(
                                    parameters_stringed_dict_or_dict)
                            else:
                                self._simple_session_user_data = SafeDict()
                        else:
                            raise Exception(
                                f"parameters_stringed_dict_or_dict was nto None, not a str, dict and could"
                                f"not be json converted to a dict : {parameters_stringed_dict_or_dict}"
                            )

        if not isinstance(self._simple_session_user_data, SafeDict):
            self._simple_session_user_data = SafeDict()
        return self._simple_session_user_data
 def settings(self, settings_dict: dict):
     validator = self.ExtendedValidator()
     is_valid = validator.validate(settings_dict,
                                   self._settings_file_validator_schema)
     if is_valid is not True:
         raise Exception(
             f"The settings file was not valid. Please modify it or recreate it : {validator.errors}"
         )
     else:
         Settings._settings = SafeDict(settings_dict)
         Settings.settings_loaded = True
Exemple #10
0
 def _fetch_attributes(self, user_id: str) -> SafeDict:
     try:
         response = self.dynamodb.get_item(
             TableName=self.table_name,
             Key={"id": self.utils.python_to_dynamodb(user_id)},
             ConsistentRead=True)
         if "Item" in response:
             return SafeDict(self.utils.dynamodb_to_python(
                 response["Item"]))
         else:
             return SafeDict()
     except ResourceNotExistsError:
         raise Exception(
             f"DynamoDb table {self.table_name} do not exist or in the process"
             "of being created. Failed to get attributes from DynamoDb table."
         )
     except Exception as e:
         raise Exception(
             f"Failed to retrieve attributes from DynamoDb table."
             f"Exception of type {type(e).__name__} occurred: {str(e)}")
    def persistent_user_id(self) -> str:
        if not isinstance(self._persistent_user_id, str) or (self._persistent_user_id.replace(" ", "") == ""):
            if self.is_alexa_v1 is True:
                user_id = SafeDict(self.alexaHandlerInput.session.user).get("userId").to_str(default=None)
            elif self.is_dialogflow_v1 is True:
                user_id = self.dialogFlowHandlerInput.user_id
            elif self.is_bixby_v1 is True:
                user_id = self.bixbyHandlerInput.request.context.userId

            if not isinstance(user_id, str) or user_id.replace(" ", "") == "":
                from inoft_vocal_framework.utils.general import generate_uuid4
                self._persistent_user_id = generate_uuid4()
                # We need to set the persistent_user_id before memorizing it, because the memorize function will access the
                # persistent_user_data, and if the user_id is not set, we will get stuck in an infinite recursion loop
                self.persistent_memorize("userId", user_id)
                print(f"user_id {self._persistent_user_id} has been memorized in the database.")
            else:
                self._persistent_user_id = user_id
            logging.debug(f"_persistent_user_id = {self._persistent_user_id}")
        return self._persistent_user_id
Exemple #12
0
class LaunchRequestHandler:
    CLASS_TYPE = "RequestHandler"

    def __init__(self, node_dict: dict):
        self.node_safedict = SafeDict(node_dict)
        self.node_name = self.node_safedict.get("name").to_str()
        self.class_name = to_class_name(self.node_name)
        self.code = None
        self.state_handler_class = None

    def process(self, parent_core: Core):
        next_paths = self.node_safedict.get("next").to_list()
        if len(next_paths) > 0:
            self.state_handler_class = StateHandler(node_name=self.node_name)
            for path in next_paths:
                self.state_handler_class.next_paths.append(
                    path)  # all_nodes_classes_dict[next_paths[0]["name"]]

    def render(
            self,
            parent_core: Core):  # dict, parent_all_nodes_classes_dict: dict):
        created_classes = list()

        next_state_handler_class = None
        if self.state_handler_class is not None:
            state_handler = StateHandler(node_name=self.node_name)
            state_handler.process(parent_core=parent_core)
            state_handler.render(parent_core=parent_core)
            created_classes.append(state_handler)
            next_state_handler_class = f"{self.class_name}StateHandler"

        self.code = TemplatesAccess().launch_request_handler_template.render(
            class_name=self.class_name,
            node_name=self.node_name,
            next_state_handler_class=next_state_handler_class,
            code_elements=parent_core.process_on_enter(
                self.node_safedict.get("onEnter").to_list()))

        created_classes.insert(0, self)
        # We always want for the request handler to be the first element in the classes.
        return created_classes
    def simple_session_user_data(self) -> SafeDict:
        if self._simple_session_user_data is None:
            if self.is_alexa_v1 is True:
                self._simple_session_user_data = self.alexaHandlerInput.session_attributes
            elif self.is_dialogflow_v1 is True:
                self._simple_session_user_data = self.dialogFlowHandlerInput.simple_session_user_data
            elif self.is_bixby_v1 is True:
                print("simple_session_user_data is not implemented for the bixby platform.")

            if not isinstance(self._simple_session_user_data, SafeDict):
                self._simple_session_user_data = SafeDict()
        return self._simple_session_user_data
 def __init__(self):
     self._queryText = str()
     self._action = str()
     self._parameters = SafeDict()
     self._allRequiredParamsPresent = bool()
     self._fulfillmentText = str()
     self._fulfillmentMessages = list()
     self._outputContexts = list()
     self._intent = Intent()
     self._intentDetectionConfidence = int()
     self._diagnosticInfo = dict()
     self._languageCode = str()
Exemple #15
0
    def process_paths(self, parent_core: Core, paths: list) -> list:
        processed_paths = list()

        for i, path in enumerate(paths):
            path = SafeDict(path)
            path_condition = path.get("condition").to_str(default=None)
            path_target_node_name = path.get("node").to_str(default=None)

            if path_condition is not None and path_target_node_name is not None:
                current_path_instance = StateHandler.Path(
                    path_index=i,
                    condition=path_condition,
                    target_node_name=path_target_node_name)
                no_code_generated_for_path = current_path_instance.process(
                    parent_core=parent_core)
                if no_code_generated_for_path is False:
                    processed_paths.append(current_path_instance)
                else:
                    print(
                        f"\nWarning ! The node {self.node_name} had a condition {path_condition} that did not generated any code."
                    )
                    if path_target_node_name == "":
                        print(
                            "It is likely because you did not define a target node for this condition."
                        )
                    else:
                        print(
                            f"Yet you defined a target node. There is something fishy, you should look in botpress what is strange about the node {self.node_name}"
                        )

                if current_path_instance.condition_type == self.Path.CONDITION_TYPE_INTENT_NAME:
                    if current_path_instance.condition_intent_name in self.counts_used_condition_intent_names.keys(
                    ):
                        self.counts_used_condition_intent_names[
                            current_path_instance.condition_intent_name] += 1
                    else:
                        self.counts_used_condition_intent_names[
                            current_path_instance.condition_intent_name] = 1

        return processed_paths
Exemple #16
0
    def get_smart_session_attributes(self, user_id: str, session_id: str,
                                     timeout_seconds: int) -> (SafeDict, bool):
        # If the value from get_field is of dict or list type, the SafeDict will be populated, otherwise it will be empty without errors.
        timeout_expired = True

        last_session_id = self.get_field(user_id=user_id,
                                         field_key="lastSessionId")
        if session_id == last_session_id:
            timeout_expired = False
        else:
            last_interaction_time = self.get_field(
                user_id=user_id, field_key="lastInteractionTime")
            if last_interaction_time is not None and time.time(
            ) <= last_interaction_time + timeout_seconds:
                timeout_expired = False

        if timeout_expired is False:
            return SafeDict(
                self.get_field(
                    user_id=user_id,
                    field_key=self.smart_session_attributes_key_name)), True
        else:
            return SafeDict(), False
    def persistent_user_id(self) -> str:
        if not isinstance(self._persistent_user_id, str) or (
                not (len(self._persistent_user_id.replace(" ", "")) > 0)):
            user_id: Optional[str] = None
            if self.is_alexa is True:
                user_id = SafeDict(
                    self.alexaHandlerInput.session.user).get('userId').to_str(
                        default=None)
            elif self.is_dialogflow is True:
                user_id = self.dialogFlowHandlerInput.get_user_id()
            elif self.is_bixby is True:
                user_id = self.bixbyHandlerInput.request.context.userId
            elif self.is_discord is True:
                user_id = self.discordHandlerInput.request.author.id

            if user_id is None or not isinstance(
                    user_id, str) or not (len(user_id.replace(" ", "")) > 0):
                self._persistent_user_id = self.settings.user_data_plugin.register_new_user(
                )
            else:
                self._persistent_user_id = user_id
            logging.debug(f"_persistent_user_id = {self._persistent_user_id}")
        return self._persistent_user_id
Exemple #18
0
    def process(self):
        for message_dict in self.input_messages_items:
            message_dict = SafeDict(message_dict)
            speech_items = list()

            # todo: make multilang (might require the premium version of botpress)
            main_speech_dict = message_dict.get("formData").to_dict()
            for key, value in main_speech_dict.items():
                if "text" in key:
                    if value is not None and value != "":
                        speech_items.append(prettify_speech_text(value))

                if "variations" in key:
                    if isinstance(value, list):
                        for speech_variation in value:
                            if speech_variation is not None and speech_variation != "":
                                speech_items.append(
                                    prettify_speech_text(value))

            message_item = self.MessageItem(
                id_value=message_dict.get("id").to_str(),
                speech_items=speech_items)
            self.output_messages_dict[message_item.id] = message_item
    def __init__(self, identifier: str, audio_item_dict: dict = None):
        self.identifier = identifier

        if audio_item_dict is not None:
            if isinstance(audio_item_dict, dict):
                audio_item_dict = SafeDict(audio_item_dict)
            if not isinstance(audio_item_dict, SafeDict):
                raise Exception(
                    f"The audio_item_dict must be of type dict or SafeDict but was {type(audio_item_dict)}: {audio_item_dict}"
                )

            self.mp3_file_url = audio_item_dict.get("url").to_str()
            self.title = audio_item_dict.get("title").to_str()
            self.subtitle = audio_item_dict.get("subtitle").to_str()
            self.offset_in_milliseconds = audio_item_dict.get(
                "offsetInMilliseconds").to_int()
            self.icon_image_url = audio_item_dict.get("iconImageUrl").to_str()
            self.background_image_url = audio_item_dict.get(
                "backgroundImageUrl").to_str()
Exemple #20
0
    def handle_any_platform(self, event: dict, context: dict):
        print(f"Event = {json_dumps(event)}\nContext = {context}")
        self.check_everything_implemented()
        event_safedict = SafeDict(classic_dict=event)

        # The 'rawPath' is for ApiGatewayV2, use the key 'resource' (without the comma) if using ApiGatewayV1
        if event_safedict.get(
                "rawPath").to_str() == "/googleAssistantDialogflowV1":
            # A google-assistant or dialogflow request always pass trough an API gateway
            self.handler_input.is_dialogflow_v1 = True
            event = NestedObjectToDict.get_dict_from_json(
                event_safedict.get("body").to_str())

        elif event_safedict.get("rawPath").to_str() == "/samsungBixbyV1":
            # A samsung bixby request always pass trough an API gateway
            self.handler_input.is_bixby_v1 = True
            from urllib import parse
            event = {
                "context":
                NestedObjectToDict.get_dict_from_json(
                    stringed_json_dict=event_safedict.get("body").to_str())
                ["$vivContext"],
                "parameters":
                dict(
                    parse.parse_qsl(
                        event_safedict.get("rawQueryString").to_str()))
            }

        elif "amzn1." in event_safedict.get("context").get("System").get(
                "application").get("applicationId").to_str():
            # Alexa always go last, since it do not pass trough an api resource, its a less robust identification than the other platforms.
            self.handler_input.is_alexa_v1 = True
        else:
            from inoft_vocal_framework.messages import ERROR_PLATFORM_NOT_SUPPORTED
            raise Exception(ERROR_PLATFORM_NOT_SUPPORTED)

        self.handler_input.load_event(event=event)
        return self.process_request()
Exemple #21
0
 def api_gateway_v2_url(self, api_id: str):
     try:
         return SafeDict(self.api_gateway_client.get_api(ApiId=api_id)).get("ApiEndpoint").to_str(default=None)
     except Exception as e:
         return False
Exemple #22
0
 def get_lambda_function_arn(self, function_name: str):
     return SafeDict(self.lambda_client.get_function(FunctionName=function_name)).get("Configuration").get("FunctionArn").to_str()
Exemple #23
0
class Core(CoreClients):
    def __init__(self):  # , pool: ThreadPoolExecutor):
        super().__init__()
        self.settings = Settings()
        self.tags = {"framework": "InoftVocalFramework"}

        self._iam_role = None
        self._credentials_arn = None
        self._aws_account_id = None

        self._session_unix_time = None
        self._session_count_created_statement_ids = 0

        self.role_name = "InoftVocalFrameworkLambdaExecution"
        self.http_methods = ['ANY']

        self.default_description = "Created with the Inoft Vocal Framework"

    def get_lambda_function_arn(self, function_name: str):
        return SafeDict(self.lambda_client.get_function(FunctionName=function_name)).get("Configuration").get("FunctionArn").to_str()

    def api_gateway_v2_url(self, api_id: str):
        try:
            return SafeDict(self.api_gateway_client.get_api(ApiId=api_id)).get("ApiEndpoint").to_str(default=None)
        except Exception as e:
            return False

    def get_lambda_function_versions(self, function_name: str) -> list:
        try:
            response = self.lambda_client.list_versions_by_function(FunctionName=function_name)
            return response.get('Versions', list())
        except Exception as e:
            click.echo(f"Lambda function {function_name} not found. Error : {e}")
            return list()

    def create_lambda_function(self, bucket=None, s3_key: str = None, local_zip: bytes = None, function_name: str = None, handler=None,
                               description: str = "Inoft Vocal Framework Deployment",
                               timeout: int = 30, memory_size: int = 512, publish: bool = True, runtime=None):
        """
        Given a bucket and key (or a local path) of a valid Lambda-zip, a function name and a handler, register that Lambda function.
        """
        kwargs = dict(
            FunctionName=function_name,
            Runtime=runtime,
            Role=self.credentials_arn,  # "arn:aws:iam::631258222318:role/service-role/alexa_hackaton-cite-des-sciences_fakenews-challeng-role-ck3sxsyt",  # self.credentials_arn,
            # todo: make dynamic and create automaticly role if missing
            Handler=handler,
            Description=description,
            Timeout=timeout,
            MemorySize=memory_size,
            Publish=publish,
            Layers=[
                "arn:aws:lambda:eu-west-3:631258222318:layer:inoft-vocal-framework_0-38-5:1",
            ]
        )
        if local_zip is not None:
            kwargs['Code'] = {
                'ZipFile': local_zip
            }
        else:
            kwargs['Code'] = {
                'S3Bucket': bucket,
                'S3Key': s3_key
            }

        response = self.lambda_client.create_function(**kwargs)

        lambda_arn = response["FunctionArn"]
        version = response['Version']

        click.echo(f"Created new lambda function {function_name} with arn of {lambda_arn}")
        return lambda_arn

    def update_lambda_function_code(self, lambda_arn: str, object_key_name: str, bucket_name: str):
        response = self.lambda_client.update_function_code(
            FunctionName=lambda_arn,
            S3Bucket=bucket_name,
            S3Key=object_key_name,
            Publish=True,
        )

    def update_lambda_function_configuration(self, function_name: str, handler_function_path: str = None, lambda_layers_arns: list = None):
        kwargs = dict(FunctionName=function_name)
        if handler_function_path is not None:
            kwargs["Handler"] = handler_function_path
        if lambda_layers_arns is not None and len(lambda_layers_arns) > 0:
            kwargs["Layers"] = lambda_layers_arns

        response = self.lambda_client.update_function_configuration(**kwargs)


    def create_api_gateway(self, lambda_arn: str, lambda_name: str, description: str = None) -> str:
        # todo: fix bug if id of api gateway is present in file, but the api has been deleted, it will not try to recreate it
        api_name = lambda_name or lambda_arn.split(":")[-1]

        api_creation_response = SafeDict(self.api_gateway_client.create_api(Name=api_name,
            Description=description or self.default_description, Target=lambda_arn, ProtocolType="HTTP"))
        api_id = api_creation_response.get("ApiId").to_str()

        self.create_and_setup_api_routes(api_id=api_id, lambda_arn=lambda_arn)
        return api_id

    def create_and_setup_api_routes(self, api_id: str, lambda_arn: str):
        integration_creation_response = SafeDict(self.api_gateway_client.create_integration(ApiId=api_id,
            IntegrationType="AWS_PROXY", PayloadFormatVersion="2.0", IntegrationUri=lambda_arn, TimeoutInMillis=10000))

        integration_id = integration_creation_response.get("IntegrationId").to_str(default=None)
        if integration_id is None:
            raise Exception(f"Error while creating the route integration of the api towards the lambda_function."
                            f"The integration_id was not found in the integration creation response."
                            f"Please delete the api and redo the deployment."
                            f"If the issue persist, create an Issue topic on the github page of the framework.")

        route_names = ["amazonAlexaV1", "googleAssistantDialogflowV1", "samsungBixbyV1", "appleSiriV1"]
        route_names_to_settings_keys = {"amazonAlexaV1": "alexaApiEndpointUrlNotRecommendedToUse",
                                        "googleAssistantDialogflowV1": "googleAssistantApiEndointUrl",
                                        "samsungBixbyV1": "samsungBixbyApiEndointUrl",
                                        "appleSiriV1": "siriApiEndointUrl"}

        api_gateway_root_url = self.api_gateway_v2_url(api_id=api_id)
        for route_name in route_names:
            self.boto_session.get_credentials()
            response = self.api_gateway_client.create_route(
                ApiId=api_id,
                AuthorizationType="None",
                RouteKey=f"ANY /{route_name}",
                # A space is required between the HTTP method and the /
                Target=f"integrations/{integration_id}",
            )
            self.add_lambda_permission_to_call_api_resource(lambda_arn=lambda_arn, api_id=api_id, route_key=route_name)
            api_route_url = f"{api_gateway_root_url}/{route_name}"
            click.echo(f"Api route {click.style(route_name, fg='green')} creation complete accessible on {api_route_url}")
            self.settings.settings.get_set("deployment", {}).get_set("endpoints", {}).put(
                route_names_to_settings_keys[route_name], api_route_url).reset_navigated_dict()
            # We reset the navigated dict after a final put

    def add_lambda_permission_to_call_api_resource(self, lambda_arn: str, api_id: str, route_key: str):
        response = self.lambda_client.add_permission(
            FunctionName=lambda_arn,
            StatementId=self.get_session_new_statement_id(),
            Action="lambda:InvokeFunction",
            Principal="apigateway.amazonaws.com",
            SourceArn=f"arn:aws:execute-api:{self.boto_session.region_name}:{self.aws_account_id}:{api_id}/*/*/{route_key}",
        )

    @property
    def iam_role(self) -> SafeDict:
        if self._iam_role is None:
            try:
                self._iam_role = SafeDict(self.iam.get_role(RoleName=self.role_name)["Role"])
            except botocore.exceptions.ClientError:
                # If a ClientError happened while getting the role, it means he do not exist.
                logging.debug(f"Creating {self.role_name} IAM Role..")

                attach_policy_obj = json.loads(self.attach_policy)
                assume_policy_obj = json.loads(self.assume_policy)

                self._iam_role = SafeDict(self.iam.create_role(RoleName=self.role_name, AssumeRolePolicyDocument=self.assume_policy)["Role"])

                # create or update the role's policies if needed
                policy = self.iam_resource.RolePolicy(self.role_name, "inoft-vocal-permissions")
                try:
                    if policy.policy_document != attach_policy_obj:
                        logging.debug(f"Updating inoft-vocal-permissions policy on {self.role_name} IAM Role.")
                        policy.put(PolicyDocument=self.attach_policy)

                except botocore.exceptions.ClientError:
                    logging.debug(f"Creating inoft-vocal-permissions policy on {self.role_name} IAM Role.")
                    policy.put(PolicyDocument=self.attach_policy)

                role_policy_dict = self._iam_role.get("AssumeRolePolicyDocument").to_dict()
                if role_policy_dict != assume_policy_obj:
                    if (SafeDict(role_policy_dict["Statement"][0]).get("Principal").get("Service").to_any()
                            != assume_policy_obj["Statement"][0]["Principal"]["Service"]):

                        logging.debug(f"Updating assume role policy on {self.role_name} IAM Role.")
                        self.iam_client.update_assume_role_policy(RoleName=self.role_name, PolicyDocument=self.assume_policy)

        return self._iam_role

    @property
    def credentials_arn(self):
        if self._credentials_arn is None:
            self._credentials_arn = self.iam_role.get("Arn").to_str()
        return self._credentials_arn

    @credentials_arn.setter
    def credentials_arn(self, credentials_arn) -> None:
        self._credentials_arn = credentials_arn

    @property
    def aws_account_id(self) -> str:
        if self._aws_account_id is None:
            self._aws_account_id = boto3.client("sts").get_caller_identity().get("Account")
        return self._aws_account_id

    def get_session_new_statement_id(self) -> str:
        # No restriction is set on the statement id. To created my type of ids, i take the same unix
        # time across the session, and each time we generated a new statement id, i add 1 to the unix time.
        # Dumb and simple, but it assure that i will never have the same id twice.
        if self._session_unix_time is None:
            self._session_unix_time = time.time()
        self._session_count_created_statement_ids += 1

        # After turning the modified unix time into a string, we remove any point, that would have
        # been used to  separate the decimals, because AWS cannot accept a point in a id string.
        return str(self._session_unix_time + self._session_count_created_statement_ids).replace(".", "")

    def create_s3_bucket_if_missing(self, bucket_name: str, region_name: str):
        try:
            self.s3_client.head_bucket(Bucket=bucket_name)
        except ClientError as e:
            click.echo(f"Trying to create a new S3 Bucket with name {click.style(text=bucket_name, fg='yellow', bold=True)}"
                  f" in region {click.style(text=region_name, fg='yellow', bold=True)}")
            available_regions_for_s3 = self.boto_session.get_available_regions(service_name="s3")
            if region_name not in available_regions_for_s3:
                raise Exception(f"The region {region_name} was not available for s3. Here is the available regions : {available_regions_for_s3}")

            self.s3_client.create_bucket(Bucket=bucket_name, CreateBucketConfiguration={"LocationConstraint": region_name})
            click.echo(f"Completed creation of the new bucket.")

    def upload_to_s3(self, filepath: str, object_key_name: str, bucket_name: str, region_name: str) -> bool:
        # If an error happen while uploading to S3, then the upload will not be
        # successful. We use that as our way to send a success response.
        try:
            self.create_s3_bucket_if_missing(bucket_name=bucket_name, region_name=region_name)
            self.s3_client.upload_file(Filename=filepath, Bucket=bucket_name, Key=object_key_name)
            return True
        except NoCredentialsError as e:
            click.echo(f"Almost there ! You just need to configure your AWS credentials."
                  f"\nYou can follow the official documentation (you will need to install the awscli by running pip install awscli) "
                  f"then go to https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html#configuration"
                  f"\nOr you can follow a video made by Robinson Labourdette from Inoft, as a guide to configure your credentials.")
            if click.confirm("Press Y to access the video."):
                selected_language = click.prompt("Type the language in which you would like the video. The followings are available :", type=click.Choice(["English", "French"]))
                if selected_language == "English":
                    click.echo("English here you go !")
                elif selected_language == "French":
                    click.echo("Français la voila !")
                click.echo("Follow the instructions that is available in the video, then when you are all set up, redo the command you just tried")
                while True:
                    if click.confirm("Press y to exit"):
                        exit(201)
                        break
                        # A little break, just to make sure that if the exit do not work, we do not stay stuck in this loop.
            else:
                click.echo("Ok, then follow the boto documentation, and once you have configured your credentials, relaunch the cli command that you were trying to use"
                      " (https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html#configuration)")
        except Exception as e:
            click.echo(f"Error while getting/creating/uploading to the S3 bucket : {e}")
            return False

    def remove_from_s3(self, file_name: str, bucket_name: str):
        try:
            self.s3_client.head_bucket(Bucket=bucket_name)
        except botocore.exceptions.ClientError as e:
            # If a client error is thrown, then check that it was a 404 error.
            # If it was a 404 error, then the bucket does not exist.
            error_code = int(e.response["Error"]["Code"])
            if error_code == 404:
                return False

        try:
            self.s3_client.delete_object(Bucket=bucket_name, Key=file_name)
            return True
        except (botocore.exceptions.ParamValidationError, botocore.exceptions.ClientError):
            return False
import jinja2

from inoft_vocal_framework.bixby_core.templates.templates_access import TemplatesAccess
from inoft_vocal_framework.safe_dict import SafeDict
from inoft_vocal_framework.utils.general import load_json

model_dict = SafeDict(load_json("F:/Inoft/skill_histoire_decryptage_1/inoft_vocal_framework/bixby_core/test_model.json"))
intents = model_dict.get("intents").to_dict()

class Core:
    def render(self):
        out = TemplatesAccess().endpoints_template.render(intents=intents)
        print(out)

    @staticmethod
    def write_to_file(text: str, filepath: str):
        with open(filepath, "w+") as file:
            file.write(text)

Core().render()
Exemple #25
0
 def slots(self) -> SafeDict:
     if isinstance(self._slots, dict):
         self._slots = SafeDict(self._slots)
     return self._slots
Exemple #26
0
 def slots(self, slots: dict) -> None:
     if not isinstance(slots, dict):
         raise Exception(f"slots was type {type(slots)} which is not valid value for his parameter.")
     self._slots = SafeDict(slots)
Exemple #27
0
 def parameters(self, parameters: dict) -> None:
     if not isinstance(parameters, dict):
         raise Exception(
             f"parameters was type {type(parameters)} which is not valid value for his parameter."
         )
     self._parameters = SafeDict(parameters)
Exemple #28
0
 def parameters(self) -> SafeDict:
     if isinstance(self._parameters, dict):
         self._parameters = SafeDict(self._parameters)
     return self._parameters
 def get_last_used_audioplayer_handlers_group(self) -> SafeDict:
     return SafeDict(
         self._parent_handler_input.persistent_remember(
             'lastUsedAudioPlayerHandlersGroupClass',
             specific_object_type=dict))
Exemple #30
0
 def __init__(self):
     self._name = str()
     self._confirmationStatus = str()
     self._slots = SafeDict()