From 86f18e9a5a5bcaf21ec11e457b8ed51a4e3ea229 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Fri, 19 Jun 2015 20:49:24 -0500 Subject: [PATCH] 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 }; }