Merge branch 'release' into develop

This commit is contained in:
Matteo Pagliazzi
2020-10-19 16:54:35 +02:00
8 changed files with 51 additions and 31 deletions

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "habitica", "name": "habitica",
"version": "4.165.2", "version": "4.165.3",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@@ -1,7 +1,7 @@
{ {
"name": "habitica", "name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.", "description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.165.2", "version": "4.165.3",
"main": "./website/server/index.js", "main": "./website/server/index.js",
"dependencies": { "dependencies": {
"@babel/core": "^7.12.3", "@babel/core": "^7.12.3",

View File

@@ -592,6 +592,20 @@ describe('User Model', () => {
}); });
context('pre-save hook', () => { context('pre-save hook', () => {
it('enrolls users that signup through web in the Drop Cap AB test', async () => {
let user = new User();
user.registeredThrough = 'habitica-web';
user = await user.save();
expect(user._ABtests.dropCapNotif).to.exist;
});
it('does not enroll users that signup through modal in the Drop Cap AB test', async () => {
let user = new User();
user.registeredThrough = 'habitica-ios';
user = await user.save();
expect(user._ABtests.dropCapNotif).to.not.exist;
});
it('marks the last news post as read for new users', async () => { it('marks the last news post as read for new users', async () => {
const lastNewsPost = { _id: '1' }; const lastNewsPost = { _id: '1' };
sandbox.stub(NewsPost, 'lastNewsPost').returns(lastNewsPost); sandbox.stub(NewsPost, 'lastNewsPost').returns(lastNewsPost);

View File

@@ -3,7 +3,7 @@
id="drop-cap-reached" id="drop-cap-reached"
size="md" size="md"
:hide-header="true" :hide-header="true"
:hide-footer="!hasSubscription" :hide-footer="hasSubscription"
> >
<div class="text-center"> <div class="text-center">
<div <div
@@ -235,15 +235,15 @@ export default {
}); });
}, },
toLearnMore () { toLearnMore () {
this.close();
this.$router.push('/user/settings/subscription');
Analytics.track({ Analytics.track({
hitType: 'event', hitType: 'event',
eventCategory: 'drop-cap-reached', eventCategory: 'drop-cap-reached',
eventAction: 'click', eventAction: 'click',
eventLabel: 'Drop Cap Reached > Modal > Subscriptions', eventLabel: 'Drop Cap Reached > Modal > Subscriptions',
}); });
this.close();
this.$router.push('/user/settings/subscription');
}, },
}, },
}; };

View File

@@ -38,6 +38,10 @@
class="topbar-dropdown-item dropdown-item" class="topbar-dropdown-item dropdown-item"
@click="showAvatar('body', 'size')" @click="showAvatar('body', 'size')"
>{{ $t('editAvatar') }}</a> >{{ $t('editAvatar') }}</a>
<a
class="topbar-dropdown-item dropdown-item dropdown-separated"
@click="showAvatar('backgrounds', '2020')"
>{{ $t('backgrounds') }}</a>
<a <a
class="topbar-dropdown-item dropdown-item" class="topbar-dropdown-item dropdown-item"
@click="showProfile('profile')" @click="showProfile('profile')"
@@ -94,7 +98,7 @@
<button <button
v-once v-once
class="btn btn-primary mb-4" class="btn btn-primary mb-4"
@click="$router.push({name: 'subscription'})" @click="toLearnMore()"
> >
{{ $t('learnMore') }} {{ $t('learnMore') }}
</button> </button>
@@ -173,15 +177,15 @@ export default {
showProfile (startingPage) { showProfile (startingPage) {
this.$router.push({ name: startingPage }); this.$router.push({ name: startingPage });
}, },
showBuyGemsModal () { toLearnMore () {
Analytics.track({ Analytics.track({
hitType: 'event', hitType: 'event',
eventCategory: 'button', eventCategory: 'button',
eventAction: 'click', eventAction: 'click',
eventLabel: 'Gems > User Dropdown', eventLabel: 'User Dropdown > Subscriptions',
}); });
this.$root.$emit('bv::show::modal', 'buy-gems', { alreadyTracked: true }); this.$router.push({ name: 'subscription' });
}, },
logout () { logout () {
this.$store.dispatch('auth:logout'); this.$store.dispatch('auth:logout');

View File

@@ -52,26 +52,6 @@ async function unlockUser (user) {
}).exec(); }).exec();
} }
// Enroll users in the Drop Cap A/B Test
function dropCapABTest (user, req) {
// Only target users that use web for cron and aren't subscribed.
// Those using mobile aren't excluded as they may use it later
const isWeb = req.headers['x-client'] === 'habitica-web';
if (isWeb && !user._ABtests.dropCapNotif && !user.isSubscribed()) {
const testGroup = Math.random();
// Enroll 20% of users, splitting them 50/50
if (testGroup <= 0.25) {
user._ABtests.dropCapNotif = 'drop-cap-notif-enabled';
} else if (testGroup <= 0.5) {
user._ABtests.dropCapNotif = 'drop-cap-notif-disabled';
} else {
user._ABtests.dropCapNotif = 'drop-cap-notif-not-enrolled';
}
user.markModified('_ABtests');
}
}
async function cronAsync (req, res) { async function cronAsync (req, res) {
let { user } = res.locals; let { user } = res.locals;
if (!user) return null; // User might not be available when authentication is not mandatory if (!user) return null; // User might not be available when authentication is not mandatory
@@ -86,7 +66,7 @@ async function cronAsync (req, res) {
res.locals.user = user; res.locals.user = user;
const { daysMissed, timezoneUtcOffsetFromUserPrefs } = user.daysUserHasMissed(now, req); const { daysMissed, timezoneUtcOffsetFromUserPrefs } = user.daysUserHasMissed(now, req);
dropCapABTest(user, req); user.enrollInDropCapABTest(req.headers['x-client']);
await updateLastCron(user, now); await updateLastCron(user, now);
if (daysMissed <= 0) { if (daysMissed <= 0) {

View File

@@ -164,6 +164,8 @@ function _setUpNewUser (user) {
user.markModified('items achievements'); user.markModified('items achievements');
user.enrollInDropCapABTest(user.registeredThrough);
if (user.registeredThrough === 'habitica-web') { if (user.registeredThrough === 'habitica-web') {
taskTypes = ['habit', 'daily', 'todo', 'reward', 'tag']; taskTypes = ['habit', 'daily', 'todo', 'reward', 'tag'];

View File

@@ -525,3 +525,23 @@ schema.methods.getSecretData = function getSecretData () {
return user.secret; return user.secret;
}; };
// Enroll users in the Drop Cap A/B Test
schema.methods.enrollInDropCapABTest = function enrollInDropCapABTest (xClientHeader) {
// Only target users that use web for cron and aren't subscribed.
// Those using mobile aren't excluded as they may use it later
const isWeb = xClientHeader === 'habitica-web';
if (isWeb && !this._ABtests.dropCapNotif && !this.isSubscribed()) {
const testGroup = Math.random();
// Enroll 20% of users, splitting them 50/50
if (testGroup <= 0.25) {
this._ABtests.dropCapNotif = 'drop-cap-notif-enabled';
} else if (testGroup <= 0.5) {
this._ABtests.dropCapNotif = 'drop-cap-notif-disabled';
} else {
this._ABtests.dropCapNotif = 'drop-cap-notif-not-enrolled';
}
this.markModified('_ABtests');
}
};