mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 15:48:04 +01:00
challenges: get Challenges (mostly) working along the same ui-router
principles as groups. Having some $scope variable resolution timing issues
This commit is contained in:
@@ -17,15 +17,9 @@ db.users.find().forEach(function(user){
|
|||||||
});
|
});
|
||||||
|
|
||||||
_.each(groups, function(usersInvited, groupId){
|
_.each(groups, function(usersInvited, groupId){
|
||||||
var group = db.groups.findOne({_id: groupId});
|
try {
|
||||||
|
db.groups.update({_id: groupId}, {$set: {'group.invites': usersInvited} });
|
||||||
if(group){
|
} catch(e) {
|
||||||
group.invites = usersInvited;
|
print(e);
|
||||||
|
}
|
||||||
try {
|
|
||||||
db.groups.update({_id: groupId}, group);
|
|
||||||
} catch(e) {
|
|
||||||
print(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -110,16 +110,23 @@ window.habitrpg = angular.module('habitrpg',
|
|||||||
.state('options.challenges', {
|
.state('options.challenges', {
|
||||||
url: "/challenges",
|
url: "/challenges",
|
||||||
controller: 'ChallengesCtrl',
|
controller: 'ChallengesCtrl',
|
||||||
templateUrl: "partials/options.challenges.html",
|
templateUrl: "partials/options.challenges.html"
|
||||||
resolve: {
|
})
|
||||||
groups: ['$http', 'API_URL', function($http, API_URL){
|
.state('options.challenges.detail', {
|
||||||
// TODO come up with more unified ngResource-style approach
|
url: '/:cid',
|
||||||
return $http.get(API_URL + '/api/v1/groups?minimal=true');
|
templateUrl: 'partials/options.challenges.detail.html',
|
||||||
}],
|
// resolve: {
|
||||||
challenges: ['Challenges', function(Challenges){
|
// challenge: ['$scope', 'Challenges', '$stateParams', '$q',
|
||||||
return Challenges.Challenge.query();
|
// function($scope, Challenges, $stateParams, $q){
|
||||||
}]
|
// // FIXME does ui-router not work with ng-resource by default?
|
||||||
}
|
// var challenge = $q.defer();
|
||||||
|
// Challenges.Challenge.get({cid:$stateParams.cid}, function(_challenge){
|
||||||
|
// challenge._locked = true;
|
||||||
|
// challenge.resolve(_challenge);
|
||||||
|
// });
|
||||||
|
// return challenge.promise;
|
||||||
|
// }]
|
||||||
|
// }
|
||||||
})
|
})
|
||||||
|
|
||||||
// Options > Settings
|
// Options > Settings
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
habitrpg.controller("ChallengesCtrl", ['$scope', 'User', 'Challenges', 'Notification', '$compile', 'groups', 'challenges',
|
habitrpg.controller("ChallengesCtrl", ['$scope', 'User', 'Challenges', 'Notification', '$compile', 'Groups',
|
||||||
function($scope, User, Challenges, Notification, $compile, groups, challenges) {
|
function($scope, User, Challenges, Notification, $compile, Groups) {
|
||||||
|
|
||||||
// groups & challenges are loaded as `resolve` via ui-router (see app.js)
|
// FIXME get this from cache
|
||||||
$scope.groups = groups;
|
Groups.Group.query(function(groups){
|
||||||
$scope.challenges = challenges;
|
groups.tavern[0].name = 'Tavern';
|
||||||
|
$scope.groups = groups.party.concat(groups.guilds).concat(groups.tavern);
|
||||||
|
});
|
||||||
|
// FIXME $scope.challenges needs to be resolved first (see app.js)
|
||||||
|
$scope.challenges = Challenges.Challenge.query();
|
||||||
|
// we should fix this, that's pretty brittle
|
||||||
|
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
// Challenge
|
// Challenge
|
||||||
|
|||||||
@@ -17,26 +17,39 @@ var api = module.exports;
|
|||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
api.list = function(req, res) {
|
||||||
|
var user = res.locals.user;
|
||||||
|
Challenge.find({
|
||||||
|
$or:[
|
||||||
|
{leader: user._id},
|
||||||
|
{members:{$in:[user._id]}},
|
||||||
|
{group: 'habitrpg'}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.select('name description memberCount groups')
|
||||||
|
.populate('groups', '_id name')
|
||||||
|
.exec(function(err, challenges){
|
||||||
|
if (err) return res.json(500,{err:err});
|
||||||
|
res.json(challenges);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// GET
|
// GET
|
||||||
api.get = function(req, res) {
|
api.get = function(req, res) {
|
||||||
var user = res.locals.user;
|
var user = res.locals.user;
|
||||||
Challenge.find({$or:[{leader: user._id}, {members:{$in:[user._id]}}]})
|
Challenge.findById(req.params.cid)
|
||||||
.populate('members', 'profile.name habits dailys rewards todos')
|
.populate('members', 'profile.name habits dailys rewards todos')
|
||||||
.exec(function(err, challenges){
|
.exec(function(err, challenge){
|
||||||
if(err) return res.json(500, {err:err});
|
if(err) return res.json(500, {err:err});
|
||||||
|
|
||||||
// slim down the return members' tasks to only the ones in the challenge
|
// slim down the return members' tasks to only the ones in the challenge
|
||||||
_.each(challenges, function(challenge){
|
_.each(challenge.members, function(member){
|
||||||
_.each(challenge.members, function(member){
|
_.each(['habits', 'dailys', 'todos', 'rewards'], function(type){
|
||||||
_.each(['habits', 'dailys', 'todos', 'rewards'], function(type){
|
member[type] = _.where(member[type], function(task){
|
||||||
member[type] = _.where(member[type], function(task){
|
return task.challenge && task.challenge.id == challenge._id;
|
||||||
return task.challenge && task.challenge.id == challenge._id;
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
res.json(challenge);
|
||||||
res.json(challenges);
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ api.getMember = function(req, res) {
|
|||||||
* Fetch groups list. This no longer returns party or tavern, as those can be requested indivdually
|
* Fetch groups list. This no longer returns party or tavern, as those can be requested indivdually
|
||||||
* as /groups/party or /groups/tavern
|
* as /groups/party or /groups/tavern
|
||||||
*/
|
*/
|
||||||
api.getGroups = function(req, res) {
|
api.list = function(req, res) {
|
||||||
var user = res.locals.user;
|
var user = res.locals.user;
|
||||||
var groupFields = 'name description memberCount';
|
var groupFields = 'name description memberCount';
|
||||||
var sort = '-memberCount';
|
var sort = '-memberCount';
|
||||||
@@ -45,7 +45,11 @@ api.getGroups = function(req, res) {
|
|||||||
|
|
||||||
// unecessary given our ui-router setup
|
// unecessary given our ui-router setup
|
||||||
party: function(cb){
|
party: function(cb){
|
||||||
return cb(null, [{}]);
|
Group.findOne({type: 'party', members: {'$in': [user._id]}})
|
||||||
|
.select(groupFields).exec(function(err, party){
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, [party]); // return as an array for consistent ngResource use
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
guilds: function(cb) {
|
guilds: function(cb) {
|
||||||
@@ -70,7 +74,10 @@ api.getGroups = function(req, res) {
|
|||||||
|
|
||||||
// unecessary given our ui-router setup
|
// unecessary given our ui-router setup
|
||||||
tavern: function(cb) {
|
tavern: function(cb) {
|
||||||
return cb(null, [{}]);
|
Group.findById('habitrpg').select(groupFields).exec(function(err, tavern){
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, [tavern]); // return as an array for consistent ngResource use
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}, function(err, results){
|
}, function(err, results){
|
||||||
@@ -83,7 +90,7 @@ api.getGroups = function(req, res) {
|
|||||||
* Get group
|
* Get group
|
||||||
* TODO: implement requesting fields ?fields=chat,members
|
* TODO: implement requesting fields ?fields=chat,members
|
||||||
*/
|
*/
|
||||||
api.getGroup = function(req, res) {
|
api.get = function(req, res) {
|
||||||
var user = res.locals.user;
|
var user = res.locals.user;
|
||||||
var gid = req.params.gid;
|
var gid = req.params.gid;
|
||||||
|
|
||||||
@@ -111,7 +118,7 @@ api.getGroup = function(req, res) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
api.createGroup = function(req, res, next) {
|
api.create = function(req, res, next) {
|
||||||
var group = new Group(req.body);
|
var group = new Group(req.body);
|
||||||
var user = res.locals.user;
|
var user = res.locals.user;
|
||||||
|
|
||||||
@@ -136,7 +143,7 @@ api.createGroup = function(req, res, next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
api.updateGroup = function(req, res, next) {
|
api.update = function(req, res, next) {
|
||||||
var group = res.locals.group;
|
var group = res.locals.group;
|
||||||
var user = res.locals.user;
|
var user = res.locals.user;
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,8 @@ var ChallengeSchema = new Schema({
|
|||||||
//id: group._id
|
//id: group._id
|
||||||
//},
|
//},
|
||||||
timestamp: {type: Date, 'default': Date.now},
|
timestamp: {type: Date, 'default': Date.now},
|
||||||
members: [{type: String, ref: 'User'}]
|
members: [{type: String, ref: 'User'}],
|
||||||
}, {
|
memberCount: [{type: Number, 'default': 0}]
|
||||||
minimize: 'false'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ChallengeSchema.virtual('tasks').get(function () {
|
ChallengeSchema.virtual('tasks').get(function () {
|
||||||
@@ -30,5 +29,10 @@ ChallengeSchema.virtual('tasks').get(function () {
|
|||||||
return tasks;
|
return tasks;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ChallengeSchema.pre('save', function(next){
|
||||||
|
this.memberCount = _.size(this.members);
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
|
||||||
module.exports.schema = ChallengeSchema;
|
module.exports.schema = ChallengeSchema;
|
||||||
module.exports.model = mongoose.model("Challenge", ChallengeSchema);
|
module.exports.model = mongoose.model("Challenge", ChallengeSchema);
|
||||||
@@ -58,10 +58,10 @@ router['delete']('/user', auth.auth, user['delete']);
|
|||||||
router['delete']('/user/tags/:tid', auth.auth, user.deleteTag);
|
router['delete']('/user/tags/:tid', auth.auth, user.deleteTag);
|
||||||
|
|
||||||
/* Groups*/
|
/* Groups*/
|
||||||
router.get('/groups', auth.auth, groups.getGroups);
|
router.get('/groups', auth.auth, groups.list);
|
||||||
router.post('/groups', auth.auth, groups.createGroup);
|
router.post('/groups', auth.auth, groups.create);
|
||||||
router.get('/groups/:gid', auth.auth, groups.getGroup);
|
router.get('/groups/:gid', auth.auth, groups.get);
|
||||||
router.post('/groups/:gid', auth.auth, groups.attachGroup, groups.updateGroup);
|
router.post('/groups/:gid', auth.auth, groups.attachGroup, groups.update);
|
||||||
//DELETE /groups/:gid
|
//DELETE /groups/:gid
|
||||||
|
|
||||||
router.post('/groups/:gid/join', auth.auth, groups.attachGroup, groups.join);
|
router.post('/groups/:gid/join', auth.auth, groups.attachGroup, groups.join);
|
||||||
@@ -84,8 +84,9 @@ router.post('/market/buy', auth.auth, user.marketBuy);
|
|||||||
// Note: while challenges belong to groups, and would therefore make sense as a nested resource
|
// Note: while challenges belong to groups, and would therefore make sense as a nested resource
|
||||||
// (eg /groups/:gid/challenges/:cid), they will also be referenced by users from the "challenges" tab
|
// (eg /groups/:gid/challenges/:cid), they will also be referenced by users from the "challenges" tab
|
||||||
// without knowing which group they belong to. So to prevent unecessary lookups, we have them as a top-level resource
|
// without knowing which group they belong to. So to prevent unecessary lookups, we have them as a top-level resource
|
||||||
router.get('/challenges', auth.auth, challenges.get)
|
router.get('/challenges', auth.auth, challenges.list)
|
||||||
router.post('/challenges', auth.auth, challenges.create)
|
router.post('/challenges', auth.auth, challenges.create)
|
||||||
|
router.get('/challenges/:cid', auth.auth, challenges.get)
|
||||||
router.post('/challenges/:cid', auth.auth, challenges.update)
|
router.post('/challenges/:cid', auth.auth, challenges.update)
|
||||||
router['delete']('/challenges/:cid', auth.auth, challenges['delete'])
|
router['delete']('/challenges/:cid', auth.auth, challenges['delete'])
|
||||||
router.post('/challenges/:cid/join', auth.auth, challenges.join)
|
router.post('/challenges/:cid/join', auth.auth, challenges.join)
|
||||||
|
|||||||
@@ -1,3 +1,27 @@
|
|||||||
|
script(type='text/ng-template', id='partials/options.challenges.detail.html')
|
||||||
|
// Edit button
|
||||||
|
ul.unstyled()
|
||||||
|
li(ng-show='challenge.leader==user._id && challenge._locked')
|
||||||
|
button.btn.btn-default(ng-click='challenge._locked = false') Edit
|
||||||
|
li(ng-hide='challenge._locked')
|
||||||
|
button.btn.btn-primary(ng-click='save(challenge)') Save
|
||||||
|
button.btn.btn-danger(ng-click='delete(challenge)') Delete
|
||||||
|
button.btn.btn-default(ng-click='challenge._locked=true') Cancel
|
||||||
|
|
||||||
|
div(ng-hide='challenge._locked')
|
||||||
|
.-options
|
||||||
|
input.option-content(type='text', ng-model='challenge.name')
|
||||||
|
textarea.option-content(cols='3', placeholder='Description', ng-model='challenge.description')
|
||||||
|
// <input type=number class='option-content' placeholder='Gems Prize' value={@challenge.prize} />
|
||||||
|
hr
|
||||||
|
|
||||||
|
div(ng-if='challenge.description') {{challenge.description}}
|
||||||
|
habitrpg-tasks(obj='challenge', main=false)
|
||||||
|
h3 Statistics
|
||||||
|
div(ng-repeat='member in challenge.members', ng-init='member._locked = true')
|
||||||
|
h4 {{member.profile.name}}
|
||||||
|
habitrpg-tasks(main=false, obj='member')
|
||||||
|
|
||||||
script(type='text/ng-template', id='partials/options.challenges.html')
|
script(type='text/ng-template', id='partials/options.challenges.html')
|
||||||
.row-fluid
|
.row-fluid
|
||||||
.span2.well
|
.span2.well
|
||||||
@@ -47,28 +71,7 @@ script(type='text/ng-template', id='partials/options.challenges.html')
|
|||||||
a.btn.btn-small.btn-success(ng-hide='indexOf(challenge.members, user._id)', ng-click='challenge.$join()')
|
a.btn.btn-small.btn-success(ng-hide='indexOf(challenge.members, user._id)', ng-click='challenge.$join()')
|
||||||
i.icon-ok
|
i.icon-ok
|
||||||
| Subscribe
|
| Subscribe
|
||||||
a.accordion-toggle(data-toggle='collapse', data-target='#accordion-challenge-{{challenge._id}}') {{challenge.name}} (by {{challenge.leader.name}})
|
a.accordion-toggle(ui-sref='options.challenges.detail({cid:challenge._id})') {{challenge.name}} (by {{challenge.leader.name}})
|
||||||
.accordion-body.collapse(id='accordion-challenge-{{challenge._id}}')
|
.accordion-body(ng-class='{collapse: !$stateParams.cid == challenge._id}')
|
||||||
.accordion-inner
|
.accordion-inner(ng-if='$stateParams.cid == challenge._id')
|
||||||
// Edit button
|
div(ui-view)
|
||||||
ul.unstyled()
|
|
||||||
li(ng-show='challenge.leader==user._id && challenge._locked')
|
|
||||||
button.btn.btn-default(ng-click='challenge._locked = false') Edit
|
|
||||||
li(ng-hide='challenge._locked')
|
|
||||||
button.btn.btn-primary(ng-click='save(challenge)') Save
|
|
||||||
button.btn.btn-danger(ng-click='delete(challenge)') Delete
|
|
||||||
button.btn.btn-default(ng-click='challenge._locked=true') Cancel
|
|
||||||
|
|
||||||
div(ng-hide='challenge._locked')
|
|
||||||
.-options
|
|
||||||
input.option-content(type='text', ng-model='challenge.name')
|
|
||||||
textarea.option-content(cols='3', placeholder='Description', ng-model='challenge.description')
|
|
||||||
// <input type=number class='option-content' placeholder='Gems Prize' value={@challenge.prize} />
|
|
||||||
hr
|
|
||||||
|
|
||||||
div(ng-if='challenge.description') {{challenge.description}}
|
|
||||||
habitrpg-tasks(obj='challenge', main=false)
|
|
||||||
h3 Statistics
|
|
||||||
div(ng-repeat='member in challenge.members', ng-init='member._locked = true')
|
|
||||||
h4 {{member.profile.name}}
|
|
||||||
habitrpg-tasks(main=false, obj='member')
|
|
||||||
Reference in New Issue
Block a user