mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-14 13:17:24 +01:00
Compare commits
21 Commits
release
...
phillip/se
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40d5172972 | ||
|
|
ebb58e4470 | ||
|
|
c3ef26b2f3 | ||
|
|
108bd59296 | ||
|
|
5228ed40d1 | ||
|
|
becb6e49f0 | ||
|
|
aa8f0f0c4e | ||
|
|
d1891f4c43 | ||
|
|
2381be8c46 | ||
|
|
5c7545f32a | ||
|
|
ffed5a9a97 | ||
|
|
cd58ce2233 | ||
|
|
a2b5e3621e | ||
|
|
a06dfc9ed8 | ||
|
|
58b0e323a3 | ||
|
|
9ca60d7551 | ||
|
|
6f63583a12 | ||
|
|
d952239d35 | ||
|
|
2c7f6fd9e3 | ||
|
|
ddba450630 | ||
|
|
187238d39a |
13394
package-lock.json
generated
13394
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,6 @@
|
|||||||
"@babel/core": "^7.22.10",
|
"@babel/core": "^7.22.10",
|
||||||
"@babel/preset-env": "^7.22.10",
|
"@babel/preset-env": "^7.22.10",
|
||||||
"@babel/register": "^7.22.15",
|
"@babel/register": "^7.22.15",
|
||||||
"@google-analytics/data": "^4.12.1",
|
|
||||||
"@google-cloud/trace-agent": "^7.1.2",
|
"@google-cloud/trace-agent": "^7.1.2",
|
||||||
"@parse/node-apn": "^5.2.3",
|
"@parse/node-apn": "^5.2.3",
|
||||||
"@slack/webhook": "^6.1.0",
|
"@slack/webhook": "^6.1.0",
|
||||||
@@ -43,6 +42,7 @@
|
|||||||
"habitica-markdown": "^3.0.0",
|
"habitica-markdown": "^3.0.0",
|
||||||
"helmet": "^4.6.0",
|
"helmet": "^4.6.0",
|
||||||
"in-app-purchase": "^1.11.3",
|
"in-app-purchase": "^1.11.3",
|
||||||
|
"ip-location-api": "^4.0.0",
|
||||||
"js2xmlparser": "^5.0.0",
|
"js2xmlparser": "^5.0.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"jwks-rsa": "^2.1.5",
|
"jwks-rsa": "^2.1.5",
|
||||||
|
|||||||
112
website/client/package-lock.json
generated
112
website/client/package-lock.json
generated
@@ -12,7 +12,6 @@
|
|||||||
"@froxz/vite-plugin-s3": "^1.6.0",
|
"@froxz/vite-plugin-s3": "^1.6.0",
|
||||||
"@vitejs/plugin-vue2": "^2.3.3",
|
"@vitejs/plugin-vue2": "^2.3.3",
|
||||||
"@vue/test-utils": "1.0.0-beta.29",
|
"@vue/test-utils": "1.0.0-beta.29",
|
||||||
"amplitude-js": "^8.21.3",
|
|
||||||
"assert": "^2.1.0",
|
"assert": "^2.1.0",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"axios": "^0.28.0",
|
"axios": "^0.28.0",
|
||||||
@@ -68,49 +67,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@amplitude/analytics-connector": {
|
|
||||||
"version": "1.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@amplitude/analytics-connector/-/analytics-connector-1.5.0.tgz",
|
|
||||||
"integrity": "sha512-T8mOYzB9RRxckzhL0NTHwdge9xuFxXEOplC8B1Y3UX3NHa3BLh7DlBUZlCOwQgMc2nxDfnSweDL5S3bhC+W90g=="
|
|
||||||
},
|
|
||||||
"node_modules/@amplitude/types": {
|
|
||||||
"version": "1.10.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@amplitude/types/-/types-1.10.2.tgz",
|
|
||||||
"integrity": "sha512-I8qenRI7uU6wKNb9LiZrAosSHVoNHziXouKY81CrqxH9xhVTEIJFXeuCV0hbtBr0Al/8ejnGjQRx+S2SvU/pPg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@amplitude/ua-parser-js": {
|
|
||||||
"version": "0.7.33",
|
|
||||||
"resolved": "https://registry.npmjs.org/@amplitude/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
|
|
||||||
"integrity": "sha512-wKEtVR4vXuPT9cVEIJkYWnlF++Gx3BdLatPBM+SZ1ztVIvnhdGBZR/mn9x/PzyrMcRlZmyi6L56I2J3doVBnjA==",
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/ua-parser-js"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "paypal",
|
|
||||||
"url": "https://paypal.me/faisalman"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@amplitude/utils": {
|
|
||||||
"version": "1.10.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@amplitude/utils/-/utils-1.10.2.tgz",
|
|
||||||
"integrity": "sha512-tVsHXu61jITEtRjB7NugQ5cVDd4QDzne8T3ifmZye7TiJeUfVRvqe44gDtf55A+7VqhDhyEIIXTA1iVcDGqlEw==",
|
|
||||||
"dependencies": {
|
|
||||||
"@amplitude/types": "^1.10.2",
|
|
||||||
"tslib": "^2.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
|
||||||
@@ -1231,6 +1187,7 @@
|
|||||||
"version": "7.23.6",
|
"version": "7.23.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz",
|
||||||
"integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==",
|
"integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
},
|
},
|
||||||
@@ -3050,19 +3007,6 @@
|
|||||||
"ajv": "^6.9.1"
|
"ajv": "^6.9.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/amplitude-js": {
|
|
||||||
"version": "8.21.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-8.21.9.tgz",
|
|
||||||
"integrity": "sha512-d0jJH00wbXu7sxKtVwkdSXtVffjqdUrxuACKlnzP7jU5qt9wriXXMgHifdH5Oq+buKmyF8wKL9S02gAykysURA==",
|
|
||||||
"dependencies": {
|
|
||||||
"@amplitude/analytics-connector": "^1.4.6",
|
|
||||||
"@amplitude/ua-parser-js": "0.7.33",
|
|
||||||
"@amplitude/utils": "^1.10.2",
|
|
||||||
"@babel/runtime": "^7.21.0",
|
|
||||||
"blueimp-md5": "^2.19.0",
|
|
||||||
"query-string": "8.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ansi-colors": {
|
"node_modules/ansi-colors": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
|
||||||
@@ -3351,11 +3295,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/blueimp-md5": {
|
|
||||||
"version": "2.19.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz",
|
|
||||||
"integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w=="
|
|
||||||
},
|
|
||||||
"node_modules/bootstrap": {
|
"node_modules/bootstrap": {
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz",
|
||||||
@@ -3768,14 +3707,6 @@
|
|||||||
"integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==",
|
"integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/decode-uri-component": {
|
|
||||||
"version": "0.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.4.1.tgz",
|
|
||||||
"integrity": "sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/deep-eql": {
|
"node_modules/deep-eql": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.1.tgz",
|
||||||
@@ -4987,17 +4918,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/filter-obj": {
|
|
||||||
"version": "5.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz",
|
|
||||||
"integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.16"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/find-up": {
|
"node_modules/find-up": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||||
@@ -7283,22 +7203,6 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/query-string": {
|
|
||||||
"version": "8.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-8.1.0.tgz",
|
|
||||||
"integrity": "sha512-BFQeWxJOZxZGix7y+SByG3F36dA0AbTy9o6pSmKFcFz7DAj0re9Frkty3saBn3nHo3D0oZJ/+rx3r8H8r8Jbpw==",
|
|
||||||
"dependencies": {
|
|
||||||
"decode-uri-component": "^0.4.1",
|
|
||||||
"filter-obj": "^5.1.0",
|
|
||||||
"split-on-first": "^3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.16"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ramda": {
|
"node_modules/ramda": {
|
||||||
"version": "0.26.1",
|
"version": "0.26.1",
|
||||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz",
|
||||||
@@ -7344,7 +7248,8 @@
|
|||||||
"node_modules/regenerator-runtime": {
|
"node_modules/regenerator-runtime": {
|
||||||
"version": "0.14.1",
|
"version": "0.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/regexp.prototype.flags": {
|
"node_modules/regexp.prototype.flags": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
@@ -7858,17 +7763,6 @@
|
|||||||
"source-map": "^0.6.0"
|
"source-map": "^0.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/split-on-first": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sprintf-js": {
|
"node_modules/sprintf-js": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
"@froxz/vite-plugin-s3": "^1.6.0",
|
"@froxz/vite-plugin-s3": "^1.6.0",
|
||||||
"@vitejs/plugin-vue2": "^2.3.3",
|
"@vitejs/plugin-vue2": "^2.3.3",
|
||||||
"@vue/test-utils": "1.0.0-beta.29",
|
"@vue/test-utils": "1.0.0-beta.29",
|
||||||
"amplitude-js": "^8.21.3",
|
|
||||||
"assert": "^2.1.0",
|
"assert": "^2.1.0",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"axios": "^0.28.0",
|
"axios": "^0.28.0",
|
||||||
|
|||||||
@@ -445,7 +445,7 @@ export default {
|
|||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
mirror: newVal,
|
mirror: newVal,
|
||||||
group: this.group._id,
|
group: this.group._id,
|
||||||
}, { trackOnClient: true });
|
});
|
||||||
const groupsToMirror = this.user.preferences.tasks.mirrorGroupTasks || [];
|
const groupsToMirror = this.user.preferences.tasks.mirrorGroupTasks || [];
|
||||||
if (newVal) { // we're turning copy ON for this group
|
if (newVal) { // we're turning copy ON for this group
|
||||||
groupsToMirror.push(this.group._id);
|
groupsToMirror.push(this.group._id);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="banner d-flex align-items-center justify-content-between py-3 px-4"
|
|
||||||
id="privacy-banner"
|
|
||||||
v-if="!hidden"
|
v-if="!hidden"
|
||||||
|
id="privacy-banner"
|
||||||
|
class="banner d-flex align-items-center justify-content-between py-3 px-4"
|
||||||
>
|
>
|
||||||
<p
|
<p
|
||||||
class="mr-3 mb-0"
|
class="mr-3 mb-0"
|
||||||
|
|||||||
@@ -546,7 +546,7 @@ export default {
|
|||||||
eventCategory: 'behavior',
|
eventCategory: 'behavior',
|
||||||
demographics: this.upgradedGroup.demographics,
|
demographics: this.upgradedGroup.demographics,
|
||||||
type: this.paymentData.group.type,
|
type: this.paymentData.group.type,
|
||||||
}, { trackOnClient: true });
|
});
|
||||||
}
|
}
|
||||||
this.paymentData = {};
|
this.paymentData = {};
|
||||||
this.$root.$emit('bv::hide::modal', 'payments-success-modal');
|
this.$root.$emit('bv::hide::modal', 'payments-success-modal');
|
||||||
|
|||||||
@@ -64,9 +64,11 @@
|
|||||||
<li>sexual orientation; and</li>
|
<li>sexual orientation; and</li>
|
||||||
<li>information collected from a known child.</li>
|
<li>information collected from a known child.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p><strong>
|
<p>
|
||||||
NOTE: Please do not provide us “sensitive personal information” or “sensitive personal data”, as those terms are defined under applicable privacy laws, unless we directly request that you do so. If you feel, after careful consideration, that it is necessary to provide us certain sensitive personal information or data, please provide us the minimum amount of such information or data that is necessary.
|
<strong>
|
||||||
</strong></p>
|
NOTE: Please do not provide us “sensitive personal information” or “sensitive personal data”, as those terms are defined under applicable privacy laws, unless we directly request that you do so. If you feel, after careful consideration, that it is necessary to provide us certain sensitive personal information or data, please provide us the minimum amount of such information or data that is necessary.
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
<h3 id="section_1_1">
|
<h3 id="section_1_1">
|
||||||
1.1 Information You Provide Directly
|
1.1 Information You Provide Directly
|
||||||
</h3>
|
</h3>
|
||||||
@@ -617,7 +619,7 @@
|
|||||||
7. General Audience Services
|
7. General Audience Services
|
||||||
</h2>
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
The Service is intended for users 18 years or older; you are not permitted to access or use the Service if you are younger than 18. We do not knowingly collect personal information from children under the age of 18 through the Service. We encourage parents and legal guardians to monitor their children’s Internet usage and to help enforce our Privacy Policy by instructing their children to never provide personal information without their permission. If you have reason to believe that a child under the age of 18 has provided personal information to us, please contact us at <a href='mailto:privacy@habitica.com'>privacy@habitica.com</a>, and we will delete that information from our databases.
|
The Service is intended for users 18 years or older; you are not permitted to access or use the Service if you are younger than 18. We do not knowingly collect personal information from children under the age of 18 through the Service. We encourage parents and legal guardians to monitor their children’s Internet usage and to help enforce our Privacy Policy by instructing their children to never provide personal information without their permission. If you have reason to believe that a child under the age of 18 has provided personal information to us, please contact us at <a href="mailto:privacy@habitica.com">privacy@habitica.com</a>, and we will delete that information from our databases.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 id="section_8">
|
<h2 id="section_8">
|
||||||
@@ -708,7 +710,7 @@
|
|||||||
|
|
||||||
<p><strong><u>Nevada Residents</u></strong></p>
|
<p><strong><u>Nevada Residents</u></strong></p>
|
||||||
<p>
|
<p>
|
||||||
Nevada residents may opt out of the sale of certain “covered information” collected by operators of websites or online services. We currently do not sell covered information, as “sale” is defined by such law, and do not have plans to do so. In accordance with Nevada law, you may submit to us a verified request instructing us not to sell your covered information by sending an email to <a href='mailto:privacy@habitica.com'>privacy@habitica.com</a>.
|
Nevada residents may opt out of the sale of certain “covered information” collected by operators of websites or online services. We currently do not sell covered information, as “sale” is defined by such law, and do not have plans to do so. In accordance with Nevada law, you may submit to us a verified request instructing us not to sell your covered information by sending an email to <a href="mailto:privacy@habitica.com">privacy@habitica.com</a>.
|
||||||
</p>
|
</p>
|
||||||
<p><strong><u>Notice to United Kingdom/European/Switzerland Residents.</u></strong></p>
|
<p><strong><u>Notice to United Kingdom/European/Switzerland Residents.</u></strong></p>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
<router-view />
|
<router-view />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
id="bottom-background"
|
|
||||||
v-if="loginFlow"
|
v-if="loginFlow"
|
||||||
|
id="bottom-background"
|
||||||
class="bg-purple-300"
|
class="bg-purple-300"
|
||||||
>
|
>
|
||||||
<div class="seamless_mountains_demo_repeat"></div>
|
<div class="seamless_mountains_demo_repeat"></div>
|
||||||
@@ -31,7 +31,10 @@
|
|||||||
id="bottom-wrap"
|
id="bottom-wrap"
|
||||||
class="purple-4"
|
class="purple-4"
|
||||||
>
|
>
|
||||||
<div id="bottom-background" v-if="!loginFlow">
|
<div
|
||||||
|
v-if="!loginFlow"
|
||||||
|
id="bottom-background"
|
||||||
|
>
|
||||||
<div class="seamless_mountains_demo_repeat"></div>
|
<div class="seamless_mountains_demo_repeat"></div>
|
||||||
<div class="midground_foreground_extended2"></div>
|
<div class="midground_foreground_extended2"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -158,7 +158,7 @@
|
|||||||
BY PURCHASING PREMIUM YOU EXPRESSLY UNDERSTAND AND AGREE TO OUR REFUND POLICY:
|
BY PURCHASING PREMIUM YOU EXPRESSLY UNDERSTAND AND AGREE TO OUR REFUND POLICY:
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
YOU CAN REQUEST A REFUND OF YOUR MOST RECENT PAYMENT TO US BY CONTACTING US AT <a href='mailto:admin@habitica.com'>ADMIN@HABITICA.COM</a>. THE AMOUNT OF YOUR REFUND, IF ANY, WILL BE BASED ON (1) THE AMOUNT OF YOUR PURCHASED BUT UNUSED SUBSCRIPTION BENEFITS AND (2) THE TERMS IMPOSED ON US BY OUR PAYMENT PROCESSING VENDORS (E.G., WITH RESPECT TO THE DURATION OF THE REFUND PERIOD).
|
YOU CAN REQUEST A REFUND OF YOUR MOST RECENT PAYMENT TO US BY CONTACTING US AT <a href="mailto:admin@habitica.com">ADMIN@HABITICA.COM</a>. THE AMOUNT OF YOUR REFUND, IF ANY, WILL BE BASED ON (1) THE AMOUNT OF YOUR PURCHASED BUT UNUSED SUBSCRIPTION BENEFITS AND (2) THE TERMS IMPOSED ON US BY OUR PAYMENT PROCESSING VENDORS (E.G., WITH RESPECT TO THE DURATION OF THE REFUND PERIOD).
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
FOR ANY CUSTOMER WHO PURCHASED PREMIUM IN APPLE INC.'s APP STORE ("APP STORE"), PLEASE CONTACT APPLE INC.'s SUPPORT TEAM: <a
|
FOR ANY CUSTOMER WHO PURCHASED PREMIUM IN APPLE INC.'s APP STORE ("APP STORE"), PLEASE CONTACT APPLE INC.'s SUPPORT TEAM: <a
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
:checked="isChecked"
|
:checked="isChecked"
|
||||||
:value="value"
|
:value="value"
|
||||||
@change="handleChange"
|
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
|
@change="handleChange"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="toggle-switch-label"
|
class="toggle-switch-label"
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
import forEach from 'lodash/forEach';
|
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
import keys from 'lodash/keys';
|
import keys from 'lodash/keys';
|
||||||
import pick from 'lodash/pick';
|
import pick from 'lodash/pick';
|
||||||
import amplitude from 'amplitude-js';
|
|
||||||
import { gtag, install } from 'ga-gtag';
|
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import getStore from '@/store';
|
import getStore from '@/store';
|
||||||
|
|
||||||
const AMPLITUDE_KEY = import.meta.env.AMPLITUDE_KEY;
|
|
||||||
const DEBUG_ENABLED = import.meta.env.DEBUG_ENABLED === 'true';
|
|
||||||
const GA_ID = import.meta.env.GA_ID;
|
|
||||||
const IS_PRODUCTION = import.meta.env.NODE_ENV === 'production';
|
|
||||||
const REQUIRED_FIELDS = ['eventCategory', 'eventAction'];
|
const REQUIRED_FIELDS = ['eventCategory', 'eventAction'];
|
||||||
|
|
||||||
let analyticsLoading = false;
|
|
||||||
let analyticsReady = false;
|
|
||||||
|
|
||||||
function _getConsentedUser () {
|
function _getConsentedUser () {
|
||||||
const store = getStore();
|
const store = getStore();
|
||||||
const user = store.state.user.data;
|
const user = store.state.user.data;
|
||||||
@@ -66,49 +56,24 @@ function _gatherUserStats (properties) {
|
|||||||
if (user.purchased.plan.planId) properties.subscription = user.purchased.plan.planId;
|
if (user.purchased.plan.planId) properties.subscription = user.purchased.plan.planId;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function safeSetup (userId) {
|
export function track (properties) {
|
||||||
if (analyticsLoading || analyticsReady) return;
|
|
||||||
analyticsLoading = true;
|
|
||||||
install(GA_ID, {
|
|
||||||
debug_mode: DEBUG_ENABLED || !IS_PRODUCTION,
|
|
||||||
user_id: userId,
|
|
||||||
});
|
|
||||||
amplitude.getInstance().init(AMPLITUDE_KEY, userId);
|
|
||||||
analyticsReady = true;
|
|
||||||
analyticsLoading = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function track (properties, options = {}) {
|
|
||||||
const user = _getConsentedUser();
|
const user = _getConsentedUser();
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
safeSetup(user._id);
|
|
||||||
// Use nextTick to avoid blocking the UI
|
// Use nextTick to avoid blocking the UI
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
if (_doesNotHaveRequiredFields(properties)) return;
|
if (_doesNotHaveRequiredFields(properties)) return;
|
||||||
|
const store = getStore();
|
||||||
const trackOnClient = options && options.trackOnClient === true;
|
store.dispatch('analytics:trackEvent', properties);
|
||||||
// Track events on the server by default
|
|
||||||
if (trackOnClient === true) {
|
|
||||||
amplitude.getInstance().logEvent(properties.eventAction, properties);
|
|
||||||
gtag('event', properties.eventAction, properties);
|
|
||||||
} else {
|
|
||||||
const store = getStore();
|
|
||||||
store.dispatch('analytics:trackEvent', properties);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateUser (properties = {}) {
|
export function updateUser (properties = {}) {
|
||||||
const user = _getConsentedUser();
|
const user = _getConsentedUser();
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
safeSetup(user._id);
|
|
||||||
// Use nextTick to avoid blocking the UI
|
// Use nextTick to avoid blocking the UI
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
_gatherUserStats(properties);
|
_gatherUserStats(properties);
|
||||||
gtag('set', 'user_properties', properties);
|
const store = getStore();
|
||||||
forEach(properties, (value, key) => {
|
store.dispatch('analytics:updateUserProperties', properties);
|
||||||
const identify = new amplitude.Identify().set(key, value);
|
|
||||||
amplitude.getInstance().identify(identify);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ export default {
|
|||||||
eventCategory: 'behavior',
|
eventCategory: 'behavior',
|
||||||
demographics: appState.newGroup.demographics,
|
demographics: appState.newGroup.demographics,
|
||||||
type: appState.newGroup.type,
|
type: appState.newGroup.type,
|
||||||
}, { trackOnClient: true });
|
});
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error while redirecting to Stripe', err); // eslint-disable-line
|
console.error('Error while redirecting to Stripe', err); // eslint-disable-line
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export default {
|
|||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
taskType: task.type,
|
taskType: task.type,
|
||||||
direction,
|
direction,
|
||||||
}, { trackOnClient: true });
|
});
|
||||||
if (!tasksScoredCount) {
|
if (!tasksScoredCount) {
|
||||||
setLocalSetting(CONSTANTS.keyConstants.TASKS_SCORED_COUNT, 1);
|
setLocalSetting(CONSTANTS.keyConstants.TASKS_SCORED_COUNT, 1);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="3"
|
<td
|
||||||
v-if="!mixinData.inlineSettingMixin.modalVisible"
|
v-if="!mixinData.inlineSettingMixin.modalVisible"
|
||||||
|
colspan="3"
|
||||||
>
|
>
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
<h3
|
<h3
|
||||||
@@ -18,8 +19,9 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td colspan="3"
|
<td
|
||||||
v-if="mixinData.inlineSettingMixin.modalVisible"
|
v-if="mixinData.inlineSettingMixin.modalVisible"
|
||||||
|
colspan="3"
|
||||||
>
|
>
|
||||||
<h3
|
<h3
|
||||||
v-once
|
v-once
|
||||||
@@ -59,8 +61,8 @@
|
|||||||
{{ $t('performanceAnalytics') }}
|
{{ $t('performanceAnalytics') }}
|
||||||
</label>
|
</label>
|
||||||
<toggle-switch
|
<toggle-switch
|
||||||
class="mb-auto"
|
|
||||||
v-model="user.preferences.analyticsConsent"
|
v-model="user.preferences.analyticsConsent"
|
||||||
|
class="mb-auto"
|
||||||
@change="prefToggled()"
|
@change="prefToggled()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -128,7 +128,6 @@ import PrivacyBanner from '@/components/header/banners/privacy';
|
|||||||
import AppFooter from '@/components/appFooter';
|
import AppFooter from '@/components/appFooter';
|
||||||
import notificationsDisplay from '@/components/notifications';
|
import notificationsDisplay from '@/components/notifications';
|
||||||
import { mapState } from '@/libs/store';
|
import { mapState } from '@/libs/store';
|
||||||
import * as Analytics from '@/libs/analytics';
|
|
||||||
import BuyModal from '@/components/shops/buyModal.vue';
|
import BuyModal from '@/components/shops/buyModal.vue';
|
||||||
import SelectMembersModal from '@/components/selectMembersModal.vue';
|
import SelectMembersModal from '@/components/selectMembersModal.vue';
|
||||||
import notifications from '@/mixins/notifications';
|
import notifications from '@/mixins/notifications';
|
||||||
@@ -280,7 +279,6 @@ export default {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Analytics.updateUser();
|
|
||||||
return axios.get(
|
return axios.get(
|
||||||
'/api/v4/i18n/browser-script',
|
'/api/v4/i18n/browser-script',
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
eventName: 'View Find Members',
|
eventName: 'View Find Members',
|
||||||
eventAction: 'View Find Members',
|
eventAction: 'View Find Members',
|
||||||
eventCategory: 'behavior',
|
eventCategory: 'behavior',
|
||||||
}, { trackOnClient: true });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect old guild urls
|
// Redirect old guild urls
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ import axios from 'axios';
|
|||||||
|
|
||||||
export async function trackEvent (store, params) {
|
export async function trackEvent (store, params) {
|
||||||
const url = `/analytics/track/${params.eventAction}`;
|
const url = `/analytics/track/${params.eventAction}`;
|
||||||
|
await axios.post(url, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateUserProperties (store, params) {
|
||||||
|
const url = '/analytics/update';
|
||||||
await axios.post(url, params);
|
await axios.post(url, params);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { authAsCredentialsState, LOCALSTORAGE_AUTH_KEY } from '@/libs/auth';
|
import { authAsCredentialsState, LOCALSTORAGE_AUTH_KEY } from '@/libs/auth';
|
||||||
|
|
||||||
const GA_ID = import.meta.env.GA_ID;
|
|
||||||
|
|
||||||
function saveLocalDataAuth (store, apiId, apiToken) {
|
function saveLocalDataAuth (store, apiId, apiToken) {
|
||||||
const credentialsObj = {
|
const credentialsObj = {
|
||||||
auth: {
|
auth: {
|
||||||
@@ -123,9 +121,6 @@ export async function appleAuth (store, params) {
|
|||||||
export function logout (store, options = {}) {
|
export function logout (store, options = {}) {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
sessionStorage.clear();
|
sessionStorage.clear();
|
||||||
if (window.gtag) {
|
|
||||||
window.gtag('config', GA_ID, { user_id: null });
|
|
||||||
}
|
|
||||||
const query = options.redirectToLogin === true ? '?redirectToLogin=true' : '';
|
const query = options.redirectToLogin === true ? '?redirectToLogin=true' : '';
|
||||||
window.location.href = `/logout-server${query}`;
|
window.location.href = `/logout-server${query}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ export async function create (store, createdTask) {
|
|||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
uuid,
|
uuid,
|
||||||
taskType: taskRes.type,
|
taskType: taskRes.type,
|
||||||
}, { trackOnClient: true });
|
});
|
||||||
if (!tasksCreatedCount) {
|
if (!tasksCreatedCount) {
|
||||||
setLocalSetting(CONSTANTS.keyConstants.TASKS_CREATED_COUNT, 1);
|
setLocalSetting(CONSTANTS.keyConstants.TASKS_CREATED_COUNT, 1);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -26,11 +26,9 @@ const envVars = [
|
|||||||
'EMAILS_COMMUNITY_MANAGER_EMAIL',
|
'EMAILS_COMMUNITY_MANAGER_EMAIL',
|
||||||
'EMAILS_TECH_ASSISTANCE_EMAIL',
|
'EMAILS_TECH_ASSISTANCE_EMAIL',
|
||||||
'EMAILS_PRESS_ENQUIRY_EMAIL',
|
'EMAILS_PRESS_ENQUIRY_EMAIL',
|
||||||
'GA_ID',
|
|
||||||
'STRIPE_PUB_KEY',
|
'STRIPE_PUB_KEY',
|
||||||
'GOOGLE_CLIENT_ID',
|
'GOOGLE_CLIENT_ID',
|
||||||
'APPLE_AUTH_CLIENT_ID',
|
'APPLE_AUTH_CLIENT_ID',
|
||||||
'AMPLITUDE_KEY',
|
|
||||||
'LOGGLY_CLIENT_TOKEN',
|
'LOGGLY_CLIENT_TOKEN',
|
||||||
'TRUSTED_DOMAINS',
|
'TRUSTED_DOMAINS',
|
||||||
'TIME_TRAVEL_ENABLED',
|
'TIME_TRAVEL_ENABLED',
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import isFunction from 'lodash/isFunction';
|
|||||||
import min from 'lodash/min';
|
import min from 'lodash/min';
|
||||||
import reduce from 'lodash/reduce';
|
import reduce from 'lodash/reduce';
|
||||||
import filter from 'lodash/filter';
|
import filter from 'lodash/filter';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import pickBy from 'lodash/pickBy';
|
import pickBy from 'lodash/pickBy';
|
||||||
import size from 'lodash/size';
|
import size from 'lodash/size';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
@@ -160,7 +159,7 @@ export default function randomDrop (user, options, req = {}, analytics) {
|
|||||||
|
|
||||||
if (analytics && moment().diff(user.auth.timestamps.created, 'days') < 7) {
|
if (analytics && moment().diff(user.auth.timestamps.created, 'days') < 7) {
|
||||||
analytics.track('dropped item', {
|
analytics.track('dropped item', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
itemKey: drop.key,
|
itemKey: drop.key,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import pick from 'lodash/pick';
|
|
||||||
|
|
||||||
export function hasCompletedOnboarding (user) {
|
export function hasCompletedOnboarding (user) {
|
||||||
return (
|
return (
|
||||||
user.achievements.createdTask === true
|
user.achievements.createdTask === true
|
||||||
@@ -21,7 +19,7 @@ export function checkOnboardingStatus (user, req, analytics) {
|
|||||||
user.addNotification('ONBOARDING_COMPLETE');
|
user.addNotification('ONBOARDING_COMPLETE');
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
analytics.track('onboarding complete', {
|
analytics.track('onboarding complete', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
/* eslint-disable max-classes-per-file */
|
/* eslint-disable max-classes-per-file */
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import merge from 'lodash/merge';
|
import merge from 'lodash/merge';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
import {
|
import {
|
||||||
NotAuthorized,
|
NotAuthorized,
|
||||||
@@ -114,7 +113,7 @@ export class AbstractBuyOperation {
|
|||||||
sendToAnalytics (additionalData = {}) {
|
sendToAnalytics (additionalData = {}) {
|
||||||
// spread-operator produces an "unexpected token" error
|
// spread-operator produces an "unexpected token" error
|
||||||
const analyticsData = merge(additionalData, {
|
const analyticsData = merge(additionalData, {
|
||||||
user: pick(this.user, ['preferences', 'registeredThrough']),
|
user: this.user,
|
||||||
uuid: this.user._id,
|
uuid: this.user._id,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
headers: this.req.headers,
|
headers: this.req.headers,
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ export class BuyArmoireOperation extends AbstractGoldItemOperation { // eslint-d
|
|||||||
this.analytics.track(
|
this.analytics.track(
|
||||||
'Enchanted Armoire',
|
'Enchanted Armoire',
|
||||||
{
|
{
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
itemKey: key,
|
itemKey: key,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import each from 'lodash/each';
|
import each from 'lodash/each';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
import content from '../../content/index';
|
import content from '../../content/index';
|
||||||
import {
|
import {
|
||||||
@@ -37,7 +36,7 @@ export default async function buyMysterySet (user, req = {}, analytics) {
|
|||||||
|
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
analytics.track('buy', {
|
analytics.track('buy', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
itemKey: mysterySet.key,
|
itemKey: mysterySet.key,
|
||||||
itemType: 'Subscriber Gear',
|
itemType: 'Subscriber Gear',
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import includes from 'lodash/includes';
|
import includes from 'lodash/includes';
|
||||||
import keys from 'lodash/keys';
|
import keys from 'lodash/keys';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
import content from '../../content/index';
|
import content from '../../content/index';
|
||||||
import {
|
import {
|
||||||
@@ -96,7 +95,7 @@ export default async function purchaseHourglass (user, req = {}, analytics, quan
|
|||||||
|
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
analytics.track('buy', {
|
analytics.track('buy', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
itemKey: key,
|
itemKey: key,
|
||||||
itemType: type,
|
itemType: type,
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ export default async function purchase (user, req = {}, analytics) {
|
|||||||
/* eslint-enable no-await-in-loop */
|
/* eslint-enable no-await-in-loop */
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
analytics.track('buy', {
|
analytics.track('buy', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
itemKey: key,
|
itemKey: key,
|
||||||
itemType: type,
|
itemType: type,
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export default async function changeClass (user, req = {}, analytics) {
|
|||||||
|
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
analytics.track('change class', {
|
analytics.track('change class', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
class: klass,
|
class: klass,
|
||||||
currency: balanceRemoved === 0 ? 'Free' : 'Gems',
|
currency: balanceRemoved === 0 ? 'Free' : 'Gems',
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import forEach from 'lodash/forEach';
|
|||||||
import findIndex from 'lodash/findIndex';
|
import findIndex from 'lodash/findIndex';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import keys from 'lodash/keys';
|
import keys from 'lodash/keys';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import upperFirst from 'lodash/upperFirst';
|
import upperFirst from 'lodash/upperFirst';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import i18n from '../i18n';
|
import i18n from '../i18n';
|
||||||
@@ -143,7 +142,7 @@ export default function feed (user, req = {}, analytics) {
|
|||||||
|
|
||||||
if (analytics && moment().diff(user.auth.timestamps.created, 'days') < 7) {
|
if (analytics && moment().diff(user.auth.timestamps.created, 'days') < 7) {
|
||||||
analytics.track('pet feed', {
|
analytics.track('pet feed', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
foodKey: food.key,
|
foodKey: food.key,
|
||||||
petKey: pet.key,
|
petKey: pet.key,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import findIndex from 'lodash/findIndex';
|
|||||||
import forEach from 'lodash/forEach';
|
import forEach from 'lodash/forEach';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import keys from 'lodash/keys';
|
import keys from 'lodash/keys';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import upperFirst from 'lodash/upperFirst';
|
import upperFirst from 'lodash/upperFirst';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import i18n from '../i18n';
|
import i18n from '../i18n';
|
||||||
@@ -154,7 +153,7 @@ export default function hatch (user, req = {}, analytics) {
|
|||||||
|
|
||||||
if (analytics && moment().diff(user.auth.timestamps.created, 'days') < 7) {
|
if (analytics && moment().diff(user.auth.timestamps.created, 'days') < 7) {
|
||||||
analytics.track('pet hatch', {
|
analytics.track('pet hatch', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
petKey: pet,
|
petKey: pet,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import each from 'lodash/each';
|
import each from 'lodash/each';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import i18n from '../i18n';
|
import i18n from '../i18n';
|
||||||
import { capByLevel } from '../statHelpers';
|
import { capByLevel } from '../statHelpers';
|
||||||
import { MAX_LEVEL } from '../constants';
|
import { MAX_LEVEL } from '../constants';
|
||||||
@@ -23,7 +22,7 @@ export default async function rebirth (user, tasks = [], req = {}, analytics) {
|
|||||||
|
|
||||||
const analyticsData = {
|
const analyticsData = {
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import pick from 'lodash/pick';
|
|
||||||
import content from '../content/index';
|
import content from '../content/index';
|
||||||
import { mountMasterProgress } from '../count';
|
import { mountMasterProgress } from '../count';
|
||||||
import i18n from '../i18n';
|
import i18n from '../i18n';
|
||||||
@@ -44,7 +43,7 @@ export default async function releaseMounts (user, req = {}, analytics) {
|
|||||||
|
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
analytics.track('release mounts', {
|
analytics.track('release mounts', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
currency: 'Gems',
|
currency: 'Gems',
|
||||||
gemCost: 4,
|
gemCost: 4,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import pick from 'lodash/pick';
|
|
||||||
import content from '../content/index';
|
import content from '../content/index';
|
||||||
import { beastMasterProgress } from '../count';
|
import { beastMasterProgress } from '../count';
|
||||||
import i18n from '../i18n';
|
import i18n from '../i18n';
|
||||||
@@ -44,7 +43,7 @@ export default function releasePets (user, req = {}, analytics) {
|
|||||||
|
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
analytics.track('release pets', {
|
analytics.track('release pets', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
currency: 'Gems',
|
currency: 'Gems',
|
||||||
gemCost: 4,
|
gemCost: 4,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import each from 'lodash/each';
|
import each from 'lodash/each';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import i18n from '../i18n';
|
import i18n from '../i18n';
|
||||||
import {
|
import {
|
||||||
NotAuthorized,
|
NotAuthorized,
|
||||||
@@ -24,7 +23,7 @@ export default async function reroll (user, tasks = [], req = {}, analytics) {
|
|||||||
|
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
analytics.track('Fortify Potion', {
|
analytics.track('Fortify Potion', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
currency: 'Gems',
|
currency: 'Gems',
|
||||||
gemCost: 4,
|
gemCost: 4,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import merge from 'lodash/merge';
|
import merge from 'lodash/merge';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import reduce from 'lodash/reduce';
|
import reduce from 'lodash/reduce';
|
||||||
import each from 'lodash/each';
|
import each from 'lodash/each';
|
||||||
import i18n from '../i18n';
|
import i18n from '../i18n';
|
||||||
@@ -112,7 +111,7 @@ export default function revive (user, req = {}, analytics) {
|
|||||||
|
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
analytics.track('Death', {
|
analytics.track('Death', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
lostItem,
|
lostItem,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import pick from 'lodash/pick';
|
|
||||||
|
|
||||||
export function sleep (user, req = {}, analytics) {
|
export function sleep (user, req = {}, analytics) {
|
||||||
user.preferences.sleep = !user.preferences.sleep;
|
user.preferences.sleep = !user.preferences.sleep;
|
||||||
|
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
analytics.track('sleep', {
|
analytics.track('sleep', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
status: user.preferences.sleep,
|
status: user.preferences.sleep,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import setWith from 'lodash/setWith';
|
import setWith from 'lodash/setWith';
|
||||||
import i18n from '../i18n';
|
import i18n from '../i18n';
|
||||||
import { NotAuthorized, BadRequest } from '../libs/errors';
|
import { NotAuthorized, BadRequest } from '../libs/errors';
|
||||||
@@ -318,7 +317,7 @@ export default async function unlock (user, req = {}, analytics) {
|
|||||||
|
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
analytics.track('buy', {
|
analytics.track('buy', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
itemKey: path,
|
itemKey: path,
|
||||||
itemType: 'customization',
|
itemType: 'customization',
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import validator from 'validator';
|
import validator from 'validator';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import sortBy from 'lodash/sortBy';
|
import sortBy from 'lodash/sortBy';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import {
|
import {
|
||||||
@@ -128,7 +127,7 @@ api.loginLocal = {
|
|||||||
await user.save();
|
await user.save();
|
||||||
|
|
||||||
res.analytics.track('login', {
|
res.analytics.track('login', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
type: 'local',
|
type: 'local',
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import escapeRegExp from 'lodash/escapeRegExp';
|
import escapeRegExp from 'lodash/escapeRegExp';
|
||||||
import merge from 'lodash/merge';
|
import merge from 'lodash/merge';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import reduce from 'lodash/reduce';
|
import reduce from 'lodash/reduce';
|
||||||
import times from 'lodash/times';
|
import times from 'lodash/times';
|
||||||
import { authWithHeaders, authWithSession } from '../../middlewares/auth';
|
import { authWithHeaders, authWithSession } from '../../middlewares/auth';
|
||||||
@@ -291,7 +290,7 @@ api.createChallenge = {
|
|||||||
response.group = getChallengeGroupResponse(group);
|
response.group = getChallengeGroupResponse(group);
|
||||||
|
|
||||||
res.analytics.track('challenge create', {
|
res.analytics.track('challenge create', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
@@ -360,7 +359,7 @@ api.joinChallenge = {
|
|||||||
response.leader = chalLeader ? chalLeader.toJSON({ minimize: true }) : null;
|
response.leader = chalLeader ? chalLeader.toJSON({ minimize: true }) : null;
|
||||||
|
|
||||||
res.analytics.track('challenge join', {
|
res.analytics.track('challenge join', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
@@ -411,7 +410,7 @@ api.leaveChallenge = {
|
|||||||
await challenge.unlinkTasks(user, keep);
|
await challenge.unlinkTasks(user, keep);
|
||||||
|
|
||||||
res.analytics.track('challenge leave', {
|
res.analytics.track('challenge leave', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
@@ -896,7 +895,7 @@ api.deleteChallenge = {
|
|||||||
await challenge.closeChal({ broken: 'CHALLENGE_DELETED' });
|
await challenge.closeChal({ broken: 'CHALLENGE_DELETED' });
|
||||||
|
|
||||||
res.analytics.track('challenge delete', {
|
res.analytics.track('challenge delete', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
@@ -957,7 +956,7 @@ api.selectChallengeWinner = {
|
|||||||
await challenge.closeChal({ broken: 'CHALLENGE_CLOSED', winner });
|
await challenge.closeChal({ broken: 'CHALLENGE_CLOSED', winner });
|
||||||
|
|
||||||
res.analytics.track('challenge close', {
|
res.analytics.track('challenge close', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import pick from 'lodash/pick';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import { authWithHeaders } from '../../middlewares/auth';
|
import { authWithHeaders } from '../../middlewares/auth';
|
||||||
@@ -187,7 +186,7 @@ api.postChat = {
|
|||||||
// Check if account is newer than the minimum age for chat participation
|
// Check if account is newer than the minimum age for chat participation
|
||||||
if (moment().diff(user.auth.timestamps.created, 'minutes') < ACCOUNT_MIN_CHAT_AGE) {
|
if (moment().diff(user.auth.timestamps.created, 'minutes') < ACCOUNT_MIN_CHAT_AGE) {
|
||||||
analytics.track('chat age error', {
|
analytics.track('chat age error', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
@@ -239,7 +238,7 @@ api.postChat = {
|
|||||||
await Promise.all(toSave);
|
await Promise.all(toSave);
|
||||||
|
|
||||||
const analyticsObject = {
|
const analyticsObject = {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import findIndex from 'lodash/findIndex';
|
|||||||
import includes from 'lodash/includes';
|
import includes from 'lodash/includes';
|
||||||
import isArray from 'lodash/isArray';
|
import isArray from 'lodash/isArray';
|
||||||
import mergeWith from 'lodash/mergeWith';
|
import mergeWith from 'lodash/mergeWith';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import uniqBy from 'lodash/uniqBy';
|
import uniqBy from 'lodash/uniqBy';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
@@ -169,7 +168,7 @@ api.createGroup = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const analyticsObject = {
|
const analyticsObject = {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
@@ -220,7 +219,7 @@ api.createGroupPlan = {
|
|||||||
const savedGroup = results[1];
|
const savedGroup = results[1];
|
||||||
|
|
||||||
res.analytics.track('join group', {
|
res.analytics.track('join group', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
@@ -705,7 +704,7 @@ api.joinGroup = {
|
|||||||
promises.push(group.save());
|
promises.push(group.save());
|
||||||
|
|
||||||
const analyticsObject = {
|
const analyticsObject = {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import escapeRegExp from 'lodash/escapeRegExp';
|
import escapeRegExp from 'lodash/escapeRegExp';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import { authWithHeaders } from '../../middlewares/auth';
|
import { authWithHeaders } from '../../middlewares/auth';
|
||||||
import {
|
import {
|
||||||
model as User,
|
model as User,
|
||||||
@@ -737,7 +736,7 @@ api.transferGems = {
|
|||||||
|
|
||||||
if (res.analytics) {
|
if (res.analytics) {
|
||||||
res.analytics.track('transfer gems', {
|
res.analytics.track('transfer gems', {
|
||||||
user: pick(sender, ['preferences', 'registeredThrough']),
|
user: sender,
|
||||||
uuid: sender._id,
|
uuid: sender._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import each from 'lodash/each';
|
import each from 'lodash/each';
|
||||||
import every from 'lodash/every';
|
import every from 'lodash/every';
|
||||||
import isBoolean from 'lodash/isBoolean';
|
import isBoolean from 'lodash/isBoolean';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import { authWithHeaders } from '../../middlewares/auth';
|
import { authWithHeaders } from '../../middlewares/auth';
|
||||||
import { getAnalyticsServiceByEnvironment } from '../../libs/analyticsService';
|
import { getAnalyticsServiceByEnvironment } from '../../libs/analyticsService';
|
||||||
import {
|
import {
|
||||||
@@ -168,7 +167,7 @@ api.inviteToQuest = {
|
|||||||
|
|
||||||
// track that the inviting user has accepted the quest
|
// track that the inviting user has accepted the quest
|
||||||
analytics.track('quest', {
|
analytics.track('quest', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
headers: req.headers,
|
headers: req.headers,
|
||||||
@@ -233,7 +232,7 @@ api.acceptQuest = {
|
|||||||
|
|
||||||
// track that a user has accepted the quest
|
// track that a user has accepted the quest
|
||||||
analytics.track('quest', {
|
analytics.track('quest', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
owner: false,
|
owner: false,
|
||||||
response: 'accept',
|
response: 'accept',
|
||||||
@@ -298,7 +297,7 @@ api.rejectQuest = {
|
|||||||
res.respond(200, savedGroup.quest);
|
res.respond(200, savedGroup.quest);
|
||||||
|
|
||||||
analytics.track('quest', {
|
analytics.track('quest', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
owner: false,
|
owner: false,
|
||||||
response: 'reject',
|
response: 'reject',
|
||||||
@@ -362,7 +361,7 @@ api.forceStart = {
|
|||||||
res.respond(200, savedGroup.quest);
|
res.respond(200, savedGroup.quest);
|
||||||
|
|
||||||
analytics.track('quest', {
|
analytics.track('quest', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
owner: user._id === group.quest.leader,
|
owner: user._id === group.quest.leader,
|
||||||
response: 'force-start',
|
response: 'force-start',
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import assign from 'lodash/assign';
|
import assign from 'lodash/assign';
|
||||||
import find from 'lodash/find';
|
import find from 'lodash/find';
|
||||||
import merge from 'lodash/merge';
|
import merge from 'lodash/merge';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { authWithHeaders } from '../../middlewares/auth';
|
import { authWithHeaders } from '../../middlewares/auth';
|
||||||
import {
|
import {
|
||||||
@@ -333,7 +332,7 @@ api.createChallengeTasks = {
|
|||||||
|
|
||||||
tasks.forEach(task => {
|
tasks.forEach(task => {
|
||||||
res.analytics.track('challenge task created', {
|
res.analytics.track('challenge task created', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
@@ -703,7 +702,7 @@ api.updateTask = {
|
|||||||
|
|
||||||
if (group) {
|
if (group) {
|
||||||
res.analytics.track('task edit', {
|
res.analytics.track('task edit', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import pick from 'lodash/pick';
|
|
||||||
import isUUID from 'validator/lib/isUUID';
|
import isUUID from 'validator/lib/isUUID';
|
||||||
import { authWithHeaders } from '../../../middlewares/auth';
|
import { authWithHeaders } from '../../../middlewares/auth';
|
||||||
import * as Tasks from '../../../models/task';
|
import * as Tasks from '../../../models/task';
|
||||||
@@ -64,7 +63,7 @@ api.createGroupTasks = {
|
|||||||
|
|
||||||
tasks.forEach(task => {
|
tasks.forEach(task => {
|
||||||
res.analytics.track('team task created', {
|
res.analytics.track('team task created', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
@@ -253,7 +252,7 @@ api.assignTask = {
|
|||||||
res.respond(200, task);
|
res.respond(200, task);
|
||||||
|
|
||||||
res.analytics.track('task assign', {
|
res.analytics.track('task assign', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import forEach from 'lodash/forEach';
|
import forEach from 'lodash/forEach';
|
||||||
import isFunction from 'lodash/isFunction';
|
import isFunction from 'lodash/isFunction';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { authWithHeaders } from '../../middlewares/auth';
|
import { authWithHeaders } from '../../middlewares/auth';
|
||||||
@@ -326,7 +325,7 @@ api.deleteUser = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.analytics.track('account delete', {
|
res.analytics.track('account delete', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import pick from 'lodash/pick';
|
|
||||||
import {
|
import {
|
||||||
NotAuthorized,
|
NotAuthorized,
|
||||||
} from '../../libs/errors';
|
} from '../../libs/errors';
|
||||||
@@ -22,16 +21,17 @@ api.trackEvent = {
|
|||||||
// we authenticate these requests to make sure they actually came from a real user
|
// we authenticate these requests to make sure they actually came from a real user
|
||||||
middlewares: [authWithHeaders()],
|
middlewares: [authWithHeaders()],
|
||||||
async handler (req, res) {
|
async handler (req, res) {
|
||||||
// As of now only web can track events using this route
|
if (req.headers['x-client'] !== 'habitica-web'
|
||||||
if (req.headers['x-client'] !== 'habitica-web') {
|
&& req.headers['x-client'] !== 'habitica-ios'
|
||||||
throw new NotAuthorized('Only habitica.com is allowed to track analytics events.');
|
&& req.headers['x-client'] !== 'habitica-android') {
|
||||||
|
throw new NotAuthorized('Only official clients are allowed to track analytics events.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = res.locals;
|
const { user } = res.locals;
|
||||||
const eventProperties = req.body;
|
const eventProperties = req.body;
|
||||||
|
|
||||||
res.analytics.track(req.params.eventName, {
|
res.analytics.track(req.params.eventName, {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
headers: req.headers,
|
headers: req.headers,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
@@ -44,4 +44,31 @@ api.trackEvent = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
api.updateUserProperties = {
|
||||||
|
method: 'POST',
|
||||||
|
url: '/analytics/update',
|
||||||
|
// we authenticate these requests to make sure they actually came from a real user
|
||||||
|
middlewares: [authWithHeaders()],
|
||||||
|
async handler (req, res) {
|
||||||
|
if (req.headers['x-client'] !== 'habitica-web'
|
||||||
|
&& req.headers['x-client'] !== 'habitica-ios'
|
||||||
|
&& req.headers['x-client'] !== 'habitica-android') {
|
||||||
|
throw new NotAuthorized('Only official clients are allowed to track analytics events.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { user } = res.locals;
|
||||||
|
const properties = req.body;
|
||||||
|
|
||||||
|
res.analytics.updateUserData({
|
||||||
|
user,
|
||||||
|
uuid: user._id,
|
||||||
|
properties,
|
||||||
|
});
|
||||||
|
|
||||||
|
// not using res.respond
|
||||||
|
// because we don't want to send back notifications and other user-related data
|
||||||
|
res.status(200).send({});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import Amplitude from 'amplitude';
|
import Amplitude from 'amplitude';
|
||||||
import useragent from 'useragent';
|
import useragent from 'useragent';
|
||||||
|
import validator from 'validator';
|
||||||
|
import { lookup } from 'ip-location-api';
|
||||||
|
import { createHash } from 'crypto';
|
||||||
import {
|
import {
|
||||||
omit,
|
omit,
|
||||||
toArray,
|
toArray,
|
||||||
@@ -27,6 +30,36 @@ if (AMPLITUDE_TOKEN) amplitude = new Amplitude(AMPLITUDE_TOKEN);
|
|||||||
|
|
||||||
const Content = common.content;
|
const Content = common.content;
|
||||||
|
|
||||||
|
function _hashUUID (uuid) {
|
||||||
|
return createHash('sha256').update(uuid).digest('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
function _anonymizeProperties (properties) {
|
||||||
|
if (Array.isArray(properties)) {
|
||||||
|
return properties.map(userProp => {
|
||||||
|
if (typeof userProp === 'string' && validator.isEmail(userProp)) {
|
||||||
|
return _hashUUID(userProp);
|
||||||
|
}
|
||||||
|
return userProp;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (typeof properties === 'object' && properties !== null) {
|
||||||
|
const anonymizedProps = {};
|
||||||
|
Object.keys(properties).forEach(key => {
|
||||||
|
const value = properties[key];
|
||||||
|
if (typeof value === 'string' && validator.isEmail(value)) {
|
||||||
|
anonymizedProps[key] = _hashUUID(value);
|
||||||
|
} else if (typeof value === 'object' && value !== null) {
|
||||||
|
anonymizedProps[key] = _anonymizeProperties(value);
|
||||||
|
} else {
|
||||||
|
anonymizedProps[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return anonymizedProps;
|
||||||
|
}
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
function _lookUpItemName (itemKey) {
|
function _lookUpItemName (itemKey) {
|
||||||
if (!itemKey) return null;
|
if (!itemKey) return null;
|
||||||
|
|
||||||
@@ -56,7 +89,7 @@ function _lookUpItemName (itemKey) {
|
|||||||
return itemName;
|
return itemName;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _formatUserData (user) {
|
function _formatUserData (user, ipaddress, anonymize = false) {
|
||||||
const properties = {};
|
const properties = {};
|
||||||
|
|
||||||
if (user.stats) {
|
if (user.stats) {
|
||||||
@@ -72,7 +105,7 @@ function _formatUserData (user) {
|
|||||||
properties.balanceGemAmount = properties.balance * 4;
|
properties.balanceGemAmount = properties.balance * 4;
|
||||||
properties.tutorialComplete = user.flags && user.flags.tour && user.flags.tour.intro === -2;
|
properties.tutorialComplete = user.flags && user.flags.tour && user.flags.tour.intro === -2;
|
||||||
properties.verifiedUsername = user.flags && user.flags.verifiedUsername;
|
properties.verifiedUsername = user.flags && user.flags.verifiedUsername;
|
||||||
if (properties.verifiedUsername && user.auth && user.auth.local) {
|
if (properties.verifiedUsername && user.auth && user.auth.local && !anonymize) {
|
||||||
properties.username = user.auth.local.lowerCaseUsername;
|
properties.username = user.auth.local.lowerCaseUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,10 +122,12 @@ function _formatUserData (user) {
|
|||||||
properties.contributorLevel = user.contributor.level;
|
properties.contributorLevel = user.contributor.level;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.purchased && user.purchased.plan.planId) {
|
if (!anonymize) {
|
||||||
properties.subscription = user.purchased.plan.planId;
|
if (user.purchased && user.purchased.plan.planId) {
|
||||||
} else {
|
properties.subscription = user.purchased.plan.planId;
|
||||||
properties.subscription = null;
|
} else {
|
||||||
|
properties.subscription = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user._ABtests) {
|
if (user._ABtests) {
|
||||||
@@ -103,6 +138,16 @@ function _formatUserData (user) {
|
|||||||
properties.loginIncentives = user.loginIncentives;
|
properties.loginIncentives = user.loginIncentives;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ipaddress) {
|
||||||
|
const location = lookup(ipaddress);
|
||||||
|
properties.country = location.country;
|
||||||
|
properties.region = location.region1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anonymize) {
|
||||||
|
return _anonymizeProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,16 +184,20 @@ function _formatUserAgentForAmplitude (platform, agentString) {
|
|||||||
return formattedAgent;
|
return formattedAgent;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _formatUUIDForAmplitude (uuid) {
|
function _formatUUIDForAmplitude (uuid, anonymize = false) {
|
||||||
|
if (anonymize) {
|
||||||
|
return _hashUUID(uuid);
|
||||||
|
}
|
||||||
return uuid || 'no-user-id-was-provided';
|
return uuid || 'no-user-id-was-provided';
|
||||||
}
|
}
|
||||||
|
|
||||||
function _formatDataForAmplitude (data) {
|
function _formatDataForAmplitude (data) {
|
||||||
|
const consented = data.user && data.user.preferences && data.user.preferences.analyticsConsent;
|
||||||
const event_properties = omit(data, AMPLITUDE_PROPERTIES_TO_SCRUB);
|
const event_properties = omit(data, AMPLITUDE_PROPERTIES_TO_SCRUB);
|
||||||
const platform = _formatPlatformForAmplitude(data.headers && data.headers['x-client']);
|
const platform = _formatPlatformForAmplitude(data.headers && data.headers['x-client']);
|
||||||
const agent = _formatUserAgentForAmplitude(platform, data.headers && data.headers['user-agent']);
|
const agent = _formatUserAgentForAmplitude(platform, data.headers && data.headers['user-agent']);
|
||||||
const ampData = {
|
const ampData = {
|
||||||
user_id: _formatUUIDForAmplitude(data.uuid),
|
user_id: _formatUUIDForAmplitude(data.uuid, !consented),
|
||||||
platform,
|
platform,
|
||||||
os_name: agent.name,
|
os_name: agent.name,
|
||||||
os_version: agent.version,
|
os_version: agent.version,
|
||||||
@@ -156,7 +205,12 @@ function _formatDataForAmplitude (data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (data.user) {
|
if (data.user) {
|
||||||
ampData.user_properties = _formatUserData(data.user);
|
const ipaddress = data.ipaddress || (data.headers && data.headers['x-forwarded-for']);
|
||||||
|
ampData.user_properties = _formatUserData(data.user, ipaddress, !consented);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!consented) {
|
||||||
|
ampData.event_properties = _anonymizeProperties(ampData.event_properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemName = _lookUpItemName(data.itemKey);
|
const itemName = _lookUpItemName(data.itemKey);
|
||||||
@@ -215,12 +269,18 @@ function _setOnce (dataToSetOnce, uuid) {
|
|||||||
.catch(err => logger.error(err, 'Error while sending data to Amplitude.'));
|
.catch(err => logger.error(err, 'Error while sending data to Amplitude.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's no error handling directly here because it's handled inside _sendDataTo{Amplitude|Google}
|
function _updateProperties (properties, uuid) {
|
||||||
|
return amplitude
|
||||||
|
.identify({
|
||||||
|
user_id: _formatUUIDForAmplitude(uuid),
|
||||||
|
user_properties: properties,
|
||||||
|
})
|
||||||
|
.catch(err => logger.error(err, 'Error while sending data to Amplitude.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's no error handling directly here because it's handled inside _sendDataToAmplitude
|
||||||
async function track (eventType, data, loggerOnly = false) {
|
async function track (eventType, data, loggerOnly = false) {
|
||||||
const { user } = data;
|
const { user } = data;
|
||||||
if (!user || !user.preferences || !user.preferences.analyticsConsent) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const promises = [
|
const promises = [
|
||||||
_sendDataToAmplitude(eventType, data, loggerOnly),
|
_sendDataToAmplitude(eventType, data, loggerOnly),
|
||||||
];
|
];
|
||||||
@@ -234,29 +294,37 @@ async function track (eventType, data, loggerOnly = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// There's no error handling directly here because
|
// There's no error handling directly here because
|
||||||
// it's handled inside _sendPurchaseDataTo{Amplitude|Google}
|
// it's handled inside _sendPurchaseDataToAmplitude
|
||||||
async function trackPurchase (data) {
|
async function trackPurchase (data) {
|
||||||
const { user } = data;
|
|
||||||
if (!user || !user.preferences || !user.preferences.analyticsConsent) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
_sendPurchaseDataToAmplitude(data),
|
_sendPurchaseDataToAmplitude(data),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateUserData (data) {
|
||||||
|
const { user, properties } = data;
|
||||||
|
const toUpdate = {
|
||||||
|
..._formatUserData(user, data.ipaddress),
|
||||||
|
...properties,
|
||||||
|
};
|
||||||
|
|
||||||
|
return _updateProperties(toUpdate, user._id);
|
||||||
|
}
|
||||||
|
|
||||||
// Stub for non-prod environments
|
// Stub for non-prod environments
|
||||||
const mockAnalyticsService = {
|
const mockAnalyticsService = {
|
||||||
track: () => { },
|
track: () => { },
|
||||||
trackPurchase: () => { },
|
trackPurchase: () => { },
|
||||||
|
updateUserData: () => { },
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return the production or mock service based on the current environment
|
// Return the production or mock service based on the current environment
|
||||||
function getServiceByEnvironment () {
|
function getServiceByEnvironment () {
|
||||||
if (nconf.get('IS_PROD') || (nconf.get('DEBUG_ENABLED') && !nconf.get('BASE_URL').includes('localhost'))) {
|
if (nconf.get('IS_PROD') || nconf.get('USE_PROD_ANALYTICS') || (nconf.get('DEBUG_ENABLED') && !nconf.get('BASE_URL').includes('localhost'))) {
|
||||||
return {
|
return {
|
||||||
track,
|
track,
|
||||||
trackPurchase,
|
trackPurchase,
|
||||||
|
updateUserData,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return mockAnalyticsService;
|
return mockAnalyticsService;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import {
|
import {
|
||||||
BadRequest,
|
BadRequest,
|
||||||
NotAuthorized,
|
NotAuthorized,
|
||||||
@@ -219,7 +218,7 @@ async function registerLocal (req, res, { isV3 = false }) {
|
|||||||
|
|
||||||
if (!existingUser) {
|
if (!existingUser) {
|
||||||
res.analytics.track('register', {
|
res.analytics.track('register', {
|
||||||
user: pick(savedUser, ['preferences', 'registeredThrough']),
|
user: savedUser,
|
||||||
category: 'acquisition',
|
category: 'acquisition',
|
||||||
type: 'local',
|
type: 'local',
|
||||||
uuid: savedUser._id,
|
uuid: savedUser._id,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import pick from 'lodash/pick';
|
|
||||||
import passport from 'passport';
|
import passport from 'passport';
|
||||||
import common from '../../../common';
|
import common from '../../../common';
|
||||||
import { BadRequest, NotAuthorized, NotFound } from '../errors';
|
import { BadRequest, NotAuthorized, NotFound } from '../errors';
|
||||||
@@ -158,7 +157,7 @@ export async function loginSocial (req, res) { // eslint-disable-line import/pre
|
|||||||
|
|
||||||
if (!existingUser) {
|
if (!existingUser) {
|
||||||
res.analytics.track('register', {
|
res.analytics.track('register', {
|
||||||
user: pick(savedUser, ['preferences', 'registeredThrough']),
|
user: savedUser,
|
||||||
uuid: savedUser._id,
|
uuid: savedUser._id,
|
||||||
category: 'acquisition',
|
category: 'acquisition',
|
||||||
type: network,
|
type: network,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import { model as User } from '../models/user';
|
import { model as User } from '../models/user';
|
||||||
import * as Tasks from '../models/task';
|
import * as Tasks from '../models/task';
|
||||||
@@ -104,7 +103,7 @@ function trackCronAnalytics (analytics, user, _progress, options) {
|
|||||||
analytics.track('Cron', {
|
analytics.track('Cron', {
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
resting: user.preferences.sleep,
|
resting: user.preferences.sleep,
|
||||||
cronCount: user.flags.cronCount,
|
cronCount: user.flags.cronCount,
|
||||||
progressUp: Math.min(_progress.up, 900),
|
progressUp: Math.min(_progress.up, 900),
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import find from 'lodash/find';
|
import find from 'lodash/find';
|
||||||
import includes from 'lodash/includes';
|
import includes from 'lodash/includes';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
|
|
||||||
import { encrypt } from '../encryption';
|
import { encrypt } from '../encryption';
|
||||||
import { sendNotification as sendPushNotification } from '../pushNotifications';
|
import { sendNotification as sendPushNotification } from '../pushNotifications';
|
||||||
@@ -144,11 +143,10 @@ async function inviteByUUID (uuid, group, inviter, req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const analyticsObject = {
|
const analyticsObject = {
|
||||||
user: pick(inviter, ['preferences', 'registeredThrough']),
|
user: inviter,
|
||||||
uuid: inviter._id,
|
uuid: inviter._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
invitee: uuid,
|
|
||||||
groupId: group._id,
|
groupId: group._id,
|
||||||
groupType: group.type,
|
groupType: group.type,
|
||||||
headers: req.headers,
|
headers: req.headers,
|
||||||
@@ -209,11 +207,10 @@ async function inviteByEmail (invite, group, inviter, req, res) {
|
|||||||
if (!userIsUnsubscribed) sendTxnEmail(invite, `invite-friend${groupLabel}`, variables);
|
if (!userIsUnsubscribed) sendTxnEmail(invite, `invite-friend${groupLabel}`, variables);
|
||||||
|
|
||||||
const analyticsObject = {
|
const analyticsObject = {
|
||||||
user: pick(inviter, ['preferences', 'registeredThrough']),
|
user: inviter,
|
||||||
uuid: inviter._id,
|
uuid: inviter._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
invitee: 'email',
|
|
||||||
groupId: group._id,
|
groupId: group._id,
|
||||||
groupType: group.type,
|
groupType: group.type,
|
||||||
headers: req.headers,
|
headers: req.headers,
|
||||||
@@ -247,11 +244,10 @@ async function inviteByUserName (username, group, inviter, req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const analyticsObject = {
|
const analyticsObject = {
|
||||||
user: pick(inviter, ['preferences', 'registeredThrough']),
|
user: inviter,
|
||||||
uuid: inviter._id,
|
uuid: inviter._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
invitee: userToInvite._id,
|
|
||||||
groupId: group._id,
|
groupId: group._id,
|
||||||
groupType: group.type,
|
groupType: group.type,
|
||||||
headers: req.headers,
|
headers: req.headers,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import find from 'lodash/find';
|
import find from 'lodash/find';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import { getAnalyticsServiceByEnvironment } from '../analyticsService';
|
import { getAnalyticsServiceByEnvironment } from '../analyticsService';
|
||||||
import { getCurrentEventList } from '../worldState'; // eslint-disable-line import/no-cycle
|
import { getCurrentEventList } from '../worldState'; // eslint-disable-line import/no-cycle
|
||||||
import { // eslint-disable-line import/no-cycle
|
import { // eslint-disable-line import/no-cycle
|
||||||
@@ -115,7 +114,7 @@ export async function buyGems (data) {
|
|||||||
if (!data.gift) txnEmail(data.user, 'donation');
|
if (!data.gift) txnEmail(data.user, 'donation');
|
||||||
|
|
||||||
analytics.trackPurchase({
|
analytics.trackPurchase({
|
||||||
user: pick(data.user, ['preferences', 'registeredThrough']),
|
user: data.user,
|
||||||
uuid: data.user._id,
|
uuid: data.user._id,
|
||||||
itemPurchased: 'Gems',
|
itemPurchased: 'Gems',
|
||||||
sku: `${data.paymentMethod.toLowerCase()}-checkout`,
|
sku: `${data.paymentMethod.toLowerCase()}-checkout`,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import pick from 'lodash/pick';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {
|
import {
|
||||||
BadRequest,
|
BadRequest,
|
||||||
@@ -32,7 +31,7 @@ async function buyGryphatrice (data) {
|
|||||||
data.user.purchased.txnCount += 1;
|
data.user.purchased.txnCount += 1;
|
||||||
|
|
||||||
analytics.trackPurchase({
|
analytics.trackPurchase({
|
||||||
user: pick(data.user, ['preferences', 'registeredThrough']),
|
user: data.user,
|
||||||
uuid: data.user._id,
|
uuid: data.user._id,
|
||||||
itemPurchased: 'Gryphatrice',
|
itemPurchased: 'Gryphatrice',
|
||||||
sku: `${data.paymentMethod.toLowerCase()}-checkout`,
|
sku: `${data.paymentMethod.toLowerCase()}-checkout`,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
import defaults from 'lodash/defaults';
|
import defaults from 'lodash/defaults';
|
||||||
import each from 'lodash/each';
|
import each from 'lodash/each';
|
||||||
import find from 'lodash/find';
|
import find from 'lodash/find';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { getAnalyticsServiceByEnvironment } from '../analyticsService';
|
import { getAnalyticsServiceByEnvironment } from '../analyticsService';
|
||||||
@@ -465,7 +464,7 @@ async function cancelSubscription (data) {
|
|||||||
|
|
||||||
analytics.track(cancelType, {
|
analytics.track(cancelType, {
|
||||||
uuid: data.user._id,
|
uuid: data.user._id,
|
||||||
user: pick(data.user, ['preferences', 'registeredThrough']),
|
user: data.user,
|
||||||
groupId,
|
groupId,
|
||||||
paymentMethod: data.paymentMethod,
|
paymentMethod: data.paymentMethod,
|
||||||
headers: data.headers,
|
headers: data.headers,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import cloneDeep from 'lodash/cloneDeep';
|
|||||||
import compact from 'lodash/compact';
|
import compact from 'lodash/compact';
|
||||||
import forEach from 'lodash/forEach';
|
import forEach from 'lodash/forEach';
|
||||||
import keys from 'lodash/keys';
|
import keys from 'lodash/keys';
|
||||||
import pick from 'lodash/pick';
|
|
||||||
import remove from 'lodash/remove';
|
import remove from 'lodash/remove';
|
||||||
import validator from 'validator';
|
import validator from 'validator';
|
||||||
import {
|
import {
|
||||||
@@ -516,7 +515,7 @@ async function scoreTask (user, task, direction, req, res) {
|
|||||||
role = 'member';
|
role = 'member';
|
||||||
}
|
}
|
||||||
res.analytics.track('team task scored', {
|
res.analytics.track('team task scored', {
|
||||||
user: pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ export async function update (req, res, { isV3 = false }) {
|
|||||||
user.invitations.party = {};
|
user.invitations.party = {};
|
||||||
user.invitations.parties = [];
|
user.invitations.parties = [];
|
||||||
res.analytics.track('Starts Looking for Party', {
|
res.analytics.track('Starts Looking for Party', {
|
||||||
user: _.pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
@@ -201,7 +201,7 @@ export async function update (req, res, { isV3 = false }) {
|
|||||||
if (key === 'party.seeking' && val === null) {
|
if (key === 'party.seeking' && val === null) {
|
||||||
user.party.seeking = undefined;
|
user.party.seeking = undefined;
|
||||||
res.analytics.track('Leaves Looking for Party', {
|
res.analytics.track('Leaves Looking for Party', {
|
||||||
user: _.pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
@@ -292,7 +292,7 @@ export async function reset (req, res, { isV3 = false }) {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
res.analytics.track('account reset', {
|
res.analytics.track('account reset', {
|
||||||
user: _.pick(user, ['preferences', 'registeredThrough']),
|
user,
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
hitType: 'event',
|
hitType: 'event',
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
|
|||||||
Reference in New Issue
Block a user