Merge remote-tracking branch 'origin/develop' into develop

pull/21833/head
Weblate 2018-01-11 11:02:40 +00:00
commit 52607c4122
4 changed files with 113 additions and 17 deletions

View File

@ -14,25 +14,54 @@
limitations under the License.
*/
import { getCurrentLanguage } from './languageHandler';
import { getCurrentLanguage, _t, _td } from './languageHandler';
import PlatformPeg from './PlatformPeg';
import SdkConfig from './SdkConfig';
import SdkConfig, { DEFAULTS } from './SdkConfig';
import Modal from './Modal';
import sdk from './index';
function getRedactedHash() {
return window.location.hash.replace(/#\/(group|room|user)\/(.+)/, "#/$1/<redacted>");
}
function getRedactedUrl() {
const redactedHash = window.location.hash.replace(/#\/(group|room|user)\/(.+)/, "#/$1/<redacted>");
// hardcoded url to make piwik happy
return 'https://riot.im/app/' + redactedHash;
return 'https://riot.im/app/' + getRedactedHash();
}
const customVariables = {
'App Platform': 1,
'App Version': 2,
'User Type': 3,
'Chosen Language': 4,
'Instance': 5,
'RTE: Uses Richtext Mode': 6,
'Homeserver URL': 7,
'Identity Server URL': 8,
'App Platform': {
id: 1,
expl: _td('The platform you\'re on'),
},
'App Version': {
id: 2,
expl: _td('The version of Riot.im'),
},
'User Type': {
id: 3,
expl: _td('Whether or not you\'re logged in (we don\'t record your user name)'),
},
'Chosen Language': {
id: 4,
expl: _td('Your language of choice'),
},
'Instance': {
id: 5,
expl: _td('Which officially provided instance you are using, if any'),
},
'RTE: Uses Richtext Mode': {
id: 6,
expl: _td('Whether or not you\'re using the Richtext mode of the Rich Text Editor'),
},
'Homeserver URL': {
id: 7,
expl: _td('Your homeserver\'s URL'),
},
'Identity Server URL': {
id: 8,
expl: _td('Your identity server\'s URL'),
},
};
function whitelistRedact(whitelist, str) {
@ -40,9 +69,6 @@ function whitelistRedact(whitelist, str) {
return '<redacted>';
}
const whitelistedHSUrls = ["https://matrix.org"];
const whitelistedISUrls = ["https://vector.im"];
class Analytics {
constructor() {
this._paq = null;
@ -140,11 +166,16 @@ class Analytics {
}
_setVisitVariable(key, value) {
this._paq.push(['setCustomVariable', customVariables[key], key, value, 'visit']);
this._paq.push(['setCustomVariable', customVariables[key].id, key, value, 'visit']);
}
setLoggedIn(isGuest, homeserverUrl, identityServerUrl) {
if (this.disabled) return;
const config = SdkConfig.get();
const whitelistedHSUrls = config.piwik.whitelistedHSUrls || DEFAULTS.piwik.whitelistedHSUrls;
const whitelistedISUrls = config.piwik.whitelistedISUrls || DEFAULTS.piwik.whitelistedISUrls;
this._setVisitVariable('User Type', isGuest ? 'Guest' : 'Logged In');
this._setVisitVariable('Homeserver URL', whitelistRedact(whitelistedHSUrls, homeserverUrl));
this._setVisitVariable('Identity Server URL', whitelistRedact(whitelistedISUrls, identityServerUrl));
@ -154,6 +185,44 @@ class Analytics {
if (this.disabled) return;
this._setVisitVariable('RTE: Uses Richtext Mode', state ? 'on' : 'off');
}
showDetailsModal() {
const Tracker = window.Piwik.getAsyncTracker();
const rows = Object.values(customVariables).map((v) => Tracker.getCustomVariable(v.id)).filter(Boolean);
const resolution = `${window.screen.width}x${window.screen.height}`;
const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog');
Modal.createTrackedDialog('Analytics Details', '', ErrorDialog, {
title: _t('Analytics'),
description: <div>
<div>
{ _t('The information being sent to us to help make Riot.im better includes:') }
</div>
<table>
{ rows.map((row) => <tr key={row[0]}>
<td>{ _t(customVariables[row[0]].expl) }</td>
<td><code>{ row[1] }</code></td>
</tr>) }
</table>
<br />
<div>
{ _t('We also record each page you use in the app (currently <CurrentPageHash>), your User Agent'
+ ' (<CurrentUserAgent>) and your device resolution (<CurrentDeviceResolution>).',
{},
{
CurrentPageHash: <code>{ getRedactedHash() }</code>,
CurrentUserAgent: <code>{ navigator.userAgent }</code>,
CurrentDeviceResolution: <code>{ resolution }</code>,
},
) }
{ _t('Where this page includes identifiable information, such as a room, '
+ 'user or group ID, that data is removed before being sent to the server.') }
</div>
</div>,
});
}
}
if (!global.mxAnalytics) {

View File

@ -21,6 +21,13 @@ const DEFAULTS = {
integrations_rest_url: "https://scalar.vector.im/api",
// Where to send bug reports. If not specified, bugs cannot be sent.
bug_report_endpoint_url: null,
piwik: {
url: "https://piwik.riot.im/",
whitelistedHSUrls: ["https://matrix.org"],
whitelistedISUrls: ["https://vector.im", "https://matrix.org"],
siteId: 1,
},
};
class SdkConfig {
@ -45,3 +52,4 @@ class SdkConfig {
}
module.exports = SdkConfig;
module.exports.DEFAULTS = DEFAULTS;

View File

@ -812,6 +812,12 @@ module.exports = React.createClass({
<h3>{ _t('Analytics') }</h3>
<div className="mx_UserSettings_section">
{ _t('Riot collects anonymous analytics to allow us to improve the application.') }
<br />
{ _t('Privacy is important to us, so we don\'t collect any personal'
+ ' or identifiable data for our analytics.') }
<div className="mx_UserSettings_advanced_spoiler" onClick={Analytics.showDetailsModal}>
{ _t('Learn more about how we use analytics.') }
</div>
{ ANALYTICS_SETTINGS.map( this._renderDeviceSetting ) }
</div>
</div>;

View File

@ -842,6 +842,8 @@
"Report it": "Report it",
"Analytics": "Analytics",
"Riot collects anonymous analytics to allow us to improve the application.": "Riot collects anonymous analytics to allow us to improve the application.",
"Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.",
"Learn more about how we use analytics.": "Learn more about how we use analytics.",
"Labs": "Labs",
"These are experimental features that may break in unexpected ways": "These are experimental features that may break in unexpected ways",
"Use with caution": "Use with caution",
@ -965,5 +967,16 @@
"This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.": "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.",
"The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.",
"File to import": "File to import",
"Import": "Import"
"Import": "Import",
"The information being sent to us to help make Riot.im better includes:": "The information being sent to us to help make Riot.im better includes:",
"We also record each page you use in the app (currently <CurrentPageHash>), your User Agent (<CurrentUserAgent>) and your device resolution (<CurrentDeviceResolution>).": "We also record each page you use in the app (currently <CurrentPageHash>), your User Agent (<CurrentUserAgent>) and your device resolution (<CurrentDeviceResolution>).",
"Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.",
"The platform you're on": "The platform you're on",
"The version of Riot.im": "The version of Riot.im",
"Whether or not you're logged in (we don't record your user name)": "Whether or not you're logged in (we don't record your user name)",
"Your language of choice": "Your language of choice",
"Which officially provided instance you are using, if any": "Which officially provided instance you are using, if any",
"Whether or not you're using the Richtext mode of the Rich Text Editor": "Whether or not you're using the Richtext mode of the Rich Text Editor",
"Your homeserver's URL": "Your homeserver's URL",
"Your identity server's URL": "Your identity server's URL"
}