feat(content): mystery items Feb 2018

This commit is contained in:
SabreCat
2018-02-22 22:56:33 +00:00
parent 9487811d31
commit 8b8cee40a7
18 changed files with 149 additions and 70 deletions

View File

@@ -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 });
}

View File

@@ -7,7 +7,7 @@ let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
*/ */
let monk = require('monk'); 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 }); let dbUsers = monk(connectionString).get('users', { castIds: false });
function processUsers (lastId) { function processUsers (lastId) {

View File

@@ -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;

View File

@@ -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.", "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", "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.", "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", "armorMystery301404Text": "Steampunk Suit",
"armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.", "armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.",
"armorMystery301703Text": "Steampunk Peacock Gown", "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.", "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", "headMystery201712Text": "Candlemancer Crown",
"headMystery201712Notes": "This crown will bring light and warmth to even the darkest winter night. Confers no benefit. December 2017 Subscriber Item.", "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", "headMystery301404Text": "Fancy Top Hat",
"headMystery301404Notes": "A fancy top hat for the finest of gentlefolk! January 3015 Subscriber Item. Confers no benefit.", "headMystery301404Notes": "A fancy top hat for the finest of gentlefolk! January 3015 Subscriber Item. Confers no benefit.",
"headMystery301405Text": "Basic Top Hat", "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.", "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", "shieldMystery201709Text": "Sorcery Handbook",
"shieldMystery201709Notes": "This book will guide you through your forays into sorcery. Confers no benefit. September 2017 Subscriber Item.", "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", "shieldMystery301405Text": "Clock Shield",
"shieldMystery301405Notes": "Time is on your side with this towering clock shield! Confers no benefit. June 3015 Subscriber Item.", "shieldMystery301405Notes": "Time is on your side with this towering clock shield! Confers no benefit. June 3015 Subscriber Item.",
"shieldMystery301704Text": "Fluttery Fan", "shieldMystery301704Text": "Fluttery Fan",

View File

@@ -140,6 +140,7 @@
"mysterySet201711": "Carpet Rider Set", "mysterySet201711": "Carpet Rider Set",
"mysterySet201712": "Candlemancer Set", "mysterySet201712": "Candlemancer Set",
"mysterySet201801": "Frost Sprite Set", "mysterySet201801": "Frost Sprite Set",
"mysterySet201802": "Love Bug Set",
"mysterySet301404": "Steampunk Standard Set", "mysterySet301404": "Steampunk Standard Set",
"mysterySet301405": "Steampunk Accessories Set", "mysterySet301405": "Steampunk Accessories Set",
"mysterySet301703": "Peacock Steampunk Set", "mysterySet301703": "Peacock Steampunk Set",

View File

@@ -187,6 +187,12 @@ let armor = {
mystery: '201712', mystery: '201712',
value: 0, value: 0,
}, },
201802: {
text: t('armorMystery201802Text'),
notes: t('armorMystery201802Notes'),
mystery: '201802',
value: 0,
},
301404: { 301404: {
text: t('armorMystery301404Text'), text: t('armorMystery301404Text'),
notes: t('armorMystery301404Notes'), notes: t('armorMystery301404Notes'),
@@ -541,6 +547,12 @@ let head = {
mystery: '201712', mystery: '201712',
value: 0, value: 0,
}, },
201802: {
text: t('headMystery201802Text'),
notes: t('headMystery201802Notes'),
mystery: '201802',
value: 0,
},
301404: { 301404: {
text: t('headMystery301404Text'), text: t('headMystery301404Text'),
notes: t('headMystery301404Notes'), notes: t('headMystery301404Notes'),
@@ -637,6 +649,12 @@ let shield = {
mystery: '201709', mystery: '201709',
value: 0, value: 0,
}, },
201802: {
text: t('shieldMystery201802Text'),
notes: t('shieldMystery201802Notes'),
mystery: '201802',
value: 0,
},
301405: { 301405: {
text: t('shieldMystery301405Text'), text: t('shieldMystery301405Text'),
notes: t('shieldMystery301405Notes'), notes: t('shieldMystery301405Notes'),

View File

@@ -194,6 +194,10 @@ let mysterySets = {
start: '2018-01-23', start: '2018-01-23',
end: '2018-02-02', end: '2018-02-02',
}, },
201802: {
start: '2018-02-22',
end: '2018-03-02',
},
301404: { 301404: {
start: '3014-03-24', start: '3014-03-24',
end: '3014-04-02', end: '3014-04-02',

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -3,7 +3,7 @@ import { authWithHeaders } from '../../middlewares/auth';
let api = {}; let api = {};
// @TODO export this const, cannot export it from here because only routes are exported from controllers // @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 const worldDmg = { // @TODO
bailey: false, bailey: false,
}; };
@@ -32,27 +32,20 @@ api.getNews = {
<h1 class="align-self-center">${res.t('newStuff')}</h1> <h1 class="align-self-center">${res.t('newStuff')}</h1>
</div> </div>
</div> </div>
<h2>2/21/2018 - ${LAST_ANNOUNCEMENT_TITLE}</h2> <h2>2/22/2018 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
<hr/> <hr/>
<h3>World Boss: Dysheartener attacks the Seasonal Sorceress!</h3> <h3>February Subscriber Items Revealed!</h3>
<p>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 <a href='/shops/seasonal'>the Seasonal Shop</a>! The concussive blast of magic shreds the wood, and the Seasonal Sorceress is overcome by sorrow at the sight.</p> <p>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 <a href='/user/settings/subscription'>subscribe</a>. If you're already an active subscriber, reload the site and then head to Inventory > Items to claim your gear!</p>
<p>Quickly, let's keep doing our Dailies so that the beast won't strike again!</p> <p>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.</p>
<div class="small">by Lemoness, Beffymaroo, SabreCat, viirus, Apollo, and piyorii</div> <div class="promo_mystery_201802 center-block"></div>
<div class="small mb-3">by Beffymaroo</div>
<div class="media align-items-center"> <div class="media align-items-center">
<div class="media-body"> <div class="media-body">
<h3>Sharing the Love: Guilds for Interpersonal Relationships</h3> <h3>Behind the Scenes: Bringing a World Boss to Life</h3>
<p>There's a new <a href='https://habitica.wordpress.com/2018/02/19/sharing-the-love-guilds-for-interpersonal-relationships/' target='_blank'>Guild Spotlight on the blog</a> 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.</p> <p>There's a new <a href='https://habitica.wordpress.com/2018/02/22/behind-the-scenes-bringing-a-world-boss-to-life/' target='_blank'>Behind the Scenes post</a> 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)!</p>
<div class="small">by Beffymaroo</div> <div class="small mb-3">by Beffymaroo</div>
</div>
<div class="scene_tavern"></div>
</div>
<div class="media">
<div class="scene_coding mr-3"></div>
<div class="media-body">
<h3>Blog Post: Routines</h3>
<p>This month's <a href='https://habitica.wordpress.com/2018/02/21/routines/' target='_blank'>featured Wiki article</a> 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 <a href='https://twitter.com/habitica' target='_blank'>Twitter</a>, <a href='http://blog.habitrpg.com' target='_blank'>Tumblr</a>, and <a href='https://facebook.com/habitica' target='_blank'>Facebook</a>.</p>
<div class="small">by Beffymaroo and the Wiki Wizards</div>
</div> </div>
<div class="promo_seasonalshop_broken ml-3"></div>
</div> </div>
</div> </div>
`, `,