Skip to content

Commit 5071913

Browse files
committed
Discontinue and deactivate study functionality
1 parent c0f9ef3 commit 5071913

10 files changed

+77
-348
lines changed

app/pages/options.html

+1-25
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,9 @@
2121
</select>
2222
<label for="example">Example</label>
2323
<input name="example" id="example" type="datetime-local" readonly>
24-
<label for="study-optin">Participate in anonymised study (<a href="https://empri-devops.de/timestamp-precision-study/" target="_blank">learn more</a>)</label>
25-
<input name="study-optin" id="study-optin" type="checkbox">
26-
<a href="studydataview.html" target="_blank">Show data</a>
24+
<p id="study-info">Click <a href="studydataview.html" target="_blank">here</a> to view your local data for the discontinued <a href="https://empri-devops.de/timestamp-precision-study/" target="_blank">study</a>.</p>
2725
</form>
28-
<!-- The Modal -->
29-
<div id="datapurgemodal" class="modal">
30-
<div class="modal-content">
31-
<p>
32-
Opting out will end your participation and delete the study data from your browser.
33-
You can also choose to remove all your data from our study.
34-
However we appreciate if you let us use previously sent data.
35-
<br>
36-
If you want to keep a copy you should
37-
<a href="studydataview.html" target="_blank">make one</a>
38-
before continuing.
39-
</p>
40-
<p id="deleteServer-box">
41-
<label for="deleteServer">Remove data from study</label>
42-
<input type="checkbox" id="deleteServer" name="deleteServer">
43-
</p>
44-
<p id="action-box">
45-
<span id="purgeCont" class="button btn-red" role="button">Delete and opt-out</span>
46-
<span id="purgeAbort" class="button btn-gray" role="button">Don't opt-out now</span>
47-
</p>
48-
</div>
4926
</div>
50-
<p id="response" class="message"></p>
5127
<p id="contact">
5228
<a href="mailto:[email protected]?subject=GHTimestampStudy">Contact support</a>
5329
</p>

app/pages/update.html

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!DOCTYPE html>
2+
3+
<html>
4+
<head>
5+
<meta charset="utf-8">
6+
<link rel="stylesheet" href="../styles/welcome.css"/>
7+
</head>
8+
9+
<body>
10+
<div class="content">
11+
<img id="logo" src="../images/on.svg" alt="">
12+
<h1>
13+
<span class="pretitle">Update on</span>
14+
GitHub Timestamp Privacy Extension
15+
</h1>
16+
<img src="../images/gh-usage.png" class="screenshot" alt="">
17+
<div id="study">
18+
<h2>Study has ended – Thanks!</h2>
19+
<p>
20+
Our research project <a href="https://empri-devops.de">EMPRI-DEVOPS</a> ended in July 2022 and with it our GitHub Timestamp Study.
21+
<strong>Thanks very much for taking part!</strong>
22+
Unfortunately, we managed to receive only very little usage data.
23+
For that reason, we cannot show you any results at this point.
24+
</p>
25+
26+
<p>
27+
<strong>You are welcome to keep using this extension.</strong>
28+
For the time being, this extension will <em>no longer collect or submit data</em> for our study.
29+
You can still view and export previously collected data in the settings.
30+
</p>
31+
32+
<p>
33+
If you want to learn more about other results of our research project,
34+
please <strong><a href="https://empri-devops.de">visit our project site</a></strong>.
35+
</p>
36+
<div>
37+
<div>
38+
</body>
39+
</html>
40+

app/pages/welcome.html

-18
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,7 @@ <h1>
1717
<h2>Hide precise timestamps unless you need them</h2>
1818
<img src="../images/gh-usage.png" class="screenshot" alt="">
1919
<div>
20-
<div id="study">
21-
<h2>Contribute statistics to study</h2>
22-
<div>
23-
<div>
24-
Help us figure out users' demands for the precision of timestamps
25-
by sharing statistics about the precisions you select in this extension.<br>
26-
Opt-in and automatically send daily privacy-respecting reports.
27-
<a href="https://empri-devops.de/timestamp-precision-study/" target="_blank">Learn more</a>
28-
</div>
29-
<form>
30-
<label class="switch">
31-
<input id="studyoptin" name="studyoptin" type="checkbox">
32-
<span class="slider round"></span>
33-
</label>
34-
</form>
35-
</div>
36-
<div>
3720
<div>
38-
<script src="../scripts/onboarding.js"></script>
3921
</body>
4022
</html>
4123

app/scripts/background.js

+16-25
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
import { sendReport } from "./study.js";
2-
31
browser.storage.sync.get("ghrOn").then((res) => {
42
if (typeof res.ghrOn == "undefined") {
53
browser.storage.sync.set({
64
ghrOn: true,
75
mostsigunit: "year",
8-
studyOptIn: false,
96
});
107
} else if (!res.ghrOn) {
118
browser.browserAction.setIcon({
@@ -26,27 +23,21 @@ browser.runtime.onInstalled.addListener(async ({ reason, temporary }) => {
2623
await browser.tabs.create({ url });
2724
}
2825
break;
26+
case "update":
27+
{
28+
browser.storage.local.get("studyOptIn")
29+
.then((res) => {
30+
if (res.studyOptIn) {
31+
const url = browser.runtime.getURL("pages/update.html");
32+
return browser.tabs.create({ url });
33+
}
34+
})
35+
.then(() => {
36+
// opt out to not show message again
37+
return browser.storage.local.set({ studyOptIn: false });
38+
})
39+
.catch((error) => console.error(error));
40+
}
41+
break;
2942
}
3043
});
31-
32-
33-
// Synchronise reporting in background script to avoid
34-
// duplicate reporting by parallel active content scripts
35-
var reportRunning = false;
36-
function manageReporting(message, sender, respond) {
37-
if (message.type != "sendReport") {
38-
return; // message not for us
39-
}
40-
if (reportRunning) {
41-
return; // already triggered by another sender
42-
}
43-
reportRunning = true;
44-
sendReport()
45-
.then(() => respond("done"))
46-
.catch((err) => respond(err))
47-
.finally(() => {
48-
reportRunning = false;
49-
});
50-
return true; // make caller wait for async response
51-
}
52-
browser.runtime.onMessage.addListener(manageReporting);

app/scripts/onboarding.js

+1-24
Original file line numberDiff line numberDiff line change
@@ -1,24 +1 @@
1-
import { clearStudyData, initStudy } from "./study.js";
2-
3-
function setOptInState() {
4-
browser.storage.local.get("studyOptIn").then((res) => {
5-
let optInBox = document.querySelector("#studyoptin");
6-
optInBox.checked = res.studyOptIn || false;
7-
});
8-
}
9-
10-
setOptInState();
11-
document.querySelector("#studyoptin").addEventListener("click", function() {
12-
clearStudyData()
13-
.then(() => {
14-
// init if checked
15-
if (this.checked) {
16-
return initStudy();
17-
}
18-
})
19-
.then(() => {
20-
// save opt-in state
21-
return browser.storage.local.set({ studyOptIn: this.checked });
22-
})
23-
.catch(error => console.error(error));
24-
});
1+
// no longer need to setup anything

app/scripts/options.js

+13-100
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,38 @@
11
import { DateTime } from "luxon";
2-
import { clearStudyData, initStudy, requestDeletion } from "./study.js";
2+
import { clearStudyData, initStudy} from "./study.js";
33

44
(() => {
55
let msu = document.querySelector("#mostsigunit");
66
let exampleField = document.querySelector("#example");
7-
let studyOptIn = document.querySelector("#study-optin");
8-
let purgeModal = document.querySelector("#datapurgemodal");
9-
let serverDeleteBox = document.querySelector("#deleteServer");
10-
let responseEl = document.querySelector("#response");
7+
let studyInfo = document.querySelector("#study-info");
118

129
function saveOptions() {
13-
console.assert(!studyOptIn.checked || msu.value == "year");
1410
return browser.storage.sync.set({ mostsigunit: msu.value })
15-
.then(() => {
16-
return browser.storage.local.set({ studyOptIn: studyOptIn.checked });
17-
})
1811
.catch(error => console.error(error));
1912
}
2013

2114
function restoreOptions() {
15+
// load old study data to check if we should show the notice
2216
return Promise.all([
2317
browser.storage.sync.get("mostsigunit"),
24-
browser.storage.local.get("studyOptIn"),
18+
browser.storage.local.get([
19+
"msuChoices",
20+
"studyOptIn",
21+
"viewCounts",
22+
]),
2523
])
2624
.then((results) => {
2725
let msuval = results[0].mostsigunit;
2826
let optin = results[1].studyOptIn;
27+
let choices = results[1].msuChoices;
28+
let views = results[1].viewCounts;
2929

3030
if (msuval) {
3131
msu.value = msuval;
3232
}
33-
studyOptIn.checked = optin;
34-
if (optin) {
35-
disableMsuSelection();
33+
// hide notice if no signs of prev study participation is found
34+
if (!optin && !choices && !views) {
35+
studyInfo.style.display = "none";
3636
}
3737
})
3838
.then(() => updateExampleField())
@@ -61,23 +61,6 @@ import { clearStudyData, initStudy, requestDeletion } from "./study.js";
6161
exampleField.value = v;
6262
}
6363

64-
function disableMsuSelection() {
65-
msu.value = "year";
66-
msu.disabled = true;
67-
msu.title = "Study participation requires Year precision.";
68-
updateExampleField();
69-
}
70-
71-
function enableMsuSelection() {
72-
msu.disabled = false;
73-
msu.title = "";
74-
}
75-
76-
function abortOptOut() {
77-
purgeModal.style.display = "none";
78-
studyOptIn.checked = true;
79-
}
80-
8164
document.addEventListener("DOMContentLoaded", restoreOptions);
8265
document.querySelector("#mostsigunit").addEventListener("change", function () {
8366
saveOptions()
@@ -86,74 +69,4 @@ import { clearStudyData, initStudy, requestDeletion } from "./study.js";
8669
})
8770
.catch(error => console.error(error));
8871
});
89-
document.querySelector("#study-optin").addEventListener("change", function() {
90-
if (this.checked) {
91-
// opting in
92-
clearStudyData()
93-
.then(() => {
94-
disableMsuSelection();
95-
return initStudy();
96-
})
97-
.then(() => {
98-
return saveOptions();
99-
})
100-
.catch(error => console.error(error));
101-
} else {
102-
// opting out
103-
purgeModal.style.display = "block";
104-
}
105-
});
106-
document.querySelector("#purgeAbort").addEventListener("click", abortOptOut);
107-
108-
function optOutHandler(event) {
109-
// purge data
110-
responseEl.classList.remove("message-success", "message-failure");
111-
let doDelete = serverDeleteBox.checked;
112-
let deletion;
113-
if (doDelete) {
114-
console.log("Requesting deletion");
115-
deletion = requestDeletion().then((res) => {
116-
console.log(res);
117-
if (res.result == "notsent" || res.result == "deleted") {
118-
return true;
119-
} else {
120-
responseEl.textContent = `Error ${res.status} while deleting study data. Please contact support.`;
121-
responseEl.classList.add("message-failure");
122-
abortOptOut();
123-
return false;
124-
}
125-
});
126-
} else {
127-
deletion = Promise.resolve(true);
128-
}
129-
deletion.then((success) => {
130-
if (success) {
131-
return clearStudyData(); // fulfilled with no return
132-
}
133-
return success; // to be distinguishable from clears undefined
134-
})
135-
.then((res) => {
136-
if (res === undefined) { // clear succeeded
137-
enableMsuSelection();
138-
return saveOptions();
139-
}
140-
})
141-
.catch(error => {
142-
console.error(error);
143-
responseEl.textContent = `Error ${error}. Please contact support.`;
144-
responseEl.classList.add("message-failure");
145-
abortOptOut();
146-
})
147-
.finally(() => {
148-
purgeModal.style.display = "none";
149-
});
150-
}
151-
document.querySelector("#purgeCont").addEventListener("click", optOutHandler);
152-
153-
// When the user clicks anywhere outside of the modal, close it
154-
window.addEventListener("click", function(event) {
155-
if (event.target == purgeModal) {
156-
abortOptOut();
157-
}
158-
});
15972
})();

0 commit comments

Comments
 (0)