From 7890abe31a09346c467f661701a6714c7f5fe74f Mon Sep 17 00:00:00 2001 From: TheHollidayInn Date: Mon, 13 Apr 2015 16:01:12 -0500 Subject: [PATCH 1/9] Added clone ability to challenges. --- common/locales/en/challenge.json | 5 ++- .../public/js/controllers/challengesCtrl.js | 40 +++++++++++++++++++ website/views/options/social/challenges.jade | 1 + 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/common/locales/en/challenge.json b/common/locales/en/challenge.json index ff0a4e8e6e..122cbe70f2 100644 --- a/common/locales/en/challenge.json +++ b/common/locales/en/challenge.json @@ -52,7 +52,8 @@ "challengedOwnedFilterHeader": "Ownership", "challengedOwnedFilter": "Owned", "challengedNotOwnedFilter": "Not Owned", - "challengedEitherOwnedFilter": "Either", + "challengedEitherOwnedFilter": "Either",, "backToChallenges": "Back to all challenges", - "prizeValue": "<%= gemcount %> <%= gemicon %> Prize" + "prizeValue": "<%= gemcount %> <%= gemicon %> Prize", + "clone": "Clone" } diff --git a/website/public/js/controllers/challengesCtrl.js b/website/public/js/controllers/challengesCtrl.js index a9d30bc506..c3d1ef1e0c 100644 --- a/website/public/js/controllers/challengesCtrl.js +++ b/website/public/js/controllers/challengesCtrl.js @@ -89,6 +89,46 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', }); }; + /** + * Clone + */ + $scope.clone = function(challenge) { + //We need to clone habits, dailys, todos, and rewards. They each need a new id and entry in the database + var clonedTasks = { + habit: [], + daily: [], + todo: [], + reward: [] + }; + + function cloneTask(element, index, array) { + var task = Shared.taskDefaults({text: element.text, type: element.type}); + clonedTasks[element.type].push(task); + } + + challenge.habits.forEach(cloneTask); + challenge.dailys.forEach(cloneTask); + challenge.todos.forEach(cloneTask); + challenge.rewards.forEach(cloneTask); + + //Use values from inc challenge. The reasons we don't use the whole challenge object is because + //Values like timestamp and memebers shouldn't be copied. + $scope.obj = $scope.newChallenge = new Challenges.Challenge({ + name: challenge.name, + shortName: challenge.shortName, + description: challenge.description, + habits: clonedTasks.habit, + dailys: clonedTasks.daily, + todos: clonedTasks.todo, + rewards: clonedTasks.reward, + leader: User.user._id, + group: challenge.group._id, + timestamp: +(new Date), + members: [], + official: false + }); + }; + /** * Save */ diff --git a/website/views/options/social/challenges.jade b/website/views/options/social/challenges.jade index 4791fd0170..997c9c25d7 100644 --- a/website/views/options/social/challenges.jade +++ b/website/views/options/social/challenges.jade @@ -25,6 +25,7 @@ script(type='text/ng-template', id='partials/options.social.challenges.detail.ht div(bindonce='challenge', ng-if='challenge.leader._id==user._id') div(ng-hide='challenge._locked==false') button.btn.btn-sm.btn-default(ng-click='edit(challenge)')=env.t('edit') + button.btn.btn-sm.btn-default(ng-click='clone(challenge)')=env.t('clone') button.btn.btn-sm.btn-warning(ng-click='close(challenge, $event)', tooltip=env.t('deleteOrSelect'))=env.t('endChallenge') form(ng-show='challenge._locked==false') From c3307dd6841cd0efb641e8c460f5d0325fecc44d Mon Sep 17 00:00:00 2001 From: TheHollidayInn Date: Sat, 13 Jun 2015 20:30:52 -0500 Subject: [PATCH 2/9] Added clone challenge test --- test/spec/controllers/challengesCtrlSpec.js | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/spec/controllers/challengesCtrlSpec.js b/test/spec/controllers/challengesCtrlSpec.js index 1982786609..836ebbd3f2 100644 --- a/test/spec/controllers/challengesCtrlSpec.js +++ b/test/spec/controllers/challengesCtrlSpec.js @@ -182,4 +182,33 @@ describe('Challenges Controller', function() { }); }); }); + + it('Clones a challenge', function() { + var copyChallenge = new challenges.Challenge({ + name: 'copyChallenge', + description: 'copyChallenge', + habits: [], + dailys: [], + todos: [], + rewards: [], + leader: user._id, + group: "copyGroup", + timestamp: +(new Date), + members: [user], + official: false, + _isMember: true + }); + scope.clone(copyChallenge) + + expect( scope.obj.name ).to.eql(copyChallenge.name ); + expect( scope.obj.description ).to.eql(copyChallenge.description ); + expect( scope.obj.habits ).to.eql(copyChallenge.habits ); + expect( scope.obj.dailys ).to.eql(copyChallenge.dailys ); + expect( scope.obj.todos ).to.eql(copyChallenge.todos ); + expect( scope.obj.rewards ).to.eql(copyChallenge.rewards ); + expect( scope.obj.leader ).to.eql(copyChallenge.leader ); + expect( scope.obj.official ).to.eql(copyChallenge.official ); + + }); + }); From 9ed3fbf613a6311b1aab3c7047304dfa93d241a8 Mon Sep 17 00:00:00 2001 From: TheHollidayInn Date: Sun, 14 Jun 2015 19:23:21 -0500 Subject: [PATCH 3/9] Clone gems, all task info, and spacing. --- .../public/js/controllers/challengesCtrl.js | 63 ++++++++++--------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/website/public/js/controllers/challengesCtrl.js b/website/public/js/controllers/challengesCtrl.js index c3d1ef1e0c..b81b8b8340 100644 --- a/website/public/js/controllers/challengesCtrl.js +++ b/website/public/js/controllers/challengesCtrl.js @@ -93,40 +93,41 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', * Clone */ $scope.clone = function(challenge) { - //We need to clone habits, dailys, todos, and rewards. They each need a new id and entry in the database - var clonedTasks = { - habit: [], - daily: [], - todo: [], - reward: [] - }; + //We need to clone habits, dailys, todos, and rewards. They each need a new id and entry in the database + var clonedTasks = { + habit: [], + daily: [], + todo: [], + reward: [] + }; - function cloneTask(element, index, array) { - var task = Shared.taskDefaults({text: element.text, type: element.type}); - clonedTasks[element.type].push(task); - } + function cloneTask(element, index, array) { + var task = Shared.taskDefaults(element); + clonedTasks[element.type].push(task); + } - challenge.habits.forEach(cloneTask); - challenge.dailys.forEach(cloneTask); - challenge.todos.forEach(cloneTask); - challenge.rewards.forEach(cloneTask); + challenge.habits.forEach(cloneTask); + challenge.dailys.forEach(cloneTask); + challenge.todos.forEach(cloneTask); + challenge.rewards.forEach(cloneTask); - //Use values from inc challenge. The reasons we don't use the whole challenge object is because - //Values like timestamp and memebers shouldn't be copied. - $scope.obj = $scope.newChallenge = new Challenges.Challenge({ - name: challenge.name, - shortName: challenge.shortName, - description: challenge.description, - habits: clonedTasks.habit, - dailys: clonedTasks.daily, - todos: clonedTasks.todo, - rewards: clonedTasks.reward, - leader: User.user._id, - group: challenge.group._id, - timestamp: +(new Date), - members: [], - official: false - }); + //Use values from inc challenge. The reasons we don't use the whole challenge object is because + //Values like timestamp and memebers shouldn't be copied. + $scope.obj = $scope.newChallenge = new Challenges.Challenge({ + name: challenge.name, + shortName: challenge.shortName, + description: challenge.description, + habits: clonedTasks.habit, + dailys: clonedTasks.daily, + todos: clonedTasks.todo, + rewards: clonedTasks.reward, + leader: User.user._id, + group: challenge.group._id, + timestamp: +(new Date), + members: [], + official: false, + prize: challenge.prize + }); }; /** From b81024bdd681f569cd8e25bd5edcce9e5e451ea7 Mon Sep 17 00:00:00 2001 From: TheHollidayInn Date: Mon, 15 Jun 2015 19:46:28 -0500 Subject: [PATCH 4/9] Fixed task clone functionality and updated code organization/semantics --- test/spec/controllers/challengesCtrlSpec.js | 78 +++++++++++++------ .../public/js/controllers/challengesCtrl.js | 16 ++-- website/views/options/social/challenges.jade | 2 +- 3 files changed, 65 insertions(+), 31 deletions(-) diff --git a/test/spec/controllers/challengesCtrlSpec.js b/test/spec/controllers/challengesCtrlSpec.js index 836ebbd3f2..49561238d9 100644 --- a/test/spec/controllers/challengesCtrlSpec.js +++ b/test/spec/controllers/challengesCtrlSpec.js @@ -183,31 +183,61 @@ describe('Challenges Controller', function() { }); }); - it('Clones a challenge', function() { - var copyChallenge = new challenges.Challenge({ - name: 'copyChallenge', - description: 'copyChallenge', - habits: [], - dailys: [], - todos: [], - rewards: [], - leader: user._id, - group: "copyGroup", - timestamp: +(new Date), - members: [user], - official: false, - _isMember: true - }); - scope.clone(copyChallenge) + describe('clone', function() { + it('Clones a challenge', function() { - expect( scope.obj.name ).to.eql(copyChallenge.name ); - expect( scope.obj.description ).to.eql(copyChallenge.description ); - expect( scope.obj.habits ).to.eql(copyChallenge.habits ); - expect( scope.obj.dailys ).to.eql(copyChallenge.dailys ); - expect( scope.obj.todos ).to.eql(copyChallenge.todos ); - expect( scope.obj.rewards ).to.eql(copyChallenge.rewards ); - expect( scope.obj.leader ).to.eql(copyChallenge.leader ); - expect( scope.obj.official ).to.eql(copyChallenge.official ); + var copyChallenge = new challenges.Challenge({ + name: 'copyChallenge', + description: 'copyChallenge', + habits: [], + dailys: [], + todos: [], + rewards: [], + leader: user._id, + group: "copyGroup", + timestamp: +(new Date), + members: [user], + official: true, + _isMember: true, + prize: 1 + }); + + copyChallenge.habits = [ + { + _id: "ae2aa6fd-fae4-44bc-940f-11976ee202f3", + id: "ae2aa6fd-fae4-44bc-940f-11976ee202f3", + dateCreated: "2015-06-15T00:18:59.440Z", + down: true, + notes: "", + priority: 1, + text: "test", + type: "habit", + up: true, + value: 0, + } + ]; + scope.clone(copyChallenge) + + expect( scope.newChallenge.name ).to.eql( copyChallenge.name ); + expect( scope.newChallenge.description ).to.eql( copyChallenge.description ); + + for( var property in copyChallenge.habits[0] ) { + if ( property == "_id" || property == "id" ) { + expect( scope.newChallenge.habits[0][property] ).to.not.eql( copyChallenge.habits[0][property] ); + } else { + expect( scope.newChallenge.habits[0][property] ).to.eql( copyChallenge.habits[0][property] ); + } + } + expect( scope.newChallenge.dailys ).to.eql( copyChallenge.dailys ); + expect( scope.newChallenge.todos ).to.eql( copyChallenge.todos ); + expect( scope.newChallenge.rewards ).to.eql( copyChallenge.rewards ); + expect( scope.newChallenge.leader ).to.eql( copyChallenge.leader ); + expect( scope.newChallenge.timestamp ).to.not.eql( copyChallenge.timestamp ); + expect( scope.newChallenge.members ).to.eql( [] ); + expect( scope.newChallenge.official ).to.eql( copyChallenge.official ); + expect( scope.newChallenge.prize ).to.eql( copyChallenge.prize ); + + }); }); diff --git a/website/public/js/controllers/challengesCtrl.js b/website/public/js/controllers/challengesCtrl.js index b81b8b8340..ba284a6146 100644 --- a/website/public/js/controllers/challengesCtrl.js +++ b/website/public/js/controllers/challengesCtrl.js @@ -101,9 +101,15 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', reward: [] }; - function cloneTask(element, index, array) { - var task = Shared.taskDefaults(element); - clonedTasks[element.type].push(task); + function cloneTask(taskToClone, index, array) { + var tmpTask = {}; + for( var property in taskToClone ) { + if ( property !== "_id" && property !== "id" ) { + tmpTask[property] = taskToClone[property]; + } + } + var task = Shared.taskDefaults(tmpTask); + clonedTasks[taskToClone.type].push(task); } challenge.habits.forEach(cloneTask); @@ -111,8 +117,6 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', challenge.todos.forEach(cloneTask); challenge.rewards.forEach(cloneTask); - //Use values from inc challenge. The reasons we don't use the whole challenge object is because - //Values like timestamp and memebers shouldn't be copied. $scope.obj = $scope.newChallenge = new Challenges.Challenge({ name: challenge.name, shortName: challenge.shortName, @@ -125,7 +129,7 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', group: challenge.group._id, timestamp: +(new Date), members: [], - official: false, + official: challenge.official, prize: challenge.prize }); }; diff --git a/website/views/options/social/challenges.jade b/website/views/options/social/challenges.jade index 997c9c25d7..df5bc66f52 100644 --- a/website/views/options/social/challenges.jade +++ b/website/views/options/social/challenges.jade @@ -25,7 +25,7 @@ script(type='text/ng-template', id='partials/options.social.challenges.detail.ht div(bindonce='challenge', ng-if='challenge.leader._id==user._id') div(ng-hide='challenge._locked==false') button.btn.btn-sm.btn-default(ng-click='edit(challenge)')=env.t('edit') - button.btn.btn-sm.btn-default(ng-click='clone(challenge)')=env.t('clone') + button.btn.btn-sm.btn-success(ng-click='clone(challenge)')=env.t('clone') button.btn.btn-sm.btn-warning(ng-click='close(challenge, $event)', tooltip=env.t('deleteOrSelect'))=env.t('endChallenge') form(ng-show='challenge._locked==false') From e9269d332c38fdce4ba34c9484612d7047b05ab8 Mon Sep 17 00:00:00 2001 From: TheHollidayInn Date: Mon, 15 Jun 2015 23:03:28 -0500 Subject: [PATCH 5/9] Removed dateCreated from being cloned in tasks --- test/spec/controllers/challengesCtrlSpec.js | 5 ++--- website/public/js/controllers/challengesCtrl.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/spec/controllers/challengesCtrlSpec.js b/test/spec/controllers/challengesCtrlSpec.js index 49561238d9..b93d28ba85 100644 --- a/test/spec/controllers/challengesCtrlSpec.js +++ b/test/spec/controllers/challengesCtrlSpec.js @@ -216,13 +216,12 @@ describe('Challenges Controller', function() { value: 0, } ]; - scope.clone(copyChallenge) + scope.clone(copyChallenge); expect( scope.newChallenge.name ).to.eql( copyChallenge.name ); expect( scope.newChallenge.description ).to.eql( copyChallenge.description ); - for( var property in copyChallenge.habits[0] ) { - if ( property == "_id" || property == "id" ) { + if ( property == "_id" || property == "id" || property == "dateCreated" ) { expect( scope.newChallenge.habits[0][property] ).to.not.eql( copyChallenge.habits[0][property] ); } else { expect( scope.newChallenge.habits[0][property] ).to.eql( copyChallenge.habits[0][property] ); diff --git a/website/public/js/controllers/challengesCtrl.js b/website/public/js/controllers/challengesCtrl.js index ba284a6146..a2b743d676 100644 --- a/website/public/js/controllers/challengesCtrl.js +++ b/website/public/js/controllers/challengesCtrl.js @@ -104,7 +104,7 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', function cloneTask(taskToClone, index, array) { var tmpTask = {}; for( var property in taskToClone ) { - if ( property !== "_id" && property !== "id" ) { + if ( property !== "_id" && property !== "id" && property !== "dateCreated" ) { tmpTask[property] = taskToClone[property]; } } From 838c912906a68c4eabd046e9adf80566d8b48875 Mon Sep 17 00:00:00 2001 From: TheHollidayInn Date: Wed, 17 Jun 2015 22:22:55 -0500 Subject: [PATCH 6/9] Moved clone tasks function to task service --- common/locales/en/challenge.json | 2 +- .../public/js/controllers/challengesCtrl.js | 23 ++++--------------- website/public/js/services/taskServices.js | 23 ++++++++++++++++--- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/common/locales/en/challenge.json b/common/locales/en/challenge.json index 122cbe70f2..51d55ae69c 100644 --- a/common/locales/en/challenge.json +++ b/common/locales/en/challenge.json @@ -52,7 +52,7 @@ "challengedOwnedFilterHeader": "Ownership", "challengedOwnedFilter": "Owned", "challengedNotOwnedFilter": "Not Owned", - "challengedEitherOwnedFilter": "Either",, + "challengedEitherOwnedFilter": "Either", "backToChallenges": "Back to all challenges", "prizeValue": "<%= gemcount %> <%= gemicon %> Prize", "clone": "Clone" diff --git a/website/public/js/controllers/challengesCtrl.js b/website/public/js/controllers/challengesCtrl.js index a2b743d676..985c0de773 100644 --- a/website/public/js/controllers/challengesCtrl.js +++ b/website/public/js/controllers/challengesCtrl.js @@ -49,8 +49,6 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', }); }; - $scope.editTask = Tasks.editTask; - /** * Create */ @@ -100,22 +98,11 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', todo: [], reward: [] }; - - function cloneTask(taskToClone, index, array) { - var tmpTask = {}; - for( var property in taskToClone ) { - if ( property !== "_id" && property !== "id" && property !== "dateCreated" ) { - tmpTask[property] = taskToClone[property]; - } - } - var task = Shared.taskDefaults(tmpTask); - clonedTasks[taskToClone.type].push(task); - } - - challenge.habits.forEach(cloneTask); - challenge.dailys.forEach(cloneTask); - challenge.todos.forEach(cloneTask); - challenge.rewards.forEach(cloneTask); + + Tasks.cloneTasks(challenge.habits, clonedTasks); + Tasks.cloneTasks(challenge.dailys, clonedTasks); + Tasks.cloneTasks(challenge.todos, clonedTasks); + Tasks.cloneTasks(challenge.rewards, clonedTasks); $scope.obj = $scope.newChallenge = new Challenges.Challenge({ name: challenge.name, diff --git a/website/public/js/services/taskServices.js b/website/public/js/services/taskServices.js index ac13b70641..0796086b52 100644 --- a/website/public/js/services/taskServices.js +++ b/website/public/js/services/taskServices.js @@ -6,10 +6,11 @@ angular tasksFactory.$inject = [ '$rootScope', - 'User' + 'User', + 'Shared' ]; -function tasksFactory($rootScope, User) { +function tasksFactory($rootScope, User, Shared) { function editTask(task) { task._editing = !task._editing; @@ -18,7 +19,23 @@ function tasksFactory($rootScope, User) { if($rootScope.charts[task.id]) $rootScope.charts[task.id] = false; } + function cloneTasks(tasksToClone, arrayWithClonedTasks) { + var len = tasksToClone.length; + for (var i = 0; i < len; i+=1) { + var tmpTask = {}; + var task = tasksToClone[i]; + for( var property in task ) { + if ( property !== "_id" && property !== "id" && property !== "dateCreated" ) { + tmpTask[property] = task[property]; + } + } + var newTask = Shared.taskDefaults(tmpTask); + arrayWithClonedTasks[newTask.type].push(newTask); + } + } + return { - editTask: editTask + editTask: editTask, + cloneTasks: cloneTasks, }; } From caec2d8476761658a8875fd64a84693606c8a8e0 Mon Sep 17 00:00:00 2001 From: TheHollidayInn Date: Wed, 17 Jun 2015 23:04:42 -0500 Subject: [PATCH 7/9] Added editTask function back --- website/public/js/controllers/challengesCtrl.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/public/js/controllers/challengesCtrl.js b/website/public/js/controllers/challengesCtrl.js index 985c0de773..3b4f473217 100644 --- a/website/public/js/controllers/challengesCtrl.js +++ b/website/public/js/controllers/challengesCtrl.js @@ -49,6 +49,8 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', }); }; + $scope.editTask = Tasks.editTask; + /** * Create */ @@ -98,7 +100,7 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', todo: [], reward: [] }; - + Tasks.cloneTasks(challenge.habits, clonedTasks); Tasks.cloneTasks(challenge.dailys, clonedTasks); Tasks.cloneTasks(challenge.todos, clonedTasks); From 86f18e9a5a5bcaf21ec11e457b8ed51a4e3ea229 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Fri, 19 Jun 2015 20:49:24 -0500 Subject: [PATCH 8/9] Refactor clone challenges PR --- test/spec/controllers/challengesCtrlSpec.js | 116 ++++++---- test/spec/services/taskServicesSpec.js | 214 +++++++++++++++++- test/spec/specHelper.js | 187 +++++++++++---- .../public/js/controllers/challengesCtrl.js | 17 +- website/public/js/services/taskServices.js | 41 ++-- 5 files changed, 455 insertions(+), 120 deletions(-) diff --git a/test/spec/controllers/challengesCtrlSpec.js b/test/spec/controllers/challengesCtrlSpec.js index b93d28ba85..47e9d29833 100644 --- a/test/spec/controllers/challengesCtrlSpec.js +++ b/test/spec/controllers/challengesCtrlSpec.js @@ -184,60 +184,78 @@ describe('Challenges Controller', function() { }); describe('clone', function() { - it('Clones a challenge', function() { - var copyChallenge = new challenges.Challenge({ - name: 'copyChallenge', - description: 'copyChallenge', - habits: [], - dailys: [], - todos: [], - rewards: [], - leader: user._id, - group: "copyGroup", - timestamp: +(new Date), - members: [user], - official: true, - _isMember: true, - prize: 1 - }); + var challengeToClone = { + name: 'copyChallenge', + description: 'copyChallenge', + habits: [newHabit()], + dailys: [newDaily()], + todos: [newTodo()], + rewards: [newReward()], + leader: 'unique-user-id', + group: { _id: "copyGroup" }, + timestamp: new Date("October 13, 2014 11:13:00"), + members: ['id', 'another-id'], + official: true, + _isMember: true, + prize: 1 + }; - copyChallenge.habits = [ - { - _id: "ae2aa6fd-fae4-44bc-940f-11976ee202f3", - id: "ae2aa6fd-fae4-44bc-940f-11976ee202f3", - dateCreated: "2015-06-15T00:18:59.440Z", - down: true, - notes: "", - priority: 1, - text: "test", - type: "habit", - up: true, - value: 0, - } - ]; - scope.clone(copyChallenge); + it('Clones the basic challenge info', function() { - expect( scope.newChallenge.name ).to.eql( copyChallenge.name ); - expect( scope.newChallenge.description ).to.eql( copyChallenge.description ); - for( var property in copyChallenge.habits[0] ) { - if ( property == "_id" || property == "id" || property == "dateCreated" ) { - expect( scope.newChallenge.habits[0][property] ).to.not.eql( copyChallenge.habits[0][property] ); - } else { - expect( scope.newChallenge.habits[0][property] ).to.eql( copyChallenge.habits[0][property] ); - } - } - expect( scope.newChallenge.dailys ).to.eql( copyChallenge.dailys ); - expect( scope.newChallenge.todos ).to.eql( copyChallenge.todos ); - expect( scope.newChallenge.rewards ).to.eql( copyChallenge.rewards ); - expect( scope.newChallenge.leader ).to.eql( copyChallenge.leader ); - expect( scope.newChallenge.timestamp ).to.not.eql( copyChallenge.timestamp ); - expect( scope.newChallenge.members ).to.eql( [] ); - expect( scope.newChallenge.official ).to.eql( copyChallenge.official ); - expect( scope.newChallenge.prize ).to.eql( copyChallenge.prize ); + scope.clone(challengeToClone); + expect(scope.newChallenge.name).to.eql(challengeToClone.name); + expect(scope.newChallenge.shortName).to.eql(challengeToClone.shortName); + expect(scope.newChallenge.description).to.eql(challengeToClone.description); + expect(scope.newChallenge.leader).to.eql(user._id); + expect(scope.newChallenge.group).to.eql(challengeToClone.group._id); + expect(scope.newChallenge.official).to.eql(challengeToClone.official); + expect(scope.newChallenge.prize).to.eql(challengeToClone.prize); }); - }); + it('does not clone members', function() { + scope.clone(challengeToClone); + expect(scope.newChallenge.members).to.not.exist; + }); + + it('does not clone timestamp', function() { + scope.clone(challengeToClone); + + expect(scope.newChallenge.timestamp).to.not.exist; + }); + + it('clones habits', function() { + scope.clone(challengeToClone); + + expect(scope.newChallenge.habits.length).to.eql(challengeToClone.habits.length); + expect(scope.newChallenge.habits[0].text).to.eql(challengeToClone.habits[0].text); + expect(scope.newChallenge.habits[0].notes).to.eql(challengeToClone.habits[0].notes); + }); + + it('clones dailys', function() { + scope.clone(challengeToClone); + + expect(scope.newChallenge.dailys.length).to.eql(challengeToClone.dailys.length); + expect(scope.newChallenge.dailys[0].text).to.eql(challengeToClone.dailys[0].text); + expect(scope.newChallenge.dailys[0].notes).to.eql(challengeToClone.dailys[0].notes); + }); + + it('clones todos', function() { + scope.clone(challengeToClone); + + expect(scope.newChallenge.todos.length).to.eql(challengeToClone.todos.length); + expect(scope.newChallenge.todos[0].text).to.eql(challengeToClone.todos[0].text); + expect(scope.newChallenge.todos[0].notes).to.eql(challengeToClone.todos[0].notes); + }); + + it('clones rewards', function() { + scope.clone(challengeToClone); + + expect(scope.newChallenge.rewards.length).to.eql(challengeToClone.rewards.length); + expect(scope.newChallenge.rewards[0].text).to.eql(challengeToClone.rewards[0].text); + expect(scope.newChallenge.rewards[0].notes).to.eql(challengeToClone.rewards[0].notes); + }); + }); }); diff --git a/test/spec/services/taskServicesSpec.js b/test/spec/services/taskServicesSpec.js index fe6cee12cb..de2e326759 100644 --- a/test/spec/services/taskServicesSpec.js +++ b/test/spec/services/taskServicesSpec.js @@ -22,7 +22,7 @@ describe('Tasks Service', function() { var task; beforeEach(function(){ - task = { id: 'task-id' }; // @TODO: replace with task factory + task = newTask(); }); it('toggles the _editing property', function() { @@ -66,4 +66,216 @@ describe('Tasks Service', function() { expect(rootScope.charts[task.id]).to.eql(false); }); }); + + describe('cloneTask', function() { + + context('generic tasks', function() { + it('clones the data from a task', function() { + var task = newTask(); + var clonedTask = tasks.cloneTask(task); + + expect(clonedTask.text).to.eql(task.text); + expect(clonedTask.notes).to.eql(task.notes); + expect(clonedTask.tags.includedTag).to.eql(task.tags.includedTag); + expect(clonedTask.tags.notIncludedTag).to.eql(task.tags.notIncludedTag); + expect(clonedTask.priority).to.eql(task.priority); + expect(clonedTask.attribute).to.eql(task.attribute); + }); + + it('does not clone original task\'s id or _id', function() { + var task = newTask(); + var clonedTask = tasks.cloneTask(task); + + expect(clonedTask.id).to.exist; + expect(clonedTask.id).to.not.eql(task.id); + expect(clonedTask._id).to.exist; + expect(clonedTask._id).to.not.eql(task._id); + }); + + it('does not clone original task\'s dateCreated attribute', function() { + var task = newTask({ + dateCreated: new Date(2014, 5, 1, 1, 1, 1, 1), + }); + var clonedTask = tasks.cloneTask(task); + + expect(clonedTask.dateCreated).to.exist; + expect(clonedTask.dateCreated).to.not.eql(task.dateCreated); + }); + + it('does not clone original task\'s value', function() { + var task = newTask({ + value: 130 + }); + var clonedTask = tasks.cloneTask(task); + + expect(clonedTask.value).to.exist; + expect(clonedTask.value).to.not.eql(task.value); + }); + }); + + context('Habits', function() { + + it('clones a habit', function() { + var habit = newHabit({ + up: true, + down: false + }); + var clonedHabit = tasks.cloneTask(habit); + + expect(clonedHabit.type).to.eql('habit'); + expect(clonedHabit.up).to.eql(habit.up); + expect(clonedHabit.down).to.eql(habit.down); + }); + }); + + context('Dailys', function() { + + it('clones a daily', function() { + var daily = newDaily({ + frequency: 'daily', + everyX: 3, + startDate: new Date(2014, 5, 1, 1, 1, 1, 1), + }); + + var clonedDaily = tasks.cloneTask(daily); + + expect(clonedDaily.type).to.eql('daily'); + expect(clonedDaily.frequency).to.eql(daily.frequency); + expect(clonedDaily.everyX).to.eql(daily.everyX); + expect(clonedDaily.startDate).to.eql(daily.startDate); + }); + + it('does not clone streak', function() { + var daily = newDaily({ + streak: 11 + }); + + var clonedDaily = tasks.cloneTask(daily); + + expect(clonedDaily.streak).to.eql(0); + }); + }); + + context('Todos', function() { + + it('clones a todo', function() { + var todo = newTodo(); + var clonedTodo = tasks.cloneTask(todo); + + expect(clonedTodo.type).to.eql('todo'); + }); + + it('does not clone due date', function() { + var todo = newTodo({ + date: '2015-06-20' + }); + + var clonedTodo = tasks.cloneTask(todo); + + expect(clonedTodo.date).to.not.exist; + }); + + it('does not clone date completed', function() { + var todo = newTodo({ + dateCompleted: new Date() + }); + + var clonedTodo = tasks.cloneTask(todo); + + expect(clonedTodo.dateCompleted).to.not.exist; + }); + }); + + context('Rewards', function() { + + it('clones a reward', function() { + var reward = newReward(); + var clonedReward = tasks.cloneTask(reward); + + expect(clonedReward.type).to.eql('reward'); + }); + + it('does clone a reward\'s value', function() { + var reward = newReward({ + value: 20 + }); + var clonedReward = tasks.cloneTask(reward); + + expect(clonedReward.value).to.eql(reward.value); + }); + }); + + context('complete', function() { + it('does not clone completed status', function() { + var todo = newTodo({ + completed: true + }); + + var clonedTodo = tasks.cloneTask(todo); + + expect(clonedTodo.completed).to.eql(false); + }); + }); + + context('history', function() { + + it('does not clone history', function() { + var habit = newHabit({ + history: [ + { date: Date.now, value: 3.1 }, + { date: Date.now, value: 2.7 } + ] + }); + var clonedHabit = tasks.cloneTask(habit); + + expect(clonedHabit.history).to.be.an.array; + expect(clonedHabit.history).to.be.empty; + }); + }); + + context('checklists', function() { + + it('clones checklist text', function() { + var todo = newTodo({ + checklist: [{ + completed: true, + text: 'checklist 1', + id: 'cl-1' + }, { + completed: false, + text: 'checklist 2', + id: 'cl-2' + }] + }); + + var clonedTodo = tasks.cloneTask(todo); + + expect(clonedTodo.checklist[0].text).to.eql(todo.checklist[0].text); + expect(clonedTodo.checklist[1].text).to.eql(todo.checklist[1].text); + }); + + it('does not clone complete or id attribute of checklist', function() { + var todo = newTodo({ + checklist: [{ + completed: true, + text: 'checklist 1', + id: 'cl-1' + }, { + completed: false, + text: 'checklist 2', + id: 'cl-2' + }] + }); + + var clonedTodo = tasks.cloneTask(todo); + + expect(clonedTodo.checklist[0].completed).to.eql(false); + expect(clonedTodo.checklist[0].id).to.not.eql(todo.checklist[0].id); + expect(clonedTodo.checklist[0].id).to.exist; + expect(clonedTodo.checklist[1].completed).to.eql(false); + expect(clonedTodo.checklist[1].id).to.not.eql(todo.checklist[1].id); + expect(clonedTodo.checklist[1].id).to.exist; + }); + }); + }); }); diff --git a/test/spec/specHelper.js b/test/spec/specHelper.js index 80f5858fe8..7018917165 100644 --- a/test/spec/specHelper.js +++ b/test/spec/specHelper.js @@ -1,49 +1,144 @@ beforeEach(module('habitrpg')); -specHelper = { - newUser: function(){ - var buffs = {per:0, int:0, con:0, str:0, stealth: 0, streaks: false}; - user = { - auth:{timestamps: {}}, - stats: {str:1, con:1, per:1, int:1, mp: 32, class: 'warrior', buffs: buffs, gp: 0}, - items:{ - lastDrop:{count: 0}, - hatchingPotions: {}, - eggs: {}, - food: {}, - pets: {}, - mounts: {}, - gear: {equipped: {}, costume: {}, owned: {}}, - }, - party: { - quest: { - progress: {down: 0} - } - }, - preferences: {}, - dailys: [], - todos: [], - rewards: [], - flags: {}, - filters: {}, - achievements: {}, - }; - return user; - }, - newGroup: function(leader) { - var quest = { progress: { }, active: false }; - group = { - "leader" : leader, - "quest" : quest, - "memberCount" : 1, - "chat" : [], - "privacy" : "public", - "invites" : [], - "members" : [ - leader - ] - }; - return group; - } -}; +function newUser() { + var buffs = {per:0, int:0, con:0, str:0, stealth: 0, streaks: false}; + user = { + auth:{timestamps: {}}, + stats: {str:1, con:1, per:1, int:1, mp: 32, class: 'warrior', buffs: buffs, gp: 0}, + items:{ + lastDrop:{count: 0}, + hatchingPotions: {}, + eggs: {}, + food: {}, + pets: {}, + mounts: {}, + gear: {equipped: {}, costume: {}, owned: {}}, + }, + party: { + quest: { + progress: {down: 0} + } + }, + preferences: {}, + dailys: [], + todos: [], + rewards: [], + flags: {}, + filters: {}, + achievements: {}, + }; + return user; +} +function newGroup(leader) { + var quest = { progress: { }, active: false }; + group = { + "leader" : leader, + "quest" : quest, + "memberCount" : 1, + "chat" : [], + "privacy" : "public", + "invites" : [], + "members" : [ + leader + ] + }; + return group; +} + +function newTask(overrides) { + var task = { + id: 'task-id', + _id: 'task-id', + dateCreated: Date.now, + text: 'task text', + notes: 'task notes', + tags: { }, + value: 0, + priority: 1, + attribute: 'str', + challenge: { } + }; + + for(var key in overrides) { + task[key] = overrides[key]; + } + + return task; +} + +function newHabit(overrides) { + var habit = newTask(); + habit.type = 'habit'; + habit.history = []; + habit.up = true; + habit.down = true; + + for(var key in overrides) { + habit[key] = overrides[key]; + } + + return habit; +} + +function newDaily(overrides) { + var daily = newTask(); + daily.type = 'daily'; + daily.frequency = 'weekly'; + daily.repeat = { + m: true, + t: true, + w: true, + th: true, + f: true, + s: true, + su: true + }; + daily.startDate = Date.now; + daily.history = []; + daily.completed = false; + daily.collapseChecklist = false; + daily.checklist = []; + daily.streak = 0; + + for(var key in overrides) { + daily[key] = overrides[key]; + } + + return daily; +} + +function newTodo(overrides) { + var todo = newTask(); + todo.type = 'todo'; + todo.completed = false; + todo.collapseChecklist = false; + todo.checklist = []; + + for(var key in overrides) { + todo[key] = overrides[key]; + } + + return todo; +} + +function newReward(overrides) { + var reward = newTask(); + reward.type = 'reward'; + + for(var key in overrides) { + reward[key] = overrides[key]; + } + + return reward; +} + +specHelper = { + newUser: newUser, + newGroup: newGroup, + newTask: newTask, + newHabit: newHabit, + newDaily: newDaily, + newTodo: newTodo, + newRward: newReward +} diff --git a/website/public/js/controllers/challengesCtrl.js b/website/public/js/controllers/challengesCtrl.js index 3b4f473217..a7f3f64ec6 100644 --- a/website/public/js/controllers/challengesCtrl.js +++ b/website/public/js/controllers/challengesCtrl.js @@ -50,7 +50,7 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', }; $scope.editTask = Tasks.editTask; - + /** * Create */ @@ -93,7 +93,6 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', * Clone */ $scope.clone = function(challenge) { - //We need to clone habits, dailys, todos, and rewards. They each need a new id and entry in the database var clonedTasks = { habit: [], daily: [], @@ -101,10 +100,9 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', reward: [] }; - Tasks.cloneTasks(challenge.habits, clonedTasks); - Tasks.cloneTasks(challenge.dailys, clonedTasks); - Tasks.cloneTasks(challenge.todos, clonedTasks); - Tasks.cloneTasks(challenge.rewards, clonedTasks); + _(clonedTasks).each(function(val, type) { + challenge[type + 's'].forEach(_cloneTaskAndPush); + }); $scope.obj = $scope.newChallenge = new Challenges.Challenge({ name: challenge.name, @@ -116,11 +114,14 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User', rewards: clonedTasks.reward, leader: User.user._id, group: challenge.group._id, - timestamp: +(new Date), - members: [], official: challenge.official, prize: challenge.prize }); + + function _cloneTaskAndPush(taskToClone) { + var task = Tasks.cloneTask(taskToClone); + clonedTasks[task.type].push(task); + } }; /** diff --git a/website/public/js/services/taskServices.js b/website/public/js/services/taskServices.js index 0796086b52..d3a4a38c48 100644 --- a/website/public/js/services/taskServices.js +++ b/website/public/js/services/taskServices.js @@ -6,11 +6,11 @@ angular tasksFactory.$inject = [ '$rootScope', - 'User', - 'Shared' + 'Shared', + 'User' ]; -function tasksFactory($rootScope, User, Shared) { +function tasksFactory($rootScope, Shared, User) { function editTask(task) { task._editing = !task._editing; @@ -19,23 +19,32 @@ function tasksFactory($rootScope, User, Shared) { if($rootScope.charts[task.id]) $rootScope.charts[task.id] = false; } - function cloneTasks(tasksToClone, arrayWithClonedTasks) { - var len = tasksToClone.length; - for (var i = 0; i < len; i+=1) { - var tmpTask = {}; - var task = tasksToClone[i]; - for( var property in task ) { - if ( property !== "_id" && property !== "id" && property !== "dateCreated" ) { - tmpTask[property] = task[property]; - } - } - var newTask = Shared.taskDefaults(tmpTask); - arrayWithClonedTasks[newTask.type].push(newTask); + function cloneTask(task) { + var clonedTask = _.cloneDeep(task); + clonedTask = _cleanUpTask(clonedTask); + + return Shared.taskDefaults(clonedTask); + } + + function _cleanUpTask(task) { + var keysToRemove = ['_id', 'completed', 'date', 'dateCompleted', 'dateCreated', 'history', 'id', 'streak']; + var cleansedTask = _.omit(task, keysToRemove); + + // Copy checklists but reset to uncomplete and assign new id + _(cleansedTask.checklist).forEach(function(item) { + item.completed = false; + item.id = Shared.uuid(); + }); + + if (cleansedTask.type !== 'reward') { + delete cleansedTask.value; } + + return cleansedTask; } return { editTask: editTask, - cloneTasks: cloneTasks, + cloneTask: cloneTask }; } From f5647ecd76b9b02f186604f3a66f76fb1472e624 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 21 Jun 2015 20:35:45 -0500 Subject: [PATCH 9/9] Wrap task service in anon function --- website/public/js/services/taskServices.js | 85 +++++++++++----------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/website/public/js/services/taskServices.js b/website/public/js/services/taskServices.js index d3a4a38c48..3f968dfa6e 100644 --- a/website/public/js/services/taskServices.js +++ b/website/public/js/services/taskServices.js @@ -1,50 +1,53 @@ 'use strict'; -angular - .module('habitrpg') - .factory('Tasks', tasksFactory); +(function(){ + var TASK_KEYS_TO_REMOVE = ['_id', 'completed', 'date', 'dateCompleted', 'dateCreated', 'history', 'id', 'streak']; -tasksFactory.$inject = [ - '$rootScope', - 'Shared', - 'User' -]; + angular + .module('habitrpg') + .factory('Tasks', tasksFactory); -function tasksFactory($rootScope, Shared, User) { + tasksFactory.$inject = [ + '$rootScope', + 'Shared', + 'User' + ]; - function editTask(task) { - task._editing = !task._editing; - task._tags = !User.user.preferences.tagsCollapsed; - task._advanced = !User.user.preferences.advancedCollapsed; - if($rootScope.charts[task.id]) $rootScope.charts[task.id] = false; - } + function tasksFactory($rootScope, Shared, User) { - function cloneTask(task) { - var clonedTask = _.cloneDeep(task); - clonedTask = _cleanUpTask(clonedTask); - - return Shared.taskDefaults(clonedTask); - } - - function _cleanUpTask(task) { - var keysToRemove = ['_id', 'completed', 'date', 'dateCompleted', 'dateCreated', 'history', 'id', 'streak']; - var cleansedTask = _.omit(task, keysToRemove); - - // Copy checklists but reset to uncomplete and assign new id - _(cleansedTask.checklist).forEach(function(item) { - item.completed = false; - item.id = Shared.uuid(); - }); - - if (cleansedTask.type !== 'reward') { - delete cleansedTask.value; + function editTask(task) { + task._editing = !task._editing; + task._tags = !User.user.preferences.tagsCollapsed; + task._advanced = !User.user.preferences.advancedCollapsed; + if($rootScope.charts[task.id]) $rootScope.charts[task.id] = false; } - return cleansedTask; - } + function cloneTask(task) { + var clonedTask = _.cloneDeep(task); + clonedTask = _cleanUpTask(clonedTask); - return { - editTask: editTask, - cloneTask: cloneTask - }; -} + return Shared.taskDefaults(clonedTask); + } + + function _cleanUpTask(task) { + var cleansedTask = _.omit(task, TASK_KEYS_TO_REMOVE); + + // Copy checklists but reset to uncomplete and assign new id + _(cleansedTask.checklist).forEach(function(item) { + item.completed = false; + item.id = Shared.uuid(); + }); + + if (cleansedTask.type !== 'reward') { + delete cleansedTask.value; + } + + return cleansedTask; + } + + return { + editTask: editTask, + cloneTask: cloneTask + }; + } +})();