|
| 1 | +/** |
| 2 | + * Represents the Salesforce service |
| 3 | + */ |
| 4 | +import _ from 'lodash'; |
| 5 | +import config from 'config'; |
| 6 | +import jwt from 'jsonwebtoken'; |
| 7 | + |
| 8 | +const axios = require('axios'); |
| 9 | + |
| 10 | +const loginBaseUrl = config.salesforce.CLIENT_AUDIENCE || 'https://login.salesforce.com'; |
| 11 | +// we are using dummy private key to fail safe when key is not provided in env |
| 12 | +let privateKey = config.salesforce.CLIENT_KEY || 'privateKey'; |
| 13 | +privateKey = privateKey.replace(/\\n/g, '\n'); |
| 14 | + |
| 15 | +const urlEncodeForm = k => |
| 16 | + Object.keys(k).reduce((a, b) => `${a}&${b}=${encodeURIComponent(k[b])}`, ''); |
| 17 | + |
| 18 | +/** |
| 19 | + * Helper class to abstract salesforce API calls |
| 20 | + */ |
| 21 | +class SalesforceService { |
| 22 | + /** |
| 23 | + * Authenticate to Salesforce with pre-configured credentials |
| 24 | + * @returns {{accessToken: String, instanceUrl: String}} the result |
| 25 | + */ |
| 26 | + static authenticate() { |
| 27 | + const jwtToken = jwt.sign({}, privateKey, { |
| 28 | + expiresIn: '1h', // any expiration |
| 29 | + issuer: config.salesforce.CLIENT_ID, |
| 30 | + audience: config.salesforce.CLIENT_AUDIENCE, |
| 31 | + subject: config.salesforce.SUBJECT, |
| 32 | + algorithm: 'RS256', |
| 33 | + }); |
| 34 | + return axios({ |
| 35 | + method: 'post', |
| 36 | + url: `${loginBaseUrl}/services/oauth2/token`, |
| 37 | + data: urlEncodeForm({ |
| 38 | + grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', |
| 39 | + assertion: jwtToken, |
| 40 | + }), |
| 41 | + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, |
| 42 | + }).then(res => ({ |
| 43 | + accessToken: res.data.access_token, |
| 44 | + instanceUrl: res.data.instance_url, |
| 45 | + })); |
| 46 | + } |
| 47 | + |
| 48 | + /** |
| 49 | + * Run the query statement |
| 50 | + * @param {String} sql the Saleforce sql statement |
| 51 | + * @param {String} accessToken the access token |
| 52 | + * @param {String} instanceUrl the salesforce instance url |
| 53 | + * @param {Object} logger logger to be used for logging |
| 54 | + * @returns {{totalSize: Number, done: Boolean, records: Array}} the result |
| 55 | + */ |
| 56 | + static query(sql, accessToken, instanceUrl, logger) { |
| 57 | + return axios({ |
| 58 | + url: `${instanceUrl}/services/data/v37.0/query?q=${sql}`, |
| 59 | + method: 'get', |
| 60 | + headers: { authorization: `Bearer ${accessToken}` }, |
| 61 | + }).then((res) => { |
| 62 | + if (logger) { |
| 63 | + logger.debug(_.get(res, 'data.records', [])); |
| 64 | + } |
| 65 | + const billingAccounts = _.get(res, 'data.records', []).map(o => ({ |
| 66 | + sfBillingAccountId: _.get(o, 'Topcoder_Billing_Account__r.Id'), |
| 67 | + tcBillingAccountId: _.get(o, 'Topcoder_Billing_Account__r.TopCoder_Billing_Account_Id__c'), |
| 68 | + name: _.get(o, 'Topcoder_Billing_Account__r.Billing_Account_Name__c'), |
| 69 | + startDate: _.get(o, 'Topcoder_Billing_Account__r.Start_Date__c'), |
| 70 | + endDate: _.get(o, 'Topcoder_Billing_Account__r.End_Date__c'), |
| 71 | + })); |
| 72 | + return billingAccounts; |
| 73 | + }); |
| 74 | + } |
| 75 | +} |
| 76 | + |
| 77 | +export default new SalesforceService(); |
0 commit comments