Merge branch 'master' into develop

This commit is contained in:
cyril lopez 2020-04-27 17:50:25 +02:00 committed by GitHub
commit 62c01a08e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 188 additions and 70 deletions

View File

@ -28,7 +28,7 @@ axios
})
.catch(error => {
// Handle error.
console.log('An error occurred:', error);
console.log('An error occurred:', error.response);
});
```
@ -57,7 +57,7 @@ axios
})
.catch(error => {
// Handle error.
console.log('An error occurred:', error);
console.log('An error occurred:', error.response);
});
```
@ -86,7 +86,7 @@ axios
})
.catch(error => {
// Handle error.
console.log('An error occurred:', error);
console.log('An error occurred:', error.response);
});
```
@ -148,7 +148,7 @@ axios
})
.catch(error => {
// Handle error.
console.log('An error occurred:', error);
console.log('An error occurred:', error.response);
});
```
@ -176,7 +176,7 @@ axios
})
.catch(error => {
// Handle error.
console.log('An error occurred:', error);
console.log('An error occurred:', error.response);
});
});
```

View File

@ -211,7 +211,7 @@ Strapi currently supports `Node.js v12.x.x`. The following steps will install No
```bash
cd ~
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
...
sudo apt-get install nodejs
...

View File

@ -70,7 +70,7 @@ axios
})
.catch(error => {
// Handle error.
console.log('An error occurred:', error);
console.log('An error occurred:', error.response);
});
```
@ -99,7 +99,7 @@ axios
})
.catch(error => {
// Handle error.
console.log('An error occurred:', error);
console.log('An error occurred:', error.response);
});
```
@ -128,7 +128,7 @@ axios
})
.catch(error => {
// Handle error.
console.log('An error occurred:', error);
console.log('An error occurred:', error.response);
});
```
@ -486,7 +486,7 @@ axios
})
.catch(error => {
// Handle error.
console.log('An error occurred:', error);
console.log('An error occurred:', error.response);
});
```
@ -519,7 +519,7 @@ axios
})
.catch(error => {
// Handle error.
console.log('An error occurred:', error);
console.log('An error occurred:', error.response);
});
```
@ -545,7 +545,7 @@ axios
})
.catch(error => {
// Handle error.
console.err('An error occured:', err);
console.error('An error occured:', error.response);
});
```

View File

@ -582,8 +582,8 @@ class Wysiwyg extends React.Component {
Modifier.replaceText(contentState, this.getSelection(), text);
onChange = editorState => {
this.setState({ editorState });
this.sendData(editorState);
this.setState({ editorState });
};
handleTab = e => {

View File

@ -23,6 +23,16 @@ const generateFileName = name => {
return `${baseName}_${randomSuffix()}`;
};
const sendMediaMetrics = data => {
if (_.has(data, 'caption') && !_.isEmpty(data.caption)) {
strapi.telemetry.send('didSaveMediaWithCaption');
}
if (_.has(data, 'alternativeText') && !_.isEmpty(data.alternativeText)) {
strapi.telemetry.send('didSaveMediaWithAlternativeText');
}
};
const combineFilters = params => {
// FIXME: until we support boolean operators for querying we need to make mime_ncontains use AND instead of OR
if (_.has(params, 'mime_ncontains') && Array.isArray(params.mime_ncontains)) {
@ -244,12 +254,16 @@ module.exports = {
},
async update(params, values) {
sendMediaMetrics(values);
const res = await strapi.query('file', 'upload').update(params, values);
strapi.eventHub.emit('media.update', { media: res });
return res;
},
async add(values) {
sendMediaMetrics(values);
const res = await strapi.query('file', 'upload').create(values);
strapi.eventHub.emit('media.create', { media: res });
return res;
@ -335,6 +349,12 @@ module.exports = {
},
setSettings(value) {
if (value.responsiveDimensions === true) {
strapi.telemetry.send('didEnableResponsiveDimensions');
} else {
strapi.telemetry.send('didDisableResponsiveDimensions');
}
return strapi
.store({
type: 'plugin',

View File

@ -1,5 +1,6 @@
const fs = require('../fs');
const fse = require('fs-extra');
const path = require('path');
jest.mock('fs-extra');
@ -23,8 +24,8 @@ describe('Strapi fs utils', () => {
await strapiFS.writeAppFile('test', content);
expect(fse.ensureFile).toHaveBeenCalledWith('/tmp/test');
expect(fse.writeFile).toHaveBeenCalledWith('/tmp/test', content);
expect(fse.ensureFile).toHaveBeenCalledWith(path.join('/', 'tmp', 'test'));
expect(fse.writeFile).toHaveBeenCalledWith(path.join('/', 'tmp', 'test'), content);
});
test('Normalize the path to avoid relative access to folders in parent directories', async () => {
@ -34,8 +35,8 @@ describe('Strapi fs utils', () => {
await strapiFS.writeAppFile('../../test', content);
expect(fse.ensureFile).toHaveBeenCalledWith('/tmp/test');
expect(fse.writeFile).toHaveBeenCalledWith('/tmp/test', content);
expect(fse.ensureFile).toHaveBeenCalledWith(path.join('/', 'tmp', 'test'));
expect(fse.writeFile).toHaveBeenCalledWith(path.join('/', 'tmp', 'test'), content);
});
test('Works with array path', async () => {
@ -45,8 +46,11 @@ describe('Strapi fs utils', () => {
await strapiFS.writeAppFile(['test', 'sub', 'path'], content);
expect(fse.ensureFile).toHaveBeenCalledWith('/tmp/test/sub/path');
expect(fse.writeFile).toHaveBeenCalledWith('/tmp/test/sub/path', content);
expect(fse.ensureFile).toHaveBeenCalledWith(path.join('/', 'tmp', 'test', 'sub', 'path'));
expect(fse.writeFile).toHaveBeenCalledWith(
path.join('/', 'tmp', 'test', 'sub', 'path'),
content
);
});
});
@ -58,11 +62,7 @@ describe('Strapi fs utils', () => {
strapiFS.writeAppFile = jest.fn(() => Promise.resolve());
await strapiFS.writePluginFile(
'users-permissions',
['test', 'sub', 'path'],
content
);
await strapiFS.writePluginFile('users-permissions', ['test', 'sub', 'path'], content);
expect(strapiFS.writeAppFile).toHaveBeenCalledWith(
'extensions/users-permissions/test/sub/path',

View File

@ -52,7 +52,7 @@ const createCoreStore = ({ environment: defaultEnv, db }) => {
return null;
}
if (data.type === 'object' || data.type === 'array' || data.type === 'boolean') {
if (data.type === 'object' || data.type === 'array' || data.type === 'boolean' || data.type === 'string') {
try {
return JSON.parse(data.value);
} catch (err) {

View File

@ -0,0 +1,48 @@
const wrapWithRateLimiter = require('../rate-limiter');
describe('Telemetry daily RateLimiter', () => {
test('Passes event and payload to sender', async () => {
const sender = jest.fn(() => Promise.resolve(true));
const send = wrapWithRateLimiter(sender, { limitedEvents: ['testEvent'] });
const payload = { key: 'value' };
await send('notRestricted', payload);
expect(sender).toHaveBeenCalledWith('notRestricted', payload);
});
test('Calls sender if event is not restricted', async () => {
const sender = jest.fn(() => Promise.resolve(true));
const send = wrapWithRateLimiter(sender, { limitedEvents: ['testEvent'] });
await send('notRestricted');
expect(sender).toHaveBeenCalledWith('notRestricted', undefined);
});
test('Calls the sender as many times as request when events is not restricted', async () => {
const sender = jest.fn(() => Promise.resolve(true));
const send = wrapWithRateLimiter(sender, { limitedEvents: ['testEvent'] });
await send('notRestricted');
await send('notRestricted');
await send('notRestricted');
expect(sender).toHaveBeenCalledTimes(3);
});
test('Calls the sender only once when event is restricted', async () => {
const sender = jest.fn(() => Promise.resolve(true));
const send = wrapWithRateLimiter(sender, { limitedEvents: ['restrictedEvent'] });
await send('restrictedEvent');
await send('restrictedEvent');
await send('restrictedEvent');
expect(sender).toHaveBeenCalledTimes(1);
});
});

View File

@ -3,60 +3,27 @@
* Strapi telemetry package.
* You can learn more at https://strapi.io/documentation/3.0.0-beta.x/global-strapi/usage-information.html#commitment-to-our-users-data-collection
*/
const os = require('os');
const isDocker = require('is-docker');
const { machineIdSync } = require('node-machine-id');
const fetch = require('node-fetch');
const ciEnv = require('ci-info');
const { scheduleJob } = require('node-schedule');
const wrapWithRateLimit = require('./rate-limiter');
const createSender = require('./sender');
const createMiddleware = require('./middleware');
const isTruthy = require('./is-truthy');
const LIMITED_EVENTS = [
'didSaveMediaWithAlternativeText',
'didSaveMediaWithCaption',
'didDisableResponsiveDimensions',
'didEnableResponsiveDimensions',
];
const createTelemetryInstance = strapi => {
const uuid = strapi.config.uuid;
const deviceId = machineIdSync();
const isDisabled = !uuid || isTruthy(process.env.STRAPI_TELEMETRY_DISABLED);
const anonymous_metadata = {
environment: strapi.config.environment,
os: os.type(),
osPlatform: os.platform(),
osRelease: os.release(),
nodeVersion: process.version,
docker: process.env.DOCKER || isDocker(),
isCI: ciEnv.isCI,
version: strapi.config.info.strapi,
strapiVersion: strapi.config.info.strapi,
};
const sendEvent = async (event, payload) => {
// do not send anything when user has disabled analytics
if (isDisabled) return true;
try {
const res = await fetch('https://analytics.strapi.io/track', {
method: 'POST',
body: JSON.stringify({
event,
uuid,
deviceId,
properties: {
...payload,
...anonymous_metadata,
},
}),
timeout: 1000,
headers: { 'Content-Type': 'application/json' },
});
return res.ok;
} catch (err) {
return false;
}
};
const sender = createSender(strapi);
const sendEvent = wrapWithRateLimit(sender, { limitedEvents: LIMITED_EVENTS });
if (!isDisabled) {
scheduleJob('0 0 12 * * *', () => sendEvent('ping'));
@ -64,7 +31,10 @@ const createTelemetryInstance = strapi => {
}
return {
send: sendEvent,
async send(event, payload) {
if (isDisabled) return true;
return sendEvent(event, payload);
},
};
};

View File

@ -0,0 +1,27 @@
'use strict';
/**
* @param events a list of events that need to be limited
*/
module.exports = (sender, { limitedEvents = [] } = {}) => {
let currentDay = new Date().getDate();
const eventCache = new Map();
return async (event, payload) => {
if (!limitedEvents.includes(event)) {
return sender(event, payload);
}
if (new Date().getDate() !== currentDay) {
eventCache.clear();
currentDay = new Date().getDate();
}
if (eventCache.has(event)) {
return false;
}
eventCache.set(event, true);
return sender(event, payload);
};
};

View File

@ -0,0 +1,53 @@
'use strict';
const os = require('os');
const isDocker = require('is-docker');
const { machineIdSync } = require('node-machine-id');
const fetch = require('node-fetch');
const ciEnv = require('ci-info');
/**
* Create a send function for event with all the necessary metadatas
* @param {Object} strapi strapi app
* @returns {Function} (event, payload) -> Promise{boolean}
*/
module.exports = strapi => {
const uuid = strapi.config.uuid;
const deviceId = machineIdSync();
const anonymous_metadata = {
environment: strapi.config.environment,
os: os.type(),
osPlatform: os.platform(),
osRelease: os.release(),
nodeVersion: process.version,
docker: process.env.DOCKER || isDocker(),
isCI: ciEnv.isCI,
version: strapi.config.info.strapi,
strapiVersion: strapi.config.info.strapi,
};
return async (event, payload = {}) => {
try {
const res = await fetch('https://analytics.strapi.io/track', {
method: 'POST',
body: JSON.stringify({
event,
uuid,
deviceId,
properties: {
...payload,
...anonymous_metadata,
},
}),
timeout: 1000,
headers: { 'Content-Type': 'application/json' },
});
return res.ok;
} catch (err) {
return false;
}
};
};