mirror of
https://github.com/HabitRPG/habitica.git
synced 2026-04-04 12:54:20 -05:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67c607216f | ||
|
|
672fd43ad0 | ||
|
|
69281f80ea | ||
|
|
ec0e5024a7 |
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"version": "4.165.2",
|
||||
"version": "4.165.3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"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",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.11.6",
|
||||
|
||||
@@ -592,6 +592,50 @@ describe('User Model', () => {
|
||||
});
|
||||
|
||||
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 () => {
|
||||
const lastNewsPost = { _id: '1' };
|
||||
sandbox.stub(NewsPost, 'lastNewsPost').returns(lastNewsPost);
|
||||
|
||||
let user = new User();
|
||||
expect(user.isNew).to.equal(true);
|
||||
user = await user.save();
|
||||
|
||||
expect(user.checkNewStuff()).to.equal(false);
|
||||
expect(user.toJSON().flags.newStuff).to.equal(false);
|
||||
expect(user.flags.lastNewStuffRead).to.equal(lastNewsPost._id);
|
||||
});
|
||||
|
||||
it('does not mark the last news post as read for existing users', async () => {
|
||||
const lastNewsPost = { _id: '1' };
|
||||
const lastNewsPostStub = sandbox.stub(NewsPost, 'lastNewsPost');
|
||||
lastNewsPostStub.returns(lastNewsPost);
|
||||
|
||||
let user = new User();
|
||||
user = await user.save();
|
||||
|
||||
expect(user.isNew).to.equal(false);
|
||||
user.profile.name = 'new name';
|
||||
|
||||
lastNewsPostStub.returns({ _id: '2' });
|
||||
user = await user.save();
|
||||
|
||||
expect(user.flags.lastNewStuffRead).to.equal(lastNewsPost._id); // not _id: 2
|
||||
});
|
||||
|
||||
it('does not try to award achievements when achievements or items not selected in query', async () => {
|
||||
let user = new User();
|
||||
user = await user.save(); // necessary for user.isSelected to work correctly
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
id="drop-cap-reached"
|
||||
size="md"
|
||||
:hide-header="true"
|
||||
:hide-footer="!hasSubscription"
|
||||
:hide-footer="hasSubscription"
|
||||
>
|
||||
<div class="text-center">
|
||||
<div
|
||||
@@ -235,15 +235,15 @@ export default {
|
||||
});
|
||||
},
|
||||
toLearnMore () {
|
||||
this.close();
|
||||
this.$router.push('/user/settings/subscription');
|
||||
|
||||
Analytics.track({
|
||||
hitType: 'event',
|
||||
eventCategory: 'drop-cap-reached',
|
||||
eventAction: 'click',
|
||||
eventLabel: 'Drop Cap Reached > Modal > Subscriptions',
|
||||
});
|
||||
|
||||
this.close();
|
||||
this.$router.push('/user/settings/subscription');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
class="topbar-dropdown-item dropdown-item"
|
||||
@click="showAvatar('body', 'size')"
|
||||
>{{ $t('editAvatar') }}</a>
|
||||
<a
|
||||
class="topbar-dropdown-item dropdown-item dropdown-separated"
|
||||
@click="showAvatar('backgrounds', '2020')"
|
||||
>{{ $t('backgrounds') }}</a>
|
||||
<a
|
||||
class="topbar-dropdown-item dropdown-item"
|
||||
@click="showProfile('profile')"
|
||||
@@ -94,7 +98,7 @@
|
||||
<button
|
||||
v-once
|
||||
class="btn btn-primary mb-4"
|
||||
@click="$router.push({name: 'subscription'})"
|
||||
@click="toLearnMore()"
|
||||
>
|
||||
{{ $t('learnMore') }}
|
||||
</button>
|
||||
@@ -173,15 +177,15 @@ export default {
|
||||
showProfile (startingPage) {
|
||||
this.$router.push({ name: startingPage });
|
||||
},
|
||||
showBuyGemsModal () {
|
||||
toLearnMore () {
|
||||
Analytics.track({
|
||||
hitType: 'event',
|
||||
eventCategory: 'button',
|
||||
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 () {
|
||||
this.$store.dispatch('auth:logout');
|
||||
|
||||
@@ -52,26 +52,6 @@ async function unlockUser (user) {
|
||||
}).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) {
|
||||
let { user } = res.locals;
|
||||
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;
|
||||
const { daysMissed, timezoneUtcOffsetFromUserPrefs } = user.daysUserHasMissed(now, req);
|
||||
|
||||
dropCapABTest(user, req);
|
||||
user.enrollInDropCapABTest(req.headers['x-client']);
|
||||
await updateLastCron(user, now);
|
||||
|
||||
if (daysMissed <= 0) {
|
||||
|
||||
@@ -12,6 +12,9 @@ import {
|
||||
import {
|
||||
model as Tag,
|
||||
} from '../tag';
|
||||
import {
|
||||
model as NewsPost,
|
||||
} from '../newsPost';
|
||||
import { // eslint-disable-line import/no-cycle
|
||||
userActivityWebhook,
|
||||
} from '../../libs/webhook';
|
||||
@@ -129,6 +132,12 @@ function pinBaseItems (user) {
|
||||
}
|
||||
|
||||
function _setUpNewUser (user) {
|
||||
// Mark the last news post as read
|
||||
const lastNewsPost = NewsPost.lastNewsPost();
|
||||
if (lastNewsPost) {
|
||||
user.flags.lastNewStuffRead = lastNewsPost._id;
|
||||
}
|
||||
|
||||
let taskTypes;
|
||||
const iterableFlags = user.flags.toObject();
|
||||
|
||||
@@ -155,6 +164,8 @@ function _setUpNewUser (user) {
|
||||
|
||||
user.markModified('items achievements');
|
||||
|
||||
user.enrollInDropCapABTest(user.registeredThrough);
|
||||
|
||||
if (user.registeredThrough === 'habitica-web') {
|
||||
taskTypes = ['habit', 'daily', 'todo', 'reward', 'tag'];
|
||||
|
||||
|
||||
@@ -525,3 +525,23 @@ schema.methods.getSecretData = function getSecretData () {
|
||||
|
||||
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');
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user