diff --git a/migrations/command-line/mystery_items.js b/migrations/command-line/mystery_items.js deleted file mode 100644 index 25d8b815af..0000000000 --- a/migrations/command-line/mystery_items.js +++ /dev/null @@ -1,51 +0,0 @@ -let UserNotification = require('../../website/server/models/userNotification').model; - -let _id = ''; - -let items = ['back_mystery_201801', 'headAccessory_mystery_201801']; - -let update = { - $addToSet: { - 'purchased.plan.mysteryItems': { - $each: items, - }, - }, - $push: { - notifications: (new UserNotification({ - type: 'NEW_MYSTERY_ITEMS', - data: { - items, - }, - })).toJSON(), - }, -}; - -/* var update = { - $set:{ - 'purchased.plan':{ - customerId: "", - dateCreated: new Date(), - dateTerminated: null, - dateUpdated:new Date(), - gemsBought: 0, - mysteryItems: [], - paymentMethod: "Paypal", - planId : "basic_earned" - } - } -};*/ - -if (_id) { - // singular (missing items) - db.users.update({_id}, update); -} else { - // multiple (once @ start of event) - db.users.update({ - 'purchased.plan.customerId': { $ne: null }, - $or: [ - { 'purchased.plan.dateTerminated': { $gte: new Date() } }, - { 'purchased.plan.dateTerminated': { $exists: false } }, - { 'purchased.plan.dateTerminated': { $eq: null } }, - ], - }, update, { multi: true }); -} diff --git a/migrations/takeThis.js b/migrations/takeThis.js index 13e4283b9b..d276727a70 100644 --- a/migrations/takeThis.js +++ b/migrations/takeThis.js @@ -7,7 +7,7 @@ let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done */ let monk = require('monk'); -let connectionString = 'mongodb://sabrecat:z8e8jyRA8CTofMQ@ds013393-a0.mlab.com:13393/habitica?auto_reconnect=true'; +let connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE let dbUsers = monk(connectionString).get('users', { castIds: false }); function processUsers (lastId) { diff --git a/migrations/users/mystery-items.js b/migrations/users/mystery-items.js new file mode 100644 index 0000000000..955eee3b6a --- /dev/null +++ b/migrations/users/mystery-items.js @@ -0,0 +1,108 @@ +const migrationName = 'mystery-items-201802.js'; // Update per month +const authorName = 'Sabe'; // in case script author needs to know when their ... +const authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done + +/* + * Award this month's mystery items to subscribers + */ +const MYSTERY_ITEMS = ['armor_mystery_201802', 'head_mystery_201802', 'shield_mystery_201802']; +const connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true'; // FOR TEST DATABASE + +let monk = require('monk'); +let dbUsers = monk(connectionString).get('users', { castIds: false }); +let UserNotification = require('../../website/server/models/userNotification').model; + +function processUsers (lastId) { + // specify a query to limit the affected users (empty for all users): + let query = { + migration: {$ne: migrationName}, + 'purchased.plan.customerId': { $ne: null }, + $or: [ + { 'purchased.plan.dateTerminated': { $gte: new Date() } }, + { 'purchased.plan.dateTerminated': { $exists: false } }, + { 'purchased.plan.dateTerminated': { $eq: null } }, + ], + }; + + if (lastId) { + query._id = { + $gt: lastId, + }; + } + + dbUsers.find(query, { + sort: {_id: 1}, + limit: 250, + fields: [ + ], // specify fields we are interested in to limit retrieved data (empty if we're not reading data): + }) + .then(updateUsers) + .catch((err) => { + console.log(err); + return exiting(1, `ERROR! ${ err}`); + }); +} + +let progressCount = 1000; +let count = 0; + +function updateUsers (users) { + if (!users || users.length === 0) { + console.warn('All appropriate users found and modified.'); + displayData(); + return; + } + + let userPromises = users.map(updateUser); + let lastUser = users[users.length - 1]; + + return Promise.all(userPromises) + .then(() => { + processUsers(lastUser._id); + }); +} + +function updateUser (user) { + count++; + + const addToSet = { + 'purchased.plan.mysteryItems': { + $each: MYSTERY_ITEMS, + }, + }; + const push = { + notifications: (new UserNotification({ + type: 'NEW_MYSTERY_ITEMS', + data: { + MYSTERY_ITEMS, + }, + })).toJSON(), + }; + + dbUsers.update({_id: user._id}, {$addToSet: addToSet, $push: push}); + + if (count % progressCount === 0) console.warn(`${count } ${ user._id}`); + if (user._id === authorUuid) console.warn(`${authorName } processed`); +} + +function displayData () { + console.warn(`\n${ count } users processed\n`); + return exiting(0); +} + +function exiting (code, msg) { + code = code || 0; // 0 = success + if (code && !msg) { + msg = 'ERROR!'; + } + if (msg) { + if (code) { + console.error(msg); + } else { + console.log(msg); + } + } + process.exit(code); +} + +module.exports = processUsers; diff --git a/website/common/locales/en/gear.json b/website/common/locales/en/gear.json index 17be223d46..05d20914c3 100644 --- a/website/common/locales/en/gear.json +++ b/website/common/locales/en/gear.json @@ -665,6 +665,8 @@ "armorMystery201711Notes": "This cozy sweater set will help keep you warm as you ride through the sky! Confers no benefit. November 2017 Subscriber Item.", "armorMystery201712Text": "Candlemancer Armor", "armorMystery201712Notes": "The heat and light generated by this magic armor will warm your heart but never burn your skin! Confers no benefit. December 2017 Subscriber Item.", + "armorMystery201802Text": "Love Bug Armor", + "armorMystery201802Notes": "This shiny armor reflects your strength of heart and infuses it into any Habiticans nearby who may need encouragement! Confers no benefit. February 2018 Subscriber Item.", "armorMystery301404Text": "Steampunk Suit", "armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.", "armorMystery301703Text": "Steampunk Peacock Gown", @@ -1064,6 +1066,8 @@ "headMystery201710Notes": "This helm makes you look intimidating... but it won't do any favors for your depth perception! Confers no benefit. October 2017 Subscriber Item.", "headMystery201712Text": "Candlemancer Crown", "headMystery201712Notes": "This crown will bring light and warmth to even the darkest winter night. Confers no benefit. December 2017 Subscriber Item.", + "headMystery201802Text": "Love Bug Helm", + "headMystery201802Notes": "The antennae on this helm act as cute dowsing rods, detecting feelings of love and support nearby. Confers no benefit. February 2018 Subscriber Item.", "headMystery301404Text": "Fancy Top Hat", "headMystery301404Notes": "A fancy top hat for the finest of gentlefolk! January 3015 Subscriber Item. Confers no benefit.", "headMystery301405Text": "Basic Top Hat", @@ -1332,6 +1336,8 @@ "shieldMystery201708Notes": "This rugged shield of molten rock protects you from bad Habits but won't singe your hands. Confers no benefit. August 2017 Subscriber Item.", "shieldMystery201709Text": "Sorcery Handbook", "shieldMystery201709Notes": "This book will guide you through your forays into sorcery. Confers no benefit. September 2017 Subscriber Item.", + "shieldMystery201802Text": "Love Bug Shield", + "shieldMystery201802Notes": "Although it may look like brittle candy, this shield is resistant to even the strongest Shattering Heartbreak attacks! Confers no benefit. February 2018 Subscriber Item.", "shieldMystery301405Text": "Clock Shield", "shieldMystery301405Notes": "Time is on your side with this towering clock shield! Confers no benefit. June 3015 Subscriber Item.", "shieldMystery301704Text": "Fluttery Fan", diff --git a/website/common/locales/en/subscriber.json b/website/common/locales/en/subscriber.json index 368e1ffe9e..b080ea816b 100644 --- a/website/common/locales/en/subscriber.json +++ b/website/common/locales/en/subscriber.json @@ -140,6 +140,7 @@ "mysterySet201711": "Carpet Rider Set", "mysterySet201712": "Candlemancer Set", "mysterySet201801": "Frost Sprite Set", + "mysterySet201802": "Love Bug Set", "mysterySet301404": "Steampunk Standard Set", "mysterySet301405": "Steampunk Accessories Set", "mysterySet301703": "Peacock Steampunk Set", diff --git a/website/common/script/content/gear/sets/mystery.js b/website/common/script/content/gear/sets/mystery.js index 41e714da78..6439cb46fe 100644 --- a/website/common/script/content/gear/sets/mystery.js +++ b/website/common/script/content/gear/sets/mystery.js @@ -187,6 +187,12 @@ let armor = { mystery: '201712', value: 0, }, + 201802: { + text: t('armorMystery201802Text'), + notes: t('armorMystery201802Notes'), + mystery: '201802', + value: 0, + }, 301404: { text: t('armorMystery301404Text'), notes: t('armorMystery301404Notes'), @@ -541,6 +547,12 @@ let head = { mystery: '201712', value: 0, }, + 201802: { + text: t('headMystery201802Text'), + notes: t('headMystery201802Notes'), + mystery: '201802', + value: 0, + }, 301404: { text: t('headMystery301404Text'), notes: t('headMystery301404Notes'), @@ -637,6 +649,12 @@ let shield = { mystery: '201709', value: 0, }, + 201802: { + text: t('shieldMystery201802Text'), + notes: t('shieldMystery201802Notes'), + mystery: '201802', + value: 0, + }, 301405: { text: t('shieldMystery301405Text'), notes: t('shieldMystery301405Notes'), diff --git a/website/common/script/content/mystery-sets.js b/website/common/script/content/mystery-sets.js index 58e010ac8b..8dbdcbbeb5 100644 --- a/website/common/script/content/mystery-sets.js +++ b/website/common/script/content/mystery-sets.js @@ -194,6 +194,10 @@ let mysterySets = { start: '2018-01-23', end: '2018-02-02', }, + 201802: { + start: '2018-02-22', + end: '2018-03-02', + }, 301404: { start: '3014-03-24', end: '3014-04-02', diff --git a/website/raw_sprites/spritesmith/gear/events/mystery_201802/broad_armor_mystery_201802.png b/website/raw_sprites/spritesmith/gear/events/mystery_201802/broad_armor_mystery_201802.png new file mode 100644 index 0000000000..6ad4bf8a5a Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/events/mystery_201802/broad_armor_mystery_201802.png differ diff --git a/website/raw_sprites/spritesmith/gear/events/mystery_201802/head_mystery_201802.png b/website/raw_sprites/spritesmith/gear/events/mystery_201802/head_mystery_201802.png new file mode 100644 index 0000000000..83f1c882e0 Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/events/mystery_201802/head_mystery_201802.png differ diff --git a/website/raw_sprites/spritesmith/gear/events/mystery_201802/shield_mystery_201802.png b/website/raw_sprites/spritesmith/gear/events/mystery_201802/shield_mystery_201802.png new file mode 100644 index 0000000000..b910f1e4db Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/events/mystery_201802/shield_mystery_201802.png differ diff --git a/website/raw_sprites/spritesmith/gear/events/mystery_201802/shop_armor_mystery_201802.png b/website/raw_sprites/spritesmith/gear/events/mystery_201802/shop_armor_mystery_201802.png new file mode 100644 index 0000000000..8e88faa619 Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/events/mystery_201802/shop_armor_mystery_201802.png differ diff --git a/website/raw_sprites/spritesmith/gear/events/mystery_201802/shop_head_mystery_201802.png b/website/raw_sprites/spritesmith/gear/events/mystery_201802/shop_head_mystery_201802.png new file mode 100644 index 0000000000..0bad684c41 Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/events/mystery_201802/shop_head_mystery_201802.png differ diff --git a/website/raw_sprites/spritesmith/gear/events/mystery_201802/shop_set_mystery_201802.png b/website/raw_sprites/spritesmith/gear/events/mystery_201802/shop_set_mystery_201802.png new file mode 100644 index 0000000000..ceebabb67a Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/events/mystery_201802/shop_set_mystery_201802.png differ diff --git a/website/raw_sprites/spritesmith/gear/events/mystery_201802/shop_shield_mystery_201802.png b/website/raw_sprites/spritesmith/gear/events/mystery_201802/shop_shield_mystery_201802.png new file mode 100644 index 0000000000..27dd07f7fe Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/events/mystery_201802/shop_shield_mystery_201802.png differ diff --git a/website/raw_sprites/spritesmith/gear/events/mystery_201802/slim_armor_mystery_201802.png b/website/raw_sprites/spritesmith/gear/events/mystery_201802/slim_armor_mystery_201802.png new file mode 100644 index 0000000000..047160b69e Binary files /dev/null and b/website/raw_sprites/spritesmith/gear/events/mystery_201802/slim_armor_mystery_201802.png differ diff --git a/website/raw_sprites/spritesmith_large/promo_mystery_201802.png b/website/raw_sprites/spritesmith_large/promo_mystery_201802.png new file mode 100644 index 0000000000..c08dd02f81 Binary files /dev/null and b/website/raw_sprites/spritesmith_large/promo_mystery_201802.png differ diff --git a/website/raw_sprites/spritesmith_large/promo_seasonalshop_broken.png b/website/raw_sprites/spritesmith_large/promo_seasonalshop_broken.png new file mode 100644 index 0000000000..7f70478f32 Binary files /dev/null and b/website/raw_sprites/spritesmith_large/promo_seasonalshop_broken.png differ diff --git a/website/server/controllers/api-v3/news.js b/website/server/controllers/api-v3/news.js index 0b88529d46..19e2777876 100644 --- a/website/server/controllers/api-v3/news.js +++ b/website/server/controllers/api-v3/news.js @@ -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 = 'WORLD BOSS RAGE STRIKE, GUILD SPOTLIGHT, AND WIKI WEDNESDAY'; +const LAST_ANNOUNCEMENT_TITLE = 'FEBRUARY SUBSCRIBER ITEMS AND BEHIND THE SCENES BLOG'; const worldDmg = { // @TODO bailey: false, }; @@ -32,27 +32,20 @@ api.getNews = {

${res.t('newStuff')}

-

2/21/2018 - ${LAST_ANNOUNCEMENT_TITLE}

+

2/22/2018 - ${LAST_ANNOUNCEMENT_TITLE}


-

World Boss: Dysheartener attacks the Seasonal Sorceress!

-

Oh, no! After feasting on our undone Dailies, the Dysheartener has gained the strength to unleash its Shattering Heartbreak attack. With a shrill shriek, it brings its spiny forelegs down upon the pavilion that houses the Seasonal Shop! The concussive blast of magic shreds the wood, and the Seasonal Sorceress is overcome by sorrow at the sight.

-

Quickly, let's keep doing our Dailies so that the beast won't strike again!

-
by Lemoness, Beffymaroo, SabreCat, viirus, Apollo, and piyorii
+

February Subscriber Items Revealed!

+

The February Subscriber Items have been revealed: The Love Bug Set!! It's a special three-piece set in honor of our ongoing battle with the Dysheartener. You only have until February 28 to receive the item set when you subscribe. If you're already an active subscriber, reload the site and then head to Inventory > Items to claim your gear!

+

Subscribers also receive the ability to buy Gems for Gold -- the longer you subscribe, the more Gems you can buy per month! There are other perks as well, such as longer access to uncompressed data and a cute Jackalope pet. Best of all, subscriptions let us keep Habitica running. Thank you very much for your support -- it means a lot to us.

+
+
by Beffymaroo
-

Sharing the Love: Guilds for Interpersonal Relationships

-

There's a new Guild Spotlight on the blog that highlights the Guilds that can help you as you work on building and maintaining your relationships with others! Check it out now to find Habitica's best places for support and help with your interpersonal connections.

-
by Beffymaroo
-
-
-
-
-
-
-

Blog Post: Routines

-

This month's featured Wiki article is about Routines! We hope that it will help you as you work on structuring your time and tasks. Be sure to check it out, and let us know what you think by reaching out on Twitter, Tumblr, and Facebook.

-
by Beffymaroo and the Wiki Wizards
+

Behind the Scenes: Bringing a World Boss to Life

+

There's a new Behind the Scenes post on the Habitica blog! Ever wonder what goes into bringing a World Boss to Habitica? Check out this post for a behind the scenes glimpse of how the team makes these events happen. It's all fun and no spoilers (we promise)!

+
by Beffymaroo
+
`,