mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 15:48:04 +01:00
feat(content): December Mystery Items prebuild
This commit is contained in:
@@ -1,110 +0,0 @@
|
|||||||
import monk from 'monk';
|
|
||||||
import nconf from 'nconf';
|
|
||||||
|
|
||||||
const migrationName = 'mystery-items-201808.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_201810', 'head_mystery_201810'];
|
|
||||||
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
|
|
||||||
|
|
||||||
let dbUsers = monk(CONNECTION_STRING).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;
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
/* eslint-disable no-console */
|
|
||||||
import { model as User } from '../../website/server/models/user';
|
|
||||||
import { model as UserNotification } from '../../website/server/models/userNotification';
|
|
||||||
|
|
||||||
const MIGRATION_NAME = 'mystery_items_201911';
|
|
||||||
const MYSTERY_ITEMS = ['weapon_mystery_201911', 'head_mystery_201911'];
|
|
||||||
|
|
||||||
const progressCount = 1000;
|
|
||||||
let count = 0;
|
|
||||||
|
|
||||||
async function updateUser (user) {
|
|
||||||
count += 1;
|
|
||||||
|
|
||||||
const addToSet = {
|
|
||||||
'purchased.plan.mysteryItems': {
|
|
||||||
$each: MYSTERY_ITEMS,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const push = {
|
|
||||||
notifications: (new UserNotification({
|
|
||||||
type: 'NEW_MYSTERY_ITEMS',
|
|
||||||
data: {
|
|
||||||
MYSTERY_ITEMS,
|
|
||||||
},
|
|
||||||
})).toJSON(),
|
|
||||||
};
|
|
||||||
const set = {
|
|
||||||
migration: MIGRATION_NAME,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
|
||||||
|
|
||||||
return User.update({ _id: user._id }, { $set: set, $push: push, $addToSet: addToSet }).exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function processUsers () {
|
|
||||||
const query = {
|
|
||||||
migration: { $ne: MIGRATION_NAME },
|
|
||||||
'purchased.plan.customerId': { $ne: null },
|
|
||||||
$or: [
|
|
||||||
{ 'purchased.plan.dateTerminated': { $gte: new Date() } },
|
|
||||||
{ 'purchased.plan.dateTerminated': { $exists: false } },
|
|
||||||
{ 'purchased.plan.dateTerminated': { $eq: null } },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const fields = {
|
|
||||||
_id: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
while (true) { // eslint-disable-line no-constant-condition
|
|
||||||
const users = await User // eslint-disable-line no-await-in-loop
|
|
||||||
.find(query)
|
|
||||||
.limit(250)
|
|
||||||
.sort({ _id: 1 })
|
|
||||||
.select(fields)
|
|
||||||
.lean()
|
|
||||||
.exec();
|
|
||||||
|
|
||||||
if (users.length === 0) {
|
|
||||||
console.warn('All appropriate users found and modified.');
|
|
||||||
console.warn(`\n${count} users processed\n`);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
query._id = {
|
|
||||||
$gt: users[users.length - 1],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1411,6 +1411,8 @@
|
|||||||
"headMystery201910Notes": "These flames reveal arcane secrets before your very eyes! Confers no benefit. October 2019 Subscriber Item.",
|
"headMystery201910Notes": "These flames reveal arcane secrets before your very eyes! Confers no benefit. October 2019 Subscriber Item.",
|
||||||
"headMystery201911Text": "Charmed Crystal Hat",
|
"headMystery201911Text": "Charmed Crystal Hat",
|
||||||
"headMystery201911Notes": "Each of the crystal points attached to this hat endows you with a special power: mystic clairvoyance, arcane wisdom, and... sorcerous plate spinning? All right then. Confers no benefit. December 2019 Subscriber Item.",
|
"headMystery201911Notes": "Each of the crystal points attached to this hat endows you with a special power: mystic clairvoyance, arcane wisdom, and... sorcerous plate spinning? All right then. Confers no benefit. December 2019 Subscriber Item.",
|
||||||
|
"headMystery201912Text": "Polar Pixie Crown",
|
||||||
|
"headMystery201912Notes": "This glittering snowflake grants you resistance to the biting cold no matter how high you fly! Confers no benefit. December 2019 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",
|
||||||
@@ -1876,6 +1878,8 @@
|
|||||||
"backMystery201805Notes": "This gorgeous feathery tail is perfect for a strut down a lovely garden path! Confers no benefit. May 2018 Subscriber Item.",
|
"backMystery201805Notes": "This gorgeous feathery tail is perfect for a strut down a lovely garden path! Confers no benefit. May 2018 Subscriber Item.",
|
||||||
"backMystery201905Text": "Dazzling Dragon Wings",
|
"backMystery201905Text": "Dazzling Dragon Wings",
|
||||||
"backMystery201905Notes": "Fly to untold realms with these iridescent wings. Confers no benefit. May 2019 Subscriber Item.",
|
"backMystery201905Notes": "Fly to untold realms with these iridescent wings. Confers no benefit. May 2019 Subscriber Item.",
|
||||||
|
"backMystery201912Text": "Polar Pixie Wings",
|
||||||
|
"backMystery201912Notes": "Glide silently across sparkling snowfields and shimmering mountains with these icy wings. Confers no benefit. December 2019 Subscriber Item.",
|
||||||
|
|
||||||
"backSpecialWonderconRedText": "Mighty Cape",
|
"backSpecialWonderconRedText": "Mighty Cape",
|
||||||
"backSpecialWonderconRedNotes": "Swishes with strength and beauty. Confers no benefit. Special Edition Convention Item.",
|
"backSpecialWonderconRedNotes": "Swishes with strength and beauty. Confers no benefit. Special Edition Convention Item.",
|
||||||
|
|||||||
@@ -165,6 +165,7 @@
|
|||||||
"mysterySet201909": "Affable Acorn Set",
|
"mysterySet201909": "Affable Acorn Set",
|
||||||
"mysterySet201910": "Cryptic Flame Set",
|
"mysterySet201910": "Cryptic Flame Set",
|
||||||
"mysterySet201911": "Crystal Charmer Set",
|
"mysterySet201911": "Crystal Charmer Set",
|
||||||
|
"mysterySet201912": "Polar Pixie 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",
|
||||||
|
|||||||
@@ -394,6 +394,12 @@ const back = {
|
|||||||
mystery: '201905',
|
mystery: '201905',
|
||||||
value: 0,
|
value: 0,
|
||||||
},
|
},
|
||||||
|
201912: {
|
||||||
|
text: t('backMystery201912Text'),
|
||||||
|
notes: t('backMystery201912Notes'),
|
||||||
|
mystery: '201912',
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
@@ -763,6 +769,12 @@ const head = {
|
|||||||
mystery: '201911',
|
mystery: '201911',
|
||||||
value: 0,
|
value: 0,
|
||||||
},
|
},
|
||||||
|
201912: {
|
||||||
|
text: t('headMystery201912Text'),
|
||||||
|
notes: t('headMystery201912Notes'),
|
||||||
|
mystery: '201912',
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
301404: {
|
301404: {
|
||||||
text: t('headMystery301404Text'),
|
text: t('headMystery301404Text'),
|
||||||
notes: t('headMystery301404Notes'),
|
notes: t('headMystery301404Notes'),
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 439 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 383 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
website/raw_sprites/spritesmith_large/promo_mystery_201912.png
Normal file
BIN
website/raw_sprites/spritesmith_large/promo_mystery_201912.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
Reference in New Issue
Block a user