Last active
November 24, 2019 13:59
-
-
Save ZainWWF/8ac966ab338a93e630c4b27c74c49cb1 to your computer and use it in GitHub Desktop.
deployed code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as functions from "firebase-functions"; | |
import * as admin from "firebase-admin" | |
import axios, { AxiosRequestConfig } from "axios" | |
const conmpanyName = "WWF Singapore" | |
const departmentName = "Pasti Service Desk" | |
/** add entry into user"s assistance map when a assistance doc is created*/ | |
export default functions.region("asia-east2").firestore | |
.document("assistance/{assistanceId}").onCreate(async (snap, context) => { | |
try { | |
const userDocSnap = await admin.firestore().collection("users").doc(snap.get("userId")).get() | |
const userProfile = userDocSnap.get("profile") | |
const { accessToken, authToken } = await getAccessToken() | |
const orgId = await getEntityID('organizations', "companyName", conmpanyName, authToken); | |
const departmentsId = await getEntityID("departments", "name", departmentName, authToken, orgId); | |
if (!departmentsId) throw new Error("department id not found") | |
const contactsId = | |
await getEntityID("contacts", "mobile", userProfile.phoneNumber, authToken, orgId) || | |
await createNewEntity("contacts", { | |
mobile: userProfile.phoneNumber, | |
lastName: userProfile.name | |
}, | |
authToken, | |
orgId) | |
if (!contactsId) throw new Error("contacts id not found") | |
//arguments for new ticket | |
const ticketDetails = { | |
subject: `Assistance request - ${snap.get("type")}`, | |
description: snap.get("comment"), | |
channel: "App", | |
phone: userProfile.phoneNumber, | |
} | |
if (!orgId) throw new Error("org id not found") | |
await createTicket(orgId, accessToken, contactsId, departmentsId, ticketDetails) | |
return | |
} catch (error) { | |
console.error(error) | |
return | |
} | |
}) | |
async function getAccessToken() { | |
const tokensZohoDeskDocSnap = await admin.firestore().collection("tokens").doc("zohoDesk").get() | |
// get access token from store | |
const existingAccessToken = tokensZohoDeskDocSnap.get("access_token") | |
const access_token = existingAccessToken ? existingAccessToken : await getNewAccessToken(tokensZohoDeskDocSnap) | |
// if access token exist, check its expiration | |
if (accessTokenIsExpired(tokensZohoDeskDocSnap)) { | |
// access token expired, get new by refresh token | |
const refreshedAcessToken = await getRefreshedAccessToken(tokensZohoDeskDocSnap) | |
return { accessToken: refreshedAcessToken, authToken: tokensZohoDeskDocSnap.get("authToken") } | |
} | |
return { accessToken: access_token, authToken: tokensZohoDeskDocSnap.get("authToken") } | |
} | |
async function getNewAccessToken(docSnap: FirebaseFirestore.DocumentSnapshot) { | |
try { | |
console.log("getNewAccessToken") | |
const existingAuthToken = docSnap.get("authToken") | |
const authtoken = !existingAuthToken || existingAuthToken === "INVALID_PASSWORD" ? await getNewAuthToken() : existingAuthToken | |
if (!authtoken) throw new Error("no auth token available") | |
const config: AxiosRequestConfig = { | |
url: "https://accounts.zoho.com/oauth/v2/token/self/authtooauth", | |
method: "POST", | |
params: { | |
client_id: functions.config().zohodesk.api.clientid, | |
client_secret: functions.config().zohodesk.api.clientsecret, | |
grant_type: "authtooauth", | |
authtoken, | |
scope: "Desk.tickets.ALL" | |
} | |
} | |
const result = await axios.request(config) | |
console.log("result: ", result.data) | |
//store new generated auth token | |
await admin.firestore().collection("tokens").doc("zohoDesk") | |
.update({ | |
createdAt: admin.firestore.Timestamp.now(), | |
error: null, | |
...result.data | |
}) | |
console.log("tokens updated") | |
return result.data.access_token | |
} catch (error) { | |
console.error(error) | |
return null | |
} | |
} | |
async function getNewAuthToken() { | |
console.log("getNewAuthToken") | |
try { | |
const config: AxiosRequestConfig = { | |
url: "https://accounts.zoho.com/apiauthtoken/nb/create", | |
method: "POST", | |
params: { | |
SCOPE: "ZohoSupport/supportapi,ZohoSearch/SearchAPI", | |
EMAIL_ID: functions.config().zohodesk.api.email, | |
PASSWORD: functions.config().zohodesk.api.emailpassword | |
} | |
} | |
const result = await axios.request(config) | |
const authTokenRequest = /((AUTHTOKEN=(.*)|CAUSE=(.*)))\nRESULT=(TRUE|FALSE)/.exec(result.data) | |
if (!authTokenRequest || authTokenRequest[5] === "FALSE") return null | |
const authToken = authTokenRequest[3] | |
//store new generated auth token | |
await admin.firestore().collection("tokens").doc("zohoDesk") | |
.set({ | |
authToken | |
}) | |
return authToken | |
} catch (error) { | |
console.log(error) | |
return null | |
} | |
} | |
function accessTokenIsExpired(docSnap: FirebaseFirestore.DocumentSnapshot) { | |
const createdAt: FirebaseFirestore.Timestamp = docSnap.get("createdAt") | |
const expiresIn: number = docSnap.get("expires_in") | |
console.log("accessTokenIsExpired: ", createdAt, expiresIn) | |
if (!createdAt) return false | |
// check is access token has expired | |
return createdAt.toMillis() + expiresIn < admin.firestore.Timestamp.now().toMillis() | |
} | |
async function getRefreshedAccessToken(docSnap: FirebaseFirestore.DocumentSnapshot) { | |
console.log("getRefreshedAccessToken") | |
try { | |
const config: AxiosRequestConfig = { | |
url: "https://accounts.zoho.com/oauth/v2/token", | |
method: "POST", | |
params: { | |
refresh_token: docSnap.get("refresh_token"), | |
client_id: functions.config().zohodesk.api.clientid, | |
client_secret: functions.config().zohodesk.api.clientsecret, | |
grant_type: "refresh_token", | |
scope: "Desk.tickets.ALL" | |
} | |
} | |
const result = await axios.request(config) | |
//store new generated auth token | |
await admin.firestore().collection("tokens").doc("zohoDesk") | |
.update({ | |
createdAt: admin.firestore.Timestamp.now(), | |
...result.data | |
}) | |
console.log("tokens updated with refresh token") | |
return result.data.access_token | |
} catch (error) { | |
console.error(error) | |
return | |
} | |
} | |
type EntityType = "organizations" | "departments" | "contacts" | |
type SearchKeyType = "organizationName" | "companyName" | "email" | "mobile" | "name"; | |
async function getEntityID(entityType: EntityType, searchKey: SearchKeyType, searchValue: string, authtoken: string, orgId: string | null = null) { | |
try { | |
const params = (entityType === "organizations") ? { authtoken } : { orgId, authtoken } | |
const url = `https://desk.zoho.com/api/v1/${entityType}` | |
const config: AxiosRequestConfig = { | |
method: "GET", | |
url, | |
params | |
} | |
console.log(`getEntityID : entityType: ${entityType}, searchKey: ${searchKey}, searchValue ${searchValue}`) | |
const result = await axios.request(config); | |
console.log("result: ", result.data) | |
const [foundEntity] = result.data.data.filter(entity => entity[searchKey] && entity[searchKey] === searchValue) | |
if (!foundEntity) return null | |
console.log(`${entityType} id: `, foundEntity.id); | |
return foundEntity.id; | |
} | |
catch (error) { | |
console.error(error) | |
return null | |
} | |
} | |
//arguments - organization id, access token, contact id, department id, ticket subject, ticket description, ticket channel | |
async function createTicket(orgId: string, access_token: string, contactId: string, departmentId: string, ticketDetails: any) { | |
try { | |
const config: AxiosRequestConfig = { | |
url: "https://desk.zoho.com/api/v1/tickets", | |
method: "POST", | |
headers: { | |
orgId: orgId, | |
Authorization: "Zoho-oauthtoken " + access_token, | |
}, | |
data: { | |
...ticketDetails, | |
contactId, //(required param) this contactId can be get through GET request. ID of the department to which the ticket belongs. | |
departmentId //(required param) this departmentId can be get through GET request. ID of the contact who raised the ticket. | |
} | |
} | |
await axios.request(config) | |
console.log("Successfully created new ticket"); | |
return | |
} catch (error) { | |
console.log(error) | |
return | |
} | |
} | |
async function createNewEntity(entityType: EntityType, data: any, authtoken: string, orgId: string) { | |
try { | |
const params = (entityType === "organizations") ? { authtoken } : { orgId, authtoken } | |
const url = `https://desk.zoho.com/api/v1/${entityType}` | |
const config: AxiosRequestConfig = { | |
method: "POST", | |
url, | |
params, | |
data | |
} | |
const result = await axios.request(config) | |
if (result) return result.data.id; | |
return null | |
} catch (error) { | |
console.log(error) | |
return null | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment