crm data mapped to frontend and created api for zoho project ansd tasks
This commit is contained in:
parent
7445a6a156
commit
b137f8cc1a
@ -45,4 +45,72 @@ async function getResources(req, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { getData, getServices, getResources };
|
async function getPortals(req, res) {
|
||||||
|
try {
|
||||||
|
const { provider } = req.query;
|
||||||
|
if (provider !== 'zoho') {
|
||||||
|
return res.status(400).json(failure('Portals are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const integrationService = new IntegrationService(req.user.id);
|
||||||
|
const portals = await integrationService.getPortals(provider);
|
||||||
|
res.json(success('Zoho portals retrieved successfully', portals));
|
||||||
|
} catch (error) {
|
||||||
|
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAllProjects(req, res) {
|
||||||
|
try {
|
||||||
|
const { provider, page, limit, filters } = req.query;
|
||||||
|
if (provider !== 'zoho') {
|
||||||
|
return res.status(400).json(failure('All projects are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const integrationService = new IntegrationService(req.user.id);
|
||||||
|
const params = { page, limit };
|
||||||
|
if (filters) {
|
||||||
|
try {
|
||||||
|
params.filters = JSON.parse(filters);
|
||||||
|
} catch (e) {
|
||||||
|
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const projects = await integrationService.getAllProjects(provider, params);
|
||||||
|
res.json(success('All Zoho projects retrieved successfully', projects));
|
||||||
|
} catch (error) {
|
||||||
|
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAllProjectTasks(req, res) {
|
||||||
|
try {
|
||||||
|
const { provider, page, limit, filters, portal_id } = req.query;
|
||||||
|
|
||||||
|
if (provider !== 'zoho') {
|
||||||
|
return res.status(400).json(failure('All project tasks are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!portal_id) {
|
||||||
|
return res.status(400).json(failure('portal_id is required in query parameters', 'MISSING_PORTAL_ID'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const integrationService = new IntegrationService(req.user.id);
|
||||||
|
const params = { page, limit };
|
||||||
|
if (filters) {
|
||||||
|
try {
|
||||||
|
params.filters = JSON.parse(filters);
|
||||||
|
} catch (e) {
|
||||||
|
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tasks = await integrationService.getAllProjectTasks(provider, portal_id, params);
|
||||||
|
res.json(success('All Zoho project tasks retrieved successfully', tasks));
|
||||||
|
} catch (error) {
|
||||||
|
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { getData, getServices, getResources, getPortals, getAllProjects, getAllProjectTasks };
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const Joi = require('joi');
|
const Joi = require('joi');
|
||||||
const { getData, getServices, getResources } = require('../controllers/integrationController');
|
const { getData, getServices, getResources, getPortals, getAllProjects, getAllProjectTasks } = require('../controllers/integrationController');
|
||||||
const auth = require('../middlewares/auth');
|
const auth = require('../middlewares/auth');
|
||||||
const ZohoHandler = require('../../integrations/zoho/handler');
|
const ZohoHandler = require('../../integrations/zoho/handler');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
function validate(schema) {
|
function validate(schema, source = 'query') {
|
||||||
return (req, res, next) => {
|
return (req, res, next) => {
|
||||||
const { error, value } = schema.validate(req.query, { abortEarly: false, stripUnknown: true });
|
const data = source === 'body' ? req.body : req.query;
|
||||||
|
const { error, value } = schema.validate(data, { abortEarly: false, stripUnknown: true });
|
||||||
if (error) {
|
if (error) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
status: 'error',
|
status: 'error',
|
||||||
@ -18,7 +19,11 @@ function validate(schema) {
|
|||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
req.query = value;
|
if (source === 'body') {
|
||||||
|
req.body = value;
|
||||||
|
} else {
|
||||||
|
req.query = value;
|
||||||
|
}
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -50,6 +55,34 @@ const resourcesSchema = Joi.object({
|
|||||||
|
|
||||||
router.get('/resources', auth, validate(resourcesSchema), getResources);
|
router.get('/resources', auth, validate(resourcesSchema), getResources);
|
||||||
|
|
||||||
|
// Get Zoho portals
|
||||||
|
const portalsSchema = Joi.object({
|
||||||
|
provider: Joi.string().valid('zoho').required()
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/portals', auth, validate(portalsSchema), getPortals);
|
||||||
|
|
||||||
|
// Get all Zoho projects (across all portals)
|
||||||
|
const allProjectsSchema = Joi.object({
|
||||||
|
provider: Joi.string().valid('zoho').required(),
|
||||||
|
page: Joi.number().min(1).default(1),
|
||||||
|
limit: Joi.number().min(1).max(100).default(20),
|
||||||
|
filters: Joi.string().optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/all-projects', auth, validate(allProjectsSchema), getAllProjects);
|
||||||
|
|
||||||
|
// Get all project tasks for a specific portal
|
||||||
|
const allProjectTasksSchema = Joi.object({
|
||||||
|
provider: Joi.string().valid('zoho').required(),
|
||||||
|
portal_id: Joi.string().required(),
|
||||||
|
page: Joi.number().min(1).default(1),
|
||||||
|
limit: Joi.number().min(1).max(100).default(20),
|
||||||
|
filters: Joi.string().optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/all-project-tasks', auth, validate(allProjectTasksSchema), getAllProjectTasks);
|
||||||
|
|
||||||
// Webhook endpoints (no auth required - uses signature verification)
|
// Webhook endpoints (no auth required - uses signature verification)
|
||||||
const zohoHandler = new ZohoHandler();
|
const zohoHandler = new ZohoHandler();
|
||||||
router.post('/webhooks/zoho/crm', zohoHandler.handleCrmWebhook.bind(zohoHandler));
|
router.post('/webhooks/zoho/crm', zohoHandler.handleCrmWebhook.bind(zohoHandler));
|
||||||
|
|||||||
@ -6,7 +6,11 @@ const ZohoMapper = require('./mapper');
|
|||||||
class ZohoClient {
|
class ZohoClient {
|
||||||
constructor(userId) {
|
constructor(userId) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.baseUrl = 'https://www.zohoapis.com';
|
this.baseUrls = {
|
||||||
|
crm: 'https://www.zohoapis.com',
|
||||||
|
people: 'https://www.zohoapis.com',
|
||||||
|
projects: 'https://projectsapi.zoho.com'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTokens() {
|
async getTokens() {
|
||||||
@ -21,10 +25,11 @@ class ZohoClient {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async makeRequest(endpoint, options = {}) {
|
async makeRequest(endpoint, options = {}, service = 'crm') {
|
||||||
const { accessToken } = await this.getTokens();
|
const { accessToken } = await this.getTokens();
|
||||||
console.log('i am in make request with token',accessToken)
|
console.log('i am in make request with token',accessToken)
|
||||||
const url = `${this.baseUrl}${endpoint}`;
|
const baseUrl = this.baseUrls[service] || this.baseUrls.crm;
|
||||||
|
const url = `${baseUrl}${endpoint}`;
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
...options,
|
...options,
|
||||||
@ -101,23 +106,68 @@ class ZohoClient {
|
|||||||
|
|
||||||
// Zoho People methods
|
// Zoho People methods
|
||||||
async getEmployees(params = {}) {
|
async getEmployees(params = {}) {
|
||||||
const response = await this.makeRequest('/people/api/v1/employees', { params });
|
const response = await this.makeRequest('/people/api/v1/employees', { params }, 'people');
|
||||||
return ZohoMapper.mapApiResponse(response, 'employees');
|
return ZohoMapper.mapApiResponse(response, 'employees');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zoho Projects methods
|
// Zoho Projects methods
|
||||||
async getProjects(params = {}) {
|
async getPortals() {
|
||||||
const response = await this.makeRequest('/projects/v1/projects', { params });
|
const response = await this.makeRequest('/api/v3/portals', {}, 'projects');
|
||||||
|
return ZohoMapper.mapApiResponse(response, 'portals');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getProjects(portalId, params = {}) {
|
||||||
|
const response = await this.makeRequest(`/api/v3/portal/${portalId}/projects`, { params }, 'projects');
|
||||||
return ZohoMapper.mapApiResponse(response, 'projects');
|
return ZohoMapper.mapApiResponse(response, 'projects');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAllProjects(params = {}) {
|
||||||
|
// First get all portals
|
||||||
|
const portalsResponse = await this.getPortals();
|
||||||
|
const portals = portalsResponse.data;
|
||||||
|
|
||||||
|
// Get projects for each portal
|
||||||
|
const allProjects = [];
|
||||||
|
for (const portal of portals) {
|
||||||
|
try {
|
||||||
|
const projectsResponse = await this.getProjects(portal.id, params);
|
||||||
|
const projects = projectsResponse.data;
|
||||||
|
console.log('all projects', projects);
|
||||||
|
|
||||||
|
// Add portal information to each project
|
||||||
|
const projectsWithPortal = projects.map(project => ({
|
||||||
|
...project,
|
||||||
|
portal: {
|
||||||
|
id: portal.id,
|
||||||
|
name: portal.portal_name,
|
||||||
|
org_name: portal.org_name,
|
||||||
|
portal_url: portal.portal_url
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
allProjects.push(...projectsWithPortal);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error fetching projects for portal ${portal.id}:`, error.message);
|
||||||
|
// Continue with other portals even if one fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: allProjects,
|
||||||
|
info: {
|
||||||
|
count: allProjects.length,
|
||||||
|
moreRecords: false,
|
||||||
|
page: 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async getProjectTasks(projectId, params = {}) {
|
async getProjectTasks(projectId, params = {}) {
|
||||||
const response = await this.makeRequest(`/projects/v1/projects/${projectId}/tasks`, { params });
|
const response = await this.makeRequest(`/projects/v1/projects/${projectId}/tasks`, { params }, 'projects');
|
||||||
return ZohoMapper.mapApiResponse(response, 'tasks');
|
return ZohoMapper.mapApiResponse(response, 'tasks');
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAllProjectTasks(params = {}) {
|
async getAllProjectTasks(portalId, params = {}) {
|
||||||
const response = await this.makeRequest('/projects/v1/tasks', { params });
|
const response = await this.makeRequest(`/api/v3/portal/${portalId}/all-tasklists`, { params }, 'projects');
|
||||||
return ZohoMapper.mapApiResponse(response, 'tasks');
|
return ZohoMapper.mapApiResponse(response, 'tasks');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -135,16 +135,56 @@ class ZohoMapper {
|
|||||||
|
|
||||||
// Map Zoho API response to standardized format
|
// Map Zoho API response to standardized format
|
||||||
static mapApiResponse(zohoResponse, recordType) {
|
static mapApiResponse(zohoResponse, recordType) {
|
||||||
const records = zohoResponse.data || [];
|
let records = [];
|
||||||
// const mappedRecords = this.mapRecords(records, recordType);
|
let pageInfo = {};
|
||||||
|
|
||||||
|
// Handle different response structures based on record type
|
||||||
|
switch (recordType) {
|
||||||
|
case 'projects':
|
||||||
|
// Projects response is directly an array
|
||||||
|
records = zohoResponse || [];
|
||||||
|
pageInfo = {
|
||||||
|
count: records.length,
|
||||||
|
moreRecords: false,
|
||||||
|
page: 1
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'tasks':
|
||||||
|
// Tasks response has tasklists array and page_info
|
||||||
|
records = zohoResponse.tasklists || [];
|
||||||
|
pageInfo = {
|
||||||
|
count: zohoResponse.page_info?.per_page || records.length,
|
||||||
|
moreRecords: zohoResponse.page_info?.has_next_page || false,
|
||||||
|
page: zohoResponse.page_info?.page || 1,
|
||||||
|
pageCount: zohoResponse.page_info?.page_count || 1
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'portals':
|
||||||
|
// Portals response is directly an array
|
||||||
|
records = zohoResponse || [];
|
||||||
|
pageInfo = {
|
||||||
|
count: records.length,
|
||||||
|
moreRecords: false,
|
||||||
|
page: 1
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Default CRM response structure (leads, contacts, deals, employees)
|
||||||
|
records = zohoResponse.data || [];
|
||||||
|
pageInfo = {
|
||||||
|
count: zohoResponse.info?.count || records.length,
|
||||||
|
moreRecords: zohoResponse.info?.more_records || false,
|
||||||
|
page: zohoResponse.info?.page || 1
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: records,
|
data: records,
|
||||||
info: {
|
info: pageInfo
|
||||||
count: zohoResponse.info?.count || mappedRecords.length,
|
|
||||||
moreRecords: zohoResponse.info?.more_records || false,
|
|
||||||
page: zohoResponse.info?.page || 1
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,6 +68,39 @@ class IntegrationService {
|
|||||||
}
|
}
|
||||||
return client.getAvailableResources(service);
|
return client.getAvailableResources(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getPortals(provider) {
|
||||||
|
const client = this.clients[provider];
|
||||||
|
if (!client) {
|
||||||
|
throw new Error(`Provider ${provider} not supported`);
|
||||||
|
}
|
||||||
|
if (provider !== 'zoho') {
|
||||||
|
throw new Error('Portals are only available for Zoho provider');
|
||||||
|
}
|
||||||
|
return await client.getPortals();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllProjects(provider, params = {}) {
|
||||||
|
const client = this.clients[provider];
|
||||||
|
if (!client) {
|
||||||
|
throw new Error(`Provider ${provider} not supported`);
|
||||||
|
}
|
||||||
|
if (provider !== 'zoho') {
|
||||||
|
throw new Error('All projects are only available for Zoho provider');
|
||||||
|
}
|
||||||
|
return await client.getAllProjects(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllProjectTasks(provider, portalId, params = {}) {
|
||||||
|
const client = this.clients[provider];
|
||||||
|
if (!client) {
|
||||||
|
throw new Error(`Provider ${provider} not supported`);
|
||||||
|
}
|
||||||
|
if (provider !== 'zoho') {
|
||||||
|
throw new Error('All project tasks are only available for Zoho provider');
|
||||||
|
}
|
||||||
|
return await client.getAllProjectTasks(portalId, params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = IntegrationService;
|
module.exports = IntegrationService;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user