zoho projects api created

This commit is contained in:
yashwin-foxy 2025-09-13 15:15:44 +05:30
parent b137f8cc1a
commit 3df5c84d3a
5 changed files with 240 additions and 6 deletions

View File

@ -113,4 +113,94 @@ async function getAllProjectTasks(req, res) {
}
}
module.exports = { getData, getServices, getResources, getPortals, getAllProjects, getAllProjectTasks };
async function getAllProjectTaskLists(req, res) {
try {
const { provider, page, limit, filters, portal_id } = req.query;
if (provider !== 'zoho') {
return res.status(400).json(failure('All project task lists 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 taskLists = await integrationService.getAllProjectTaskLists(provider, portal_id, params);
res.json(success('All Zoho project task lists retrieved successfully', taskLists));
} catch (error) {
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
}
}
async function getAllProjectIssues(req, res) {
try {
const { provider, page, limit, filters, portal_id } = req.query;
console.log('req query is', req.query)
if (provider !== 'zoho') {
return res.status(400).json(failure('All project issues 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 issues = await integrationService.getAllProjectIssues(provider, portal_id, params);
res.json(success('All Zoho project issues retrieved successfully', issues));
} catch (error) {
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
}
}
async function getAllProjectPhases(req, res) {
try {
const { provider, page, limit, filters, portal_id } = req.query;
if (provider !== 'zoho') {
return res.status(400).json(failure('All project phases 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 phases = await integrationService.getAllProjectPhases(provider, portal_id, params);
res.json(success('All Zoho project phases retrieved successfully', phases));
} catch (error) {
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
}
}
module.exports = { getData, getServices, getResources, getPortals, getAllProjects, getAllProjectTasks, getAllProjectTaskLists, getAllProjectIssues, getAllProjectPhases };

View File

@ -1,6 +1,6 @@
const express = require('express');
const Joi = require('joi');
const { getData, getServices, getResources, getPortals, getAllProjects, getAllProjectTasks } = require('../controllers/integrationController');
const { getData, getServices, getResources, getPortals, getAllProjects, getAllProjectTasks, getAllProjectTaskLists, getAllProjectIssues, getAllProjectPhases } = require('../controllers/integrationController');
const auth = require('../middlewares/auth');
const ZohoHandler = require('../../integrations/zoho/handler');
@ -83,6 +83,39 @@ const allProjectTasksSchema = Joi.object({
router.get('/all-project-tasks', auth, validate(allProjectTasksSchema), getAllProjectTasks);
// Get all project task lists for a specific portal
const allProjectTaskListsSchema = 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-tasklists', auth, validate(allProjectTaskListsSchema), getAllProjectTaskLists);
// Get all project issues for a specific portal
const allProjectIssuesSchema = 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-issues', auth, validate(allProjectIssuesSchema), getAllProjectIssues);
// Get all project phases for a specific portal
const allProjectPhasesSchema = 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-phases', auth, validate(allProjectPhasesSchema), getAllProjectPhases);
// Webhook endpoints (no auth required - uses signature verification)
const zohoHandler = new ZohoHandler();
router.post('/webhooks/zoho/crm', zohoHandler.handleCrmWebhook.bind(zohoHandler));

View File

@ -27,12 +27,19 @@ class ZohoClient {
async makeRequest(endpoint, options = {}, service = 'crm') {
const { accessToken } = await this.getTokens();
console.log('i am in make request with token',accessToken)
const baseUrl = this.baseUrls[service] || this.baseUrls.crm;
const url = `${baseUrl}${endpoint}`;
// Transform limit to per_page for Zoho APIs
let params = options.params || {};
if (params.limit) {
params.per_page = params.limit;
delete params.limit;
}
const config = {
...options,
params,
headers: {
'Authorization': `Zoho-oauthtoken ${accessToken}`,
'Content-Type': 'application/json',
@ -42,6 +49,7 @@ class ZohoClient {
try {
const response = await axios(url, config);
return response.data;
} catch (error) {
if (error.response?.status === 401) {
@ -132,7 +140,6 @@ class ZohoClient {
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 => ({
@ -167,10 +174,26 @@ class ZohoClient {
}
async getAllProjectTasks(portalId, params = {}) {
const response = await this.makeRequest(`/api/v3/portal/${portalId}/all-tasklists`, { params }, 'projects');
const response = await this.makeRequest(`/api/v3/portal/${portalId}/tasks`, { params }, 'projects');
return ZohoMapper.mapApiResponse(response, 'tasks');
}
async getAllProjectTaskLists(portalId, params = {}) {
const response = await this.makeRequest(`/api/v3/portal/${portalId}/all-tasklists`, { params }, 'projects');
return ZohoMapper.mapApiResponse(response, 'tasklists');
}
async getAllProjectIssues(portalId, params = {}) {
const response = await this.makeRequest(`/api/v3/portal/${portalId}/issues`, { params }, 'projects');
console.log('issues response i got',response)
return ZohoMapper.mapApiResponse(response, 'issues');
}
async getAllProjectPhases(portalId, params = {}) {
const response = await this.makeRequest(`/api/v3/portal/${portalId}/phases`, { params }, 'projects');
return ZohoMapper.mapApiResponse(response, 'phases');
}
// Service discovery
getAvailableServices() {
return ['crm', 'people', 'projects'];

View File

@ -152,7 +152,7 @@ class ZohoMapper {
case 'tasks':
// Tasks response has tasklists array and page_info
records = zohoResponse.tasklists || [];
records = zohoResponse.tasks || [];
pageInfo = {
count: zohoResponse.page_info?.per_page || records.length,
moreRecords: zohoResponse.page_info?.has_next_page || false,
@ -161,6 +161,28 @@ class ZohoMapper {
};
break;
case 'phases':
// Tasks response has tasklists array and page_info
records = zohoResponse.milestones || [];
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 'tasklists':
// 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 || [];
@ -171,6 +193,39 @@ class ZohoMapper {
};
break;
case 'issues':
// Issues response structure (assuming similar to tasks with page_info)
records = zohoResponse.issues || zohoResponse.data || [];
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 'tasklists':
// Task lists response structure (assuming similar to tasks with page_info)
records = zohoResponse.tasklists || zohoResponse.data || [];
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 'phases':
// Phases response structure (assuming similar to tasks with page_info)
records = zohoResponse.phases || zohoResponse.data || [];
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;
default:
// Default CRM response structure (leads, contacts, deals, employees)
records = zohoResponse.data || [];

View File

@ -101,6 +101,39 @@ class IntegrationService {
}
return await client.getAllProjectTasks(portalId, params);
}
async getAllProjectTaskLists(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 task lists are only available for Zoho provider');
}
return await client.getAllProjectTaskLists(portalId, params);
}
async getAllProjectIssues(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 issues are only available for Zoho provider');
}
return await client.getAllProjectIssues(portalId, params);
}
async getAllProjectPhases(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 phases are only available for Zoho provider');
}
return await client.getAllProjectPhases(portalId, params);
}
}
module.exports = IntegrationService;