diff --git a/common/locales/en/character.json b/common/locales/en/character.json index 885c34799e..b6909e6c63 100644 --- a/common/locales/en/character.json +++ b/common/locales/en/character.json @@ -49,7 +49,7 @@ "classBonusText": "Your class (Warrior, if you haven't unlocked or selected another class) uses its own equipment more effectively than gear from other classes. Equipped gear from your current class gets a 50% boost to the attribute bonus it grants.", "classEquipBonus": "Class Bonus", "battleGear": "Battle Gear", - "battleGearText": "This is the gear you wear into battle, it affects numbers when interacting with your tasks.", + "battleGearText": "This is the gear you wear into battle; it affects numbers when interacting with your tasks.", "costume": "Costume", "costumeText": "If you prefer the look of other gear to what you have equipped, check the \"Use Costume\" box to visually don a costume while wearing your battle gear underneath.", "useCostume": "Use Costume", diff --git a/common/locales/en/defaultTasks.json b/common/locales/en/defaultTasks.json index 48e405ab6f..cf7e179494 100644 --- a/common/locales/en/defaultTasks.json +++ b/common/locales/en/defaultTasks.json @@ -1,7 +1,7 @@ { "defaultTaskNotes": " ", "defaultHabit1Text": "Productive Work (Click the pencil to edit)", - "defaultHabit1Notes": "Sample Good Habits: + Eat a vegetable +15 minutes productive work", + "defaultHabit1Notes": "Sample Good Habits: + Eat a vegetable + 15 minutes productive work", "defaultHabit2Text": "Eat Junk Food (Click the pencil to edit)", "defaultHabit2Notes": "Sample Bad Habits: - Smoke - Procrastinate", diff --git a/common/locales/en/generic.json b/common/locales/en/generic.json index c1aa3c2118..d92d82a524 100644 --- a/common/locales/en/generic.json +++ b/common/locales/en/generic.json @@ -70,7 +70,6 @@ "lastLoggedIn": "- Last logged in", "notPorted": "This feature is not yet ported from the original site.", "buyThis": "Buy this <%= text %> with <%= price %> of your <%= gems %> Gems?", - "untilNoFace": "Until we add Facebook, use your UUID and API Token to log in (found at https://habitrpg.com > Options > Settings).", "noReachServer": "Server not currently reachable, try again later", "errorUpCase": "ERROR:", "newPassSent": "New password sent.", diff --git a/common/locales/en/groups.json b/common/locales/en/groups.json index ce6a86e786..688683fc94 100644 --- a/common/locales/en/groups.json +++ b/common/locales/en/groups.json @@ -39,6 +39,8 @@ "editGroup": "Edit Group", "newGroupName": "<%= groupType %> Name", "groupName": "Group Name", + "groupLeader": "Group Leader", + "groupID": "Group ID", "groupDescr": "Description shown in public Guilds list (Markdown OK)", "logoUrl": "Logo URL", "assignLeader": "Assign Group Leader", diff --git a/common/locales/en/quests.json b/common/locales/en/quests.json index c2aada5de6..41fa3627f0 100644 --- a/common/locales/en/quests.json +++ b/common/locales/en/quests.json @@ -3,7 +3,7 @@ "quest": "quest", "completed": "Completed!", "youReceived": "You've Received", - "questSend": "Clicking \"Invite\" will send an invitation to your party members. When all members have accepted or denied, the quest begins. See status under Options > Social > Party.", + "questSend": "Clicking \"Invite\" will send an invitation to your party members. When all members have accepted or denied, the quest begins. See status under Social > Party.", "inviteParty": "Invite Party", "questInvitation": "Quest Invitation: ", "questInvitationTitle": "Quest Invitation", diff --git a/common/locales/en/tasks.json b/common/locales/en/tasks.json index ffa781df2c..3787a391df 100644 --- a/common/locales/en/tasks.json +++ b/common/locales/en/tasks.json @@ -89,17 +89,17 @@ "dailiesRestingInInn": "You're Resting in the Inn! Your Dailies will NOT hurt you tonight, but they WILL still refresh every day. If you're in a quest, you won't deal damage/collect items until you check out of the Inn, but you can still be injured by a Boss if your Party mates skip their own Dailies.", "habitHelp1": "Good Habits are things that you do often. They award Gold and Experience every time you click the <%= plusIcon %>.", "habitHelp2": "Bad Habits are things you want to avoid doing. They remove Health every time you click the <%= minusIcon %>.", - "habitHelp3": "For inspiration, check out <%= linkStart %>these sample Habits<%= linkEnd %>.", + "habitHelp3": "For inspiration, check out these sample Habits!", "newbieGuild": "More questions? Ask in the <%= linkStart %>Newbies Guild<%= linkEnd %>!", "dailyHelp1": "Dailies repeat <%= emphasisStart %>every day<%= emphasisEnd %> that they are active. Click the <%= pencilIcon %> to change the days a Daily is active.", "dailyHelp2": "If you don't complete active Dailies, you lose Health when your day rolls over.", "dailyHelp3": "Dailies turn <%= emphasisStart %>redder<%= emphasisEnd %> when you miss them, and <%= emphasisStart %>bluer<%= emphasisEnd %> when you complete them. The redder the Daily, the more it will reward you... or hurt you.", "dailyHelp4": "To change when your day rolls over, go to <%= linkStart %> Settings > Site<%= linkEnd %> > Custom Day Start.", - "dailyHelp5": "For inspiration, check out these <%= linkStart %>sample Dailies<%= linkEnd %>!", + "dailyHelp5": "For inspiration, check out these sample Dailies!", "toDoHelp1": "To-Dos start yellow, and get redder (more valuable) the longer it takes to complete them.", "toDoHelp2": "To-Dos never hurt you! They only award Gold and Experience.", "toDoHelp3": "Breaking a To-Do down into a checklist of smaller items will make it less scary, and will increase your points!", - "toDoHelp4": "For inspiration, check out these <%= linkStart %>sample To-Dos<%= linkEnd %>!", + "toDoHelp4": "For inspiration, check out these sample To-Dos!", "rewardHelp1": "The Equipment you buy for your avatar is stored in <%= linkStart %>Inventory > Equipment<%= linkEnd %>.", "rewardHelp2": "Equipment affects your stats (<%= linkStart %>Avatar > Stats<%= linkEnd %>).", "rewardHelp3": "Special equipment will appear here during World Events.", diff --git a/common/script/content.coffee b/common/script/content.coffee index cef86206aa..30a0760b87 100644 --- a/common/script/content.coffee +++ b/common/script/content.coffee @@ -1877,9 +1877,9 @@ _.each api.subscriptionBlocks, (b,k)->b.key = k repeat = {m:true,t:true,w:true,th:true,f:true,s:true,su:true} api.userDefaults = habits: [ - {type: 'habit', text: t('defaultHabit1Text'), notes: t('defaultTaskNotes'), value: 0, up: true, down: false, attribute: 'per' } - {type: 'habit', text: t('defaultHabit2Text'), notes: t('defaultTaskNotes'), value: 0, up: false, down: true, attribute: 'str'} - {type: 'habit', text: t('defaultHabit3Text'), notes: t('defaultTaskNotes'), value: 0, up: true, down: true, attribute: 'str'} + {type: 'habit', text: t('defaultHabit1Text'), value: 0, up: true, down: false, attribute: 'per' } + {type: 'habit', text: t('defaultHabit2Text'), value: 0, up: false, down: true, attribute: 'str'} + {type: 'habit', text: t('defaultHabit3Text'), value: 0, up: true, down: true, attribute: 'str'} ] dailys: [ @@ -1898,7 +1898,7 @@ api.userDefaults = ] rewards: [ - {type: 'reward', text: t('defaultReward1Text'), notes: t('defaultTaskNotes'), value: 10 } + {type: 'reward', text: t('defaultReward1Text'), value: 10 } # {type: 'reward', text: t('defaultReward2Text'), notes: t('defaultReward2Notes'), value: 10 } ] diff --git a/test/api/groups.coffee b/test/api/groups.coffee index 40de0e4077..6c2d922476 100644 --- a/test/api/groups.coffee +++ b/test/api/groups.coffee @@ -6,16 +6,16 @@ Group = require("../../website/src/models/group").model app = require("../../website/src/server") describe "Guilds", -> - before (done) -> - registerNewUser -> - User.findByIdAndUpdate user._id, - $set: - "balance": 10 - , (err, _user) -> - done() - , true - context "creating groups", -> + before (done) -> + registerNewUser -> + User.findByIdAndUpdate user._id, + $set: + "balance": 10 + , (err, _user) -> + done() + , true + it "can create a public guild", (done) -> request.post(baseURL + "/groups").send( name: "TestGroup" @@ -53,19 +53,42 @@ describe "Guilds", -> done() , false - context "finding groups", -> - it "can find a guild", (done) -> - guild = undefined + context "get guilds", -> + guild = undefined + + beforeEach (done)-> request.post(baseURL + "/groups").send( name: "TestGroup2" type: "guild" ).end (res) -> guild = res.body - request.get(baseURL + "/groups/" + guild._id) - .send() + done() + + it "can find a guild", (done) -> + request.get(baseURL + "/groups/" + guild._id) .end (res) -> expectCode res, 200 - expect(guild._id).to.equal res.body._id + expect(res.body._id).to.equal res.body._id + done() + + it "transforms members array to an arrray of user objects", (done) -> + request.get(baseURL + "/groups/" + guild._id) + .end (res) -> + expectCode res, 200 + members = res.body.members + # @TODO: would be more instructive if it had more members in guild :( + _(members).each (member) -> + expect(member).to.be.an 'object' + expect(member.profile.name).to.exist + done() + + it "transforms leader id to a user object", (done) -> + request.get(baseURL + "/groups/" + guild._id) + .end (res) -> + expectCode res, 200 + leader = res.body.leader + expect(leader).to.be.an 'object' + expect(leader.profile.name).to.exist done() it "can list guilds", (done) -> @@ -228,38 +251,46 @@ describe "Guilds", -> describe "Public Guilds", -> guild = undefined before (done) -> - request.post(baseURL + "/groups").send( - name: "TestPublicGroup" - type: "guild" - privacy: "public" - ).end (res) -> - expectCode res, 200 - guild = res.body - expect(guild.members.length).to.equal 1 - expect(guild.leader).to.equal user._id - #Add members to guild - async.waterfall [ - (cb) -> - registerManyUsers 15, cb + async.waterfall [ + (cb) -> + registerNewUser -> + User.findByIdAndUpdate user._id, {$set: { "balance": 10 } }, (err, _user) -> + cb() + , true + (cb) -> + request.post(baseURL + "/groups").send( + name: "TestPublicGroup" + type: "guild" + privacy: "public" + ).end (res) -> + guild = res.body + expect(guild.members.length).to.equal 1 + expect(guild.leader).to.equal user._id + #Add members to guild + cb() - (_members, cb) -> - members = _members + (cb) -> + registerManyUsers 15, cb - joinGuild = (member, callback) -> - request.post(baseURL + "/groups/" + guild._id + "/join") - .set("X-API-User", member._id) - .set("X-API-Key", member.apiToken) - .end -> - callback(null, null) + (_members, cb) -> + members = _members - async.map members, joinGuild, (err, results) -> cb() - ], done + joinGuild = (member, callback) -> + request.post(baseURL + "/groups/" + guild._id + "/join") + .set("X-API-User", member._id) + .set("X-API-Key", member.apiToken) + .end -> + callback(null, null) + + async.map members, joinGuild, (err, results) -> cb() + + ], done context "is a member", -> before (done) -> registerNewUser -> request.post(baseURL + "/groups/" + guild._id + "/join") - .end -> + .end (res)-> done() , true diff --git a/website/public/css/game-pane.styl b/website/public/css/game-pane.styl index 1b6b1976ad..ea2729910d 100644 --- a/website/public/css/game-pane.styl +++ b/website/public/css/game-pane.styl @@ -21,7 +21,7 @@ padding: 1em; margin-bottom: 0.5em; -.formatting-help +.slight-vertical-padding clear: both padding-top: 0.618em diff --git a/website/public/emails/images/PROMO-Enchanted-Armoire-v1.png b/website/public/emails/images/PROMO-Enchanted-Armoire-v1.png new file mode 100644 index 0000000000..9a42b70e42 Binary files /dev/null and b/website/public/emails/images/PROMO-Enchanted-Armoire-v1.png differ diff --git a/website/src/controllers/groups.js b/website/src/controllers/groups.js index 876773491a..acb893b1ec 100644 --- a/website/src/controllers/groups.js +++ b/website/src/controllers/groups.js @@ -40,6 +40,7 @@ var populateQuery = function(type, q, additionalFields){ q.populate('members', partyFields + (additionalFields ? (' ' + additionalFields) : '')); else q.populate(guildPopulate); + q.populate('leader', nameFields); q.populate('invites', nameFields); q.populate({ path: 'challenges', diff --git a/website/src/models/user.js b/website/src/models/user.js index b24acfd886..634bb61f07 100644 --- a/website/src/models/user.js +++ b/website/src/models/user.js @@ -406,7 +406,7 @@ var UserSchema = new Schema({ rewards: {type:[TaskSchemas.RewardSchema]}, extra: Schema.Types.Mixed, - + pushDevices: {type: [{ regId: {type: String}, type: {type: String} @@ -459,7 +459,9 @@ UserSchema.pre('save', function(next) { newTask.name = newTask.name(self.preferences.language); }else{ newTask.text = newTask.text(self.preferences.language); - newTask.notes = newTask.notes(self.preferences.language); + if(newTask.notes) { + newTask.notes = newTask.notes(self.preferences.language); + } if(newTask.checklist){ newTask.checklist = _.map(newTask.checklist, function(checklistItem){ diff --git a/website/src/utils.js b/website/src/utils.js index 85ffb664ec..beb093e28e 100644 --- a/website/src/utils.js +++ b/website/src/utils.js @@ -179,8 +179,11 @@ module.exports.setupConfig = function(){ baseUrl = nconf.get('BASE_URL'); module.exports.ga = require('universal-analytics')(nconf.get('GA_ID')); - var mixpanel = require('mixpanel') - module.exports.mixpanel = mixpanel.init(nconf.get('MP_ID')); + + var mixpanel = isProd && require('mixpanel'); + module.exports.mixpanel = mixpanel + ? mixpanel.init(nconf.get('MP_ID')) + : { track: function() {} }; }; var algorithm = 'aes-256-ctr'; diff --git a/website/views/options/social/group.jade b/website/views/options/social/group.jade index 9c35139c58..0765bcd7d7 100644 --- a/website/views/options/social/group.jade +++ b/website/views/options/social/group.jade @@ -22,7 +22,7 @@ a.pull-right.gem-wallet(ng-if='group.type!="party"', popover-trigger='mouseenter span.glyphicon.glyphicon-ban-circle =env.t('leave') a.btn.btn-success.pull-right(ng-if=':: !isMemberOfGroup(User.user._id, group)', ng-click='join(group)')=env.t('join') - span(ng-if='group.leader == user.id') + span(ng-if='group.leader._id == user.id') button.btn.btn-sm.btn-primary.pull-right(ng-click='save(group)', ng-show='group._editing')=env.t('save') button.btn.btn-sm.btn-default.pull-right(ng-click='group._editing = true', ng-hide='group._editing')=env.t('editGroup') @@ -51,7 +51,13 @@ a.pull-right.gem-wallet(ng-if='group.type!="party"', popover-trigger='mouseenter img.pull-right(ng-show='group.logo', ng-src='{{group.logo}}') markdown(text='group.description') hr - small.muted Group ID: {{group._id}} + p=env.t('groupLeader') + |: + a(class='badge badge-info', ng-click='clickMember(group.leader._id, true)') + | {{group.leader.profile.name}} + .slight-vertical-padding + small.muted=env.t('groupID') + |: {{group._id}} include ./challenge-box @@ -78,14 +84,14 @@ a.pull-right.gem-wallet(ng-if='group.type!="party"', popover-trigger='mouseenter ng-change='set({"party.orderAscending": user.party.orderAscending})' ) table.table.table-striped(bindonce='group') - tr(ng-repeat='member in group.members track by member._id') + tr(ng-repeat='member in group.members track by member._id' ng-if='member._id != group.leader._id') td.media // allow leaders to ban members - div.pull-left(ng-show='group.leader == user.id && user.id!=member._id') + div.pull-left(ng-show='group.leader._id == user.id') a.media-object(ng-click='removeMember(group, member, true)') span.glyphicon.glyphicon-ban-circle(tooltip=env.t('banTip')) a.media-body - span(ng-class='{"badge badge-info": group.leader==member._id}', ng-click='clickMember(member._id, true)') + span(ng-click='clickMember(member._id, true)') | {{member.profile.name}} tr(ng-if='group.memberCount > group.members.length') td @@ -98,7 +104,7 @@ a.pull-right.gem-wallet(ng-if='group.type!="party"', popover-trigger='mouseenter tr(ng-repeat='invite in group.invites') td.media // allow leaders to ban members - div.pull-left(ng-show='group.leader == user.id') + div.pull-left(ng-show='group.leader._id == user.id') a.media-object(ng-click='removeMember(group, invite, false)') span.glyphicon.glyphicon-ban-circle(tooltip=env.t('banTip')) a.media-body @@ -117,7 +123,7 @@ a.pull-right.gem-wallet(ng-if='group.type!="party"', popover-trigger='mouseenter td .popover.static-popover.fade.right.in.wide-popover .arrow - h3.popover-title {{Members.members[group.leader].profile.name}} + h3.popover-title {{group.leader.profile.name}} .popover-content markdown(text='group.leaderMessage') div(ng-controller='ChatCtrl') diff --git a/website/views/shared/formatting-help.jade b/website/views/shared/formatting-help.jade index c4500e03b3..9ad945093e 100644 --- a/website/views/shared/formatting-help.jade +++ b/website/views/shared/formatting-help.jade @@ -1,7 +1,7 @@ small.btn-link(ng-init='showHelp = false', ng-click='showHelp = !showHelp') | {{showHelp ? env.t('hideFormattingHelp') : env.t('showFormattingHelp')}} -.formatting-help(ng-if='showHelp') +.slight-vertical-padding(ng-if='showHelp') table.table.table-striped tr.info td.col-xs-6 #[b=env.t('youType')] diff --git a/website/views/shared/modals/classes.jade b/website/views/shared/modals/classes.jade index b199cd0e83..d9fdaa054d 100644 --- a/website/views/shared/modals/classes.jade +++ b/website/views/shared/modals/classes.jade @@ -67,6 +67,7 @@ script(type='text/ng-template', id='modals/chooseClass.html') .well(ng-show='selectedClass=="healer"')=env.t('healerText') .modal-footer - button.btn.btn-danger(ng-click='user.ops.disableClasses({}); $close()', popover-placement='top', popover-trigger='mouseenter', popover=env.t('optOutText'))=env.t('optOut') + span(popover-placement='left', popover-trigger='mouseenter', popover=env.t('optOutText')) + button.btn.btn-danger(ng-click='user.ops.disableClasses({}); $close()')=env.t('optOut') button.btn.btn-primary(ng-disabled='!selectedClass' ng-click='changeClass(selectedClass); $close()')=env.t('select') .pull-left!=env.t('chooseClassLearn') diff --git a/website/views/shared/tasks/task_view/help.jade b/website/views/shared/tasks/task_view/help.jade index 609aad5bc9..718d82e411 100644 --- a/website/views/shared/tasks/task_view/help.jade +++ b/website/views/shared/tasks/task_view/help.jade @@ -6,20 +6,20 @@ div(ng-if='list.help', ng-switch='::list.type') li!=env.t('newbieGuild', {linkStart:"", linkEnd: ""}) ul(ng-switch-when='daily') li!=env.t('dailyHelp1', {emphasisStart:"", emphasisEnd:"", pencilIcon:""}) - li!=env.t('dailyHelp2') + li=env.t('dailyHelp2') li!=env.t('dailyHelp3', {emphasisStart:"", emphasisEnd:""}) li!=env.t('dailyHelp4', {linkStart:"", linkEnd:""}) li!=env.t('dailyHelp5') li!=env.t('newbieGuild', {linkStart:"", linkEnd: ""}) ul(ng-switch-when='todo') - li!=env.t('toDoHelp1') - li!=env.t('toDoHelp2') - li!=env.t('toDoHelp3') + li=env.t('toDoHelp1') + li=env.t('toDoHelp2') + li=env.t('toDoHelp3') li!=env.t('toDoHelp4') li!=env.t('newbieGuild', {linkStart:"", linkEnd: ""}) ul(ng-switch-when='reward') li!=env.t('rewardHelp1', {linkStart:"", linkEnd: ""}) li!=env.t('rewardHelp2', {linkStart:"", linkEnd: ""}) - li!=env.t('rewardHelp3') + li=env.t('rewardHelp3') li!=env.t('rewardHelp4') li!=env.t('newbieGuild', {linkStart:"", linkEnd: ""})