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: ""})