GDPR support: SentUsageStatistics.isAllowed flag is now part of ConsentOptions;

bundled default consents.json
This commit is contained in:
Eugene Zhuravlev
2017-12-21 15:51:22 +01:00
parent fe947fc0a5
commit 7dbff73454
12 changed files with 50 additions and 252 deletions
@@ -98,6 +98,15 @@ public final class ConsentOptions {
return confirmedConsent == null? Permission.UNDEFINED : confirmedConsent.isAccepted()? Permission.YES : Permission.NO;
}
public boolean setSendingUsageStatsAllowed(boolean allowed) {
final Consent defConsent = loadDefaultConsents().get(STATISTICS_OPTION_ID);
if (defConsent != null && !defConsent.isDeleted()) {
saveConfirmedConsents(Collections.singleton(new ConfirmedConsent(defConsent.getId(), defConsent.getVersion(), allowed, 0L)));
return true;
}
return false;
}
@Nullable
public String getConfirmedConsentsString() {
final Map<String, Consent> defaults = loadDefaultConsents();
@@ -130,7 +130,7 @@ public class StartupUtil {
if (!Main.isHeadless()) {
AppUIUtil.updateWindowIcon(JOptionPane.getRootFrame());
AppUIUtil.registerBundledFonts();
AppUIUtil.showEndUserAgreement();
AppUIUtil.showUserAgreementAndConsentsIfNeeded();
}
appStarter.start(newConfigFolder);
@@ -15,11 +15,11 @@
*/
package com.intellij.internal.statistic.actions;
import com.intellij.internal.statistic.utils.StatisticsUploadAssistant;
import com.intellij.internal.statistic.ApplicationStatisticsPersistenceComponent;
import com.intellij.internal.statistic.connect.StatisticsResult;
import com.intellij.internal.statistic.connect.StatisticsService;
import com.intellij.internal.statistic.ApplicationStatisticsPersistenceComponent;
import com.intellij.internal.statistic.persistence.UsageStatisticsPersistenceComponent;
import com.intellij.internal.statistic.utils.StatisticsUploadAssistant;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
@@ -45,10 +45,14 @@ public class SendStatisticsAction extends AnAction {
@Override
public void run(@NotNull ProgressIndicator indicator) {
UsageStatisticsPersistenceComponent statisticsPersistenceComponent = UsageStatisticsPersistenceComponent.getInstance();
boolean sendAllowed = statisticsPersistenceComponent.isAllowed();
statisticsPersistenceComponent.setAllowed(true);
ApplicationStatisticsPersistenceComponent.persistOpenedProjects();
statisticsPersistenceComponent.setAllowed(sendAllowed);
final boolean sendAllowed = statisticsPersistenceComponent.isAllowed();
try {
statisticsPersistenceComponent.setAllowed(true);
ApplicationStatisticsPersistenceComponent.persistOpenedProjects();
}
finally {
statisticsPersistenceComponent.setAllowed(sendAllowed);
}
StatisticsService service = StatisticsUploadAssistant.getStatisticsService();
final StatisticsResult result = service.send();
@@ -1,76 +0,0 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.internal.statistic.configurable;
import com.intellij.internal.statistic.persistence.UsageStatisticsPersistenceComponent;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
public class StatisticsConfigurable implements SearchableConfigurable, Configurable.NoScroll {
private boolean modifiedByDefault;
public StatisticsConfigurable() {
this(false);
}
public StatisticsConfigurable(boolean isModifiedByDefault) {
modifiedByDefault = isModifiedByDefault;
}
private StatisticsConfigurationComponent myConfig;
@Nls
public String getDisplayName() {
return "Usage Statistics";
}
@Override
@Nullable
@NonNls
public String getHelpTopic() {
return "preferences.usage.statictics";
}
public JComponent createComponent() {
myConfig = new StatisticsConfigurationComponent();
return myConfig.getJComponent();
}
public boolean isModified() {
final UsageStatisticsPersistenceComponent persistenceComponent = UsageStatisticsPersistenceComponent.getInstance();
return myConfig.isAllowed() != persistenceComponent.isAllowed() ||
myConfig.getPeriod() != persistenceComponent.getPeriod() ||
modifiedByDefault;
}
public void apply() throws ConfigurationException {
final UsageStatisticsPersistenceComponent persistenceComponent = UsageStatisticsPersistenceComponent.getInstance();
//persistenceComponent.setPeriod(myConfig.getPeriod());
persistenceComponent.setAllowed(myConfig.isAllowed());
persistenceComponent.setShowNotification(false);
modifiedByDefault = false;
}
public void reset() {
myConfig.reset();
}
public void disposeUIResources() {
myConfig = null;
}
@NotNull
@Override
public String getId() {
return "usage.statistics";
}
}
@@ -1,74 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.internal.statistic.configurable.StatisticsConfigurationComponent">
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="335" height="268"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<vspacer id="4250b">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<grid id="ef0a7" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="2f6db" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="6149c" class="javax.swing.JCheckBox" binding="myAllowToSendUsagesCheckBox" default-binding="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<selected value="true"/>
<text value=""/>
</properties>
</component>
</children>
</grid>
<component id="67819" class="javax.swing.JLabel" binding="myLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
</children>
</grid>
<component id="9c047" class="javax.swing.JLabel" binding="myTitle">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value=""/>
</properties>
</component>
<hspacer id="244b1">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
</children>
</grid>
<buttonGroups>
<group name="buttonGroup">
<member id="181ac"/>
<member id="181ac"/>
<member id="1f52"/>
<member id="c628d"/>
</group>
</buttonGroups>
</form>
@@ -1,71 +0,0 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.internal.statistic.configurable;
import com.intellij.internal.statistic.StatisticsBundle;
import com.intellij.internal.statistic.connect.StatisticsService;
import com.intellij.internal.statistic.persistence.UsageStatisticsPersistenceComponent;
import com.intellij.internal.statistic.utils.StatisticsUploadAssistant;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.ui.RelativeFont;
import javax.swing.*;
import java.util.Map;
public class StatisticsConfigurationComponent {
private JPanel myMainPanel;
private JLabel myTitle;
private JCheckBox myAllowToSendUsagesCheckBox;
private JLabel myLabel;
public StatisticsConfigurationComponent() {
String product = ApplicationNamesInfo.getInstance().getFullProductName();
String company = ApplicationInfo.getInstance().getCompanyName();
myTitle.setText(StatisticsBundle.message("stats.title", product, company));
myLabel.setText(StatisticsBundle.message("stats.config.details", company));
RelativeFont.SMALL.install(myLabel);
myAllowToSendUsagesCheckBox.setText(StatisticsBundle.message("stats.config.allow.send.stats.text", company));
// Let current statistics service override labels
StatisticsService service = StatisticsUploadAssistant.getStatisticsService();
if (service != null) {
Map<String, String> overrides = service.getStatisticsConfigurationLabels();
if (overrides != null) {
String s = overrides.get(StatisticsService.TITLE);
if (s != null) {
myTitle.setText(s);
}
s = overrides.get(StatisticsService.DETAILS);
if (s != null) {
myLabel.setText(s);
}
s = overrides.get(StatisticsService.ALLOW_CHECKBOX);
if (s != null) {
myAllowToSendUsagesCheckBox.setText(s);
}
}
}
myTitle.setText(myTitle.getText().replace("%company%", company));
myLabel.setText(myLabel.getText().replace("%company%", company));
myAllowToSendUsagesCheckBox.setText(myAllowToSendUsagesCheckBox.getText().replace("%company%", company));
}
public JPanel getJComponent() {
return myMainPanel;
}
public boolean isAllowed() {
return myAllowToSendUsagesCheckBox.isSelected();
}
public void reset() {
myAllowToSendUsagesCheckBox.setSelected(UsageStatisticsPersistenceComponent.getInstance().isAllowed());
}
public SendPeriod getPeriod() {
return SendPeriod.DAILY;
}
}
@@ -2,6 +2,7 @@
package com.intellij.internal.statistic.persistence;
import com.intellij.ide.gdpr.ConsentOptions;
import com.intellij.internal.statistic.beans.ConvertUsagesUtil;
import com.intellij.internal.statistic.beans.GroupDescriptor;
import com.intellij.internal.statistic.beans.UsageDescriptor;
@@ -25,7 +26,6 @@ import java.util.Set;
public class UsageStatisticsPersistenceComponent extends BasicSentUsagesPersistenceComponent
implements NamedComponent, PersistentStateComponent<Element> {
@NonNls private boolean isAllowed = false;
@NonNls private boolean isShowNotification = true;
@NotNull private SendPeriod myPeriod = SendPeriod.DAILY;
@@ -73,8 +73,11 @@ public class UsageStatisticsPersistenceComponent extends BasicSentUsagesPersiste
setSentTime(0);
}
// compatibility: if was previously allowed, transfer the setting to the new place
final String isAllowedValue = element.getAttributeValue(IS_ALLOWED_ATTR);
setAllowed(!StringUtil.isEmptyOrSpaces(isAllowedValue) && Boolean.parseBoolean(isAllowedValue));
if (!StringUtil.isEmptyOrSpaces(isAllowedValue) && Boolean.parseBoolean(isAllowedValue)) {
setAllowed(true);
}
final String isShowNotificationValue = element.getAttributeValue(SHOW_NOTIFICATION_ATTR);
setShowNotification(StringUtil.isEmptyOrSpaces(isShowNotificationValue) || Boolean.parseBoolean(isShowNotificationValue));
@@ -100,9 +103,9 @@ public class UsageStatisticsPersistenceComponent extends BasicSentUsagesPersiste
element.setAttribute(LAST_TIME_ATTR, String.valueOf(lastTimeSent));
}
if (isAllowed()) {
element.setAttribute(IS_ALLOWED_ATTR, "true");
}
//if (isAllowed()) {
// element.setAttribute(IS_ALLOWED_ATTR, "true");
//}
if (!isShowNotification()) {
element.setAttribute(SHOW_NOTIFICATION_ATTR, "false");
}
@@ -131,12 +134,12 @@ public class UsageStatisticsPersistenceComponent extends BasicSentUsagesPersiste
}
public void setAllowed(boolean allowed) {
isAllowed = allowed;
ConsentOptions.getInstance().setSendingUsageStatsAllowed(allowed);
}
@Override
public boolean isAllowed() {
return isAllowed;
return ConsentOptions.getInstance().isSendingUsageStatsAllowed() == ConsentOptions.Permission.YES;
}
public void setShowNotification(boolean showNotification) {
@@ -1,19 +1,18 @@
package com.intellij.internal.statistic.updater;
import com.intellij.internal.statistic.configurable.StatisticsConfigurable;
import com.intellij.ide.gdpr.Consent;
import com.intellij.ide.gdpr.ConsentOptions;
import com.intellij.internal.statistic.connect.StatisticsService;
import com.intellij.internal.statistic.persistence.UsageStatisticsPersistenceComponent;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.notification.Notifications;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.ui.AppUIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import java.util.Collection;
public class StatisticsNotificationManager {
@@ -56,9 +55,10 @@ public class StatisticsNotificationManager {
notification.expire();
}
else if ("settings".equals(description)) {
final ShowSettingsUtil util = ShowSettingsUtil.getInstance();
IdeFrame ideFrame = WindowManagerEx.getInstanceEx().findFrameFor(null);
util.editConfigurable((JFrame)ideFrame, new StatisticsConfigurable(true));
final Collection<Consent> result = AppUIUtil.confirmConsentOptions(ConsentOptions.getInstance().getConsents().first);
if (result != null) {
ConsentOptions.getInstance().setConsents(result);
}
notification.expire();
}
}
@@ -253,7 +253,7 @@ public class AppUIUtil {
return iconPath;
}
public static void showEndUserAgreement() {
public static void showUserAgreementAndConsentsIfNeeded() {
if (ApplicationInfoImpl.getShadowInstance().isVendorJetBrains()) {
EndUserAgreement.Document agreement = EndUserAgreement.getLatestDocument();
if (!agreement.isAccepted()) {
@@ -415,9 +415,6 @@
<statistics.usagesCollector implementation="com.intellij.internal.statistic.customUsageCollectors.ideSettings.IdeInitialConfigUsageCollectors$DownloadedPlugins"/>
<statistics.usagesCollector implementation="com.intellij.openapi.editor.colors.impl.EditorColorSchemesUsagesCollector"/>
<applicationConfigurable parentId="preferences.general" instance="com.intellij.internal.statistic.configurable.StatisticsConfigurable" id="usage.statistics"
displayName="Usage Statistics"/>
<vfs.local.pluggableFileWatcher implementation="com.intellij.openapi.vfs.impl.local.NativeFileWatcherImpl" />
<virtualFileSystem key="dummy" implementationClass="com.intellij.openapi.vfs.ex.dummy.DummyFileSystem"/>
@@ -1,4 +1,4 @@
<!-- 1.5 -->
<!-- 1.7 -->
<head>
<meta charset="UTF-8">
</head>
@@ -12,7 +12,7 @@
<p>This Policy may be amended from time to time. The respective latest version of the policy at the
point of time of the purchase/registration of a <strong>JetBrains Software Product</strong>
(whichever occurs later) shall apply. The data controller is JetBrains s.r.o., Praha 4, Na hřebenech
II 1718/10, PSČ 147 00, Česká republika
II 1718/10, PSČ 140 00, Česká republika
</p>
<p>In this Privacy Policy, we describe the type of data, including personal data (collectively, “data”),
@@ -297,9 +297,6 @@
Website works
</li>
<li>For security purposes</li>
<li>Make sure you connect to the right service on our Website when we make any changes to the way the
Website works
</li>
</ul>
<p>Accepting these cookies is a condition of using the Website, so if you prevent these cookies we can't
@@ -0,0 +1,9 @@
[
{
"consentId": "rsch.send.usage.stat",
"version": "1.0",
"text": "I consent to submit anonymous usage statistics to help JetBrains improve their products. I agree that the following information will be sent to JetBrains and processed in accordance with JetBrains Privacy Policy https://www.jetbrains.com/company/privacy.html\n * Information about which product features are used\n * General statistics (number of files, file types) of the solutions I am working on\n * General information about my hardware configuration (for example, amount of RAM, CPU speed and number of cores)\n * General information about my software configuration (for example, OS version)\nI can revoke my consent at any time in this Data Sharing Options dialog available at Help | Data Sharing Options",
"printableName": "Send anonymous usage statistics to JetBrains",
"accepted": "false"
}
]