Skip to content

Commit

Permalink
fixed large analytics bug
Browse files Browse the repository at this point in the history
  • Loading branch information
arjunpat committed Jan 9, 2019
1 parent 463fd3d commit 4835403
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 94 deletions.
1 change: 0 additions & 1 deletion extensions/chrome/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ chrome.runtime.onMessageExternal.addListener((req, sender, sendResponse) => {
}

if (values.error !== 'not_registered') {
analytics.setRegisteredTo(values.email);
prefManager.setGoogleAccount(values);
}
showPrefs();
Expand Down
22 changes: 8 additions & 14 deletions lib/api/bell-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,24 +79,17 @@ class BellData {
});
}

isThisMe(a, b) {

for (let val of ['profile_pic', 'email', 'first_name', 'last_name'])
if (a[val] !== b[val]) return false;
return true;
}

// create user, devices, etc.
// assumes that other code checks all params to make sure not undefined

async createNewUser(params) {
let {email, first_name, last_name, profile_pic, school} = params;
let {email, first_name, last_name, profile_pic} = params;

let empty_obj = '{}';

await this.query(
'INSERT INTO users (email, first_name, last_name, profile_pic, settings, school, stats, created_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
[email, first_name, last_name, profile_pic, empty_obj, school, empty_obj, Date.now()],
'INSERT INTO users (email, first_name, last_name, profile_pic, settings, stats, created_time) VALUES (?, ?, ?, ?, ?, ?, ?)',
[email, first_name, last_name, profile_pic, empty_obj, empty_obj, Date.now()],
);

}
Expand Down Expand Up @@ -155,7 +148,7 @@ class BellData {

}

async unregister(device_id, email) {
async unregister(device_id) {

await this.query('UPDATE devices SET registered_to = NULL, time_registered = NULL WHERE device_id = ?', [device_id]);

Expand All @@ -179,15 +172,16 @@ class BellData {
// if last period update was within the last 5 minutes, save stat as one
if (typeof arr.updated_settings === 'object') {

// period name stats
if (arr.updated_settings.length > 8)
if (arr.updated_settings.length > 150)
arr.updated_settings = utils.removeEveryOtherElementFromArray(arr.updated_settings, 1);

for (let i = arr.updated_settings.length - 1; i >= 0; i--)
for (let i = arr.updated_settings.length - 1; i >= 0; i--) {
if (now - 300000 < arr.updated_settings[i])
arr.updated_settings.splice(i, 1);
else
break;
}

} else {
arr.updated_settings = [];
}
Expand Down
124 changes: 77 additions & 47 deletions lib/api/v3.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const https = require('https');
const express = require('express');
const router = express.Router();
const responses = require('./responses');
Expand Down Expand Up @@ -52,7 +53,7 @@ router.post('/init', async (req, res) => {
else if (email && profile_pic)
dataToSend = {email, profile_pic, first_name, last_name, settings, school};
else
throw "Can't get user from device id";
return res.send(responses.error('bad_device_id'));

return res.send(responses.success(dataToSend));

Expand All @@ -61,50 +62,93 @@ router.post('/init', async (req, res) => {
res.send(responses.error('missing_data'));
});

router.post('/write/login', async (req, res) => {

let {email, first_name, last_name, profile_pic} = req.body.data;;
function getGoogleUser(token) {
return new Promise((resolve, reject) => {

if (!req.device_id || !email || !first_name || !last_name || !profile_pic)
let req = https.get(new URL('https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=' + encodeURIComponent(token)), res => {
let output = '';
res.setEncoding('utf8');

res.on('data', chunk => output += chunk);

res.on('end', () => {
let obj = JSON.parse(output);

let { email, given_name, family_name, picture, email_verified } = obj;

if (email && given_name && family_name && picture && email_verified) {
resolve({
email,
first_name: given_name,
last_name: family_name,
profile_pic: picture
});
} else {
reject();
}

});
});

req.on('error', err => {
reject(err);
});

req.end();
});
}

router.post('/write/login', (req, res) => {

let { token } = req.body.data;

if (!token || !req.device_id) {
return res.send(responses.error('missing_data'));
}

getGoogleUser(token).then(async user => {

let emailUserData = await bellData.getUserByEmail(email);
let {email, first_name, last_name, profile_pic} = user;

if (emailUserData !== false) { // already have an account
let userData = await bellData.getUserByEmail(email);

if (!bellData.isThisMe(req.body.data, emailUserData))
await bellData.updateUser(req.body.data);
if (userData !== false) { // already have an account

await bellData.updateUser(user);
await bellData.registerDevice(req.device_id, email);

return res.send(responses.success({
status: 'returning_user',
user_data: {
email,
first_name,
last_name,
profile_pic,
settings: userData.settings,
school: userData.school
}
}));
}

await bellData.createNewUser(user);
await bellData.registerDevice(req.device_id, email);

return res.send(responses.success({
status: 'returning_user',
res.send(responses.success({
status: 'new_user',
user_data: {
email,
first_name,
last_name,
profile_pic,
settings: emailUserData.settings,
school: emailUserData.school
settings: {}
}
}));
}

req.body.data.school = 'mvhs';

await bellData.createNewUser(req.body.data);
await bellData.registerDevice(req.device_id, email);

res.send(responses.success({
status: 'new_user',
user_data: {
email,
first_name,
last_name,
profile_pic,
settings: {}
}
}));
}).catch(err => {
console.log(err);
res.send(responses.error('bad_token'));
});

});

Expand All @@ -114,21 +158,14 @@ router.post('/write/logout', async (req, res) => {
return res.send(responses.error('missing_data'));
}

let deviceInfo = await bellData.getDeviceByDeviceId(req.device_id);

if (deviceInfo.registered_to) {

await bellData.unregister(req.device_id, deviceInfo.registered_to);
return res.send(responses.success());
}

res.send(responses.error('bad_data'));
await bellData.unregister(req.device_id);
return res.send(responses.success());

});

router.post('/write/analytics', async (req, res) => {

let { pathname, prefs, referrer, speed, registered_to, version, school } = req.body.data;
let { pathname, prefs, referrer, speed, version, school } = req.body.data;

if (!req.device_id || !pathname || !prefs || typeof referrer !== 'string' || !speed || !school)
return res.send(responses.error('missing_data'));
Expand All @@ -140,13 +177,12 @@ router.post('/write/analytics', async (req, res) => {
ip: req.headers['x-forwarded-for'] || req.connection.remoteAddress,
referrer,
version,
period: prefs.period || undefined,
period: prefs.period,
prefs: prefs,
theme: prefs.theme,
speed: speed,
tti: speed.tti,
ttfb: speed.ttfb,
user: registered_to || undefined,
school
}

Expand All @@ -158,11 +194,6 @@ router.post('/write/analytics', async (req, res) => {
values.prefs = JSON.stringify(values.prefs);
values.speed = JSON.stringify(values.speed);

for (let key in values) {
if (typeof values[key] !== 'string' && typeof values[key] !== 'number' && typeof values[key] !== 'boolean' && typeof values[key] !== 'undefined') {
return res.send(responses.error('bad_data'));
}
}

if (typeof values.school !== 'string' || values.school.length > 30) {
return res.send(responses.error('bad_data'));
Expand All @@ -174,7 +205,6 @@ router.post('/write/analytics', async (req, res) => {
}

res.send(responses.error('bad_data'));

});

router.post('/write/close-analytics', async (req, res) => {
Expand Down Expand Up @@ -235,7 +265,7 @@ router.post('/update/preferences', async (req, res) => {
let response = await bellData.updatePreferences(req.device_id, period_names, theme, school);

if (response.error) {
return res.send(responses.error(res.error));
return res.send(responses.error(response.error));
}

res.send(responses.success());
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "period-countdown",
"version": "3.0.3",
"version": "3.0.4",
"description": "A simple way to keep track of the remaining time in class",
"main": "server.js",
"scripts": {
Expand Down
4 changes: 4 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ <h3><span id="location-uri">This link</span> is either outdated, inaccurate, or
<span class="modal-login">Log in with Google</span>
<span class="modal-server-down">There&#8217;s a problem</span>
<span class="modal-found-bug">Report a bug</span>
<span class="modal-loading">Please wait</span>
</div>
<div id="modal-body">
<div class="log-in-first">
Expand Down Expand Up @@ -164,6 +165,9 @@ <h3><span id="location-uri">This link</span> is either outdated, inaccurate, or
<br><br>
The code helps us fix the bug rapidly.
</div>
<div class="modal-loading">
Loading...
</div>
</div>
<div id="modal-footer">
<a>Close</a>
Expand Down
10 changes: 1 addition & 9 deletions public/js/Analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default class Analytics {
if (!this.pathname || !this.deviceId || typeof this.theme !== 'number' || !this.version || !this.school)
return;

if ((this.pathname === '/' || this.pathname === 'extn') && typeof this.period !== 'number')
if ((this.pathname === '/' || this.pathname === 'extn') && !this.period)
return;

this.sent = true;
Expand Down Expand Up @@ -51,9 +51,6 @@ export default class Analytics {

data.version = this.version;

if (this.registeredTo)
data.registered_to = this.registeredTo;

RequestManager.sendAnalytics(data).then(data => {
if (data.success) {
Logger.log('Analytics', 'analytics data sent!');
Expand Down Expand Up @@ -88,11 +85,6 @@ export default class Analytics {
this.a();
}

setRegisteredTo(x) {
this.registeredTo = x;
this.a();
}

setVersion(x) {
this.version = x;
this.a();
Expand Down
22 changes: 15 additions & 7 deletions public/js/RequestManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,20 @@ export default class RequestManager {
});
else {

let ua = window.navigator.userAgent;

let temp = {
chrome: !!window.chrome,
int_exp: false || !!document.documentMode,
int_exp: /*@cc_on!@*/false || !!document.documentMode,
edge: !this.int_exp && !!window.StyleMedia,
safari: /constructor/i.test(window.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]" })(!window['safari'] || (typeof safari !== 'undefined' && safari.pushNotification)),
safari: (
/constructor/i.test(window.HTMLElement)
|| (function (p) { return p.toString() === "[object SafariRemoteNotification]" })(!window['safari'] || (typeof safari !== 'undefined' && safari.pushNotification)))
|| ((!!ua.match(/iPad/i) || !!ua.match(/iPhone/i) && !window.chrome)
),
firefox: typeof InstallTrigger !== 'undefined',
opera: (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0
};
opera: (!!window.opr && !!opr.addons) || !!window.opera || ua.indexOf(' OPR/') >= 0
}

let browser = {};

Expand All @@ -72,7 +78,7 @@ export default class RequestManager {
method: 'POST',
data: {
data: {
user_agent: window.navigator.userAgent,
user_agent: ua,
platform: window.navigator.platform,
browser
}
Expand All @@ -86,13 +92,15 @@ export default class RequestManager {
}
}

static login(account) {
static login(token) {
return this.ajax({
url: '/api/v3/write/login',
method: 'POST',
data: {
device_id: Storage.getDeviceId(),
data: account
data: {
token
}
}
}).then(res => res.json);
}
Expand Down
4 changes: 3 additions & 1 deletion public/js/components/PeriodNameEnterArea.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ export default class PeriodNameEnterArea extends Component {
let map = {};

for (let input of this.getElement().querySelectorAll('input')) {
map[ this._decodePeriodNameId(input.id) ] = input.value;

if (input.value !== '')
map[ this._decodePeriodNameId(input.id) ] = input.value;
}

return map;
Expand Down
Loading

0 comments on commit 4835403

Please sign in to comment.