UNPKG

@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
"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;