Implemented new Achievement and Badge: Joined a Challenge (Fixes #8613) (#8761)

* Added image

* Added new achievement to user schema

* Added new achievement to content

* Added new achievement to libs

* Added achievement text to locale

* Added achievement to notification model and controller

* Grant achievement on joining or creating first challenge

* Added achievement to modal template

* Compiled new sprites

* Added integration tests

* Fix linting error
This commit is contained in:
Kevin Smith
2017-06-07 17:43:16 +01:00
committed by Sabe Jones
parent 234328f2ba
commit c5d9ee1e0a
16 changed files with 503 additions and 461 deletions

View File

@@ -304,5 +304,15 @@ describe('POST /challenges', () => {
await expect(groupLeader.sync()).to.eventually.have.property('challenges').to.include(challenge._id);
});
it('awards achievement if this is creator\'s first challenge', async () => {
await groupLeader.post('/challenges', {
group: group._id,
name: 'Test Challenge',
shortName: 'TC Label',
});
groupLeader = await groupLeader.sync();
expect(groupLeader.achievements.joinedChallenge).to.be.true;
});
});
});

View File

@@ -123,5 +123,12 @@ describe('POST /challenges/:challengeId/join', () => {
await expect(authorizedUser.get('/tags')).to.eventually.have.length(userTagsLength + 1);
});
it('awards achievement if this is user\'s first challenge', async () => {
await authorizedUser.post(`/challenges/${challenge._id}/join`);
await authorizedUser.sync();
expect(authorizedUser.achievements.joinedChallenge).to.be.true;
});
});
});

View File

@@ -100,8 +100,8 @@ describe('POST /challenges/:challengeId/winner/:winnerId', () => {
await sleep(0.5);
await expect(winningUser.sync()).to.eventually.have.deep.property('achievements.challenges').to.include(challenge.name);
expect(winningUser.notifications.length).to.equal(1);
expect(winningUser.notifications[0].type).to.equal('WON_CHALLENGE');
expect(winningUser.notifications.length).to.equal(2); // 2 because winningUser just joined the challenge, which now awards an achievement
expect(winningUser.notifications[1].type).to.equal('WON_CHALLENGE');
});
it('gives winner gems as reward', async () => {

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 506 KiB

After

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -147,6 +147,10 @@ habitrpg.controller('NotificationCtrl',
$rootScope.playSound('Achievement_Unlocked');
Achievement.displayAchievement('joinedGuild', {size: 'md'});
break;
case 'CHALLENGE_JOINED_ACHIEVEMENT':
$rootScope.playSound('Achievement_Unlocked');
Achievement.displayAchievement('joinedChallenge', {size: 'md'});
break;
case 'NEW_CONTRIBUTOR_LEVEL':
$rootScope.playSound('Achievement_Unlocked');
Achievement.displayAchievement('contributor', {size: 'md'});

File diff suppressed because it is too large Load Diff

View File

@@ -79,5 +79,7 @@
"onlyChalLeaderEditTasks": "Tasks belonging to a challenge can only be edited by the leader.",
"userAlreadyInChallenge": "User is already participating in this challenge.",
"cantOnlyUnlinkChalTask": "Only broken challenges tasks can be unlinked.",
"shortNameTooShort": "Tag Name must have at least 3 characters."
"shortNameTooShort": "Tag Name must have at least 3 characters.",
"joinedChallenge": "Joined a Challenge",
"joinedChallengeText": "This user put themselves to the test by joining a Challenge!"
}

View File

@@ -107,6 +107,11 @@ let basicAchievs = {
titleKey: 'joinedGuild',
textKey: 'joinedGuildText',
},
joinedChallenge: {
icon: 'achievement-challenge',
titleKey: 'joinedChallenge',
textKey: 'joinedChallengeText',
},
};
Object.assign(achievementsData, basicAchievs);

View File

@@ -181,6 +181,7 @@ function _getBasicAchievements (user, language) {
_addSimple(result, user, {path: 'partyOn', language});
_addSimple(result, user, {path: 'joinedGuild', language});
_addSimple(result, user, {path: 'royallyLoyal', language});
_addSimple(result, user, {path: 'joinedChallenge', language});
_addSimpleWithMasterCount(result, user, {path: 'beastMaster', language});
_addSimpleWithMasterCount(result, user, {path: 'mountMaster', language});

View File

@@ -228,6 +228,12 @@ api.createChallenge = {
let challengeValidationErrors = challenge.validateSync();
if (challengeValidationErrors) throw challengeValidationErrors;
// Add achievement if user's first challenge
if (!user.achievements.joinedChallenge) {
user.achievements.joinedChallenge = true;
user.addNotification('CHALLENGE_JOINED_ACHIEVEMENT');
}
let results = await Bluebird.all([challenge.save({
validateBeforeSave: false, // already validate
}), group.save()]);
@@ -286,6 +292,12 @@ api.joinChallenge = {
challenge.memberCount += 1;
// Add achievement if user's first challenge
if (!user.achievements.joinedChallenge) {
user.achievements.joinedChallenge = true;
user.addNotification('CHALLENGE_JOINED_ACHIEVEMENT');
}
// Add all challenge's tasks to user's tasks and save the challenge
let results = await Bluebird.all([challenge.syncToUser(user), challenge.save()]);

View File

@@ -115,6 +115,7 @@ let schema = new Schema({
getwell: Number,
royallyLoyal: Boolean,
joinedGuild: Boolean,
joinedChallenge: Boolean,
},
backer: {

View File

@@ -20,6 +20,7 @@ const NOTIFICATION_TYPES = [
'BOSS_DAMAGE', // Not used currently but kept to avoid validation errors
'GUILD_PROMPT',
'GUILD_JOINED_ACHIEVEMENT',
'CHALLENGE_JOINED_ACHIEVEMENT',
];
const Schema = mongoose.Schema;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 506 KiB

After

Width:  |  Height:  |  Size: 506 KiB

View File

@@ -163,3 +163,14 @@ script(id='modals/achievements/joinedGuild.html', type='text/ng-template')
br
button.btn.btn-primary(ng-click='$close()')=env.t('huzzah')
+achievementFooter
// Joined Challenge
script(id='modals/achievements/joinedChallenge.html', type='text/ng-template')
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0')=env.t('modalAchievement')
+achievementAvatar('challenge',0)
p=env.t('joinedChallengeText')
br
button.btn.btn-primary(ng-click='$close()')=env.t('huzzah')
+achievementFooter