def compile_proto_stubs(org_id, service_id):
     boto_utils = BotoUtils(region_name=REGION_NAME)
     base_url = f"s3://{ASSETS_COMPONENT_BUCKET_NAME}/assets/{org_id}/{service_id}/proto.tar.gz"
     output_url = f"s3://{ASSETS_COMPONENT_BUCKET_NAME}/assets/{org_id}/{service_id}/"
     lambda_payload = {
         "input_s3_path": base_url,
         "output_s3_path": output_url,
         "org_id": org_id,
         "service_id": service_id
     }
     response = boto_utils.invoke_lambda(
         invocation_type="RequestResponse",
         lambda_function_arn=MANAGE_PROTO_COMPILATION,
         payload=json.dumps(lambda_payload))
     generated_stubs_url = []
     if response['statusCode'] == 200:
         output_bucket, output_key = boto_utils.get_bucket_and_key_from_url(
             url=f"{output_url}stubs")
         stub_objects = boto_utils.get_objects_from_s3(bucket=output_bucket,
                                                       key=output_key)
         for object in stub_objects:
             generated_stubs_url.append(
                 f"https://{output_bucket}.s3.{REGION_NAME}.amazonaws.com/{object['Key']}"
             )
         return generated_stubs_url
     else:
         msg = f"Error generating stubs :: {response}"
         logger.info(msg)
         raise Exception(msg)
 def __init__(self, repo):
     self.repo = repo
     self.boto_utils = BotoUtils(region_name=REGION_NAME)
     self.blockchain_util = BlockChainUtil(
         provider_type="HTTP_PROVIDER",
         provider=NETWORKS[NETWORK_ID]['http_provider'])
     self.utils = Utils()
     self.channel_dao = ChannelDAO(repo=self.repo)
     self.wallet_dao = WalletDAO(repo=self.repo)
class OrganizationOrchestratorService:

    def __init__(self):
        self.boto_client = BotoUtils(REGION_NAME)

    def register_org_member(self, username, payload):
        wallet_address = payload["wallet_address"]
        invite_code = payload["invite_code"]
        self.registry_register_org_member(username, wallet_address, invite_code)
        self.register_wallet(username, wallet_address)
        return "OK"

    def registry_register_org_member(self, username, wallet_address, invite_code):
        register_member_event = {
            "path": f"/org/member/register",
            "body": json.dumps({"wallet_address": wallet_address,
                                "invite_code": invite_code}),
            "httpMethod": "POST",
            "requestContext": {
                "authorizer": {
                    "claims": {
                        "email": username
                    }
                }
            }
        }

        logger.info(f"Requesting register user for invite_code: {invite_code} "
                    f"username: {username} wallet_address:{wallet_address}")

        register_member_response = self.boto_client.invoke_lambda(
            lambda_function_arn=REGISTRY_ARN["REGISTER_MEMBER_ARN"],
            invocation_type='RequestResponse',
            payload=json.dumps(register_member_event)
        )
        if register_member_response["statusCode"] != 201:
            raise Exception(f"Failed to register user for invite_code: {invite_code} "
                            f"username: {username} wallet_address:{wallet_address}")

    def register_wallet(self, username, wallet_address, wallet_type="METAMASK"):
        register_wallet_body = {
            'address': wallet_address,
            'type': wallet_type,
            'username': username
        }
        register_wallet_payload = {
            "path": "/wallet/register",
            "body": json.dumps(register_wallet_body),
            "httpMethod": "POST"
        }
        raw_response = self.boto_client.invoke_lambda(lambda_function_arn=WALLETS_SERVICE_ARN,
                                                      invocation_type="RequestResponse",
                                                      payload=json.dumps(register_wallet_payload))
        status = raw_response["statusCode"]
        if int(status) != 200:
            raise Exception("Unable to register wallet for username %s", username)
 def __init__(self, obj_repo):
     self.repo = obj_repo
     self.obj_transaction_history_dao = TransactionHistoryDAO(self.repo)
     self.lambda_client = boto3.client('lambda', region_name=REGION_NAME)
     self.boto_client = BotoUtils(REGION_NAME)
     self.wallet_service = WalletService()
     self.obj_blockchain_util = BlockChainUtil(
         provider_type="HTTP_PROVIDER",
         provider=NETWORKS[NETWORK_ID]['http_provider']
     )
     self.utils = Utils()
class UploadService:
    def __init__(self):
        self.boto_utils = BotoUtils(region_name=REGION_NAME)

    def store_file(self, upload_type, file_data, request_params, username):
        """
            TODO: persist user history of the storage request
        """
        if upload_type == UploadType.ORG_ASSETS.value:
            org_id = request_params["org_uuid"]
            bucket = UPLOAD_TYPE_DETAILS[upload_type]["bucket"]
            dest_file_path = UPLOAD_TYPE_DETAILS[upload_type][
                "bucket_path"].format(org_id, date_time_for_filename(),
                                      file_data["file_extension"])

            self.boto_utils.s3_upload_file(file_data["file_path"], bucket,
                                           dest_file_path)

            file_url = f"https://{bucket}.s3.amazonaws.com/{dest_file_path}"
            return file_url

        elif upload_type in [
                UploadType.SERVICE_ASSETS.value,
                UploadType.SERVICE_GALLERY_IMAGES.value,
                UploadType.SERVICE_PAGE_COMPONENTS.value,
                UploadType.SERVICE_PROTO_FILES.value
        ]:
            org_id = request_params["org_uuid"]
            service_id = request_params["service_uuid"]
            bucket = UPLOAD_TYPE_DETAILS[upload_type]["bucket"]
            dest_file_path = UPLOAD_TYPE_DETAILS[upload_type][
                "bucket_path"].format(org_id, service_id,
                                      date_time_for_filename(),
                                      file_data["file_extension"])

            self.boto_utils.s3_upload_file(file_data["file_path"], bucket,
                                           dest_file_path)

            file_url = f"https://{bucket}.s3.amazonaws.com/{dest_file_path}"
            return file_url

        else:
            logger.error(
                f"Invalid upload request type {upload_type} params: {request_params}"
            )
            raise BadRequestException()
Esempio n. 6
0
 def __make_trasaction(self, *positional_inputs, method_name):
     if self.__env_type == EnvironmentType.TEST.value:
         executor_key = BotoUtils(REGION_NAME).get_ssm_parameter(
             BLOCKCHAIN_TEST_ENV["publisher_private_key"])
         transaction_object = self.__generate_blockchain_transaction_for_test_environment(
             *positional_inputs, method_name=method_name)
     else:
         raise EnvironmentNotFoundException()
     raw_transaction = self.__blockchain_util.sign_transaction_with_private_key(
         transaction_object=transaction_object, private_key=executor_key)
     transaction_hash = self.__blockchain_util.process_raw_transaction(
         raw_transaction=raw_transaction)
     return transaction_hash
class WalletService:
    def __init__(self, repo):
        self.repo = repo
        self.boto_utils = BotoUtils(region_name=REGION_NAME)
        self.blockchain_util = BlockChainUtil(
            provider_type="HTTP_PROVIDER",
            provider=NETWORKS[NETWORK_ID]['http_provider'])
        self.utils = Utils()
        self.channel_dao = ChannelDAO(repo=self.repo)
        self.wallet_dao = WalletDAO(repo=self.repo)

    def create_and_register_wallet(self, username):
        address, private_key = self.blockchain_util.create_account()
        wallet = Wallet(address=address,
                        private_key=private_key,
                        type=GENERAL_WALLET_TYPE,
                        status=WalletStatus.ACTIVE.value)
        self._register_wallet(wallet, username)
        return wallet.to_dict()

    def _register_wallet(self, wallet, username):
        existing_wallet = self.wallet_dao.get_wallet_details(wallet)
        if len(existing_wallet) == 0:
            self.wallet_dao.insert_wallet(wallet)
        self.wallet_dao.add_user_for_wallet(wallet, username)

    def register_wallet(self, wallet_address, wallet_type, status, username):
        wallet = Wallet(address=wallet_address,
                        type=wallet_type,
                        status=status)
        self._register_wallet(wallet, username)
        return wallet.to_dict()

    def remove_user_wallet(self, username):
        self.wallet_dao.remove_user_wallet(username)

    def get_wallet_details(self, username):
        """ Method to get wallet details for a given username. """
        logger.info(f"Fetching wallet details for {username}")
        wallet_data = self.wallet_dao.get_wallet_data_by_username(username)
        self.utils.clean(wallet_data)

        logger.info(
            f"Fetched {len(wallet_data)} wallets for username: {username}")
        wallet_response = {"username": username, "wallets": wallet_data}
        return wallet_response

    def __generate_signature_details(self, recipient, group_id, agi_tokens,
                                     expiration, message_nonce, signer_key):
        data_types = [
            "string", "address", "address", "address", "address", "bytes32",
            "uint256", "uint256", "uint256"
        ]
        values = [
            "__openChannelByThirdParty", self.mpe_address,
            self.EXECUTOR_WALLET_ADDRESS, SIGNER_ADDRESS, recipient, group_id,
            agi_tokens, expiration, message_nonce
        ]
        signature = self.blockchain_util.generate_signature(
            data_types=data_types, values=values, signer_key=signer_key)
        v, r, s = Web3.toInt(
            hexstr="0x" +
            signature[-2:]), signature[:66], "0x" + signature[66:130]
        return r, s, v, signature

    def __calculate_amount_in_cogs(self, amount, currency):
        if currency == "USD":
            amount_in_cogs = round(amount)
        else:
            raise Exception("Currency %s not supported.", currency)

        return amount_in_cogs

    def record_create_channel_event(self, payload):
        current_time = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
        if not self.channel_dao.persist_create_channel_event(
                payload, current_time):
            raise Exception("Failed to create record")
        return {}

    def open_channel_by_third_party(self, order_id, sender, signature, r, s, v,
                                    group_id, org_id, amount, currency,
                                    recipient, current_block_no,
                                    amount_in_cogs):
        self.EXECUTOR_WALLET_ADDRESS = self.boto_utils.get_ssm_parameter(
            EXECUTOR_ADDRESS)
        self.EXECUTOR_WALLET_KEY = self.boto_utils.get_ssm_parameter(
            EXECUTOR_KEY)
        method_name = "openChannelByThirdParty"
        self.mpe_address = self.blockchain_util.read_contract_address(
            net_id=NETWORK_ID, path=MPE_ADDR_PATH, key='address')

        # 1 block no is mined in 15 sec on average, setting expiration as 10 years
        expiration = current_block_no + (10 * 365 * 24 * 60 * 4)
        # amount_in_cogs = self.__calculate_amount_in_cogs(amount=amount, currency=currency)
        self.__validate__cogs(amount_in_cogs=amount_in_cogs)

        group_id_in_hex = "0x" + base64.b64decode(group_id).hex()

        positional_inputs = (sender, SIGNER_ADDRESS, recipient,
                             group_id_in_hex, amount_in_cogs, expiration,
                             current_block_no, v, r, s)

        transaction_object = self.blockchain_util.create_transaction_object(
            *positional_inputs,
            method_name=method_name,
            address=self.EXECUTOR_WALLET_ADDRESS,
            contract_path=MPE_CNTRCT_PATH,
            contract_address_path=MPE_ADDR_PATH,
            net_id=NETWORK_ID)

        raw_transaction = self.blockchain_util.sign_transaction_with_private_key(
            transaction_object=transaction_object,
            private_key=self.EXECUTOR_WALLET_KEY)
        transaction_hash = self.blockchain_util.process_raw_transaction(
            raw_transaction=raw_transaction)

        logger.info(
            "openChannelByThirdParty::transaction_hash : %s for order_id : %s",
            transaction_hash, order_id)

        self.channel_dao.insert_channel_history(
            order_id=order_id,
            amount=amount,
            currency=currency,
            group_id=group_id,
            org_id=org_id,
            type=method_name,
            recipient=recipient,
            address=sender,
            signature=signature,
            request_parameters=str(positional_inputs),
            transaction_hash=transaction_hash,
            status=TransactionStatus.PENDING)

        return {
            "transaction_hash": transaction_hash,
            "signature": signature,
            "amount_in_cogs": amount_in_cogs,
            "type": method_name
        }

    def set_default_wallet(self, username, address):
        self.wallet_dao.set_default_wallet(username=username, address=address)
        return "OK"

    def add_funds_to_channel(self, org_id, group_id, channel_id, sender,
                             recipient, order_id, amount, currency,
                             amount_in_cogs):
        self.EXECUTOR_WALLET_ADDRESS = self.boto_utils.get_ssm_parameter(
            EXECUTOR_ADDRESS)
        self.EXECUTOR_WALLET_KEY = self.boto_utils.get_ssm_parameter(
            EXECUTOR_KEY)
        method_name = "channelAddFunds"
        # amount_in_cogs = self.__calculate_amount_in_cogs(amount=amount, currency=currency)
        self.__validate__cogs(amount_in_cogs=amount_in_cogs)
        positional_inputs = (channel_id, amount_in_cogs)

        transaction_object = self.blockchain_util.create_transaction_object(
            *positional_inputs,
            method_name=method_name,
            address=self.EXECUTOR_WALLET_ADDRESS,
            contract_path=MPE_CNTRCT_PATH,
            contract_address_path=MPE_ADDR_PATH,
            net_id=NETWORK_ID)

        raw_transaction = self.blockchain_util.sign_transaction_with_private_key(
            transaction_object=transaction_object,
            private_key=self.EXECUTOR_WALLET_KEY)

        transaction_hash = self.blockchain_util.process_raw_transaction(
            raw_transaction=raw_transaction)
        logger.info("channelAddFunds::transaction_hash: %s for order_id: %s",
                    transaction_hash, order_id)

        self.channel_dao.insert_channel_history(
            order_id=order_id,
            amount=amount,
            currency=currency,
            group_id=group_id,
            org_id=org_id,
            type=method_name,
            recipient=recipient,
            address=sender,
            signature=None,
            request_parameters=str(positional_inputs),
            transaction_hash=transaction_hash,
            status=TransactionStatus.PENDING)
        return {
            "transaction_hash": transaction_hash,
            "amount_in_cogs": amount_in_cogs,
            "type": method_name
        }

    def get_transactions_from_username_recipient(self, username, org_id,
                                                 group_id):
        logger.info(
            f"Fetching transactions for {username} to org_id: {org_id} group_id: {org_id}"
        )
        channel_data = self.channel_dao.get_channel_transactions_for_username_recipient(
            username=username, group_id=group_id, org_id=org_id)
        self.utils.clean(channel_data)

        logger.info(f"Fetched {len(channel_data)} transactions")
        transaction_details = {"username": username, "wallets": []}

        wallet_transactions = dict()
        for rec in channel_data:
            sender_address = rec["address"]
            if rec["address"] not in wallet_transactions:
                wallet_transactions[rec["address"]] = {
                    "address": sender_address,
                    "is_default": rec["is_default"],
                    "type": rec["type"],
                    "transactions": []
                }
            if rec['recipient'] is None:
                continue

            transaction = {
                "org_id": org_id,
                "group_id": group_id,
                "recipient": rec["recipient"],
                "amount": rec["amount"],
                "transaction_type": rec["transaction_type"],
                "currency": rec["currency"],
                "status": rec["status"],
                "created_at": rec["created_at"],
            }

            wallet_transactions[sender_address]["transactions"].append(
                transaction)

        for key in wallet_transactions:
            wallet = wallet_transactions[key]
            transaction_details["wallets"].append(wallet)
        return transaction_details

    def get_channel_transactions_against_order_id(self, order_id):
        transaction_history = self.channel_dao.get_channel_transactions_against_order_id(
            order_id)

        for record in transaction_history:
            record["created_at"] = record["created_at"].strftime(
                "%Y-%m-%d %H:%M:%S")

        return {"order_id": order_id, "transactions": transaction_history}

    def __validate__cogs(self, amount_in_cogs):
        if amount_in_cogs < MINIMUM_AMOUNT_IN_COGS_ALLOWED:
            raise Exception(
                "Insufficient amount to buy minimum amount in cogs allowed.")
Esempio n. 8
0
 def __init__(self, obj_repo):
     self.repo = obj_repo
     self.obj_utils = Utils()
     self.ssm_client = boto3.client('ssm')
     self.boto_client = BotoUtils(region_name=REGION_NAME)
Esempio n. 9
0
import tempfile
import uuid
from pathlib import Path

import pkg_resources
from grpc_tools.protoc import main as protoc

from common import utils
from common.boto_utils import BotoUtils
from common.logger import get_logger
from contract_api.config import REGION_NAME
from utility.config import SLACK_HOOK
from utility.exceptions import ProtoNotFound

TEMP_FILE_DIR = tempfile.gettempdir()
boto_utils = BotoUtils(region_name=REGION_NAME)
logger = get_logger(__name__)


def generate_python_stubs(input_s3_path, output_s3_path):
    try:
        input_bucket, input_key = boto_utils.get_bucket_and_key_from_url(
            url=input_s3_path)
        if output_s3_path:
            output_bucket, output_key = boto_utils.get_bucket_and_key_from_url(
                url=output_s3_path)
        tmp_paths = initialize_temp_paths()
        boto_utils.download_folder_contents_from_s3(bucket=input_bucket,
                                                    key=input_key,
                                                    target=tmp_paths["base"])
        proto_location = None
Esempio n. 10
0
class UserService:
    def __init__(self):
        self.user_factory = UserFactory()
        self.user_repo = UserRepository()
        self.boto_client = BotoUtils(REGION_NAME)

    def add_or_update_user_preference(self, payload, username):
        user_preference_list = self.user_factory.parse_raw_user_preference_data(
            payload=payload)
        response = []
        for user_preference in user_preference_list:
            if user_preference.status and user_preference.opt_out_reason is not None:
                raise Exception("Invalid Payload.")
            user_data = self.user_repo.get_user_data_for_given_username(
                username=username)
            if len(user_data) == 0:
                raise Exception("User is not registered.")
            if user_preference.status is False:
                self.user_repo.disable_preference(
                    user_preference=user_preference,
                    user_row_id=user_data[0]["row_id"])
                response.append(Status.DISABLED.value)
            else:
                self.user_repo.enable_preference(
                    user_preference=user_preference,
                    user_row_id=user_data[0]["row_id"])
                response.append(Status.ENABLED.value)

        return response

    def get_user_preference(self, username):
        user_data = self.user_repo.get_user_data_for_given_username(
            username=username)
        if len(user_data) == 0:
            raise Exception("User is not registered.")
        user_preference_raw_data = self.user_repo.get_user_preferences(
            user_row_id=user_data[0]["row_id"])
        preferences = self.user_factory.parse_user_preference_raw_data(
            user_preference_raw_data)
        return [preference.to_dict() for preference in preferences]

    def delete_user(self, username):
        self.user_repo.delete_user(username)
        self._unlink_wallets_from_user(username)

    def _unlink_wallets_from_user(self, username):
        delete_user_wallet_event = {
            "path": "/wallet/delete",
            "queryStringParameters": {
                "username": username
            },
            "httpMethod": "POST"
        }

        delete_user_wallet_response = self.boto_client.invoke_lambda(
            lambda_function_arn=DELETE_USER_WALLET_ARN,
            invocation_type='RequestResponse',
            payload=json.dumps(delete_user_wallet_event))

        logger.info(f"create_channel_response {delete_user_wallet_response}")
        if delete_user_wallet_response["statusCode"] != 201:
            raise Exception(f"Failed to delete user wallet")

    def _get_no_of_free_calls_from_daemon(self, email, token_to_get_free_call,
                                          expiry_date_block, signature,
                                          current_block_number,
                                          daemon_endpoint):

        request = state_service_pb2.FreeCallStateRequest()
        request.user_id = email
        request.token_for_free_call = token_to_get_free_call
        request.token_expiry_date_block = expiry_date_block
        request.signature = signature
        request.current_block = current_block_number

        endpoint_object = urlparse(daemon_endpoint)
        if endpoint_object.port is not None:
            channel_endpoint = endpoint_object.hostname + ":" + str(
                endpoint_object.port)
        else:
            channel_endpoint = endpoint_object.hostname

        if endpoint_object.scheme == "http":
            channel = grpc.insecure_channel(channel_endpoint)
        elif endpoint_object.scheme == "https":
            channel = grpc.secure_channel(
                channel_endpoint,
                grpc.ssl_channel_credentials(root_certificates=certificate))
        else:
            raise ValueError(
                'Unsupported scheme in service metadata ("{}")'.format(
                    endpoint_object.scheme))

        stub = state_service_pb2_grpc.FreeCallStateServiceStub(channel)
        response = stub.GetFreeCallsAvailable(request)
        logger.info(
            f"No of free  free call for {email} {daemon_endpoint} {current_block_number} is {response.free_calls_available}"
        )
        return response.free_calls_available

    def get_free_call(self, event):
        # passing event here as metering contract is that it need the entire event object
        # metering will eventually go out  then we will clean this up.
        try:
            payload_dict = event['queryStringParameters']
            email = payload_dict['username']
            lambda_client = boto3.client('lambda')
            org_id = payload_dict['organization_id']
            service_id = payload_dict['service_id']
            group_id = unquote(payload_dict['group_id'])
            response = lambda_client.invoke(
                FunctionName=GET_SIGNATURE_TO_GET_FREE_CALL_FROM_DAEMON,
                InvocationType='RequestResponse',
                Payload=json.dumps({
                    "queryStringParameters": {
                        "username": email,
                        "org_id": org_id,
                        "service_id": service_id,
                        "group_id": group_id
                    }
                }))

            result = json.loads(response.get('Payload').read())
            signature_response = json.loads(result['body'])

            if signature_response["status"] == "success":
                logger.info(
                    f"Got signature to make free call to daemon for {email} : {signature_response['data']}"
                )
                token_to_get_free_call = signature_response["data"].get(
                    "token_to_get_free_call", "")
                expiry_date_block = signature_response["data"].get(
                    "expiry_date_block", "")
                signature = signature_response["data"].get("signature", "")
                current_block_number = signature_response["data"].get(
                    "current_block_number", "")
                daemon_endpoint = signature_response["data"].get(
                    "daemon_endpoint", "")
                free_calls_allowed = signature_response["data"].get(
                    "free_calls_allowed", 0)
                free_call_available = self._get_no_of_free_calls_from_daemon(
                    email,
                    bytes.fromhex(token_to_get_free_call), expiry_date_block,
                    bytes.fromhex(signature), current_block_number,
                    daemon_endpoint)

                response = {
                    "username": email,
                    "org_id": org_id,
                    "service_id": service_id,
                    "total_calls_made":
                    free_calls_allowed - free_call_available,
                    "free_calls_allowed": free_calls_allowed
                }

                return generate_lambda_response(200,
                                                response,
                                                cors_enabled=True)
            else:
                raise Exception(
                    "Error while getting signature to make free call to daemon"
                )

        except Exception as e:
            logger.info(
                f"Failed to get freecall from daemon  {email} {org_id} {service_id} error {str(e)}"
            )
            lambda_client = boto3.client('lambda')
            response = lambda_client.invoke(
                FunctionName=GET_FREE_CALLS_METERING_ARN,
                InvocationType='RequestResponse',
                Payload=json.dumps(event))
            result = json.loads(response.get('Payload').read())
            return result

    def register_user(self, user_attribute, client_id):
        user = self.user_factory.create_user_domain_model(
            payload=user_attribute, client_id=client_id)
        if not user.email_verified:
            raise EmailNotVerifiedException()
        return self.user_repo.register_user_data(user)
Esempio n. 11
0
 def __init__(self):
     self.user_factory = UserFactory()
     self.user_repo = UserRepository()
     self.boto_client = BotoUtils(REGION_NAME)
class OrderService:
    def __init__(self, obj_repo):
        self.repo = obj_repo
        self.obj_transaction_history_dao = TransactionHistoryDAO(self.repo)
        self.lambda_client = boto3.client('lambda', region_name=REGION_NAME)
        self.boto_client = BotoUtils(REGION_NAME)
        self.wallet_service = WalletService()
        self.obj_blockchain_util = BlockChainUtil(
            provider_type="HTTP_PROVIDER",
            provider=NETWORKS[NETWORK_ID]['http_provider']
        )
        self.utils = Utils()

    def initiate_order(self, username, payload_dict):
        """
            Initiate Order
                Step 1  Order Creation
                Step 2  Initiate Payment
                Step 3  Persist Transaction History
        """
        price = payload_dict["price"]
        order_type = payload_dict["item_details"]["order_type"]
        item_details = payload_dict["item_details"]
        group_id = item_details["group_id"]
        org_id = item_details["org_id"]
        channel_id = ""
        amount_in_cogs = self.calculate_amount_in_cogs(amount=price["amount"], currency=price["currency"])
        if amount_in_cogs < 1:
            raise Exception("Amount in cogs should be greater than equal to 1")
        item_details["amount_in_cogs"] = amount_in_cogs

        if order_type == OrderType.CREATE_WALLET_AND_CHANNEL.value:
            item_details["wallet_address"] = ""
            recipient = self.get_payment_address_for_org(group_id=group_id, org_id=org_id)

        elif order_type == OrderType.CREATE_CHANNEL.value:
            recipient = self.get_payment_address_for_org(group_id=group_id, org_id=org_id)

        elif order_type == OrderType.FUND_CHANNEL.value:
            channel = self.get_channel_for_topup(username=username, group_id=group_id, org_id=org_id)
            if channel is None:
                raise Exception(f"Channel not found for the user: {username} with org: {org_id} group: {group_id}")
            recipient = channel["recipient"]
            channel_id = channel["channel_id"]
            item_details["wallet_address"] = channel["address"]

        else:
            raise Exception("Invalid order type")

        item_details["channel_id"] = channel_id
        item_details["recipient"] = recipient
        order_details = self.manage_create_order(
            username=username, item_details=item_details,
            price=price
        )
        order_id = order_details["order_id"]

        try:
            payment_data = self.manage_initiate_payment(
                username=username, order_id=order_id, price=price,
                payment_method=payload_dict["payment_method"]
            )

            payment_id = payment_data["payment_id"]
            raw_payment_data = json.dumps(payment_data["payment"])
            obj_transaction_history = TransactionHistory(
                username=username, order_id=order_id, order_type=order_type,
                payment_id=payment_id, raw_payment_data=raw_payment_data,
                status=Status.PAYMENT_INITIATED.value
            )
            self.obj_transaction_history_dao.insert_transaction_history(obj_transaction_history=obj_transaction_history)
            return payment_data
        except Exception as e:
            obj_transaction_history = TransactionHistory(
                username=username, order_id=order_id, order_type=order_type,
                status=Status.PAYMENT_INITIATION_FAILED.value
            )
            self.obj_transaction_history_dao.insert_transaction_history(obj_transaction_history=obj_transaction_history)
            print(repr(e))
            raise e

    def get_channel_for_topup(self, username, group_id, org_id):
        channel_details = self.wallet_service.get_channel_details(
            username=username, group_id=group_id, org_id=org_id
        )
        wallets = channel_details["wallets"]
        for wallet in wallets:
            if (wallet["type"] == "GENERAL") and len(wallet["channels"]) > 0:
                if wallet["channels"][0]["signer"] == SIGNER_ADDRESS:
                    wallet_address = wallet["address"]
                    channel = wallet["channels"][0]
                    channel["address"] = wallet_address
                    return channel
        return None

    def get_payment_address_for_org(self, org_id, group_id):

        group_details_event = {
            "path": f"/org/{org_id}/group/{quote(group_id, safe='')}",
            "pathParameters": {
                "orgId": org_id,
                "group_id": quote(group_id, safe='')
            },
            "httpMethod": "GET"
        }
        logger.info(f"get_group_for_org request: {org_id} and {group_id}")
        group_details_lambda_response = self.lambda_client.invoke(
            FunctionName=GET_GROUP_FOR_ORG_API_ARN,
            InvocationType='RequestResponse',
            Payload=json.dumps(group_details_event)
        )
        group_details_response = json.loads(group_details_lambda_response.get('Payload').read())
        logger.info(f"get_group_for_org response: {group_details_response}")
        if group_details_response["statusCode"] != 200:
            raise Exception(f"Failed to fetch group details for org_id:{org_id} "
                            f"group_id {group_id}")

        group_details_response_body = json.loads(group_details_response["body"])
        groups = group_details_response_body["data"]["groups"]
        if len(groups) == 0:
            raise Exception(f"Failed to find group {group_id} for org_id: {org_id}")
        return groups[0]["payment"]["payment_address"]

    def calculate_amount_in_cogs(self, amount, currency):
        if currency == "USD":
            amount_in_cogs = round(amount * USD_TO_COGS_CONVERSION_FACTOR)
            return amount_in_cogs
        else:
            raise Exception("Currency %s not supported.", currency)

    def execute_order(self, username, payload_dict):
        """
            Execute Order
                Step 1  Execute Payment
                Step 2  Get Receipient Address
                Step 3  Process Order
                Step 4  Update Transaction History
        """
        order_id = payload_dict["order_id"]
        payment_id = payload_dict["payment_id"]
        order = self.get_order_details_by_order_id(order_id, username)
        payment = None
        for payment_item in order["payments"]:
            if payment_item["payment_id"] == payment_id:
                payment = payment_item
                break

        if payment is None:
            raise Exception(f"Failed to fetch order details for order_id {order_id} \n"
                            f"payment_id {payment_id} \n"
                            f"username{username}")

        order_type = order["item_details"]["order_type"]
        item_details = order["item_details"]
        payment_method = payment["payment_details"]["payment_method"]
        paid_payment_details = payload_dict["payment_details"]
        price = payment["price"]
        status = Status.PAYMENT_EXECUTION_FAILED.value
        self.manage_execute_payment(
            username=username, order_id=order_id, payment_id=payment_id,
            payment_details=paid_payment_details, payment_method=payment_method
        )

        status = Status.PAYMENT_EXECUTED.value
        try:
            status = Status.ORDER_PROCESSING_FAILED.value
            amount_in_cogs = self.calculate_amount_in_cogs(amount=price["amount"], currency=price["currency"])
            if amount_in_cogs < 1:
                raise Exception("Amount in cogs should be greater than equal to 1")
            processed_order_data = self.manage_process_order(
                username=username,
                order_id=order_id, order_type=order_type,
                amount=price["amount"],
                currency=price["currency"], order_data=item_details,
                amount_in_cogs=amount_in_cogs
            )
            status = Status.ORDER_PROCESSED.value
            obj_transaction_history = TransactionHistory(
                username=username, order_id=order_id, order_type=order_type,
                status=status, payment_id=payment_id,
                payment_method=payment_method,
                raw_payment_data=json.dumps(paid_payment_details)
            )
            self.obj_transaction_history_dao.insert_transaction_history(obj_transaction_history=obj_transaction_history)
            processed_order_data["price"] = price
            processed_order_data["item_details"] = item_details
            return processed_order_data

        except Exception as e:
            obj_transaction_history = TransactionHistory(
                username=username, order_id=order_id,
                order_type=order_type, status=status
            )
            self.obj_transaction_history_dao.insert_transaction_history(obj_transaction_history=obj_transaction_history)
            print(repr(e))
            raise e

    def get_order_details_by_order_id(self, order_id, username):
        order_details_event = {
            "path": f"order/{order_id}",
            "pathParameters": {"order_id": order_id},
            "httpMethod": "GET"
        }

        logger.info(f"Requesting order details for order_id {order_id}")
        response = self.lambda_client.invoke(
            FunctionName=ORDER_DETAILS_ORDER_ID_ARN,
            InvocationType='RequestResponse',
            Payload=json.dumps(order_details_event)
        )
        order_details_response = json.loads(response.get('Payload').read())
        if order_details_response["statusCode"] != 200:
            raise Exception(f"Failed to fetch order details for order_id {order_id} username{username}")

        order_details_data = json.loads(order_details_response["body"])
        if order_details_data["username"] != username:
            raise Exception(f"Failed to fetch order details for order_id {order_id} username{username}")
        return order_details_data

    def manage_initiate_payment(self, username, order_id, price, payment_method):
        initiate_payment_event = {
            "pathParameters": {"order_id": order_id},
            "httpMethod": "POST",
            "body": json.dumps({"price": price, "payment_method": payment_method})
        }
        response = self.lambda_client.invoke(
            FunctionName=INITIATE_PAYMENT_SERVICE_ARN,
            InvocationType='RequestResponse',
            Payload=json.dumps(initiate_payment_event)
        )
        initiate_payment_data = json.loads(response.get('Payload').read())
        if initiate_payment_data["statusCode"] == 201:
            return json.loads(initiate_payment_data["body"])
        else:
            logger.error("Error initiating payment for user %s", username)
            raise PaymentInitiateFailed

    def manage_create_order(self, username, item_details, price):
        create_order_event = {
            "path": "/order/create",
            "httpMethod": "POST",
            "body": json.dumps({"price": price, "item_details": item_details, "username": username})
        }
        create_order_service_response = self.boto_client.invoke_lambda(
            lambda_function_arn=CREATE_ORDER_SERVICE_ARN,
            invocation_type='RequestResponse',
            payload=json.dumps(create_order_event)
        )
        logger.info(f"create_order_service_response: {create_order_service_response}")

        if create_order_service_response["statusCode"] == 201:
            return json.loads(create_order_service_response["body"])
        else:
            raise Exception(f"Error creating order for user {username}")

    def manage_execute_payment(self, username, order_id, payment_id, payment_details, payment_method):
        execute_payment_event = {
            "pathParameters": {"order_id": order_id, "payment_id": payment_id},
            "body": json.dumps({"payment_method": payment_method, "payment_details": payment_details})
        }
        response = self.lambda_client.invoke(
            FunctionName=EXECUTE_PAYMENT_SERVICE_ARN,
            InvocationType='RequestResponse',
            Payload=json.dumps(execute_payment_event)
        )
        payment_executed = json.loads(response.get('Payload').read())
        if payment_executed["statusCode"] == 201:
            return payment_executed
        else:
            raise Exception(f"Error executing payment for username {username} against order_id {order_id}")

    def manage_process_order(self, username, order_id, order_type, amount, currency, order_data, amount_in_cogs):
        logger.info(f"Order Data {order_data}")
        group_id = order_data["group_id"]
        org_id = order_data["org_id"]
        recipient = order_data["recipient"]
        channel_id = order_data["channel_id"]
        sender = order_data["wallet_address"]
        if order_type == OrderType.CREATE_WALLET_AND_CHANNEL.value:
            wallet_create_payload = {
                "path": "/wallet",
                "body": json.dumps({"username": username}),
                "httpMethod": "POST"
            }
            wallet_create_lambda_response = self.lambda_client.invoke(
                FunctionName=WALLETS_SERVICE_ARN,
                InvocationType='RequestResponse',
                Payload=json.dumps(wallet_create_payload)
            )
            wallet_create_response = json.loads(wallet_create_lambda_response.get("Payload").read())
            if wallet_create_response["statusCode"] != 200:
                raise Exception("Failed to create wallet")
            wallet_create_response_body = json.loads(wallet_create_response["body"])
            wallet_details = wallet_create_response_body["data"]

            try:
                current_block_no = self.obj_blockchain_util.get_current_block_no()
                # 1 block no is mined in 15 sec on average, setting expiration as 10 years
                expiration = current_block_no + (10 * 365 * 24 * 60 * 4)
                message_nonce = current_block_no
                self.EXECUTOR_WALLET_ADDRESS = self.boto_client.get_ssm_parameter(EXECUTOR_ADDRESS)
                group_id_in_hex = "0x" + base64.b64decode(group_id).hex()
                signature_details = self.generate_signature_for_open_channel_for_third_party(
                    recipient=recipient, group_id=group_id_in_hex,
                    amount_in_cogs=amount_in_cogs, expiration=expiration,
                    message_nonce=message_nonce, sender_private_key=wallet_details["private_key"],
                    executor_wallet_address=self.EXECUTOR_WALLET_ADDRESS
                )

                logger.info(f"Signature Details {signature_details}")
                open_channel_body = {
                    'order_id': order_id,
                    'sender': wallet_details["address"],
                    'signature': signature_details["signature"],
                    'r': signature_details["r"],
                    's': signature_details["s"],
                    'v': signature_details["v"],
                    'group_id': group_id,
                    'org_id': org_id,
                    'amount': amount,
                    'currency': currency,
                    'recipient': recipient,
                    'current_block_no': current_block_no,
                    'amount_in_cogs': amount_in_cogs
                }
                channel_details = self.wallet_service.create_channel(open_channel_body=open_channel_body)
                channel_details.update(wallet_details)
                return channel_details
            except Exception as e:
                logger.error("Failed to create channel")
                logger.error(repr(e))
                response = {
                    "transaction_hash": "",
                    "signature": "",
                    "amount_in_cogs": 0,
                    "price": {
                        "amount": amount,
                        "currency": currency
                    },
                    "item_details": order_data
                }
                response.update(wallet_details)
                raise ChannelCreationFailed("Failed to create channel", wallet_details=response)

        elif order_type == OrderType.CREATE_CHANNEL.value:
            try:
                logger.info(f"Order Data {order_data}")
                signature = order_data["signature"]
                v, r, s = Web3.toInt(hexstr="0x" + signature[-2:]), signature[:66], "0x" + signature[66:130]
                open_channel_body = {
                    'order_id': order_id, 'sender': order_data["wallet_address"],
                    'signature': order_data["signature"], 'r': r, 's': s, 'v': v,
                    'group_id': group_id, 'org_id': org_id, 'amount': amount, 'currency': currency,
                    'recipient': recipient, 'current_block_no': order_data["current_block_number"],
                    'amount_in_cogs': amount_in_cogs
                }
                channel_details = self.wallet_service.create_channel(open_channel_body=open_channel_body)
                logger.info("channel_details: ", channel_details)
                return channel_details
            except Exception as e:
                logger.error("Failed to create channel")
                logger.error(repr(e))
                raise ChannelCreationFailed("Failed to create channel", wallet_details=order_data)

        elif order_type == OrderType.FUND_CHANNEL.value:

            try:
                fund_channel_body = {
                    'order_id': order_id,
                    'group_id': group_id,
                    'org_id': org_id,
                    'amount': amount,
                    'channel_id': channel_id,
                    'currency': currency,
                    'recipient': recipient,
                    'sender': sender,
                    'amount_in_cogs': amount_in_cogs
                }
                fund_channel_payload = {
                    "path": "/wallet/channel/deposit",
                    "body": json.dumps(fund_channel_body),
                    "httpMethod": "POST"
                }

                fund_channel_lambda_response = self.lambda_client.invoke(
                    FunctionName=WALLETS_SERVICE_ARN,
                    InvocationType='RequestResponse',
                    Payload=json.dumps(fund_channel_payload)
                )

                fund_channel_response = json.loads(fund_channel_lambda_response.get("Payload").read())
                if fund_channel_response["statusCode"] != 200:
                    raise Exception(f"Failed to add funds in channel for {fund_channel_body}")

                fund_channel_response_body = json.loads(fund_channel_response["body"])
                fund_channel_transaction_details = fund_channel_response_body["data"]
                return fund_channel_transaction_details
            except Exception as e:
                logger.error("Failed to fund channel")
                logger.error(repr(e))
                raise FundChannelFailed()
        else:
            raise Exception("Order type is not valid.")

    def get_order_details_by_username(self, username):
        order_details_event = {
            "path": f"/order",
            "queryStringParameters": {"username": username},
            "httpMethod": "GET"
        }

        logger.info(f"Requesting order details for username {username}")
        order_details_response = self.boto_client.invoke_lambda(
            lambda_function_arn=ORDER_DETAILS_BY_USERNAME_ARN,
            invocation_type='RequestResponse',
            payload=json.dumps(order_details_event)
        )
        if order_details_response["statusCode"] != 200:
            raise Exception(f"Failed to fetch order details for username{username}")

        org_id_name_mapping = self.get_organizations_from_contract()

        order_details_response_body = json.loads(order_details_response["body"])
        orders = order_details_response_body["orders"]

        for order in orders:
            order_id = order["order_id"]
            order["wallet_type"] = "GENERAL"
            if "org_id" in order["item_details"]:
                org_id = order["item_details"]["org_id"]
                if org_id in org_id_name_mapping:
                    order["item_details"]["organization_name"] = org_id_name_mapping[org_id]

            transaction_details_event = {
                "path": f"/wallet/channel/transactions",
                "queryStringParameters": {"order_id": order_id},
                "httpMethod": "GET"
            }
            transaction_details_lambda_response = self.lambda_client.invoke(
                FunctionName=WALLETS_SERVICE_ARN,
                InvocationType='RequestResponse',
                Payload=json.dumps(transaction_details_event)
            )
            transaction_details_response = json.loads(transaction_details_lambda_response.get('Payload').read())
            if transaction_details_response["statusCode"] != 200:
                raise Exception(f"Failed to fetch transaction details for username{order_id}")
            transaction_details_response_body = json.loads(transaction_details_response["body"])
            order["wallet_transactions"] = transaction_details_response_body["data"]["transactions"]
            order_status = TransactionStatus.SUCCESS
            for payment in order["payments"]:
                if payment["payment_status"] != TransactionStatus.SUCCESS:
                    order_status = payment["payment_status"]
                    break

            for wallet_transaction in order["wallet_transactions"]:
                if wallet_transaction["status"] != TransactionStatus.SUCCESS:
                    order_status = wallet_transaction["status"]
                    break

            order["order_status"] = order_status
        return {"orders": orders}

    def get_organizations_from_contract(self):
        org_details_event = {
            "path": f"/org",
            "httpMethod": "GET"
        }
        org_details_response = self.boto_client.invoke_lambda(
            lambda_function_arn=GET_ALL_ORG_API_ARN,
            invocation_type='RequestResponse',
            payload=json.dumps(org_details_event)
        )
        if org_details_response["statusCode"] != 200:
            raise Exception("Failed to get org details")

        org_details = json.loads(org_details_response["body"])["data"]
        org_id_name_mapping = {}
        for org in org_details:
            org_id_name_mapping[org["org_id"]] = org["org_name"]

        return org_id_name_mapping

    def generate_signature_for_open_channel_for_third_party(self, recipient, group_id, amount_in_cogs, expiration,
                                                            message_nonce, sender_private_key, executor_wallet_address):

        signature_for_open_channel_for_third_party_body = {
            'recipient': recipient,
            'group_id': group_id,
            'amount_in_cogs': amount_in_cogs,
            'expiration': expiration,
            'message_nonce': message_nonce,
            'signer_key': sender_private_key,
            'executor_wallet_address': executor_wallet_address
        }

        signature_for_open_channel_for_third_party_payload = {
            "path": "/signer/open-channel-for-third-party",
            "body": json.dumps(signature_for_open_channel_for_third_party_body),
            "httpMethod": "POST"
        }

        signature_for_open_channel_for_third_party_response = self.lambda_client.invoke(
            FunctionName=SIGNER_SERVICE_ARN,
            InvocationType='RequestResponse',
            Payload=json.dumps(signature_for_open_channel_for_third_party_payload)
        )

        signature_response = json.loads(signature_for_open_channel_for_third_party_response.get("Payload").read())
        if signature_response["statusCode"] != 200:
            raise Exception(f"Failed to create signature for {signature_for_open_channel_for_third_party_body}")
        signature_details = json.loads(signature_response["body"])
        return signature_details["data"]

    def cancel_order(self):
        logger.info("Start of UpdateTransactionStatus::manage_update_canceled_order_in_txn_history")
        list_of_order_id_for_expired_transaction = self.obj_transaction_history_dao.get_order_id_for_expired_transaction()
        logger.info(f"List of order_id to be updated with ORDER CANCELED: {list_of_order_id_for_expired_transaction}")
        update_transaction_status = self.obj_transaction_history_dao.update_transaction_status(
            list_of_order_id=list_of_order_id_for_expired_transaction, status=OrderStatus.ORDER_CANCELED.value)
        return update_transaction_status

    def cancel_order_for_given_order_id(self, order_id):
        logger.info("UpdateTransactionStatus::cancel_order_for_given_order_id: %s", order_id)
        transaction_data_dict = self.obj_transaction_history_dao.get_transaction_details_for_given_order_id(
            order_id=order_id)
        if transaction_data_dict["status"] == OrderStatus.ORDER_CANCELED.value:
            return f"Order with order_id {order_id} is already canceled."
        elif transaction_data_dict["status"] in [OrderStatus.PAYMENT_INITIATED.value,
                                                 OrderStatus.PAYMENT_INITIATION_FAILED.value,
                                                 OrderStatus.PAYMENT_EXECUTION_FAILED]:
            self.obj_transaction_history_dao.update_transaction_status(list_of_order_id=[order_id],
                                                                       status=OrderStatus.ORDER_CANCELED.value)
            return f"Order with order_id {order_id} is canceled successfully."
        else:
            return f"Unable to cancel order with order_id {order_id}"

    def currency_to_token(self, amount, currency):
        amount_in_cogs = self.calculate_amount_in_cogs(amount=decimal.Decimal(amount), currency=currency)
        conversion_data = {"base": currency, "amount": amount, "amount_in_cogs": str(amount_in_cogs),
                           "amount_in_agi": str(self.utils.cogs_to_agi(cogs=amount_in_cogs)),
                           f"{currency}/cogs": str(USD_TO_COGS_CONVERSION_FACTOR), "agi/cogs": str(COGS_TO_AGI)}
        logger.debug(f"currency_to_token::conversion_data {conversion_data}")
        return conversion_data
class OrganizationPublisherService:
    def __init__(self, org_uuid, username):
        self.org_uuid = org_uuid
        self.username = username
        self.boto_utils = BotoUtils(region_name=registry.config.REGION_NAME)

    def get_approval_pending_organizations(self, limit, type=None):
        status = OrganizationStatus.ONBOARDING.value
        organizations = org_repo.get_organizations(status, limit, type)
        return [org.to_response() for org in organizations]

    def get_all_org_for_user(self):
        logger.info(f"get organization for user: {self.username}")
        organizations = org_repo.get_all_orgs_for_user(username=self.username)
        return [org.to_response() for org in organizations]

    def get_all_org_id(self):
        organizations = org_repo.get_organizations()
        return [org.id for org in organizations]

    def get_org_id_availability_status(self, org_id):
        org_id_list = self.get_all_org_id()

        if org_id in org_id_list:
            return OrganizationIDAvailabilityStatus.UNAVAILABLE.value
        if RegistryBlockChainUtil(
                EnvironmentType.MAIN.value).is_org_published(org_id):
            return OrganizationIDAvailabilityStatus.UNAVAILABLE.value
        return OrganizationIDAvailabilityStatus.AVAILABLE.value

    def get_groups_for_org(self):
        logger.info(f"get groups for org_uuid: {self.org_uuid}")
        groups = org_repo.get_groups_for_org(self.org_uuid)
        return {
            "org_uuid": self.org_uuid,
            "groups": [group.to_response() for group in groups]
        }

    def create_organization(self, payload):
        logger.info(f"create organization for user: {self.username}")
        organization = OrganizationFactory.org_domain_entity_from_payload(
            payload)
        organization.setup_id()
        logger.info(f"assigned org_uuid : {organization.uuid}")
        org_ids = self.get_all_org_id()
        if organization.id in org_ids:
            raise Exception("Org_id already exists")
        updated_state = Organization.next_state(
            None, None, OrganizationActions.CREATE.value)
        org_repo.add_organization(organization, self.username, updated_state)
        organization = org_repo.get_organization(org_id=organization.id)
        return organization.to_response()

    def update_organization(self, payload, action):
        logger.info(
            f"update organization for user: {self.username} org_uuid: {self.org_uuid} action: {action}"
        )
        updated_organization = OrganizationFactory.org_domain_entity_from_payload(
            payload)
        current_organization = org_repo.get_organization(
            org_uuid=self.org_uuid)
        self._archive_current_organization(current_organization)
        updated_state = Organization.next_state(current_organization,
                                                updated_organization, action)
        org_repo.update_organization(updated_organization, self.username,
                                     updated_state)
        return "OK"

    def notify_user_on_start_of_onboarding_process(self, org_id, recipients):
        if not recipients:
            logger.info(
                f"Unable to find recipients for organization with org_id {org_id}"
            )
            return
        mail_template = get_notification_mail_template_for_service_provider_when_org_is_submitted_for_onboarding(
            org_id)
        for recipient in recipients:
            send_notification_payload = {
                "body":
                json.dumps({
                    "message": mail_template["body"],
                    "subject": mail_template["subject"],
                    "notification_type": "support",
                    "recipient": recipient
                })
            }
            self.boto_utils.invoke_lambda(
                lambda_function_arn=registry.config.NOTIFICATION_ARN,
                invocation_type="RequestResponse",
                payload=json.dumps(send_notification_payload))
            logger.info(
                f"Recipient {recipient} notified for successfully starting onboarding process."
            )

    def _archive_current_organization(self, organization):
        if organization.get_status() == OrganizationStatus.PUBLISHED.value:
            org_repo.add_organization_archive(organization)

    def publish_org_to_ipfs(self):
        logger.info(f"publish organization to ipfs org_uuid: {self.org_uuid}")
        organization = org_repo.get_organization(org_uuid=self.org_uuid)
        organization.publish_to_ipfs()
        org_repo.store_ipfs_hash(organization, self.username)
        return organization.to_response()

    def save_transaction_hash_for_publish_org(self, payload):
        transaction_hash = payload.get("transaction_hash")
        if transaction_hash is None:
            raise BadRequestException()
        user_address = payload.get("wallet_address")
        nonce = payload.get("nonce")
        logger.info(
            f"save transaction hash for publish organization org_uuid: {self.org_uuid} "
            f"transaction_hash: {transaction_hash} user_address: {user_address} nonce: {nonce}"
        )
        org_repo.persist_publish_org_transaction_hash(self.org_uuid,
                                                      transaction_hash,
                                                      user_address, nonce,
                                                      self.username)
        return "OK"

    def get_all_member(self, status, role, pagination_details):
        offset = pagination_details.get("offset", None)
        limit = pagination_details.get("limit", None)
        sort = pagination_details.get("sort", None)
        org_members_list = org_repo.get_org_member(org_uuid=self.org_uuid,
                                                   status=status,
                                                   role=role)
        return [member.to_response() for member in org_members_list]

    def get_member(self, member_username):
        members = org_repo.get_org_member(username=member_username,
                                          org_uuid=self.org_uuid)
        if len(members) == 0:
            logger.info(
                f"No member {member_username} for the organization {self.org_uuid}"
            )
            return []
        return [member.to_response() for member in members]

    def verify_invite(self, invite_code):
        logger.info(
            f"verify member invite_code: {invite_code} username: {self.username}"
        )
        if org_repo.org_member_verify(self.username, invite_code):
            return "OK"
        return "NOT_FOUND"

    def delete_members(self, org_members):
        logger.info(
            f"user: {self.username} requested to delete members: {org_members} of org_uuid: {self.org_uuid}"
        )
        org_member_list = OrganizationFactory.org_member_domain_entity_from_payload_list(
            org_members, self.org_uuid)
        org_repo.delete_members(org_member_list,
                                member_status=[
                                    OrganizationMemberStatus.PENDING.value,
                                    OrganizationMemberStatus.ACCEPTED.value
                                ])
        return "OK"

    def publish_members(self, transaction_hash, org_members):
        logger.info(
            f"user: {self.username} published members: {org_members} with transaction_hash: {transaction_hash}"
        )
        org_member = OrganizationFactory.org_member_domain_entity_from_payload_list(
            org_members, self.org_uuid)
        org_repo.persist_publish_org_member_transaction_hash(
            org_member, transaction_hash, self.org_uuid)
        return "OK"

    def register_member(self, invite_code, wallet_address):
        logger.info(
            f"register user: {self.username} with invite_code: {invite_code}")
        if Web3.isAddress(wallet_address):
            org_repo.update_org_member(self.username, wallet_address,
                                       invite_code)
        else:
            raise Exception("Invalid wallet address")
        return "OK"

    def invite_members(self, members_payload):
        current_time = datetime.utcnow()
        requested_invite_member_list = OrganizationFactory.org_member_domain_entity_from_payload_list(
            members_payload, self.org_uuid)
        current_org_member = org_repo.get_org_member(org_uuid=self.org_uuid)
        current_org_member_username_list = [
            member.username for member in current_org_member
        ]
        eligible_invite_member_list = [
            member for member in requested_invite_member_list
            if member.username not in current_org_member_username_list
        ]
        for org_member in eligible_invite_member_list:
            org_member.generate_invite_code()
            org_member.set_status(OrganizationMemberStatus.PENDING.value)
            org_member.set_role(Role.MEMBER.value)
            org_member.set_invited_on(current_time)
            org_member.set_updated_on(current_time)

        organization = org_repo.get_organization(org_uuid=self.org_uuid)
        org_name = organization.name
        self._send_email_notification_for_inviting_organization_member(
            eligible_invite_member_list, org_name)
        org_repo.add_member(eligible_invite_member_list)

        failed_invitation = [
            member.username for member in requested_invite_member_list
            if member.username in current_org_member_username_list
        ]
        return {
            "member":
            [member.to_response() for member in eligible_invite_member_list],
            "failed_invitation":
            failed_invitation
        }

    def _send_email_notification_for_inviting_organization_member(
            self, org_members_list, org_name):
        for org_member in org_members_list:
            recipient = org_member.username
            mail_template = get_org_member_invite_mail(org_name,
                                                       org_member.invite_code)
            send_notification_payload = {
                "body":
                json.dumps({
                    "message": mail_template["body"],
                    "subject": mail_template["subject"],
                    "notification_type": "support",
                    "recipient": recipient
                })
            }
            self.boto_utils.invoke_lambda(
                lambda_function_arn=registry.config.NOTIFICATION_ARN,
                invocation_type="RequestResponse",
                payload=json.dumps(send_notification_payload))
            logger.info(f"Org Membership Invite sent to {recipient}")

    def update_verification(self, verification_type, verification_details):
        if verification_type in ORG_TYPE_VERIFICATION_TYPE_MAPPING:
            if ORG_TYPE_VERIFICATION_TYPE_MAPPING[
                    verification_type] == OrganizationType.INDIVIDUAL.value:
                owner_username = verification_details["username"]
                status = verification_details["status"]
                updated_by = verification_details["updated_by"]
                org_repo.update_all_individual_organization_for_user(
                    owner_username, status, updated_by)

            elif ORG_TYPE_VERIFICATION_TYPE_MAPPING[
                    verification_type] == OrganizationType.ORGANIZATION.value:
                status = verification_details["status"]
                org_uuid = verification_details["org_uuid"]
                updated_by = verification_details["updated_by"]
                comment = verification_details["comment"]
                if status in ORG_STATUS_LIST:
                    org_repo.update_organization_status(
                        org_uuid, status, updated_by)
                    organization = org_repo.get_organization(org_uuid=org_uuid)
                    owner = org_repo.get_org_member(org_uuid=org_uuid,
                                                    role=Role.OWNER.value)
                    owner_username = owner[0].username
                    self.send_mail_to_owner(owner_username, comment,
                                            organization.id, status)
                else:
                    logger.error(f"Invalid status {status}")
                    raise MethodNotImplemented()
            else:
                logger.error(
                    f"Invalid organization type with verification type {verification_type}"
                )
                raise MethodNotImplemented()
        else:
            logger.error(f"Invalid verification type {verification_type}")
            raise MethodNotImplemented()
        return {}

    def send_mail_to_owner(self, owner_email_address, comment, org_id, status):
        if status == OrganizationStatus.REJECTED.value:
            mail_template = get_owner_mail_for_org_rejected(org_id, comment)
        elif status == OrganizationStatus.CHANGE_REQUESTED.value:
            mail_template = get_owner_mail_for_org_changes_requested(
                org_id, comment)
        elif status == OrganizationStatus.APPROVED.value:
            mail_template = get_owner_mail_for_org_approved(org_id)
        else:
            logger.info(f"Organization status: {status}")
            raise InvalidOrganizationStateException()

        utils.send_email_notification([owner_email_address],
                                      mail_template["subject"],
                                      mail_template["body"],
                                      registry.config.NOTIFICATION_ARN,
                                      self.boto_utils)
Esempio n. 14
0
 def __init__(self):
     self.boto_utils = BotoUtils(region_name=REGION_NAME)
class WalletService:
    def __init__(self):
        self.boto_client = BotoUtils(REGION_NAME)

    def create_channel(self, open_channel_body):
        create_channel_transaction_payload = {
            "path": "/wallet/channel/event",
            "body": json.dumps(open_channel_body),
            "httpMethod": "POST"
        }

        create_channel_response = self.boto_client.invoke_lambda(
            lambda_function_arn=CREATE_CHANNEL_EVENT_ARN,
            invocation_type='RequestResponse',
            payload=json.dumps(create_channel_transaction_payload))

        logger.info(f"create_channel_response {create_channel_response}")
        if create_channel_response["statusCode"] != 201:
            raise Exception(f"Failed to create channel")

        create_channel_response_body = json.loads(
            create_channel_response["body"])
        channel_details = create_channel_response_body["data"]
        return channel_details

    def get_channel_details(self, username, org_id, group_id):
        """ Method to get wallet details for a given username. """
        try:
            wallet_channel_transactions = self.get_channel_transactions(
                username=username, org_id=org_id, group_id=group_id)
            wallet_response = {
                "username": username,
                "org_id": org_id,
                "group_id": group_id,
                "wallets": wallet_channel_transactions
            }
            for wallet in wallet_response["wallets"]:
                user_address = wallet["address"]
                wallet["channels"] = self.get_channels_from_contract(
                    user_address=user_address,
                    org_id=org_id,
                    group_id=group_id)
            return wallet_response
        except Exception as e:
            print(repr(e))
            raise e

    def get_channel_transactions(self, username, org_id, group_id):

        channel_transactions_event = {
            "path": "/wallet/channel/transactions",
            "queryStringParameters": {
                "username": username,
                "group_id": group_id,
                "org_id": org_id
            },
            "httpMethod": "GET"
        }

        channel_transactions_response = self.boto_client.invoke_lambda(
            lambda_function_arn=WALLETS_SERVICE_ARN,
            invocation_type='RequestResponse',
            payload=json.dumps(channel_transactions_event))
        if channel_transactions_response["statusCode"] != 200:
            raise Exception(
                f"Failed to fetch wallet details for username: {username}")

        channel_transactions_response_body = json.loads(
            channel_transactions_response["body"])
        channel_transactions = channel_transactions_response_body["data"][
            "wallets"]
        return channel_transactions

    def get_channels_from_contract(self, user_address, org_id, group_id):
        event = {
            "httpMethod": "GET",
            "path": "/channel",
            "queryStringParameters": {
                "user_address": user_address,
                "org_id": org_id,
                "group_id": group_id
            }
        }

        channel_details_response = self.boto_client.invoke_lambda(
            lambda_function_arn=GET_CHANNEL_API_OLD_ARN,
            invocation_type="RequestResponse",
            payload=json.dumps(event))

        if "statusCode" not in channel_details_response:
            logger.error(
                f"contract API boto call failed {channel_details_response}")
            raise Exception(
                f"Failed to get channel details from contract API {event}")

        if channel_details_response["statusCode"] != 200:
            raise Exception(
                f"Failed to get channel details from contract API username: {user_address} "
                f"group_id: {group_id} "
                f"org_id: {org_id}")

        channel_details = json.loads(channel_details_response["body"])["data"]
        return channel_details["channels"]

    def get_wallets(self, username):
        get_wallet_event = {
            "path": "/wallet",
            "queryStringParameters": {
                "username": username
            },
            "httpMethod": "GET"
        }
        get_wallet_response = self.boto_client.invoke_lambda(
            lambda_function_arn=WALLETS_SERVICE_ARN,
            invocation_type="RequestResponse",
            payload=json.dumps(get_wallet_event))
        status = get_wallet_response["statusCode"]
        if status != 200:
            raise Exception("Unable to get wallets for username %s", username)
        wallets = json.loads(get_wallet_response["body"])["data"]
        return wallets

    def register_wallet(self, username, wallet_details):
        register_wallet_body = {
            'address': wallet_details["address"],
            'type': wallet_details["type"],
            'username': username
        }
        register_wallet_payload = {
            "path": "/wallet/register",
            "body": json.dumps(register_wallet_body),
            "httpMethod": "POST"
        }
        raw_response = self.boto_client.invoke_lambda(
            lambda_function_arn=WALLETS_SERVICE_ARN,
            invocation_type="RequestResponse",
            payload=json.dumps(register_wallet_payload))
        status = raw_response["statusCode"]
        if int(status) != 200:
            raise Exception("Unable to register wallet for username %s",
                            username)
        return json.loads(raw_response["body"])["data"]

    def set_default_wallet(self, username, address):
        set_default_wallet_body = {'address': address, 'username': username}
        set_default_wallet_payload = {
            "path": "/wallet/status",
            "body": json.dumps(set_default_wallet_body),
            "httpMethod": "POST"
        }
        response = self.boto_client.invoke_lambda(
            lambda_function_arn=WALLETS_SERVICE_ARN,
            invocation_type="RequestResponse",
            payload=json.dumps(set_default_wallet_payload))
        return json.loads(response["body"])["data"]

    def get_default_wallet(self, username):
        wallets = self.get_wallets(username)["wallets"]
        default_wallet = None
        for wallet in wallets:
            if wallet["is_default"] == 1 and wallet["type"] == "GENERAL":
                default_wallet = wallet

        if default_wallet is None:
            raise Exception("No active paypal wallet")

        return default_wallet
 def __init__(self, org_uuid, username):
     self.org_uuid = org_uuid
     self.username = username
     self.boto_utils = BotoUtils(region_name=REGION_NAME)
class PaypalPayment(Payment):

    def __init__(self, payment_id, amount, currency, payment_status, created_at, payment_details):
        super().__init__(payment_id, amount, currency, payment_status, created_at, payment_details)
        self.boto_utils = BotoUtils(region_name=REGION_NAME)

    def initiate_payment(self, order_id, item_details):
        try:
            payee_client_api = paypalrestsdk.Api({
                'mode': MODE,
                'client_id': self.boto_utils.get_ssm_parameter(PAYPAL_CLIENT),
                'client_secret': self.boto_utils.get_ssm_parameter(PAYPAL_SECRET)
            })
        except Exception as e:
            logger.error("Failed to get ssm parameters")
            raise e
        paypal_payload = self.get_paypal_payload(order_id, item_details["org_id"], item_details["service_id"])
        payment = paypalrestsdk.Payment(paypal_payload, api=payee_client_api)

        if not payment.create():
            logger.error(f"Paypal error:{payment.error}")
            raise Exception("Payment failed to create")

        logger.info(f"Paypal payment initiated with paypal_payment_id: {payment.id}")

        approval_url = ""
        for link in payment.links:
            if link.rel == "approval_url":
                approval_url = str(link.href)

        if len(approval_url) == 0:
            raise Exception("Payment link not found")
        self._payment_details["payment_id"] = payment.id

        response_payload = {
            "payment": {
                "id": payment.id,
                "payment_url": approval_url
            }
        }

        return response_payload

    def execute_transaction(self, paid_payment_details):
        try:
            payee_client_api = paypalrestsdk.Api({
                'mode': MODE,
                'client_id': self.boto_utils.get_ssm_parameter(PAYPAL_CLIENT),
                'client_secret': self.boto_utils.get_ssm_parameter(PAYPAL_SECRET)
            })
        except Exception as e:
            logger.error("Failed to get ssm parameters")
            raise e
        paypal_payment_id = self._payment_details["payment_id"]
        payer_id = paid_payment_details["payer_id"]
        payment = paypalrestsdk.Payment.find(paypal_payment_id, api=payee_client_api)

        if payment.execute({"payer_id": payer_id}):
            logger.info(f"Paypal payment execution is success for paypal_payment_id:{paypal_payment_id}")
            self._payment_status = PaymentStatus.SUCCESS

            return True
        elif self._payment_status == PaymentStatus.PENDING:
            logger.info(f"Paypal payment execution is failed for paypal_payment_id:{paypal_payment_id}")
            self._payment_status = PaymentStatus.FAILED

        logger.error(payment.error)
        return False

    def get_paypal_payload(self, order_id, org_id, service_id):
        paypal_payload = {
            "intent": "sale",
            "payer": {
                "payment_method": PAYMENT_METHOD_PAYPAL
            },
            "redirect_urls": {
                "return_url": PAYMENT_RETURN_URL.format(org_id, service_id, order_id, self._payment_id),
                "cancel_url": PAYMENT_CANCEL_URL.format(org_id, service_id, order_id, self._payment_id)
            },
            "transactions": [
                {
                    "item_list": {
                        "items": [
                            {
                                "name": "item",
                                "sku": "item",
                                "price": self._amount,
                                "currency": self._currency,
                                "quantity": 1
                            }
                        ]
                    },
                    "amount": {
                        "total": self._amount,
                        "currency": self._currency
                    },
                    "description": ""
                }
            ]
        }
        return paypal_payload
class OrganizationPublisherService:
    def __init__(self, org_uuid, username):
        self.org_uuid = org_uuid
        self.username = username
        self.boto_utils = BotoUtils(region_name=REGION_NAME)

    def get_for_admin(self, params):
        status = params.get("status", None)
        organizations = org_repo.get_org(status)
        return [org.to_response() for org in organizations]

    def get_all_org_for_user(self):
        logger.info(f"get organization for user: {self.username}")
        organizations = org_repo.get_org_for_user(username=self.username)
        return [org.to_response() for org in organizations]

    def get_groups_for_org(self):
        logger.info(f"get groups for org_uuid: {self.org_uuid}")
        groups = org_repo.get_groups_for_org(self.org_uuid)
        return {
            "org_uuid": self.org_uuid,
            "groups": [group.to_response() for group in groups]
        }

    def create_organization(self, payload):
        logger.info(f"create organization for user: {self.username}")
        organization = OrganizationFactory.org_domain_entity_from_payload(
            payload)
        organization.setup_id()
        logger.info(f"assigned org_uuid : {organization.uuid}")
        org_repo.add_organization(organization, self.username,
                                  OrganizationStatus.ONBOARDING.value)
        return "OK"

    def save_organization_draft(self, payload):
        logger.info(
            f"edit organization for user: {self.username} org_uuid: {self.org_uuid}"
        )
        updated_organization = OrganizationFactory.org_domain_entity_from_payload(
            payload)
        current_organization = org_repo.get_org_for_org_uuid(self.org_uuid)
        self._archive_current_organization(current_organization)

        if current_organization.is_minor(updated_organization):
            org_repo.update_organization(updated_organization, self.username,
                                         OrganizationStatus.DRAFT.value)
        else:
            raise MethodNotImplemented()
        return "OK"

    def _archive_current_organization(self, organization):
        if organization.get_status() == OrganizationStatus.PUBLISHED.value:
            org_repo.add_organization_archive(organization)

    def submit_organization_for_approval(self, payload):
        logger.info(
            f"submit for approval organization org_uuid: {self.org_uuid}")
        organization = OrganizationFactory.org_domain_entity_from_payload(
            payload)
        if not organization.is_valid():
            raise Exception("Invalid org metadata")
        org_repo.store_organization(organization, self.username,
                                    OrganizationStatus.APPROVED.value)
        return "OK"

    def publish_org_to_ipfs(self):
        logger.info(f"publish organization to ipfs org_uuid: {self.org_uuid}")
        organization = org_repo.get_org_for_org_uuid(self.org_uuid)
        organization.publish_to_ipfs()
        org_repo.store_ipfs_hash(organization, self.username)
        return organization.to_response()

    def save_transaction_hash_for_publish_org(self, payload):
        transaction_hash = payload["transaction_hash"]
        user_address = payload["wallet_address"]
        logger.info(
            f"save transaction hash for publish organization org_uuid: {self.org_uuid} "
            f"transaction_hash: {transaction_hash} user_address: {user_address}"
        )
        org_repo.persist_publish_org_transaction_hash(self.org_uuid,
                                                      transaction_hash,
                                                      user_address,
                                                      self.username)
        return "OK"

    def get_all_member(self, status, role, pagination_details):
        offset = pagination_details.get("offset", None)
        limit = pagination_details.get("limit", None)
        sort = pagination_details.get("sort", None)
        org_members_list = org_repo.get_org_member(org_uuid=self.org_uuid,
                                                   status=status,
                                                   role=role)
        return [member.to_response() for member in org_members_list]

    def get_member(self, member_username):
        members = org_repo.get_org_member(username=member_username,
                                          org_uuid=self.org_uuid)
        if len(members) == 0:
            logger.info(
                f"No member {member_username} for the organization {self.org_uuid}"
            )
            return []
        return [member.to_response() for member in members]

    def verify_invite(self, invite_code):
        logger.info(
            f"verify member invite_code: {invite_code} username: {self.username}"
        )
        if org_repo.org_member_verify(self.username, invite_code):
            return "OK"
        return "NOT_FOUND"

    def delete_members(self, org_members):
        logger.info(
            f"user: {self.username} requested to delete members: {org_members} of org_uuid: {self.org_uuid}"
        )
        org_member_list = OrganizationFactory.org_member_domain_entity_from_payload_list(
            org_members, self.org_uuid)
        org_repo.delete_members(org_member_list)
        return "OK"

    def publish_members(self, transaction_hash, org_members):
        logger.info(
            f"user: {self.username} published members: {org_members} with transaction_hash: {transaction_hash}"
        )
        org_member = OrganizationFactory.org_member_domain_entity_from_payload_list(
            org_members, self.org_uuid)
        org_repo.persist_publish_org_member_transaction_hash(
            org_member, transaction_hash, self.org_uuid)
        return "OK"

    def register_member(self, invite_code, wallet_address):
        logger.info(
            f"register user: {self.username} with invite_code: {invite_code}")
        if Web3.isAddress(wallet_address):
            org_repo.update_org_member(self.username, wallet_address,
                                       invite_code)
        else:
            raise Exception("Invalid wallet address")
        return "OK"

    def invite_members(self, members_payload):
        current_time = datetime.utcnow()
        requested_invite_member_list = OrganizationFactory.org_member_domain_entity_from_payload_list(
            members_payload, self.org_uuid)
        current_org_member = org_repo.get_org_member(org_uuid=self.org_uuid)
        current_org_member_username_list = [
            member.username for member in current_org_member
        ]
        eligible_invite_member_list = [
            member for member in requested_invite_member_list
            if member.username not in current_org_member_username_list
        ]
        for org_member in eligible_invite_member_list:
            org_member.generate_invite_code()
            org_member.set_status(OrganizationMemberStatus.PENDING.value)
            org_member.set_role(Role.MEMBER.value)
            org_member.set_invited_on(current_time)
            org_member.set_updated_on(current_time)

        organization = org_repo.get_org_for_org_uuid(self.org_uuid)
        org_name = organization.name
        self._send_email_notification_for_inviting_organization_member(
            eligible_invite_member_list, org_name)
        org_repo.add_member(eligible_invite_member_list)

        failed_invitation = [
            member.username for member in requested_invite_member_list
            if member.username in current_org_member_username_list
        ]
        return {
            "member":
            [member.to_response() for member in eligible_invite_member_list],
            "failed_invitation":
            failed_invitation
        }

    def _send_email_notification_for_inviting_organization_member(
            self, org_members_list, org_name):
        for org_member in org_members_list:
            recipient = org_member.username
            org_member_notification_subject = self._get_org_member_notification_subject(
                org_name)
            org_member_notification_message = self._get_org_member_notification_message(
                org_member.invite_code, org_name)
            send_notification_payload = {
                "body":
                json.dumps({
                    "message": org_member_notification_message,
                    "subject": org_member_notification_subject,
                    "notification_type": "support",
                    "recipient": recipient
                })
            }
            self.boto_utils.invoke_lambda(
                lambda_function_arn=NOTIFICATION_ARN,
                invocation_type="RequestResponse",
                payload=json.dumps(send_notification_payload))
            logger.info(f"Org Membership Invite sent to {recipient}")

    @staticmethod
    def _get_org_member_notification_message(invite_code, org_name):
        return f"<html><head></head><body><div><p>Hello,</p><p>Organization {org_name} has sent you membership invite. " \
               f"Your invite code is <strong>{invite_code}</strong>.</p><br/><p>Please click on the link below to " \
               f"accept the invitation.</p><p>{PUBLISHER_PORTAL_DAPP_URL}</p><br/><br/><p>" \
               "<em>Please do not reply to the email for any enquiries for any queries please email at " \
               "[email protected].</em></p><p>Warmest regards, <br />SingularityNET Marketplace " \
               "Team</p></div></body></html>"

    @staticmethod
    def _get_org_member_notification_subject(org_name):
        return f"Membership Invitation from  Organization {org_name}"
Esempio n. 19
0
 def __init__(self, event, networks, net_id):
     self.event = event
     self.networks = networks
     self.net_id = net_id
     self.boto_utils = BotoUtils(REGION_NAME)
Esempio n. 20
0
class User:
    def __init__(self, obj_repo):
        self.repo = obj_repo
        self.obj_utils = Utils()
        self.boto_client = BotoUtils(region_name=REGION_NAME)

    def _set_user_data(self, user_data, origin):
        """ Method to set user information. """
        try:
            claims = user_data['authorizer']['claims']
            email_verified = claims['email_verified']
            status = 0
            if email_verified:
                status = 1
            else:
                raise Exception("Email verification is pending.")
            q_dta = [claims['email'], user_data['accountId'], origin, claims['nickname'], claims['email'], status,
                     status, user_data['requestId'], user_data['requestTimeEpoch'], dt.utcnow(), dt.utcnow()]
            set_usr_dta = self.repo.execute(
                "INSERT INTO user (username, account_id, origin, name, email, email_verified, status, request_id, "
                "request_time_epoch, row_created, row_updated) "
                "VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", q_dta)
            if len(set_usr_dta) > 0:
                return "success"
            else:
                return "User already exist"
        except Exception as e:
            print(repr(e))
            raise e

    def _fetch_private_key_from_ssm(self, address):
        try:
            store = self.boto_client.get_ssm_parameter(parameter=PATH_PREFIX + str(address))
            return store['Parameter']['Value']
        except Exception as e:
            print(repr(e))
            raise Exception("Error fetching value from parameter store.")

    def user_signup(self, user_data, origin):
        """ Method to assign pre-seeded wallet to user.
            This is one time process.
        """
        try:
            username = user_data['authorizer']['claims']['email']
            set_user_data = self._set_user_data(user_data, origin)
            print(set_user_data)
            return set_user_data
        except Exception as e:
            self.repo.rollback_transaction()
            print(repr(e))
            raise e

    def get_user_profile(self, user_data):
        """
            Method to fetch user profile data.
        """
        try:
            username = user_data['authorizer']['claims']['email']
            result = self.repo.execute(
                "SELECT * FROM user WHERE username = %s", [username])
            self.obj_utils.clean(result)
            return {"success": "success", "data": result}
        except Exception as e:
            print(repr(e))
            raise e

    def update_user_profile(self, email_alerts, is_terms_accepted, user_data):
        """
            Method to update user profile data.
        """
        try:
            username = user_data['authorizer']['claims']['email']
            result = self.repo.execute("UPDATE user SET email_alerts = %s, is_terms_accepted = %s WHERE username = %s",
                                       [int(email_alerts is True), int(is_terms_accepted is True), username])
            return {"success": "success", "data": []}
        except Exception as e:
            print(repr(e))
            raise e

    def validate_and_set_user_feedback(self, feedback_data, user_data):
        """
            Method to validate and set user feedback data.
        """
        schema = Schema([{'org_id': And(str),
                          'service_id': And(str),
                          'user_rating': And(str),
                          'comment': And(str)
                          }])
        try:
            feedback_data = schema.validate([feedback_data])
            feedback_recorded = self._set_user_feedback(
                feedback_data[0], user_data=user_data)
            if feedback_recorded:
                return []
            return None
        except Exception as err:
            print("Invalid Input ", err)
            return None

    def get_user_feedback(self, user_data, org_id, service_id):
        """
            Method to get user feedback data.
        """
        try:
            user_rating_dict = {}
            username = user_data['authorizer']['claims']['email']
            query_part = ""
            query_part_values = []
            if org_id is not None:
                query_part = "AND org_id = %s "
                query_part_values.append(org_id)
                if service_id is not None:
                    query_part += "AND service_id = %s "
                    query_part_values.append(service_id)

            rating_query = "SELECT * FROM user_service_vote WHERE username = %s " + query_part
            rating = self.repo.execute(
                rating_query, [username] + query_part_values)
            self.obj_utils.clean(rating)

            feedback_query = "SELECT * FROM user_service_feedback WHERE username = %s " + query_part
            feedback = self.repo.execute(
                feedback_query, [username] + query_part_values)
            self.obj_utils.clean(feedback)

            for record in feedback:
                org_id = record['org_id']
                service_id = record['service_id']
                if org_id not in user_rating_dict.keys():
                    user_rating_dict[org_id] = {}
                if service_id not in user_rating_dict.keys():
                    user_rating_dict[org_id][service_id] = {}
                    user_rating_dict[org_id][service_id]['comment'] = []
                user_rating_dict[org_id][service_id]['comment'].append(
                    record['comment'])

            for record in rating:
                org_id = record['org_id']
                service_id = record['service_id']
                record.update({'comment': user_rating_dict.get(org_id, {})
                              .get(service_id, {})
                              .get("comment", [])})
            return rating
        except Exception as e:
            print(repr(e))
            raise e

    def _set_user_feedback(self, feedback_data, user_data):
        """
            Method to set user rating and feedback.
        """
        try:
            user_rating = str(feedback_data['user_rating'])
            if float(user_rating) > 5.0 or float(user_rating) < 1.0:
                raise Exception(
                    "Invalid Rating. Provided user rating should be between 1.0 and 5.0 .")
            curr_dt = dt.utcnow()
            username = user_data['authorizer']['claims']['email']
            org_id = feedback_data['org_id']
            service_id = feedback_data['service_id']
            comment = feedback_data['comment']
            self.repo.begin_transaction()
            set_rating = "INSERT INTO user_service_vote (username, org_id, service_id, rating, row_updated, row_created) " \
                         "VALUES (%s, %s, %s, %s, %s, %s) " \
                         "ON DUPLICATE KEY UPDATE rating = %s, row_updated = %s"
            set_rating_params = [username, org_id, service_id,
                                 user_rating, curr_dt, curr_dt, user_rating, curr_dt]
            self.repo.execute(set_rating, set_rating_params)
            set_feedback = "INSERT INTO user_service_feedback (username, org_id, service_id, comment, row_updated, row_created)" \
                           "VALUES (%s, %s, %s, %s, %s, %s)"
            set_feedback_params = [username, org_id,
                                   service_id, comment, curr_dt, curr_dt]
            self.repo.execute(set_feedback, set_feedback_params)
            self._update_service_rating(org_id=org_id, service_id=service_id)
            self.repo.commit_transaction()
            return True
        except Exception as e:
            self.repo.rollback_transaction()
            print(repr(e))
            raise e

    def _update_service_rating(self, org_id, service_id):
        """
            Method updates service_rating and total_user_rated when user rating is changed for given service_id
            and org_id.
        """
        try:
            update_service_metadata = self.repo.execute(
                "UPDATE service_metadata A  INNER JOIN (SELECT U.org_id, U.service_id, AVG(U.rating) AS service_rating, "
                "count(*) AS total_users_rated FROM user_service_vote AS U WHERE U.rating IS NOT NULL GROUP BY "
                "U.service_id, U.org_id ) AS B ON A.org_id=B.org_id AND A.service_id=B.service_id SET A.service_rating "
                "= CONCAT('{\"rating\":', B.service_rating, ' , \"total_users_rated\":', B.total_users_rated, '}') "
                "WHERE A.org_id = %s AND A.service_id = %s ", [org_id, service_id])
        except Exception as e:
            print(repr(e))
            raise e
class OrganizationOrchestratorService:
    def __init__(self):
        self.boto_client = BotoUtils(REGION_NAME)

    def register_org_member(self, username, payload):
        wallet_address = payload["wallet_address"]
        invite_code = payload["invite_code"]
        self.registry_register_org_member(username, wallet_address,
                                          invite_code)
        self.register_wallet(username, wallet_address)
        return "OK"

    def registry_register_org_member(self, username, wallet_address,
                                     invite_code):
        register_member_event = {
            "path":
            f"/org/member/register",
            "body":
            json.dumps({
                "wallet_address": wallet_address,
                "invite_code": invite_code
            }),
            "httpMethod":
            "POST",
            "requestContext": {
                "authorizer": {
                    "claims": {
                        "email": username
                    }
                }
            }
        }

        logger.info(f"Requesting register user for invite_code: {invite_code} "
                    f"username: {username} wallet_address:{wallet_address}")

        register_member_response = self.boto_client.invoke_lambda(
            lambda_function_arn=REGISTRY_ARN["REGISTER_MEMBER_ARN"],
            invocation_type='RequestResponse',
            payload=json.dumps(register_member_event))
        if register_member_response["statusCode"] != 201:
            raise Exception(
                f"Failed to register user for invite_code: {invite_code} "
                f"username: {username} wallet_address:{wallet_address}")

    def register_wallet(self,
                        username,
                        wallet_address,
                        wallet_type="METAMASK"):
        register_wallet_body = {
            'address': wallet_address,
            'type': wallet_type,
            'username': username
        }
        register_wallet_payload = {
            "path": "/wallet/register",
            "body": json.dumps(register_wallet_body),
            "httpMethod": "POST"
        }
        raw_response = self.boto_client.invoke_lambda(
            lambda_function_arn=WALLETS_SERVICE_ARN,
            invocation_type="RequestResponse",
            payload=json.dumps(register_wallet_payload))
        status = raw_response["statusCode"]
        if int(status) != 200:
            raise Exception("Unable to register wallet for username %s",
                            username)

    def create_and_initiate_verification(self, create_org_details, username):
        org_details = self.create_org(create_org_details, username)
        org_uuid = org_details["org_uuid"]
        org_type = org_details["org_type"]
        if org_type == OrganizationType.ORGANIZATION.value:
            self.initiate_verification(org_uuid, VerificationType.DUNS.value,
                                       username)
        elif org_type == OrganizationType.INDIVIDUAL.value:
            self.initiate_verification(username, VerificationType.JUMIO.value,
                                       username)
        else:
            raise Exception(
                f"Verification initiate failed for Invalid org type {org_type}"
            )

        self.notify_approval_team(org_details['org_id'],
                                  org_details['org_name'])
        self.notify_user_on_start_of_onboarding_process(
            org_id=org_details["org_id"], recipients=[username])
        return org_details

    def notify_approval_team(self, org_id, org_name):
        slack_msg = f"Organization with org_id {org_id} is submitted for approval"
        mail_template = get_org_approval_mail(org_id, org_name)
        self.send_slack_message(slack_msg)
        send_email_notification([ORG_APPROVERS_DLIST],
                                mail_template["subject"],
                                mail_template["body"], NOTIFICATION_ARN,
                                self.boto_client)

    def notify_user_on_start_of_onboarding_process(self, org_id, recipients):
        if not recipients:
            logger.info(
                f"Unable to find recipients for organization with org_id {org_id}"
            )
            return
        mail_template = get_mail_template_to_user_for_org_onboarding(org_id)
        for recipient in recipients:
            send_notification_payload = {
                "body":
                json.dumps({
                    "message": mail_template["body"],
                    "subject": mail_template["subject"],
                    "notification_type": "support",
                    "recipient": recipient
                })
            }
            self.boto_client.invoke_lambda(
                lambda_function_arn=NOTIFICATION_ARN,
                invocation_type="RequestResponse",
                payload=json.dumps(send_notification_payload))
            logger.info(
                f"Recipient {recipient} notified for successfully starting onboarding process."
            )

    def send_slack_message(self, slack_msg):
        slack_url = SLACK_HOOK['hostname'] + SLACK_HOOK['path']
        utils.send_slack_notification(
            slack_msg=slack_msg,
            slack_url=slack_url,
            slack_channel=SLACK_CHANNEL_FOR_APPROVAL_TEAM)

    def initiate_verification(self, entity_id, verification_type, username):
        if verification_type == VerificationType.JUMIO.value:
            initiate_verification_payload = {
                "requestContext": {
                    "authorizer": {
                        "claims": {
                            "email": entity_id
                        }
                    }
                },
                "body": json.dumps({"type": verification_type})
            }
        elif verification_type == VerificationType.DUNS.value:
            initiate_verification_payload = {
                "requestContext": {
                    "authorizer": {
                        "claims": {
                            "email": username
                        }
                    }
                },
                "body":
                json.dumps({
                    "type": verification_type,
                    "entity_id": entity_id
                })
            }
        else:
            raise Exception(
                f"Verification initiate failed for Invalid verification type {verification_type}"
            )

        raw_response = self.boto_client.invoke_lambda(
            lambda_function_arn=VERIFICATION_ARN["INITIATE"],
            invocation_type="RequestResponse",
            payload=json.dumps(initiate_verification_payload))
        status = raw_response["statusCode"]
        if status != 201:
            raise Exception("Failed to create Organization")

    def create_org(self, org_details, username):
        create_organization_payload = {
            "requestContext": {
                "authorizer": {
                    "claims": {
                        "email": username
                    }
                }
            },
            "body": json.dumps(org_details)
        }
        raw_response = self.boto_client.invoke_lambda(
            lambda_function_arn=REGISTRY_ARN["CREATE_ORG_ARN"],
            invocation_type="RequestResponse",
            payload=json.dumps(create_organization_payload))
        status = raw_response["statusCode"]
        if status != 200:
            raise Exception("Failed to create Organization")
        return json.loads(raw_response["body"])["data"]
Esempio n. 22
0
import re
import subprocess
import tempfile
import uuid
from pathlib import Path, PurePath

import pkg_resources
from grpc_tools.protoc import main as protoc
from snet import snet_cli

from common import utils
from common.boto_utils import BotoUtils
from utility.config import PROTO_DIRECTORY_REGEX_PATTERN, PROTO_STUB_TARGET_LANGUAGES

TEMP_FILE_DIR = tempfile.gettempdir()
boto_utils = BotoUtils(region_name=None)


class GenerateStubService:
    def __init__(self):
        pass

    def generate_service_proto_stubs(self, proto_s3_url, stub_s3_url):
        try:
            proto_bucket, proto_bucket_key = boto_utils.get_bucket_and_key_from_url(
                url=proto_s3_url)
            stub_bucket, stub_bucket_key = boto_utils.get_bucket_and_key_from_url(
                url=stub_s3_url)

            to_delete_objects = boto_utils.get_objects_from_s3(
                bucket=stub_bucket, key=stub_bucket_key)
 def __init__(self, payment_id, amount, currency, payment_status, created_at, payment_details):
     super().__init__(payment_id, amount, currency, payment_status, created_at, payment_details)
     self.boto_utils = BotoUtils(region_name=REGION_NAME)
Esempio n. 24
0
class UserService:
    def __init__(self):
        self.user_factory = UserFactory()
        self.user_repo = UserRepository()
        self.boto_client = BotoUtils(REGION_NAME)

    def add_or_update_user_preference(self, payload, username):
        user_preference_list = self.user_factory.parse_raw_user_preference_data(
            payload=payload)
        response = []
        for user_preference in user_preference_list:
            if user_preference.status and user_preference.opt_out_reason is not None:
                raise Exception("Invalid Payload.")
            user_data = self.user_repo.get_user_data_for_given_username(
                username=username)
            if len(user_data) == 0:
                raise Exception("User is not registered.")
            if user_preference.status is False:
                self.user_repo.disable_preference(
                    user_preference=user_preference,
                    user_row_id=user_data[0]["row_id"])
                response.append(Status.DISABLED.value)
            else:
                self.user_repo.enable_preference(
                    user_preference=user_preference,
                    user_row_id=user_data[0]["row_id"])
                response.append(Status.ENABLED.value)

        return response

    def get_user_preference(self, username):
        user_data = self.user_repo.get_user_data_for_given_username(
            username=username)
        if len(user_data) == 0:
            raise Exception("User is not registered.")
        user_preference_raw_data = self.user_repo.get_user_preferences(
            user_row_id=user_data[0]["row_id"])
        preferences = self.user_factory.parse_user_preference_raw_data(
            user_preference_raw_data)
        return [preference.to_dict() for preference in preferences]

    def delete_user(self, username):
        self.user_repo.delete_user(username)
        self._unlink_wallets_from_user(username)

    def _unlink_wallets_from_user(self, username):
        delete_user_wallet_event = {
            "path": "/wallet/delete",
            "queryStringParameters": {
                "username": username
            },
            "httpMethod": "POST"
        }

        delete_user_wallet_response = self.boto_client.invoke_lambda(
            lambda_function_arn=DELETE_USER_WALLET_ARN,
            invocation_type='RequestResponse',
            payload=json.dumps(delete_user_wallet_event))

        logger.info(f"create_channel_response {delete_user_wallet_response}")
        if delete_user_wallet_response["statusCode"] != 201:
            raise Exception(f"Failed to delete user wallet")
 def __init__(self):
     self.boto_client = BotoUtils(REGION_NAME)
import requests

from common.logger import get_logger
from utility.infrastructure.repository.historical_crypto_fiat_rate import HistoricalCryptoFiatRates
from utility.infrastructure.repository.crypto_fiat_rate import CryptoFiatRates
from utility.infrastructure.models import HistoricalCryptoFiatExchangeRates, CryptoFiatExchangeRates
from utility.config import CRYPTO_FIAT_CONVERSION, SLACK_HOOK
from datetime import datetime
from common.boto_utils import BotoUtils
from common.utils import Utils

rates = HistoricalCryptoFiatRates()

logger = get_logger(__name__)
boto_client = BotoUtils(region_name='us-east-1')


def cmc_rate_converter(crypto_symbol, fiat_symbol):
    try:
        api_token = boto_client.get_parameter_value_from_secrets_manager(
            secret_name='COIN_MARKETPLACE_API_TOKEN')
        URL = CRYPTO_FIAT_CONVERSION['COINMARKETCAP']['API_ENDPOINT'].format(
            fiat_symbol, crypto_symbol)
        headers = {'X-CMC_PRO_API_KEY': api_token}
        result = requests.get(url=URL, headers=headers)
        response = result.json()['data'][0]
        fiat_rate = response['amount']
        crypto_rate = response['quote'][fiat_symbol]['price']
        logger.info(f"rates_from_cmc response: {response}")
        return crypto_symbol, crypto_rate, fiat_rate, fiat_symbol
    except Exception as e: