fix duplicates in code

This commit is contained in:
Matteo Pagliazzi
2019-10-08 15:05:48 +02:00
23 changed files with 1056 additions and 1246 deletions

1624
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.116.1",
"version": "4.116.2",
"main": "./website/server/index.js",
"dependencies": {
"@google-cloud/trace-agent": "^4.0.0",

View File

@@ -100,14 +100,23 @@ describe('Items Utils', () => {
});
it('converts values for mounts paths to numbers', () => {
expect(castItemVal('items.mounts.Cactus-Base', '5')).to.equal(5);
expect(castItemVal('items.mounts.Aether-Invisible', '5')).to.equal(5);
expect(castItemVal('items.mounts.Aether-Invalid', '5')).to.equal(5);
expect(castItemVal('items.mounts.Cactus-Base', 'true')).to.equal(true);
expect(castItemVal('items.mounts.Aether-Invisible', 'false')).to.equal(false);
expect(castItemVal('items.mounts.Aether-Invalid', 'true')).to.equal(true);
expect(castItemVal('items.mounts.Aether-Invalid', 'truish')).to.equal(true);
expect(castItemVal('items.mounts.Aether-Invalid', 0)).to.equal(false);
});
it('converts values for quests paths to numbers', () => {
expect(castItemVal('items.quests.atom3', '5')).to.equal(5);
expect(castItemVal('items.quests.invalid', '5')).to.equal(5);
});
it('converts values for owned gear', () => {
expect(castItemVal('items.gear.owned.shield_warrior_0', 'true')).to.equal(true);
expect(castItemVal('items.gear.owned.invalid', 'false')).to.equal(false);
expect(castItemVal('items.gear.owned.invalid', 'thruthy')).to.equal(true);
expect(castItemVal('items.gear.owned.invalid', 0)).to.equal(false);
});
});
});

View File

@@ -49,6 +49,15 @@ describe('shared.ops.buyQuestGems', () => {
buyQuest(user, {params: {key}});
expect(user.items.quests[key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
});
it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', () => {
let key = 'dustbunnies';
user.items.quests[key] = -1;
buyQuest(user, {params: {key}});
expect(user.items.quests[key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
});

View File

@@ -1,7 +1,7 @@
import {
generateUser,
} from '../../../helpers/common.helper';
import {BuyQuestWithGoldOperation} from '../../../../website/common/script/ops/buy/buyQuest';
import {BuyQuestWithGoldOperation} from '../../../../website/common/script/ops/buy/buyQuestGold';
import {
BadRequest,
NotAuthorized,
@@ -43,6 +43,18 @@ describe('shared.ops.buyQuest', () => {
expect(analytics.track).to.be.calledOnce;
});
it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', () => {
user.stats.gp = 205;
let key = 'dilatoryDistress1';
user.items.quests[key] = -1;
buyQuest(user, {
params: {key},
}, analytics);
expect(user.items.quests[key]).to.equal(1);
expect(user.stats.gp).to.equal(5);
expect(analytics.track).to.be.calledOnce;
});
it('buys a Quest scroll with the right quantity if a string is passed for quantity', () => {
user.stats.gp = 1000;
buyQuest(user, {

File diff suppressed because it is too large Load Diff

View File

@@ -22,10 +22,6 @@
"lodash": "^4.17.15",
"moment": "^2.24.0",
"smartbanner.js": "^1.14.5",
"svg-inline-loader": "^0.8.0",
"svg-url-loader": "^3.0.2",
"svgo": "^1.3.0",
"svgo-loader": "^2.2.1",
"uuid": "^3.3.3",
"validator": "^11.1.0",
"vue": "^2.6.10",
@@ -50,6 +46,10 @@
"pug-plain-loader": "^1.0.0",
"sass": "^1.19.0",
"sass-loader": "^8.0.0",
"svg-inline-loader": "^0.8.0",
"svg-url-loader": "^3.0.2",
"svgo": "^1.3.0",
"svgo-loader": "^2.2.1",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.41.0"
}

View File

@@ -161,7 +161,7 @@ div
overflow-y: scroll !important;
}
.modal-backdrop.show {
.modal-backdrop {
opacity: .9 !important;
background-color: $purple-100 !important;
}

View File

@@ -4,9 +4,15 @@
width: 423px;
height: 147px;
}
.promo_costume_achievement {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -734px 0px;
width: 144px;
height: 156px;
}
.promo_desert_pet_achievements {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -163px -486px;
background-position: 0px -634px;
width: 204px;
height: 102px;
}
@@ -30,7 +36,7 @@
}
.promo_seasonal_shop_fall {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -486px;
background-position: -424px -486px;
width: 162px;
height: 138px;
}
@@ -40,9 +46,15 @@
width: 423px;
height: 147px;
}
.promo_spooky_sparkles {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -486px;
width: 423px;
height: 147px;
}
.promo_take_this {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -617px -338px;
background-position: -734px -157px;
width: 96px;
height: 69px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View File

@@ -26,10 +26,10 @@ div
.svg-icon(v-html="icons.delete", v-once)
div(v-once) {{$t('delete')}}
.ml-auto.d-flex(v-b-tooltip="{title: likeTooltip(msg.likes[user._id])}", v-if='!inbox')
.action.d-flex.align-items-center.mr-0(@click='like()', v-if='likeCount > 0', :class='{active: msg.likes[user._id]}')
.action.d-flex.align-items-center.mr-0(@click='like()', v-if='likeCount > 0', :class='{activeLike: msg.likes[user._id]}')
.svg-icon(v-html="icons.liked", :title='$t("liked")')
| +{{ likeCount }}
.action.d-flex.align-items-center.mr-0(@click='like()', v-if='likeCount === 0', :class='{active: msg.likes[user._id]}')
.action.d-flex.align-items-center.mr-0(@click='like()', v-if='likeCount === 0', :class='{activeLike: msg.likes[user._id]}')
.svg-icon(v-html="icons.like", :title='$t("like")')
span(v-if='!msg.likes[user._id] && !inbox') {{ $t('like') }}
</template>
@@ -106,7 +106,7 @@ div
}
}
.active {
.activeLike {
color: $purple-300;
.svg-icon {

View File

@@ -242,12 +242,6 @@
}
}
.modal-backdrop.fade.show {
background-color: $purple-50;
opacity: 0.9;
}
.last {
margin-right: 0 !important;
}

View File

@@ -77,6 +77,13 @@ dt {
}
}
// popover used in quest selection modal
.popover-body {
dt {
color: inherit;
}
}
// making sure the star-colors always correct
.star {
fill: #ffb445;

View File

@@ -7,27 +7,42 @@
:no-close-on-esc="true",
@hide="$emit('hide')",
)
.modal-body
h1.header-welcome.text-center {{ $t('welcomeBack') }}
p.call-to-action.text-center {{ $t('checkOffYesterDailies') }}
.tasks-list
task(
v-for="task in tasksByType.daily",
:key="task.id",
:task="task",
:isUser="true",
:dueDate="dueDate",
)
.start-day.text-center
button.btn.btn-primary(@click='close()') {{ $t('yesterDailiesCallToAction') }}
h1.header-welcome.text-center {{ $t('welcomeBack') }}
p.call-to-action.text-center {{ $t('checkOffYesterDailies') }}
.tasks-list
task(
v-for="task in tasksByType.daily",
:key="task.id",
:task="task",
:isUser="true",
:dueDate="dueDate",
)
.start-day.text-center
button.btn.btn-primary(@click='close()') {{ $t('yesterDailiesCallToAction') }}
</template>
<style lang="scss">
#yesterdaily {
.modal-dialog {
width: 22.625rem;
}
.task-wrapper:not(:last-of-type) {
margin-bottom: 2px;
}
.modal-content {
border-radius: 8px;
}
}
</style>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
.header-welcome {
color: $purple-200;
margin-top: 1.33333em;
margin-top: 1rem;
}
.call-to-action {
@@ -39,14 +54,12 @@
border-radius: 4px;
background: $gray-600;
padding: 8px;
padding-bottom: 0.1px;
position: relative;
height: calc(100% - 64px);
overflow: auto;
}
.start-day {
margin: 2em auto 2em auto;
margin: 1.5rem auto 1rem auto;
}
</style>

View File

@@ -2,8 +2,8 @@ const path = require('path');
const webpack = require('webpack');
const nconf = require('nconf');
const setupNconf = require('../../website/server/libs/setupNconf');
const { DuplicatesPlugin } = require("inspectpack/plugin");
const pkg = require('../../package.json');
const { DuplicatesPlugin } = require('inspectpack/plugin');
const pkg = require('./package.json');
let configFile = path.join(path.resolve(__dirname, '../../config.json'));
@@ -47,6 +47,14 @@ module.exports = {
],
},
chainWebpack: config => {
// Fix issue with duplicated deps in monorepos
// https://getpocket.com/redirect?url=https%3A%2F%2Fgithub.com%2Fwebpack%2Fwebpack%2Fissues%2F8886
// Manually resolve each dependency
Object.keys(pkg.dependencies).forEach(dep => {
config.resolve.alias
.set(dep, path.resolve(__dirname, `./node_modules/${dep}`));
});
const pugRule = config.module.rule('pug')
const svgRule = config.module.rule('svg')

View File

@@ -19,6 +19,7 @@ export default {
},
availableSpells: [
'spookySparkles',
],
availableQuests: [

View File

@@ -6,7 +6,7 @@ import {BuyArmoireOperation} from './buyArmoire';
import {BuyHealthPotionOperation} from './buyHealthPotion';
import {BuyMarketGearOperation} from './buyMarketGear';
import buyMysterySet from './buyMysterySet';
import {BuyQuestWithGoldOperation} from './buyQuest';
import {BuyQuestWithGoldOperation} from './buyQuestGold';
import {BuySpellOperation} from './buySpell';
import purchaseOp from './purchase';
import hourglassPurchase from './hourglassPurchase';

View File

@@ -46,7 +46,7 @@ export class BuyQuestWithGemOperation extends AbstractGemItemOperation {
}
executeChanges (user, item, req) {
user.items.quests[item.key] = user.items.quests[item.key] || 0;
if (!user.items.quests[item.key] || user.items.quests[item.key] < 0) user.items.quests[item.key] = 0;
user.items.quests[item.key] += this.quantity;
if (user.markModified) user.markModified('items.quests');

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -3,7 +3,7 @@ import { authWithHeaders } from '../../middlewares/auth';
let api = {};
// @TODO export this const, cannot export it from here because only routes are exported from controllers
const LAST_ANNOUNCEMENT_TITLE = 'NEW BACKGROUNDS, ARMOIRE ITEMS, AND OFFICIAL HABITICA CHALLENGES!';
const LAST_ANNOUNCEMENT_TITLE = 'SPOOKY SPARKLES AND COSTUME CHALLENGE!';
const worldDmg = { // @TODO
bailey: false,
};
@@ -30,28 +30,21 @@ api.getNews = {
<div class="mr-3 ${baileyClass}"></div>
<div class="media-body">
<h1 class="align-self-center">${res.t('newStuff')}</h1>
<h2>10/1/2019 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
<h2>10/3/2019 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
</div>
</div>
<hr/>
<div class="promo_armoire_backgrounds_201910 center-block"></div>
<h3>October Backgrounds and Armoire Items!</h3>
<p>Weve added three new backgrounds to the Background Shop! Now your avatar can experiment in a Monster Maker's Workshop, ride in a magical Pumpkin Carriage, and journey across a Foggy Moor. Check them out under User Icon > Backgrounds!</p>
<p>Plus, theres new gold-purchasable equipment in the Enchanted Armoire, including the Shadow Master Set. Better work hard on your real-life tasks to earn all the pieces! Enjoy :)</p>
<div class="small mb-3">by GeraldThePixel, QuartzFox, Tigergurke, Vikte, Daikagaru, and SabreCat</div>
<div class="scene_strength center-block"></div>
<h3>October 2019 Resolution Success Challenge and New Take This Challenge</h3>
<p>The Habitica team has launched a special official Challenge series hosted in the <a href='/groups/guild/6e6a8bd3-9f5f-4351-9188-9f11fcd80a99'>Official New Year's Resolution Guild</a>. These Challenges are designed to help you build and maintain goals that are destined for success and then stick with them as the year progresses. For this month's Challenge, <a href='/challenges/ef1f7844-a58a-48f8-aab0-0423ff67ffa2'>Staying Strong</a>, we're focusing on boosting your motivation heading into the final quarter of the year! It has a 15 Gem prize, which will be awarded to five lucky winners on November 1st.</p>
<p>Congratulations to the winners of the September Challenge: Inkblots, Betelgeuse_aOri, timohi, IceBlueMelody, and han-!</p>
<p>The next Take This Challenge has also launched, "<a href='/challenges/23f6f7b7-fcf5-46a2-b591-aae05d3e62fe'>Check Your HP!</a>", with a focus on tracking your mood over time. Be sure to check it out to earn additional pieces of the Take This armor set!</p>
<p><a href='http://www.takethis.org/' target='_blank'>Take This</a> is a nonprofit that seeks to inform the gamer community about mental health issues, to provide education about mental disorders and mental illness prevention, and to reduce the stigma of mental illness.</p>
<p>Congratulations to the winners of the last Take This Challenge, "It's Dangerous to Go Alone!": grand prize winner @Ukioye_Kana, and runners-up @TheReptilianCave, @Merilio, @DocBajillian, @Melodyheart, and @Melanchoii! Plus, all participants in that Challenge have received a piece of the <a href='http://habitica.wikia.com/wiki/Event_Item_Sequences#Take_This_Armor_Set' target='_blank'>Take This item set</a> if they hadn't completed it already. It is located in your Rewards column.</p> Enjoy!
<div class="small mb-3">by Doctor B, the Take This team, Lemoness, Beffymaroo, and SabreCat</div>
<div class="promo_take_this center-block"></div>
<h3>Back-to-School Preparation Challenge Winners</h3>
<p>The winners of the Habitica Back-to-School Preparation Challenge have been selected! Congratulations to: gils__, talklesssmilemore, Nadoko, pigmaniac1941, and French1Fry !</p>
<p>Thank you to everyone who participated! We're excited to help you pursue your goals through the new school year and beyond!</p>
<div class="small mb-3">by Beffymaroo and SabreCat</div>
<div class="promo_spooky_sparkles center-block"></div>
<h3>Spooky Sparkles in the Seasonal Shop</h3>
<p>There's a new Gold-purchasable item in the Seasonal Shop: <a href='/shops/seasonal'>Spooky Sparkles</a>! Buy some and then cast it on your friends. I wonder what it will do?</p>
<p>If you have Spooky Sparkles cast on you, you will receive the "Alarming Friends" badge! Don't worry, any mysterious effects will wear off the next day.... or you can cancel them early by buying an Opaque Potion!</p>
<p>While you're at it, be sure to check out all the other items in the Seasonal Shop! There are lots of equipment items from the previous Fall Festivals. The Seasonal Shop will only be open until October 31st, so stock up now.</p>
<div class="small mb-3">by Lemoness and SabreCat</div>
<div class="promo_costume_achievement center-block"></div>
<h3>Costume Challenge</h3>
<p>The Community Costume Challenge has begun! Between now and October 31st, dress up as your avatar in real life and post a photo on social media to get the coveted Costume Challenge badge! <a href='/challenges/b2b4b952-c79e-47ff-9c5d-ae72d04aa8ee'>Read the full rules on the Challenge page</a>.</p>
<p>Looking for inspiration? Check out the <a href='https://blog.habitrpg.com/cosplay' target='_blank'>Cosplay hashtag on our Tumblr</a> to see past entries!</p>
<div class="small mb-3">by Beffymaroo</div>
</div>
`,
});

View File

@@ -60,18 +60,26 @@ export function validateItemPath (itemPath) {
// value to the correct format.
// Example a numeric string like "5" applied to a food item (expecting an interger)
// will be converted to the number 5
// TODO cast the correct value for `items.gear.owned`
export function castItemVal (itemPath, itemVal) {
if (
itemPath.indexOf('items.pets') === 0 ||
itemPath.indexOf('items.eggs') === 0 ||
itemPath.indexOf('items.hatchingPotions') === 0 ||
itemPath.indexOf('items.food') === 0 ||
itemPath.indexOf('items.mounts') === 0 ||
itemPath.indexOf('items.quests') === 0
) {
return Number(itemVal);
}
if (
itemPath.indexOf('items.mounts') === 0 ||
itemPath.indexOf('items.gear.owned') === 0
) {
if (itemVal === 'true') return true;
if (itemVal === 'false') return false;
return Boolean(itemVal);
}
return itemVal;
}