@crowdin/app-project-module
Version:
Module that generates for you all common endpoints for serving standalone Crowdin App
664 lines (663 loc) • 28.8 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.addSwagerApiDocumentation = exports.addDefaultApiEndpoints = exports.updateCrowdinContext = exports.getApiManifest = void 0;
const path_1 = __importDefault(require("path"));
const swagger_jsdoc_1 = __importDefault(require("swagger-jsdoc"));
const crowdin_client_1 = __importDefault(require("../../middlewares/crowdin-client"));
const integration_credentials_1 = __importDefault(require("../../middlewares/integration-credentials"));
const json_response_1 = __importDefault(require("../../middlewares/json-response"));
const api_call_1 = __importDefault(require("../../middlewares/api-call"));
const redoc_html_template_1 = __importDefault(require("./redoc-helper/redoc-html-template"));
const crowdin_file_progress_1 = __importDefault(require("../integration/handlers/crowdin-file-progress"));
const crowdin_files_1 = __importDefault(require("../integration/handlers/crowdin-files"));
const crowdin_update_1 = __importDefault(require("../integration/handlers/crowdin-update"));
const integration_data_1 = __importDefault(require("../integration/handlers/integration-data"));
const job_info_deprecated_1 = __importDefault(require("../integration/handlers/job-info-deprecated"));
const job_info_1 = __importDefault(require("../integration/handlers/job-info"));
const job_list_1 = __importDefault(require("../integration/handlers/job-list"));
const job_cancel_1 = __importDefault(require("../integration/handlers/job-cancel"));
const integration_login_1 = __importDefault(require("../integration/handlers/integration-login"));
const integration_update_1 = __importDefault(require("../integration/handlers/integration-update"));
const settings_1 = __importDefault(require("../integration/handlers/settings"));
const settings_save_1 = __importDefault(require("../integration/handlers/settings-save"));
const sync_settings_1 = __importDefault(require("../integration/handlers/sync-settings"));
const sync_settings_save_1 = __importDefault(require("../integration/handlers/sync-settings-save"));
const types_1 = require("./types");
function getApiManifest(config, apiModule) {
const apiModuleManifest = [];
if (apiModule.endpoints) {
const userEndpoints = getUsersApiManifest(apiModule.endpoints);
apiModuleManifest.push(...userEndpoints);
}
if (apiModule.default) {
const defaultEndpoints = getDefaultApiEndpointsManifest(config);
apiModuleManifest.push(...defaultEndpoints);
}
return apiModuleManifest;
}
exports.getApiManifest = getApiManifest;
function generateModuleKey(moduleName) {
return moduleName.toLowerCase().split(' ').join('-') + '-api';
}
function getUsersApiManifest(endpoints) {
const apiModuleManifest = [];
for (const endpoint of endpoints) {
apiModuleManifest.push(Object.assign({ key: generateModuleKey(endpoint.name), name: endpoint.name, url: endpoint.url, method: endpoint.method, description: endpoint.description }, (endpoint.documentationUrl ? { documentationUrl: endpoint.documentationUrl } : {})));
}
return apiModuleManifest;
}
function getDefaultApiEndpointsManifest(config) {
const apiModuleManifest = [];
if (config.projectIntegration) {
apiModuleManifest.push({
key: 'crowdin-files-api',
name: 'Get Crowdin Files',
url: '/crowdin-files',
method: types_1.RequestMethods.GET,
description: 'Get a list of synced files',
documentationUrl: '/api-docs#tag/Files/operation/crowdin.files',
}, {
key: 'file-translation-progress-api',
name: 'File Translation Progress',
url: '/file-progress',
method: types_1.RequestMethods.GET,
description: 'Get file translation progress',
documentationUrl: '/api-docs#tag/Files/operation/file.progress',
}, {
key: 'integration-files-api',
name: 'Get Integration Files',
url: '/integration-files',
method: types_1.RequestMethods.GET,
description: 'Get integration data',
documentationUrl: '/api-docs#tag/Files/operation/integration.files',
}, {
key: 'crowdin-update-api',
name: 'Update Crowdin',
url: '/crowdin-update',
method: types_1.RequestMethods.POST,
description: 'Update crowdin data',
documentationUrl: '/api-docs#tag/Files/operation/crowdin.update',
}, {
key: 'integration-update-api',
name: 'Update Integration',
url: '/integration-update',
method: types_1.RequestMethods.POST,
description: 'Update integration data',
documentationUrl: '/api-docs#tag/Files/operation/integration.update',
}, {
key: 'job-list-api',
name: 'Job List',
url: '/all-jobs',
method: types_1.RequestMethods.GET,
description: 'Get All Jobs',
documentationUrl: '/api-docs#tag/Jobs/operation/job.list',
}, {
key: 'job-info-api',
name: 'Job Info',
url: '/job-info',
method: types_1.RequestMethods.GET,
description: 'Get Job Info',
documentationUrl: '/api-docs#tag/Jobs/operation/job.info',
}, {
key: 'job-get-api',
name: 'Job Status',
url: '/jobs',
method: types_1.RequestMethods.GET,
description: 'Get Job Info',
documentationUrl: '/api-docs#tag/Jobs/operation/job.get',
}, {
key: 'job-cancel-api',
name: 'Cancel Job',
url: '/jobs',
method: types_1.RequestMethods.DELETE,
description: 'Cancel Job',
documentationUrl: '/api-docs#tag/Jobs/operation/job.cancel',
}, {
key: 'settings-api',
name: 'Get App Settings',
url: '/settings',
method: types_1.RequestMethods.GET,
documentationUrl: '/api-docs#tag/Settings/operation/settings.get',
}, {
key: 'settings-update-api',
name: 'Update App Settings',
url: '/settings',
method: types_1.RequestMethods.POST,
documentationUrl: '/api-docs#tag/Settings/operation/settings.update',
}, {
key: 'sync-settings-api',
name: 'Get Sync Settings',
url: '/sync-settings',
method: types_1.RequestMethods.GET,
documentationUrl: '/api-docs#tag/Settings/operation/sync.settings.get',
}, {
key: 'sync-settings-update-api',
name: 'Update Sync Settings',
url: '/sync-settings',
method: types_1.RequestMethods.POST,
documentationUrl: '/api-docs#tag/Settings/operation/sync.settings.update',
});
if (config.projectIntegration.loginForm) {
apiModuleManifest.push({
key: 'login-data',
name: 'Get Login Fields',
url: '/login-fields',
method: types_1.RequestMethods.GET,
documentationUrl: '/api-docs#tag/Login/operation/integration.fields',
}, {
key: 'login',
name: 'Login',
url: '/login',
method: types_1.RequestMethods.POST,
documentationUrl: '/api-docs#tag/Login/operation/integration.login',
});
}
}
return apiModuleManifest;
}
function updateCrowdinContext(req, context) {
var _a, _b, _c;
if ((_a = req.body) === null || _a === void 0 ? void 0 : _a.projectId) {
if (context.clientId.includes('undefined')) {
context.clientId = `${context.jwtPayload.domain || context.jwtPayload.context.organization_id}__${(_b = req.body) === null || _b === void 0 ? void 0 : _b.projectId}__${context.jwtPayload.sub}`;
}
context.jwtPayload.context.project_id = (_c = req.body) === null || _c === void 0 ? void 0 : _c.projectId;
}
return context;
}
exports.updateCrowdinContext = updateCrowdinContext;
function getFormFields(fields) {
const formFields = [];
for (const field of fields) {
if (field === null || field === void 0 ? void 0 : field.key) {
formFields.push(Object.assign({ name: field.label, key: field.key, type: field.type }, (field.type === 'select' && field.options ? { options: field.options } : {})));
}
}
return formFields;
}
function addDefaultApiEndpoints(app, config) {
if (config.projectIntegration) {
/**
* @openapi
* /crowdin-files:
* get:
* summary: List Crowdin Files
* operationId: crowdin.files
* tags:
* - 'Files'
* parameters:
* - $ref: '#/components/parameters/ProjectId'
* responses:
* 200:
* description: 'Project files list'
* content:
* application/json:
* schema:
* properties:
* data:
* $ref: '#/components/schemas/CrowdinFiles'
*/
app.get('/crowdin-files', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'crowdin-files-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, crowdin_files_1.default)(config, config.projectIntegration));
/**
* @openapi
* /file-progress:
* get:
* tags:
* - 'Files'
* summary: 'Get File Progress'
* operationId: file.progress
* parameters:
* - $ref: '#/components/parameters/ProjectId'
* -
* name: fileId
* in: query
* required: true
* description: 'Get via [List Crowdin Files](#operation/crowdin.files)'
* schema:
* type: integer
* example: 102
* responses:
* 200:
* description: 'File translation progress'
* content:
* application/json:
* schema:
* properties:
* data:
* $ref: '#/components/schemas/FileProgress'
*/
app.get('/file-progress', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'file-translation-progress-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, crowdin_file_progress_1.default)(config.projectIntegration));
/**
* @openapi
* /integration-files:
* get:
* summary: 'List Integration Files'
* operationId: integration.files
* tags:
* - 'Files'
* parameters:
* - $ref: '#/components/parameters/ProjectId'
* responses:
* 200:
* description: 'Integration files list'
* content:
* application/json:
* schema:
* properties:
* data:
* $ref: '#/components/schemas/IntegrationFiles'
*
*/
app.get('/integration-files', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'integration-files-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, integration_data_1.default)(config.projectIntegration));
/**
* @openapi
* /crowdin-update:
* post:
* tags:
* - 'Files'
* summary: 'Update Crowdin Files'
* operationId: crowdin.update
* requestBody:
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/UpdateCrowdinFiles'
* responses:
* 200:
* content:
* application/json:
* schema:
* properties:
* data:
* $ref: '#/components/schemas/UpdateResponse'
*/
app.post('/crowdin-update', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'crowdin-update-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, crowdin_update_1.default)(config, config.projectIntegration));
/**
* @openapi
* /integration-update:
* post:
* tags:
* - 'Files'
* summary: 'Update Integration Files'
* operationId: integration.update
* requestBody:
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/FileLanguagePair'
* responses:
* 200:
* content:
* application/json:
* schema:
* properties:
* data:
* $ref: '#/components/schemas/UpdateResponse'
*/
app.post('/integration-update', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'integration-update-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, integration_update_1.default)(config, config.projectIntegration));
/**
* @openapi
* /all-jobs:
* get:
* tags:
* - 'Jobs'
* summary: 'List Jobs'
* operationId: job.list
* parameters:
* - $ref: '#/components/parameters/ProjectId'
* - name: limit
* in: query
* required: false
* description: 'Number of jobs to return'
* schema:
* type: integer
* example: 25
* - name: offset
* in: query
* required: false
* description: 'Number of jobs to skip'
* schema:
* type: integer
* example: 0
* responses:
* 200:
* description: 'Job information retrieved successfully'
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/JobResponse'
*/
app.get('/all-jobs', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'job-list-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, job_list_1.default)());
/**
* @openapi
* /job-info:
* get:
* tags:
* - 'Jobs'
* summary: 'Get Job Info'
* operationId: job.info
* parameters:
* - $ref: '#/components/parameters/ProjectId'
* - name: jobId
* in: query
* required: true
* schema:
* type: string
* example: 067da473-fc0b-43e3-b0a2-09d26af130c1
* responses:
* 200:
* description: 'Job information retrieved successfully'
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/JobResponse'
*/
app.get('/job-info', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'job-info-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, job_info_1.default)());
/**
* @openapi
* /jobs:
* get:
* tags:
* - 'Jobs'
* summary: 'Get Job Info'
* operationId: job.get
* deprecated: true
* parameters:
* - $ref: '#/components/parameters/ProjectId'
* - name: jobId
* in: query
* required: false
* schema:
* type: string
* example: 067da473-fc0b-43e3-b0a2-09d26af130c1
* responses:
* 200:
* description: 'Job information retrieved successfully'
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/JobResponse'
*/
app.get('/jobs', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'job-get-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, job_info_deprecated_1.default)(config));
/**
* @openapi
* /jobs:
* delete:
* tags:
* - 'Jobs'
* summary: 'Cancel Job'
* operationId: job.cancel
* parameters:
* - $ref: '#/components/parameters/ProjectId'
* - name: jobId
* in: query
* required: true
* schema:
* type: string
* example: 067da473-fc0b-43e3-b0a2-09d26af130c1
* responses:
* 204:
* description: 'Job canceled successfully'
*/
app.delete('/jobs', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'job-cancel-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, job_cancel_1.default)());
/**
* @openapi
* /settings:
* get:
* tags:
* - 'Settings'
* summary: 'Get Application Settings'
* operationId: settings.get
* parameters:
* - $ref: '#/components/parameters/ProjectId'
* responses:
* 200:
* description: 'File translation progress'
* content:
* application/json:
* schema:
* properties:
* data:
* $ref: '#/components/schemas/SettingsResponse'
*/
app.get('/settings', api_call_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'settings-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, settings_1.default)());
/**
* @openapi
* /settings:
* post:
* tags:
* - 'Settings'
* summary: 'Update Application Settings'
* operationId: settings.update
* requestBody:
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/UpdateSettingsData'
* responses:
* 204:
* description: 'Application Settings was successfully update'
*/
app.post('/settings', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'settings-update-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, settings_save_1.default)(config, config.projectIntegration));
/**
* @openapi
* /sync-settings:
* get:
* tags:
* - 'Settings'
* summary: 'Get Sync Settings'
* operationId: sync.settings.get
* parameters:
* - $ref: '#/components/parameters/ProjectId'
* - name: provider
* in: query
* required: true
* schema:
* type: string
* enum:
* - crowdin
* - integration
* responses:
* 200:
* description: 'Application Sync Settings'
* content:
* application/json:
* schema:
* properties:
* data:
* oneOf:
* - { $ref: '#/components/schemas/CrowdinSyncSettingsResponse' }
* - { $ref: '#/components/schemas/IntegrationSyncSettingsResponse' }
*/
app.get('/sync-settings', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'sync-settings-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, sync_settings_1.default)());
/**
* @openapi
* /sync-settings:
* post:
* tags:
* - 'Settings'
* summary: 'Update Sync Settings'
* operationId: sync.settings.update
* requestBody:
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/UpdateSyncSettingsData'
* responses:
* 204:
* description: 'Application Sync Settings was successfully update'
*/
app.post('/sync-settings', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: true,
moduleKey: 'sync-settings-update-api',
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, sync_settings_save_1.default)(config, config.projectIntegration));
if (config.projectIntegration.loginForm) {
/**
* @openapi
* /login-fields:
* get:
* tags:
* - 'Login'
* summary: 'Integration Login Form Fields'
* operationId: integration.fields
* responses:
* 200:
* description: 'Login Form Fields'
* content:
* application/json:
* schema:
* properties:
* data:
* $ref: '#/components/schemas/LoginFieldsResponse'
*/
app.get('/login-fields', api_call_1.default, json_response_1.default, (req, res) => {
var _a, _b;
let fields = [];
if ((_b = (_a = config.projectIntegration) === null || _a === void 0 ? void 0 : _a.loginForm) === null || _b === void 0 ? void 0 : _b.fields) {
fields = getFormFields(config === null || config === void 0 ? void 0 : config.projectIntegration.loginForm.fields);
}
res.send({ fields });
});
/**
* @openapi
* /login:
* post:
* tags:
* - 'Login'
* summary: 'Integration Login'
* operationId: integration.login
* requestBody:
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Login'
* responses:
* 204:
* description: 'Login successful'
*/
app.post('/login', api_call_1.default, json_response_1.default, (0, crowdin_client_1.default)({
config,
optional: false,
checkSubscriptionExpiration: false,
moduleKey: 'login',
}), (0, integration_login_1.default)(config, config.projectIntegration));
}
}
}
exports.addDefaultApiEndpoints = addDefaultApiEndpoints;
function addSwagerApiDocumentation(app, config) {
var _a, _b, _c;
const options = {
swaggerDefinition: {
openapi: '3.0.0',
info: {
title: `${config.name} Application API`,
description: "API methods of this application cannot be called directly. Instead, you should trigger Crowdin's platform API endpoint, Crowdin will authorize your request and route it to this app.\n\n" +
'Example call for crowdin.com \n\n' +
' curl --request GET \n' +
' --url "https://crowdin.com/api/v2/applications/' +
config.identifier +
'/api/data?report=raw&projects=479" \n' +
' --header "Authorization: Bearer 70cf05deasdas78c84c73c4cf986ee0a3ee911w1dsad384e3c4asd1qdbbcf6b6db5732e" \n' +
'Example call for Crowdin Enterprise \n\n' +
' curl --request GET \n' +
' --url "https://acme.crowdin.com/api/v2/applications/' +
config.identifier +
'/api/data?report=raw&projects=479&startDate=2023-06-01T06%3A32%3A01.048Z&endDate=2023-06-23T06%3A32%3A01.048Z" \n' +
' --header "Authorization: Bearer 70cf05dee35sad12rfes0a3ee911462e7b0723rfdfrg1e45bbcf6b6db5732e" \n',
version: '1.0.0',
'x-logo': {
url: 'https://support.crowdin.com/assets/crowdin-logo.svg',
},
},
servers: [
{
url: `{protocol}//{host}/api/v2/applications/${config.identifier}/api`,
},
],
},
apis: config.projectIntegration && ((_a = config.api) === null || _a === void 0 ? void 0 : _a.default)
? [path_1.default.resolve(__dirname, './base.js'), path_1.default.resolve(__dirname, './components.js'), __filename]
: [],
};
if ((_b = config.api) === null || _b === void 0 ? void 0 : _b.docFile) {
options.apis.push(config.api.docFile);
}
const swaggerSpec = (0, swagger_jsdoc_1.default)(options);
// remove Login info from doc
if (config.projectIntegration && !((_c = config.projectIntegration) === null || _c === void 0 ? void 0 : _c.loginForm)) {
delete swaggerSpec.paths['/login'];
delete swaggerSpec.paths['/login-fields'];
delete swaggerSpec.components.schemas['Login'];
delete swaggerSpec.components.schemas['LoginData'];
swaggerSpec.tags = swaggerSpec.tags.filter((tag) => tag.name !== 'Login');
}
app.get('/api-docs/swagger.json', (req, res) => res.send(swaggerSpec));
app.use('/api-docs', (req, res) => res.send((0, redoc_html_template_1.default)({ title: `${config.name} Application API`, specUrl: '/api-docs/swagger.json' })));
}
exports.addSwagerApiDocumentation = addSwagerApiDocumentation;