Api v3 challenge fixes (#7287)

* Fixed join/leave button updates

* Queried only user groups to be available when creating challenges

* Fixed bulk add tasks to challenge

* Synced challenge tasks after leave and join.

* Fixed default selected group

* Fixed challenge member info. Fixed challenge winner selection

* Fixed deleting challenge tasks

* Fixed particiapting filter

* Fixed viewing user progress on challenge

* Updated tests

* Added delete for saved challenge task
This commit is contained in:
Keith Holliday
2016-05-16 14:49:22 -05:00
committed by Matteo Pagliazzi
parent a16bc02167
commit bc44fa062e
8 changed files with 100 additions and 37 deletions

View File

@@ -41,30 +41,36 @@ describe('Challenges Controller', function() {
description: 'You are the owner and member', description: 'You are the owner and member',
leader: user._id, leader: user._id,
members: [user], members: [user],
_isMember: true _isMember: true,
_id: 'ownMem-id',
}); });
ownNotMem = specHelper.newChallenge({ ownNotMem = specHelper.newChallenge({
description: 'You are the owner, but not a member', description: 'You are the owner, but not a member',
leader: user._id, leader: user._id,
members: [], members: [],
_isMember: false _isMember: false,
_id: 'ownNotMem-id',
}); });
notOwnMem = specHelper.newChallenge({ notOwnMem = specHelper.newChallenge({
description: 'Not owner but a member', description: 'Not owner but a member',
leader: {_id:"test"}, leader: {_id:"test"},
members: [user], members: [user],
_isMember: true _isMember: true,
_id: 'notOwnMem-id',
}); });
notOwnNotMem = specHelper.newChallenge({ notOwnNotMem = specHelper.newChallenge({
description: 'Not owner or member', description: 'Not owner or member',
leader: {_id:"test"}, leader: {_id:"test"},
members: [], members: [],
_isMember: false _isMember: false,
_id: 'notOwnNotMem-id',
}); });
user.challenges = [ownMem._id, notOwnMem._id];
scope.search = { scope.search = {
group: _.transform(groups, function(m,g){m[g._id]=true;}) group: _.transform(groups, function(m,g){m[g._id]=true;})
}; };

View File

@@ -81,7 +81,7 @@ describe('challengeServices', function() {
it('calls select challenge winner endpoint', function() { it('calls select challenge winner endpoint', function() {
var challengeId = 1; var challengeId = 1;
var winnerId = 2; var winnerId = 2;
$httpBackend.expectPOST(apiV3Prefix + '/challenges/' + challengeId + 'selectWinner/' + winnerId).respond({}); $httpBackend.expectPOST(apiV3Prefix + '/challenges/' + challengeId + '/selectWinner/' + winnerId).respond({});
challenges.selectChallengeWinner(challengeId, winnerId); challenges.selectChallengeWinner(challengeId, winnerId);
$httpBackend.flush(); $httpBackend.flush();
}); });

View File

@@ -184,8 +184,8 @@ window.habitrpg = angular.module('habitrpg',
url: '/:cid', url: '/:cid',
templateUrl: 'partials/options.social.challenges.detail.html', templateUrl: 'partials/options.social.challenges.detail.html',
title: env.t('titleChallenges'), title: env.t('titleChallenges'),
controller: ['$scope', 'Challenges', '$stateParams', 'Tasks', controller: ['$scope', 'Challenges', '$stateParams', 'Tasks', 'Members',
function ($scope, Challenges, $stateParams, Tasks) { function ($scope, Challenges, $stateParams, Tasks, Members) {
Challenges.getChallenge($stateParams.cid) Challenges.getChallenge($stateParams.cid)
.then(function (response) { .then(function (response) {
$scope.obj = $scope.challenge = response.data.data; $scope.obj = $scope.challenge = response.data.data;
@@ -198,6 +198,11 @@ window.habitrpg = angular.module('habitrpg',
if (!$scope.challenge[element.type + 's']) $scope.challenge[element.type + 's'] = []; if (!$scope.challenge[element.type + 's']) $scope.challenge[element.type + 's'] = [];
$scope.challenge[element.type + 's'].push(element); $scope.challenge[element.type + 's'].push(element);
}) })
return Members.getChallengeMembers($scope.challenge._id);
})
.then(function (response) {
$scope.challenge.members = response.data.data;
}); });
}] }]
}) })
@@ -226,11 +231,22 @@ window.habitrpg = angular.module('habitrpg',
url: '/:uid', url: '/:uid',
templateUrl: 'partials/options.social.challenges.detail.member.html', templateUrl: 'partials/options.social.challenges.detail.member.html',
title: env.t('titleChallenges'), title: env.t('titleChallenges'),
controller: ['$scope', 'Challenges', '$stateParams', controller: ['$scope', 'Members', '$stateParams',
function($scope, Challenges, $stateParams){ function($scope, Members, $stateParams){
$scope.obj = Challenges.Challenge.getMember({cid:$stateParams.cid, uid:$stateParams.uid}, function(){ Members.getChallengeMemberProgress($stateParams.cid, $stateParams.uid)
$scope.obj._locked = true; .then(function(response) {
}); $scope.obj = response.data.data;
$scope.obj.habits = [];
$scope.obj.todos = [];
$scope.obj.dailys = [];
$scope.obj.rewards = [];
$scope.obj.tasks.forEach(function (element, index, array) {
$scope.obj[element.type + 's'].push(element)
});
$scope.obj._locked = true;
});
}] }]
}) })

View File

@@ -11,7 +11,7 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
// FIXME $scope.challenges needs to be resolved first (see app.js) // FIXME $scope.challenges needs to be resolved first (see app.js)
$scope.groups = []; $scope.groups = [];
Groups.Group.getGroups('party,publicGuilds,privateGuilds,tavern') Groups.Group.getGroups('party,guilds,tavern')
.then(function (response) { .then(function (response) {
$scope.groups = response.data.data; $scope.groups = response.data.data;
}); });
@@ -40,7 +40,6 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
* Create * Create
*/ */
$scope.create = function() { $scope.create = function() {
//If the user has one filter selected, assume that the user wants to default to that group //If the user has one filter selected, assume that the user wants to default to that group
var defaultGroup; var defaultGroup;
//Our filters contain all groups, but we only want groups that have atleast one challenge //Our filters contain all groups, but we only want groups that have atleast one challenge
@@ -49,12 +48,12 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
var filterCount = 0; var filterCount = 0;
for ( var i = 0; i < len; i += 1 ) { for ( var i = 0; i < len; i += 1 ) {
if ( $scope.search.group[groupsWithChallenges[i]] == true ) { if ($scope.search.group[groupsWithChallenges[i]] === true) {
filterCount += 1; filterCount += 1;
defaultGroup = groupsWithChallenges[i]; defaultGroup = groupsWithChallenges[i];
} }
if (filterCount > 1) {
defaultGroup = $scope.groups[0]._id if (filterCount >= 1 && defaultGroup) {
break; break;
} }
} }
@@ -200,7 +199,7 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
if (!challenge.winner) return; if (!challenge.winner) return;
if (!confirm(window.env.t('youSure'))) return; if (!confirm(window.env.t('youSure'))) return;
Challenges.selectWinner(challenge._id, challenge.winner) Challenges.selectChallengeWinner(challenge._id, challenge.winner)
.then(function (response) { .then(function (response) {
$scope.popoverEl.popover('destroy'); $scope.popoverEl.popover('destroy');
_backToChallenges(); _backToChallenges();
@@ -239,7 +238,7 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
//------------------------------------------------------------ //------------------------------------------------------------
// Tasks // Tasks
//------------------------------------------------------------ //------------------------------------------------------------
$scope.addTask = function(addTo, listDef, challenge) { function addTask (addTo, listDef, challenge) {
var task = Shared.taskDefaults({text: listDef.newTask, type: listDef.type}); var task = Shared.taskDefaults({text: listDef.newTask, type: listDef.type});
//If the challenge has not been created, we bulk add tasks on save //If the challenge has not been created, we bulk add tasks on save
if (challenge._id) Tasks.createChallengeTasks(challenge._id, task); if (challenge._id) Tasks.createChallengeTasks(challenge._id, task);
@@ -248,9 +247,25 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
delete listDef.newTask; delete listDef.newTask;
}; };
$scope.addTask = function(addTo, listDef, challenge) {
if (listDef.bulk) {
var tasks = listDef.newTask.split(/[\n\r]+/);
//Reverse the order of tasks so the tasks will appear in the order the user entered them
tasks.reverse();
_.each(tasks, function(t) {
listDef.newTask = t;
addTask(addTo, listDef, challenge);
});
listDef.bulk = false;
} else {
addTask(addTo, listDef, challenge);
}
}
$scope.removeTask = function(task, challenge) { $scope.removeTask = function(task, challenge) {
if (!confirm(window.env.t('sureDelete', {taskType: window.env.t(task.type), taskText: task.text}))) return; if (!confirm(window.env.t('sureDelete', {taskType: window.env.t(task.type), taskText: task.text}))) return;
Tasks.deleteTask(task._id); //We only pass to the api if the challenge exists, otherwise, the tasks only exist on the client
if (challenge._id) Tasks.deleteTask(task._id);
var index = challenge[task.type + 's'].indexOf(task); var index = challenge[task.type + 's'].indexOf(task);
challenge[task.type + 's'].splice(index, 1); challenge[task.type + 's'].splice(index, 1);
}; };
@@ -260,6 +275,14 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
// TODO persist // TODO persist
} }
$scope.toggleBulk = function(list) {
if (typeof list.bulk === 'undefined') {
list.bulk = false;
}
list.bulk = !list.bulk;
list.focus = true;
};
/* /*
-------------------------- --------------------------
Subscription Subscription
@@ -269,7 +292,13 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
$scope.join = function (challenge) { $scope.join = function (challenge) {
Challenges.joinChallenge(challenge._id) Challenges.joinChallenge(challenge._id)
.then(function (response) { .then(function (response) {
_getChallenges() User.user.challenges.push(challenge._id);
_getChallenges();
return Tasks.getUserTasks();
})
.then(function (response) {
var tasks = response.data.data;
User.syncUserTasks(tasks);
}); });
} }
@@ -279,7 +308,14 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
} else { } else {
Challenges.leaveChallenge($scope.selectedChal._id, keep) Challenges.leaveChallenge($scope.selectedChal._id, keep)
.then(function (response) { .then(function (response) {
_getChallenges() var index = User.user.challenges.indexOf($scope.selectedChal._id);
delete User.user.challenges[index];
_getChallenges();
return Tasks.getUserTasks();
})
.then(function (response) {
var tasks = response.data.data;
User.syncUserTasks(tasks);
}); });
} }
$scope.popoverEl.popover('destroy'); $scope.popoverEl.popover('destroy');
@@ -369,7 +405,7 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
$scope.groupsFilter = _.uniq(_.pluck($scope.challenges, 'group'), function(g) {return g._id}); $scope.groupsFilter = _.uniq(_.pluck($scope.challenges, 'group'), function(g) {return g._id});
$scope.search = { $scope.search = {
group: _.transform($scope.groups, function(m,g){ m[g._id] = true;}), group: _.transform($scope.groups, function(m,g) { m[g._id] = true;}),
_isMember: "either", _isMember: "either",
_isOwner: "either" _isOwner: "either"
}; };
@@ -407,7 +443,7 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
var groupSelected = $scope.search.group[chal.group._id]; var groupSelected = $scope.search.group[chal.group._id];
var checkOwner = $scope.search._isOwner === 'either' || (userIsOwner === $scope.search._isOwner); var checkOwner = $scope.search._isOwner === 'either' || (userIsOwner === $scope.search._isOwner);
var checkMember = $scope.search._isMember === 'either' || (chal._isMember === $scope.search._isMember); var checkMember = $scope.search._isMember === 'either' || ($scope.isUserMemberOf(chal) === $scope.search._isMember);
return groupSelected && checkOwner && checkMember; return groupSelected && checkOwner && checkMember;
} }

View File

@@ -76,7 +76,7 @@ angular.module('habitrpg')
function selectChallengeWinner (challengeId, winnerId) { function selectChallengeWinner (challengeId, winnerId) {
return $http({ return $http({
method: 'POST', method: 'POST',
url: apiV3Prefix + '/challenges/' + challengeId + 'selectWinner/' + winnerId, url: apiV3Prefix + '/challenges/' + challengeId + '/selectWinner/' + winnerId,
}); });
} }

View File

@@ -45,6 +45,16 @@ angular.module('habitrpg')
user._wrapped = false; user._wrapped = false;
function syncUserTasks (tasks) {
user.habits = [];
user.todos = [];
user.dailys = [];
user.rewards = [];
tasks.forEach(function (element, index, array) {
user[element.type + 's'].push(element)
});
}
function sync() { function sync() {
return $http({ return $http({
method: "GET", method: "GET",
@@ -76,14 +86,7 @@ angular.module('habitrpg')
}) })
.then(function (response) { .then(function (response) {
var tasks = response.data.data; var tasks = response.data.data;
user.habits = []; syncUserTasks(tasks);
user.todos = [];
user.dailys = [];
user.rewards = [];
tasks.forEach(function (element, index, array) {
user[element.type + 's'].push(element)
})
save(); save();
$rootScope.$emit('userSynced'); $rootScope.$emit('userSynced');
}); });
@@ -496,6 +499,8 @@ angular.module('habitrpg')
return sync(); return sync();
}, },
syncUserTasks: syncUserTasks,
save: save, save: save,
settings: settings settings: settings

View File

@@ -178,7 +178,7 @@ script(type='text/ng-template', id='partials/options.social.challenges.html')
// Challenges list // Challenges list
.panel-group .panel-group
.panel.panel-default(ng-repeat='challenge in challenges|filter:filterChallenges track by challenge._id ') .panel.panel-default(ng-repeat='challenge in challenges | filter:filterChallenges track by challenge._id ')
.panel-heading .panel-heading
ul.pull-right.challenge-accordion-header-specs ul.pull-right.challenge-accordion-header-specs
li.bg-transparent(ng-if='challenge.official') li.bg-transparent(ng-if='challenge.official')
@@ -199,10 +199,10 @@ script(type='text/ng-template', id='partials/options.social.challenges.html')
p!=env.t('prizeValue', {gemcount: "{{challenge.prize}}", gemicon: "<span class='inline-block Pet_Currency_Gem1x'></span>"}) p!=env.t('prizeValue', {gemcount: "{{challenge.prize}}", gemicon: "<span class='inline-block Pet_Currency_Gem1x'></span>"})
li.bg-transparent li.bg-transparent
// leave / join // leave / join
a.btn.btn-sm.btn-danger(ng-show='::isUserMemberOf(challenge)', ng-click='clickLeave(challenge, $event)') a.btn.btn-sm.btn-danger(ng-show='isUserMemberOf(challenge)', ng-click='clickLeave(challenge, $event)')
span.glyphicon.glyphicon-ban-circle span.glyphicon.glyphicon-ban-circle
=env.t('leave') =env.t('leave')
a.btn.btn-sm.btn-success(ng-hide='::isUserMemberOf(challenge)', ng-click='join(challenge)') a.btn.btn-sm.btn-success(ng-hide='isUserMemberOf(challenge)', ng-click='join(challenge)')
span.glyphicon.glyphicon-ok span.glyphicon.glyphicon-ok
=env.t('join') =env.t('join')
a.accordion-toggle(id="{{challenge._id}}" ng-click='toggle(challenge._id)') a.accordion-toggle(id="{{challenge._id}}" ng-click='toggle(challenge._id)')

View File

@@ -43,7 +43,7 @@
span.glyphicon.glyphicon-bullhorn(tooltip=env.t('challenge')) span.glyphicon.glyphicon-bullhorn(tooltip=env.t('challenge'))
| &nbsp; | &nbsp;
// delete // delete
a(ng-if='!task.challenge.id', ng-click='removeTask(task, $index)', tooltip=env.t('delete')) a(ng-if='!task.challenge.id || obj.leader._id === User.user._id', ng-click='removeTask(task, obj)', tooltip=env.t('delete'))
span.glyphicon.glyphicon-trash span.glyphicon.glyphicon-trash
| &nbsp; | &nbsp;