feat(event): Habitica Naming Day
and Bailey announcements
124
migrations/users/naming-day.js
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
let migrationName = '20180731_naming-day.js'; // Update when running in future years
|
||||
let authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||
let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
||||
|
||||
/*
|
||||
* Award Naming Day ladder items to participants in this month's Naming Day festivities
|
||||
*/
|
||||
|
||||
import monk from 'monk';
|
||||
import nconf from 'nconf';
|
||||
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING'); // FOR TEST DATABASE
|
||||
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
|
||||
|
||||
function processUsers (lastId) {
|
||||
// specify a query to limit the affected users (empty for all users):
|
||||
let query = {
|
||||
migration: {$ne: migrationName},
|
||||
'auth.timestamps.loggedin': {$gt: new Date('2018-07-01')}, // rerun without date restriction after initial run
|
||||
};
|
||||
|
||||
if (lastId) {
|
||||
query._id = {
|
||||
$gt: lastId,
|
||||
};
|
||||
}
|
||||
|
||||
dbUsers.find(query, {
|
||||
sort: {_id: 1},
|
||||
limit: 250,
|
||||
fields: [
|
||||
'items.gear.owned',
|
||||
'items.mounts',
|
||||
'items.pets',
|
||||
], // 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++;
|
||||
|
||||
let set = {};
|
||||
let push;
|
||||
|
||||
const inc = {
|
||||
'items.food.Cake_Base': 1,
|
||||
'items.food.Cake_CottonCandyBlue': 1,
|
||||
'items.food.Cake_CottonCandyPink': 1,
|
||||
'items.food.Cake_Desert': 1,
|
||||
'items.food.Cake_Golden': 1,
|
||||
'items.food.Cake_Red': 1,
|
||||
'items.food.Cake_Shade': 1,
|
||||
'items.food.Cake_Skeleton': 1,
|
||||
'items.food.Cake_White': 1,
|
||||
'items.food.Cake_Zombie': 1,
|
||||
'achievements.habiticaDays': 1,
|
||||
};
|
||||
|
||||
if (user && user.items && user.items.gear && user.items.gear.owned && typeof user.items.gear.owned.head_special_namingDay2017 !== 'undefined') {
|
||||
set = {migration: migrationName, 'items.gear.owned.body_special_namingDay2018': false};
|
||||
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.body_special_namingDay2018', _id: monk.id()}};
|
||||
} else if (user && user.items && user.items.pets && typeof user.items.pets['Gryphon-RoyalPurple'] !== 'undefined') {
|
||||
set = {migration: migrationName, 'items.gear.owned.head_special_namingDay2017': false};
|
||||
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.head_special_namingDay2017', _id: monk.id()}};
|
||||
} else if (user && user.items && user.items.mounts && typeof user.items.mounts['Gryphon-RoyalPurple'] !== 'undefined') {
|
||||
set = {migration: migrationName, 'items.pets.Gryphon-RoyalPurple': 5};
|
||||
} else {
|
||||
set = {migration: migrationName, 'items.mounts.Gryphon-RoyalPurple': true};
|
||||
}
|
||||
|
||||
if (push) {
|
||||
dbUsers.update({_id: user._id}, {$set: set, $push: push, $inc: inc});
|
||||
} else {
|
||||
dbUsers.update({_id: user._id}, {$set: set, $inc: inc});
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -22,6 +22,12 @@
|
|||
width: 114px;
|
||||
height: 120px;
|
||||
}
|
||||
.promo_naming_day_2018 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -518px -365px;
|
||||
width: 285px;
|
||||
height: 162px;
|
||||
}
|
||||
.promo_orcas {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -954px;
|
||||
|
|
@ -42,7 +48,7 @@
|
|||
}
|
||||
.promo_seasonal_shop_summer {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -642px -552px;
|
||||
background-position: -142px -811px;
|
||||
width: 162px;
|
||||
height: 138px;
|
||||
}
|
||||
|
|
@ -72,7 +78,7 @@
|
|||
}
|
||||
.promo_unconventional_armor {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -518px -365px;
|
||||
background-position: -642px -552px;
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 165 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
|
|
@ -1579,6 +1579,9 @@
|
|||
"bodySpecialSummer2015HealerText": "Sailor's Neckerchief",
|
||||
"bodySpecialSummer2015HealerNotes": "Yo ho ho? No, no, no! Confers no benefit. Limited Edition 2015 Summer Gear.",
|
||||
|
||||
"bodySpecialNamingDay2018Text": "Royal Purple Gryphon Cloak",
|
||||
"bodySpecialNamingDay2018Notes": "Happy Naming Day! Wear this fancy and feathery cloak as you celebrate Habitica. Confers no benefit.",
|
||||
|
||||
"bodyMystery201705Text": "Folded Feathered Fighter Wings",
|
||||
"bodyMystery201705Notes": "These folded wings don't just look snazzy: they will give you the speed and agility of a gryphon! Confers no benefit. May 2017 Subscriber Item.",
|
||||
"bodyMystery201706Text": "Ragged Corsair's Cloak",
|
||||
|
|
|
|||
|
|
@ -1110,6 +1110,12 @@ let body = {
|
|||
con: 10,
|
||||
canOwn: ownsItem('body_special_aetherAmulet'),
|
||||
},
|
||||
namingDay2018: {
|
||||
text: t('bodySpecialNamingDay2018Text'),
|
||||
notes: t('bodySpecialNamingDay2018Notes'),
|
||||
value: 0,
|
||||
canOwn: ownsItem('body_special_namingDay2018'),
|
||||
},
|
||||
};
|
||||
|
||||
let eyewear = {
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 410 B |
BIN
website/raw_sprites/spritesmith_large/promo_naming_day_2018.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
|
|
@ -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 GROUP PLANS FEATURE: SHARED COMPLETION FOR TO-DOS';
|
||||
const LAST_ANNOUNCEMENT_TITLE = 'HABITICA NAMING DAY; LAST CHANCE FOR SUMMER SPLASH AND JULY SUBSCRIBER ITEMS';
|
||||
const worldDmg = { // @TODO
|
||||
bailey: false,
|
||||
};
|
||||
|
|
@ -30,17 +30,38 @@ api.getNews = {
|
|||
<div class="mr-3 ${baileyClass}"></div>
|
||||
<div class="media-body">
|
||||
<h1 class="align-self-center">${res.t('newStuff')}</h1>
|
||||
<h2>7/26/2018 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
|
||||
<h2>7/31/2018 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="media align-items-center">
|
||||
<div class="media-body">
|
||||
<p>We've added a new feature for To-Dos in Group Plans: Shared Completion! Now, you can set To-Dos on the Task Board so that the group task is completed when group members finish the task. A "Single" task is done when anyone finishes it (it's a race!), while a task set to "All" is completed when everyone assigned is done. You can find these options by editing To-Dos on your Task Board.</p>
|
||||
<p>Many of you have been eager to see this feature implemented. We hope it'll help you better organize and motivate your Group for success!</p>
|
||||
<div class="small mb-3">by SabreCat, TheHollidayInn, and paglias</div>
|
||||
<h3>Habitica Naming Day and Purple Gryphon Rewards!</h3>
|
||||
<p>Happy Habitica Naming day! In honor of the day when we changed the name of the app from HabitRPG to Habitica, we've given everyone an achievement, as well as some delicious cake for your pets and mounts.</p>
|
||||
</div>
|
||||
<div class="scene_todos ml-3 mb-3"></div>
|
||||
<div class="promo_naming_day_2018 ml-3 mb-3"></div>
|
||||
</div>
|
||||
<p>Speaking of pets and mounts, we've given all users Royal Purple Gryphon rewards! Depending on how many Naming Days you've celebrated with us, you've received Melior (a Purple Gryphon mount), his little sister Meliora (a Purple Gryphon pet), a Purple Gryphon Helm, or the Purple Gryphon Wing Cloak !</p>
|
||||
<p>Thanks for being a Habitica user -- you all mean so much to us. We hope that you enjoy your presents!</p>
|
||||
<div class="small mb-3">by Lemoness, Beffymaroo, and Baconsaur</div>
|
||||
<div class="media align-items-center">
|
||||
<div class="media-body">
|
||||
<div class="media align-items-center">
|
||||
<div class="promo_mystery_201807 mr-3"></div>
|
||||
<div class="media-body">
|
||||
<h3>Last Chance for Sea Serpent Set</h3>
|
||||
<p>Reminder: this is the final day to <a href='/user/settings/subscription' target='_blank'>subscribe</a> and receive the Sea Serpent Set! Subscribing also lets you buy Gems for Gold. The longer your subscription, the more Gems you can get!</p>
|
||||
<p>Thanks so much for your support! You help keep Habitica running.</p>
|
||||
<div class="small mb-3">by Beffymaroo</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3>Last Chance for Glass and Aquatic Hatching Potions</h3>
|
||||
<p>Reminder: this is the final day to <a href='/shops/market' target='_blank'>buy Glass and Aquatic Hatching Potions</a> If they come back, it won't be until next year at the earliest, so don't delay!</p>
|
||||
<div class="small mb-3">by stefalupagus, Beffymaroo, Mako413, Willow The Witty, and SabreCat</div>
|
||||
<h3>Last Chance for Summer Splash Goodies!</h3>
|
||||
<p>A reminder that Summer Splash is ending as well! Be sure to grab your special class gear from your Rewards column and any items you've been eyeing in the <a href='/shops/seasonal' target='_blank'>Seasonal Shop</a>!</p>
|
||||
</div>
|
||||
<div class="promo_aquatic_glass_potions ml-3 mb-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
|
|
|
|||