diff --git a/migrations/archive/2022/20220201_pet_group_achievements.js b/migrations/archive/2022/20220201_pet_group_achievements.js new file mode 100644 index 0000000000..86a2617660 --- /dev/null +++ b/migrations/archive/2022/20220201_pet_group_achievements.js @@ -0,0 +1,178 @@ +/* eslint-disable no-console */ +const MIGRATION_NAME = '20220201_pet_group_achievements'; +import { model as User } from '../../../website/server/models/user'; + +const progressCount = 1000; +let count = 0; + +async function updateUser (user) { + count++; + + const set = { + migration: MIGRATION_NAME, + }; + + if (user && user.items && user.items.pets) { + const pets = user.items.pets; + if (pets['FlyingPig-Base'] + && pets['FlyingPig-CottonCandyBlue'] + && pets['FlyingPig-CottonCandyPink'] + && pets['FlyingPig-Desert'] + && pets['FlyingPig-Golden'] + && pets['FlyingPig-Red'] + && pets['FlyingPig-Shade'] + && pets['FlyingPig-Skeleton'] + && pets['FlyingPig-White'] + && pets['FlyingPig-Zombie'] + && pets['Snake-Base'] + && pets['Snake-CottonCandyBlue'] + && pets['Snake-CottonCandyPink'] + && pets['Snake-Desert'] + && pets['Snake-Golden'] + && pets['Snake-Red'] + && pets['Snake-Shade'] + && pets['Snake-Skeleton'] + && pets['Snake-White'] + && pets['Snake-Zombie'] + && pets['Sheep-Base'] + && pets['Sheep-CottonCandyBlue'] + && pets['Sheep-CottonCandyPink'] + && pets['Sheep-Desert'] + && pets['Sheep-Golden'] + && pets['Sheep-Red'] + && pets['Sheep-Shade'] + && pets['Sheep-Skeleton'] + && pets['Sheep-White'] + && pets['Sheep-Zombie'] + && pets['Rooster-Base'] + && pets['Rooster-CottonCandyBlue'] + && pets['Rooster-CottonCandyPink'] + && pets['Rooster-Desert'] + && pets['Rooster-Golden'] + && pets['Rooster-Red'] + && pets['Rooster-Shade'] + && pets['Rooster-Skeleton'] + && pets['Rooster-White'] + && pets['Rooster-Zombie'] + && pets['Rat-Base'] + && pets['Rat-CottonCandyBlue'] + && pets['Rat-CottonCandyPink'] + && pets['Rat-Desert'] + && pets['Rat-Golden'] + && pets['Rat-Red'] + && pets['Rat-Shade'] + && pets['Rat-Skeleton'] + && pets['Rat-White'] + && pets['Rat-Zombie'] + && pets['Bunny-Base'] + && pets['Bunny-CottonCandyBlue'] + && pets['Bunny-CottonCandyPink'] + && pets['Bunny-Desert'] + && pets['Bunny-Golden'] + && pets['Bunny-Red'] + && pets['Bunny-Shade'] + && pets['Bunny-Skeleton'] + && pets['Bunny-White'] + && pets['Bunny-Zombie'] + && pets['Horse-Base'] + && pets['Horse-CottonCandyBlue'] + && pets['Horse-CottonCandyPink'] + && pets['Horse-Desert'] + && pets['Horse-Golden'] + && pets['Horse-Red'] + && pets['Horse-Shade'] + && pets['Horse-Skeleton'] + && pets['Horse-White'] + && pets['Horse-Zombie'] + && pets['Cow-Base'] + && pets['Cow-CottonCandyBlue'] + && pets['Cow-CottonCandyPink'] + && pets['Cow-Desert'] + && pets['Cow-Golden'] + && pets['Cow-Red'] + && pets['Cow-Shade'] + && pets['Cow-Skeleton'] + && pets['Cow-White'] + && pets['Cow-Zombie'] + && pets['Monkey-Base'] + && pets['Monkey-CottonCandyBlue'] + && pets['Monkey-CottonCandyPink'] + && pets['Monkey-Desert'] + && pets['Monkey-Golden'] + && pets['Monkey-Red'] + && pets['Monkey-Shade'] + && pets['Monkey-Skeleton'] + && pets['Monkey-White'] + && pets['Monkey-Zombie'] + && pets['Wolf-Base'] + && pets['Wolf-CottonCandyBlue'] + && pets['Wolf-CottonCandyPink'] + && pets['Wolf-Desert'] + && pets['Wolf-Golden'] + && pets['Wolf-Red'] + && pets['Wolf-Shade'] + && pets['Wolf-Skeleton'] + && pets['Wolf-White'] + && pets['Wolf-Zombie'] + && pets['Tiger-Base'] + && pets['Tiger-CottonCandyBlue'] + && pets['Tiger-CottonCandyPink'] + && pets['Tiger-Desert'] + && pets['Tiger-Golden'] + && pets['Tiger-Red'] + && pets['Tiger-Shade'] + && pets['Tiger-Skeleton'] + && pets['Tiger-White'] + && pets['Tiger-Zombie'] + && pets['Dragon-Base'] + && pets['Dragon-CottonCandyBlue'] + && pets['Dragon-CottonCandyPink'] + && pets['Dragon-Desert'] + && pets['Dragon-Golden'] + && pets['Dragon-Red'] + && pets['Dragon-Shade'] + && pets['Dragon-Skeleton'] + && pets['Dragon-White'] + && pets['Dragon-Zombie']) { + set['achievements.zodiacZookeeper'] = true; + } + } + + if (count % progressCount === 0) console.warn(`${count} ${user._id}`); + + return await User.update({ _id: user._id }, { $set: set }).exec(); +} + +export default async function processUsers () { + let query = { + // migration: { $ne: MIGRATION_NAME }, + 'auth.timestamps.loggedin': { $gt: new Date('2021-08-01') }, + }; + + const fields = { + _id: 1, + items: 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]._id, + }; + } + + await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop + } +}; diff --git a/website/client/src/components/notifications.vue b/website/client/src/components/notifications.vue index 567bb098b8..2960b0889e 100644 --- a/website/client/src/components/notifications.vue +++ b/website/client/src/components/notifications.vue @@ -442,6 +442,14 @@ const NOTIFICATIONS = { achievement: 'shadeOfItAll', }, }, + ACHIEVEMENT_ZODIAC_ZOOKEEPER: { + achievement: true, + label: $t => `${$t('achievement')}: ${$t('achievementZodiacZookeeper')}`, + modalId: 'generic-achievement', + data: { + achievement: 'zodiacZookeeper', + }, + }, }; export default { @@ -505,7 +513,7 @@ export default { 'ACHIEVEMENT_BONE_COLLECTOR', 'ACHIEVEMENT_SKELETON_CREW', 'ACHIEVEMENT_SEEING_RED', 'ACHIEVEMENT_RED_LETTER_DAY', 'ACHIEVEMENT_LEGENDARY_BESTIARY', 'ACHIEVEMENT_SEASONAL_SPECIALIST', 'ACHIEVEMENT_VIOLETS_ARE_BLUE', 'ACHIEVEMENT_WILD_BLUE_YONDER', 'ACHIEVEMENT_DOMESTICATED', - 'ACHIEVEMENT_SHADY_CUSTOMER', 'ACHIEVEMENT_SHADE_OF_IT_ALL', + 'ACHIEVEMENT_SHADY_CUSTOMER', 'ACHIEVEMENT_SHADE_OF_IT_ALL', 'ACHIEVEMENT_ZODIAC_ZOOKEEPER', ].forEach(type => { handledNotifications[type] = true; }); @@ -939,6 +947,7 @@ export default { case 'ACHIEVEMENT_DOMESTICATED': case 'ACHIEVEMENT_SHADY_CUSTOMER': case 'ACHIEVEMENT_SHADE_OF_IT_ALL': + case 'ACHIEVEMENT_ZODIAC_ZOOKEEPER': case 'GENERIC_ACHIEVEMENT': this.showNotificationWithModal(notification); break; diff --git a/website/common/locales/en/achievements.json b/website/common/locales/en/achievements.json index d079d7e953..a5ab0beb81 100644 --- a/website/common/locales/en/achievements.json +++ b/website/common/locales/en/achievements.json @@ -123,5 +123,8 @@ "achievementShadyCustomerModalText": "You collected all the Shade Pets!", "achievementShadeOfItAll": "The Shade of It All", "achievementShadeOfItAllText": "Has tamed all Shade Mounts.", - "achievementShadeOfItAllModalText": "You tamed all the Shade Mounts!" + "achievementShadeOfItAllModalText": "You tamed all the Shade Mounts!", + "achievementZodiacZookeeper": "Zodiac Zookeeper", + "achievementZodiacZookeeperText": "Has hatched all the zodiac pets: Rat, Cow, Bunny, Snake, Horse, Sheep, Monkey, Rooster, Wolf, Tiger, Flying Pig, and Dragon!", + "achievementZodiacZookeeperModalText": "You collected all the zodiac pets!" } diff --git a/website/common/script/content/achievements.js b/website/common/script/content/achievements.js index 945e8f3596..7d798eb638 100644 --- a/website/common/script/content/achievements.js +++ b/website/common/script/content/achievements.js @@ -267,6 +267,11 @@ const basicAchievs = { titleKey: 'achievementShadeOfItAll', textKey: 'achievementShadeOfItAllText', }, + zodiacZookeeper: { + icon: 'achievement-zodiac', + titleKey: 'achievementZodiacZookeeper', + textKey: 'achievementZodiacZookeeperText', + }, }; Object.assign(achievementsData, basicAchievs); diff --git a/website/common/script/content/constants/animalSetAchievements.js b/website/common/script/content/constants/animalSetAchievements.js index 6119918d07..e8f0280b3d 100644 --- a/website/common/script/content/constants/animalSetAchievements.js +++ b/website/common/script/content/constants/animalSetAchievements.js @@ -26,6 +26,25 @@ const ANIMAL_SET_ACHIEVEMENTS = { achievementKey: 'domesticated', notificationType: 'ACHIEVEMENT_DOMESTICATED', }, + zodiacZookeeper: { + type: 'pet', + species: [ + 'Rat', + 'Cow', + 'Bunny', + 'Snake', + 'Horse', + 'Sheep', + 'Monkey', + 'Rooster', + 'Wolf', + 'Tiger', + 'FlyingPig', + 'Dragon', + ], + achievementKey: 'zodiacZookeeper', + notificationType: 'ACHIEVEMENT_ZODIAC_ZOOKEEPER', + }, }; export default ANIMAL_SET_ACHIEVEMENTS; diff --git a/website/common/script/libs/achievements.js b/website/common/script/libs/achievements.js index 59deb1e7f6..0718d63d40 100644 --- a/website/common/script/libs/achievements.js +++ b/website/common/script/libs/achievements.js @@ -215,6 +215,7 @@ function _getBasicAchievements (user, language) { _addSimple(result, user, { path: 'domesticated', language }); _addSimple(result, user, { path: 'shadyCustomer', language }); _addSimple(result, user, { path: 'shadeOfItAll', language }); + _addSimple(result, user, { path: 'zodiacZookeeper', language }); _addSimpleWithMasterCount(result, user, { path: 'beastMaster', language }); _addSimpleWithMasterCount(result, user, { path: 'mountMaster', language }); diff --git a/website/server/models/user/schema.js b/website/server/models/user/schema.js index d61a07ae81..1525f4f434 100644 --- a/website/server/models/user/schema.js +++ b/website/server/models/user/schema.js @@ -147,6 +147,7 @@ export default new Schema({ domesticated: Boolean, shadyCustomer: Boolean, shadeOfItAll: Boolean, + zodiacZookeeper: Boolean, // Onboarding Guide createdTask: Boolean, completedTask: Boolean, diff --git a/website/server/models/userNotification.js b/website/server/models/userNotification.js index cafb80ce4c..4171b14cbe 100644 --- a/website/server/models/userNotification.js +++ b/website/server/models/userNotification.js @@ -70,6 +70,7 @@ const NOTIFICATION_TYPES = [ 'ACHIEVEMENT_DOMESTICATED', 'ACHIEVEMENT_SHADY_CUSTOMER', 'ACHIEVEMENT_SHADE_OF_IT_ALL', + 'ACHIEVEMENT_ZODIAC_ZOOKEEPER', 'ACHIEVEMENT', // generic achievement notification, details inside `notification.data` 'DROP_CAP_REACHED', ];