Security News
tea.xyz Spam Plagues npm and RubyGems Package Registries
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
@crowdin/app-project-module
Advanced tools
Readme
Module that will automatically add all necessary endpoints for Crowdin App.
It either can extends your Express application or even create it for you.
Module expose two main methods:
createApp
to fully create for you Express applicationaddCrowdinEndpoints
to extend your Express applicationIn both options you will need to provide Crowdin App configuration file. Please refer to jsdoc for more details.
npm i @crowdin/app-project-module
yarn add @crowdin/app-project-module
const crowdinModule = require('@crowdin/app-project-module');
const crowdinAppFunctions = require('@crowdin/crowdin-apps-functions');
const axios = require('axios').default;
const configuration = {
baseUrl: 'https://123.ngrok.io',
clientId: 'clientId',
clientSecret: 'clientSecret',
name: 'Sample App',
identifier: 'sample-app',
description: 'Sample App description',
dbFolder: __dirname,
imagePath: __dirname + '/' + 'logo.png',
integration: {
withRootFolder: true,
getIntegrationFiles: async (credentials, appSettings) => {
//here you need to fetch files/objects from integration
return [
{
id: '12',
name: 'File from integration',
type: 'json',
parentId: '10'
},
{
id: '14',
name: 'File from integration2',
type: 'xml',
parentId: '11'
},
{
id: '10',
name: 'Folder from integration'
},
{
id: '11',
name: 'Folder from integratio2'
},
];
},
updateCrowdin: async (projectId, client, credentials, request, rootFolder, appSettings) => {
//here you need to get data from integration and upload it to Crowdin
console.log(`Request for updating data in Crowdin ${JSON.stringify(request)}`);
const directories = await client.sourceFilesApi
.withFetchAll()
.listProjectDirectories(projectId);
const { folder, files } = await crowdinAppFunctions.getOrCreateFolder(
directories.data.map((d) => d.data),
client,
projectId,
'Folder from integration',
rootFolder
);
const fileContent = {
title: 'Hello World',
};
await crowdinAppFunctions.updateOrCreateFile(
client,
projectId,
'integration.json',
'Sample file from integration',
'json',
folder.id,
fileContent,
files.find((f) => f.name === 'integration.json'),
);
},
updateIntegration: async (projectId, client, credentials, request, rootFolder, appSettings) => {
////here should be logic to get translations from Crowdin and upload them to integration
console.log(`Request for updating data in Integration ${JSON.stringify(request)}`);
const directories = await client.sourceFilesApi
.withFetchAll()
.listProjectDirectories(projectId);
const { files } = await crowdinAppFunctions.getFolder(
directories.data.map((d) => d.data),
client,
projectId,
'Folder from integration',
rootFolder
);
const file = files.find((f) => f.name === 'integration.json');
if (file) {
const translationsLink =
await client.translationsApi.buildProjectFileTranslation(
projectId,
file.id,
{ targetLanguageId: 'uk' },
);
if (!translationsLink) {
return;
}
const response = await axios.get(translationsLink.data.url);
console.log(response.data);
}
},
}
};
crowdinModule.createApp(configuration);
By default login page for your app will require only to enter apiToken
to communicate with third party service.
But there is also a possibility to customize it.
configuration.loginForm = {
fields: [
{
key: 'username',
label: 'Username',
},
{
key: 'password',
label: 'Password',
type: 'password'
},
{
helpText: 'Api Key for http requests',
key: 'apiKey',
label: 'Api Key'
}
]
};
In case if third party service uses OAuth2 for authorization use oauthLogin
field to configure it.
loginForm
in this case should remain undefined.
Github example:
configuration.oauthLogin = {
authorizationUrl: 'https://github.com/login/oauth/authorize',
clientId: 'github_app_client_id',
clientSecret: 'github_app_client_secret',
accessTokenUrl: 'https://github.com/login/oauth/access_token'
}
Google example:
configuration.oauthLogin = {
scope: 'https%3A//www.googleapis.com/auth/userinfo.email',
authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
clientId: 'google_web_app_client_id',
clientSecret: 'google_web_app_client_secret',
accessTokenUrl: 'https://oauth2.googleapis.com/token',
extraAutorizationUrlParameters: {
response_type: 'code',
access_type: 'offline',
prompt: 'consent'
},
extraAccessTokenParameters: {
grant_type: 'authorization_code'
},
extraRefreshTokenParameters: {
grant_type: 'refresh_token'
},
refresh: true
}
The oauthLogin
property allows you to customize many different properties, mappings, etc. So that you can integrate with any OAuth2 implementation.
Main default values:
/oauth/code
client_id
client_secret
access_token
refresh
flag so then refresh token and expires in will be taken into considerationrefresh_token
expires_in
(value should be in seconds)This module rely that OAuth2 protocol is implemented by third party service in this way:
accessTokenUrl
with JSON body that will contain at least clientId
, clientSecret
, code
and redirectUri
(also possible to add extra fields via extraAccessTokenParameters
property)accessTokenUrl
(or refreshTokenUrl
if definied) with JSON body that will contain at least clientId
, clientSecret
and refreshToken
(also possible to add extra fields via extraRefreshTokenParameters
property)accessToken
and, if enabled, refreshToken
(optional) and expireIn
To override those requests please use performGetTokenRequest
and performRefreshTokenRequest
(e.g. when requests should be done with different HTTP methods or data should be tranfered as query string or form data).
Mailup example:
const clientId = 'client_id';
const clientSecret = 'client_secret';
const tokenUrl = 'https://services.mailup.com/Authorization/OAuth/Token';
configuration.oauthLogin = {
authorizationUrl: 'https://services.mailup.com/Authorization/OAuth/LogOn',
clientId,
clientSecret,
extraAutorizationUrlParameters: {
response_type: 'code'
},
refresh: true,
performGetTokenRequest: async (code) => {
const url = `${tokenUrl}?code=${code}&grant_type=authorization_code`;
const headers = {
'Authorization': `Bearer ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`
};
return (await axios.get(url, { headers })).data;
},
performRefreshTokenRequest: async (credentials) => {
const params = {
refresh_token: credentials.refreshToken,
grant_type: 'refresh_token',
client_id: clientId,
client_secret: clientSecret
};
const data = Object.keys(params)
.map((key) => `${key}=${encodeURIComponent(params[key])}`)
.join('&');
const headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
return (await axios.post(tokenUrl, data, { headers })).data;
}
}
Please refer to jsdoc for more details.
It is also possible to define settings window for your app where users can customize integration flow.
configuration.integration.getConfiguration = (projectId, crowdinClient, integrationCredentials) => {
return [
{
key: 'flag',
label: 'Checkbox',
type: 'checkbox'
},
{
key: 'text',
label: 'Text input',
type: 'text',
helpText: 'Help text'
},
{
key: 'option',
label: 'Select',
type: 'select',
options: [
{
value: '12',
label: 'Option'
}
]
}
]
}
You also can define section with some information notes or help section for your app.
configuration.integration.infoModal = {
title: 'Info',
content: `
<h1>This is your app help section</h1>
</br>
<h2>This is just an example</h2>
`
}
In order to register background tasks that app will invoke periodically invoke you can use cronJobs
field.
configuration.integration.cronJobs = [
{
//every 10 seconds
expression: '*/10 * * * * *',
task: (projectId, client, apiCredentials, appRootFolder, config) => {
console.log(`Running background task for project : ${projectId}`);
console.log(`Api credentials : ${JSON.stringify(apiCredentials)}`);
console.log(`App config : ${JSON.stringify(config)}`);
console.log(appRootFolder ? JSON.stringify(appRootFolder) : 'No root folder');
}
}
]
For cron syntax guide please refer to this documentation.
In case if something is wrong with app settings or credentials are invalid you can throw an explanation message that will be then visible on the UI side.
e.g. check if entered credentials are valid:
configuration.integration.checkConnection = (credentials) => {
if (!credentials.password || credentials.password.length < 6) {
throw 'Password is too weak';
}
//or call an service API with those credentials and check if request will be successful
};
Or if you need to manually control users liveness session you can throw an error with 401
code then your app will automatically do a log out action.
e.g. when your service has some specific session duration timeout or extra conditions which are not covered by this framework
configuration.integrartion.getIntegrationFiles = async (credentials, appSettings) => {
//do a request/custom logic here
const sessionStillValid = false;
if (!sessionStillValid) {
throw {
message: 'session expired',
code: 401
}
}
//business logic
}
If you want to contribute please read the Contributing guidelines.
If you find any problems or would like to suggest a feature, please feel free to file an issue on Github at Issues Page.
If you've found an error in these samples, please Contact Customer Success Service.
The Crowdin App Project module is licensed under the MIT License. See the LICENSE.md file distributed with this work for additional information regarding copyright ownership. Except as contained in the LICENSE file, the name(s) of the above copyright holders shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization.
FAQs
Module that generates for you all common endpoints for serving standalone Crowdin App
We found that @crowdin/app-project-module demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
Security News
As cyber threats become more autonomous, AI-powered defenses are crucial for businesses to stay ahead of attackers who can exploit software vulnerabilities at scale.
Security News
UnitedHealth Group disclosed that the ransomware attack on Change Healthcare compromised protected health information for millions in the U.S., with estimated costs to the company expected to reach $1 billion.