diff --git a/Connectivity/Esim-profile/Create-esim-switch/.gitignore b/Connectivity/Esim-profile/Create-esim-switch/.gitignore new file mode 100644 index 0000000..e3d31f7 --- /dev/null +++ b/Connectivity/Esim-profile/Create-esim-switch/.gitignore @@ -0,0 +1,2 @@ +# node_modules +node_modules \ No newline at end of file diff --git a/Connectivity/Esim-profile/Create-esim-switch/README.md b/Connectivity/Esim-profile/Create-esim-switch/README.md new file mode 100644 index 0000000..f712e09 --- /dev/null +++ b/Connectivity/Esim-profile/Create-esim-switch/README.md @@ -0,0 +1,130 @@ +# ESIM Profile Switch Example - Create an ESIM Switch + +Connectivity APIs use case - ESim Profile Switch + +### API Home Page + https://developer.korewireless.com/api?product=Connectivity#overview + + + +## Options Supported (Required) +- CLIENT_ID - client id obtained when creating a new client +- CLIENT_SECRET - client secret corresponding to client +- API_KEY - api key corresponding to client +- Connectivity_BASEURL - base URL can be configured according to Sandbox/Production environment +- TOKEN_URL - URL to obtain access_token (https://api.korewireless.com/Api/api/token) + + +## Prerequisites + +1. Stable version of Node.js +2. Stable version of NPM( Node Package Manager) + +Please refer to https://nodejs.org/en/download/ for more details + +## Installation +Navigate to code directory and run the following command to install the necessary dependencies + +1. Get client-id, client-secret and API Key from [https://developer.korewireless.com](https://developer.korewireless.com) +2. Clone the repo + ```sh + git clone https://github.com/korewireless/Developer-API.git + ``` +3. Install NPM packages + ```sh + cd Connectivity/Esim-profile/Create-esim-switch + npm install + ``` +4. Enter your credentials in `config.json` + ```JSON + CLIENT_ID:"<>" + CLIENT_SECRET:"<>" + API_KEY:"<>" + Connectivity_BASEURL:"<>" + ``` +#### Connectivity_BASEURL Possible Values +```sh +https://api.korewireless.com/connectivity - Production +https://sandbox.api.korewireless.com/connectivity - Sandbox +``` + +After Successful installation of dependencies run the following command to start off the application + ```sh + npm start + ``` +Please choose the appropriate operation from the prompt +```sh +Welcome to Esim Switch Management Console +Please select your desired option 1 or 2 ? +1.Switch a VZW Profile +2.Switch non VZW Profile +``` +If the choice is 1 please enter your IMEI also +```sh +Please enter your IMEI : +``` +Please enter your EIDs you wish to switch in a comma separated format +```sh +Please enter your desired EIDs in a comma separated format : +``` +And last please enter your Activation Profile Id +```sh +Please enter your activation-profile-id : +``` + +## API Work Flow + +- Step 1: Obtain the access_token +- Step 2: Get the account-id (Assuming we'll grab the first account from the accounts list in case the user has parent/child) +- Step 3: Choose the type (V2W profile or non-V2w) +- Step 4: If the V2W is selected then enter the IMEI +- Step 5: Enter the desired EIDs in a comma separated format +- Step 6: Enter the activation-profile-id +- Step 7: Based on the information provided perform the profile switch operation + + +#### Sample Request Body: + ```JSON +{ + "activation-profile-id": "cmp-pp-ap-000000", + "subscriptions": [ + { + "eid": "0000000000000000000000000", + "imei": "12121212121212" + } + ] +} +``` +- Step 8: Wait for the switch process to complete + +#### Sample Result after a successful ESIM Switch +```JSON +{ + "esim-profile-switch-request-id": "cmp-cpro-request-00000", + "activation-profile-id": "cmp-cpro-request-00000", + "switch-request-date": "2022-11-16T07:43:02.428Z", + "switch-request-status": "Completed", + "total-switch-processing": 0, + "total-switch-failed": 0, + "total-switch-completed": 0, + "total-switch-pending-network-connection": 0, + "total-switch-requested": 0, + "eids": [ + { + "eid": "000000000000000000000000000", + "new-subscription-id": "cmp-k1-subscription-0000000000", + "old-subscription-id": "cmp-k1-subscription-0000000000", + "switch-status": "Completed", + "switch-error-message": "Error Message" + } + ] +} +``` +### Node Dependencies Used +The Node packages required for the project are: + +1. axios (https://www.npmjs.com/package/axios) +2. prompt (https://www.npmjs.com/package/prompt) +3. colors (https://www.npmjs.com/package/colors) + +Dependencies needed for Node projects are typically listed in a file called package.json diff --git a/Connectivity/Esim-profile/Create-esim-switch/config.Json b/Connectivity/Esim-profile/Create-esim-switch/config.Json new file mode 100644 index 0000000..6783bea --- /dev/null +++ b/Connectivity/Esim-profile/Create-esim-switch/config.Json @@ -0,0 +1,7 @@ +{ + "CLIENT_ID":"<>", + "CLIENT_SECRET":"<>", + "API_KEY":"<>", + "CPRO_BASEURL":"< { + try { + const params = new URLSearchParams(); + params.append('grant_type', 'client_credentials'); + params.append('client_id', constants.CLIENT_ID); + params.append('client_secret', constants.CLIENT_SECRET); + let config = { + method: 'post', + url: constants.TOKEN_URL, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + data: params, + }; + let res = await axios(config); + return res.data; + } catch (error) { + console.error(error); + throw new Error(error); + } +}; + +const invokeConnectivityAPI = async (method, endpoint, body = {}) => { + try { + const token = await getToken(); + let requestConfig = { + method, + url: constants.CPRO_BASEURL + endpoint, + headers: { + Authorization: 'Bearer ' + token.access_token, + 'x-api-key': constants.API_KEY, + }, + }; + if (body && Object.keys(body).length > 0) { + requestConfig.data = body; + } + let res = await axios(requestConfig); + return res.data; + } catch (error) { + return({code:error.response.status,error:error.response.data}); + } +}; + +const formRequest = async ( + activationProfileId, + eid, + accountId, + imei = null +) => { + try { + let reqObj = {}; + let subscriptions=[]; + let statusRes={}; + const eids=eid.split(','); + for(let eid of eids){ + let subObj={}; + if(imei){ + subObj={ + eid, + imei + } + }else{ + subObj={ + eid + } + } + subscriptions.push(subObj); + } + reqObj={ + 'activation-profile-id': activationProfileId, + subscriptions + } + console.log(colors.yellow('Requesting profile switch. Please wait...')); + const res = await invokeConnectivityAPI( + 'POST', + `/v1/accounts/${accountId}/esim-profile-switch-requests`, + reqObj + ); + // console.log('res ', res); + if(res && res.status==="success" && res.data['esim-profile-switch-request-id']){ + console.log( + colors.green( + 'Request successfully placed. Please note the reference Id : ' ) + ); + console.log( + colors.cyan( + res.data['esim-profile-switch-request-id'] + ) + ); + console.log(colors.yellow('Requesting a status update. Please wait...')); + let status = true; + while (status) { + statusRes = await getStatus(res.data['esim-profile-switch-request-id'], accountId); + if ( + statusRes && + statusRes['switch-request-status'] && + statusRes['switch-request-status'] === 'Completed' || + statusRes['switch-request-status'] === 'Processed' + ) { + status = false; + } + await new Promise((resolve) => setTimeout(resolve, 2000)); + } + if (!status) { + console.log( + colors.magenta('Request has been completed successfully :', statusRes) + ); + } + } + if(res && res.error && res.error.status==="error" ){ + console.error( colors.red('Sorry something went wrong!..Please find the error below')); + console.error(colors.red(res.error)) + } + + } catch (error) { + console.error( colors.red('Sorry something went wrong!..Please find the error below')); + console.error(colors.red(error)); + } +}; + +const getStatus = async (switchRequestId, accountId) => { + try { + const res = await invokeConnectivityAPI( + 'GET', + `/v1/accounts/${accountId}/esim-profile-switch-requests/${switchRequestId}`, + {} + ); + return res; + } catch (error) { + console.error(error); + throw new Error(error); + } +}; + +const switchProfile = async (email) => { + try { + let accountId = ''; + let imei=""; + const getAccounts = await invokeConnectivityAPI( + 'GET', + `/v1/accounts?email=${email}`, + {} + ); + console.log('getAccounts ',getAccounts); + // Assuming we'll grab the first account from the accounts list in case the user has parent/child + if (getAccounts && getAccounts.account && getAccounts.account.length > 0) { + accountId = getAccounts.account[0]['account-id']; + } + const schema = { + properties: { + operation: { + description: colors.magenta('Welcome to ESim Switch Management Console ')+('\n')+colors.green('Please select your desired option 1 or 2 ?')+('\n')+colors.cyan('1.Switch a VZW Profile')+('\n') +colors.cyan('2.Switch non VZW Profile')+('\n'), + pattern:/^\b(1|2)\b/, + message: 'Operation must be '+colors.red('1,or 2'), + required: true, + type:'string' + } + } + }; + const EIDSchema = { + properties: { + EID: { + description: colors.magenta( + 'Please enter your desired EIDs in a comma separated format :' + )+('\n'), + pattern: /^[a-zA-Z0-9\,]+$/, + message: 'EID must be a string', + required: true, + type: 'string', + }, + }, + }; + const ProfileSchema = { + properties: { + profileId: { + description: colors.magenta( + 'Please enter your activation-profile-id :' + ), + pattern: /^[a-zA-Z0-9-]+$/, + message: colors.red('activation-profile-id must be a string'), + required: true, + type: 'string', + }, + }, + }; + const IMEISchema = { + properties: { + imei: { + description: colors.magenta('Please enter your IMEI :'), + pattern: /^[a-zA-Z0-9]+$/, + message: colors.red('imei must be a string'), + required: true, + type: 'string', + }, + }, + }; + prompt.message = ''; + prompt.delimiter = ''; + prompt.start(); + + const { operation } = await prompt.get(schema); + if (operation && operation === '1') { + imei = await prompt.get(IMEISchema); + console.log(colors.green('IMEI successfully entered')); + } + const { EID } = await prompt.get(EIDSchema); + if (EID && typeof EID === 'string') { + console.log(colors.green('EID values successfully entered')); + const { profileId } = await prompt.get(ProfileSchema); + console.log(colors.green('ProfileId successfully entered')); + const switchProfile = await formRequest( + profileId, + EID, + accountId, + imei.imei || null + ); + } + } catch (error) { + console.log('Something went wrong ', error); + } +}; + + +// Invoke the application by passing email-id +switchProfile('<>'); diff --git a/Connectivity/Esim-profile/Create-esim-switch/package-lock.json b/Connectivity/Esim-profile/Create-esim-switch/package-lock.json new file mode 100644 index 0000000..c0d82f5 --- /dev/null +++ b/Connectivity/Esim-profile/Create-esim-switch/package-lock.json @@ -0,0 +1,163 @@ +{ + "name": "connectivity-sample", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "connectivity-sample", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "axios": "^0.21.4", + "colors": "^1.4.0", + "prompt": "1.2" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==" + }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "engines": { + "node": "> 0.1.90" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "node_modules/prompt": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.2.2.tgz", + "integrity": "sha512-XNXhNv3PUHJDcDkISpCwSJxtw9Bor4FZnlMUDW64N/KCPdxhfVlpD5+YUXI/Z8a9QWmOhs9KSiVtR8nzPS0BYA==", + "dependencies": { + "@colors/colors": "1.5.0", + "async": "~0.9.0", + "read": "1.0.x", + "revalidator": "0.1.x", + "winston": "2.x" + }, + "engines": { + "node": ">= 0.6.6" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/revalidator": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", + "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "engines": { + "node": "*" + } + }, + "node_modules/winston": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz", + "integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==", + "dependencies": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/winston/node_modules/async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" + }, + "node_modules/winston/node_modules/colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "engines": { + "node": ">=0.1.90" + } + } + } +} diff --git a/Connectivity/Esim-profile/Create-esim-switch/package.json b/Connectivity/Esim-profile/Create-esim-switch/package.json new file mode 100644 index 0000000..04f23d8 --- /dev/null +++ b/Connectivity/Esim-profile/Create-esim-switch/package.json @@ -0,0 +1,16 @@ +{ + "name": "connectivity-sample", + "version": "1.0.0", + "description": "Sample application for connectivity Esim switch use case", + "main": "index.js", + "scripts": { + "start": "node index.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "axios": "^0.21.4", + "colors": "^1.4.0", + "prompt": "1.2" + } +}