diff --git a/lib/app/content.js b/lib/app/content.js deleted file mode 100644 index e8c28ca05b..0000000000 --- a/lib/app/content.js +++ /dev/null @@ -1,215 +0,0 @@ -// Generated by CoffeeScript 1.4.0 - -module.exports = { - defaultTasks: [ - { - type: 'habit', - text: '1h Productive Work', - notes: 'Habits: Constantly Track
For some habits, it only makes sense to gain points (like this one).', - value: 0, - up: true, - down: false - }, { - type: 'habit', - text: 'Eat Junk Food', - notes: 'For others, it only makes sense to lose points', - value: 0, - up: false, - down: true - }, { - type: 'habit', - text: 'Take The Stairs', - notes: 'For the rest, both + and - make sense (stairs = gain, elevator = lose)', - value: 0, - up: true, - down: true - }, { - type: 'daily', - text: '1h Personal Project', - notes: 'Dailies: Complete Once a Day
At the end of each day, non-completed Dailies dock you points.', - value: 0, - completed: false - }, { - type: 'daily', - text: 'Exercise', - notes: "If you are doing well, they turn green and are less valuable (experience, gold) and less damaging (HP). This means you can ease up on them for a bit.", - value: 3, - completed: false - }, { - type: 'daily', - text: '45m Reading', - notes: 'But if you are doing poorly, they turn red. The worse you do, the more valuable (exp, gold) and more damaging (HP) these goals become. This encourages you to focus on your shortcomings, the reds.', - value: -10, - completed: false - }, { - type: 'todo', - text: 'Call Mom', - notes: "Todos: Complete Eventually
Non-completed Todos won't hurt you, but they will become more valuable over time. This will encourage you to wrap up stale Todos.", - value: -3, - completed: false - }, { - type: 'reward', - text: '1 Episode of Game of Thrones', - notes: 'Rewards: Treat Yourself!
As you complete goals, you earn gold to buy rewards. Buy them liberally - rewards are integral in forming good habits.', - value: 20 - }, { - type: 'reward', - text: 'Cake', - notes: 'But only buy if you have enough gold - you lose HP otherwise.', - value: 10 - } - ], - tourSteps: [ - { - element: "#avatar", - title: "Welcome to HabitRPG", - content: "Welcome to HabitRPG, a habit-tracker which treats your goals like a Role Playing Game." - }, { - element: "#bars", - title: "Acheive goals and level up", - content: "As you accomplish goals, you level up. If you fail your goals, you lose hit points. Lose all your HP and you die." - }, { - element: "ul.habits", - title: "Habits", - content: "Habits are goals that you constantly track.", - placement: "bottom" - }, { - element: "ul.dailys", - title: "Dailies", - content: "Dailies are goals that you want to complete once a day.", - placement: "bottom" - }, { - element: "ul.todos", - title: "Todos", - content: "Todos are one-off goals which need to be completed eventually.", - placement: "bottom" - }, { - element: "ul.rewards", - title: "Rewards", - content: "As you complete goals, you earn gold to buy rewards. Buy them liberally - rewards are integral in forming good habits.", - placement: "bottom" - }, { - element: "ul.habits li:first-child", - title: "Hover over comments", - content: "Different task-types have special properties. Hover over each task's comment for more information. When you're ready to get started, delete the existing tasks and add your own.", - placement: "right" - } - ], - items: { - unlockedMessage: { - title: "Item Store Unlocked", - content: "Congradulations, you have unlocked the Item Store! You can now buy weapons, armor, potions, etc. Read each item's comment for more information." - }, - weapon: [ - { - type: 'weapon', - index: 0, - text: "Sword 1", - icon: "item-sword1", - notes: 'Training weapon.', - value: 0 - }, { - type: 'weapon', - index: 1, - text: "Sword 2", - icon: 'item-sword2', - notes: 'Increases experience gain by 3%.', - value: 20 - }, { - type: 'weapon', - index: 2, - text: "Axe", - icon: 'item-axe', - notes: 'Increases experience gain by 6%.', - value: 30 - }, { - type: 'weapon', - index: 3, - text: "Morningstar", - icon: 'item-morningstar', - notes: 'Increases experience gain by 9%.', - value: 45 - }, { - type: 'weapon', - index: 4, - text: "Blue Sword", - icon: 'item-bluesword', - notes: 'Increases experience gain by 12%.', - value: 65 - }, { - type: 'weapon', - index: 5, - text: "Red Sword", - icon: 'item-redsword', - notes: 'Increases experience gain by 15%.', - value: 90 - }, { - type: 'weapon', - index: 6, - text: "Golden Sword", - icon: 'item-goldensword', - notes: 'Increases experience gain by 18%.', - value: 120 - } - ], - armor: [ - { - type: 'armor', - index: 0, - text: "Cloth Armor", - icon: 'item-clotharmor', - notes: 'Training armor.', - value: 0 - }, { - type: 'armor', - index: 1, - text: "Leather Armor", - icon: 'item-leatherarmor', - notes: 'Decreases HP loss by 3%.', - value: 30 - }, { - type: 'armor', - index: 2, - text: "Chain Mail", - icon: 'item-mailarmor', - notes: 'Decreases HP loss by 6%.', - value: 45 - }, { - type: 'armor', - index: 3, - text: "Plate Mail", - icon: 'item-platearmor', - notes: 'Decreases HP loss by 9%.', - value: 65 - }, { - type: 'armor', - index: 4, - text: "Red Armor", - icon: 'item-redarmor', - notes: 'Decreases HP loss by 12%.', - value: 90 - }, { - type: 'armor', - index: 5, - text: "Golden Armor", - icon: 'item-goldenarmor', - notes: 'Decreases HP loss by 15%.', - value: 120 - } - ], - potion: { - type: 'potion', - text: "Potion", - notes: "Recover 15 HP", - value: 25, - icon: 'item-flask' - }, - reroll: { - type: 'reroll', - text: "Re-Roll", - icon: 'favicon', - notes: "Resets your tasks. When you're struggling and everything's red, use for a clean slate.", - value: 0 - } - } -}; diff --git a/lib/app/helpers.js b/lib/app/helpers.js deleted file mode 100644 index 9d908300a3..0000000000 --- a/lib/app/helpers.js +++ /dev/null @@ -1,88 +0,0 @@ -// Generated by CoffeeScript 1.4.0 -var dayMapping, moment; - -moment = require('moment'); - -module.exports.daysBetween = function(a, b) { - return Math.abs(moment(a).sod().diff(moment(b).sod(), 'days')); -}; - -module.exports.dayMapping = dayMapping = { - 0: 'su', - 1: 'm', - 2: 't', - 3: 'w', - 4: 'th', - 5: 'f', - 6: 's', - 7: 'su' -}; - -module.exports.viewHelpers = function(view) { - view.fn('taskClasses', function(type, completed, value, repeat) { - var classes; - classes = type; - if (completed || (repeat && repeat[dayMapping[moment().day()]] === false)) { - classes += " completed"; - } - switch (false) { - case !(value < -8): - classes += ' color-worst'; - break; - case !(value >= -8 && value < -5): - classes += ' color-worse'; - break; - case !(value >= -5 && value < -1): - classes += ' color-bad'; - break; - case !(value >= -1 && value < 1): - classes += ' color-neutral'; - break; - case !(value >= 1 && value < 5): - classes += ' color-good'; - break; - case !(value >= 5 && value < 10): - classes += ' color-better'; - break; - case !(value >= 10): - classes += ' color-best'; - } - return classes; - }); - view.fn("percent", function(x, y) { - if (x === 0) { - x = 1; - } - return Math.round(x / y * 100); - }); - view.fn("round", function(num) { - return Math.round(num); - }); - view.fn("gold", function(num) { - if (num) { - return num.toFixed(1).split('.')[0]; - } else { - return "0"; - } - }); - view.fn("silver", function(num) { - if (num) { - return num.toFixed(1).split('.')[1]; - } else { - return "0"; - } - }); - view.fn("money", function(num) { - if (num) { - return num.toFixed(2); - } else { - return "0.00"; - } - }); - view.fn("lessThan", function(a, b) { - return a < b; - }); - return view.fn("tokens", function(money) { - return money / 0.25; - }); -}; diff --git a/lib/app/index.js b/lib/app/index.js deleted file mode 100644 index f0410f9c3c..0000000000 --- a/lib/app/index.js +++ /dev/null @@ -1,333 +0,0 @@ -// Generated by CoffeeScript 1.4.0 -var content, derby, get, helpers, moment, ready, schema, scoring, view, _, _ref; - -derby = require('derby'); - -_ref = derby.createApp(module), get = _ref.get, view = _ref.view, ready = _ref.ready; - -derby.use(require('derby-ui-boot')); - -derby.use(require('../../ui')); - -moment = require('moment'); - -content = require('./content'); - -scoring = require('./scoring'); - -schema = require('./schema'); - -helpers = require('./helpers'); - -helpers.viewHelpers(view); - -_ = require('underscore'); - -get('/:uid?', function(page, model, _arg, next) { - var req, sess, uid; - uid = _arg.uid; - if (uid) { - if (require('derby-auth/node_modules/guid').isGuid(uid)) { - return page.redirect('/users/' + uid); - } else { - return next(); - } - } - req = page._res.req; - if (req.headers['x-forwarded-proto'] !== 'https' && process.env.NODE_ENV === 'production') { - return page.redirect('https://' + req.headers.host + req.url); - } - sess = model.session; - if (sess.loggedIn) { - model.set('_loggedIn', true); - } - model.set('_userId', sess.userId); - return model.subscribe("users." + sess.userId, function(err, user) { - model.ref('_user', user); - user.setNull('balance', 2); - model.set('_items', { - armor: content.items.armor[parseInt(user.get('items.armor')) + 1], - weapon: content.items.weapon[parseInt(user.get('items.weapon')) + 1], - potion: content.items.potion, - reroll: content.items.reroll - }); - model.refList("_habitList", "_user.tasks", "_user.habitIds"); - model.refList("_dailyList", "_user.tasks", "_user.dailyIds"); - model.refList("_todoList", "_user.tasks", "_user.todoIds"); - model.refList("_completedList", "_user.tasks", "_user.completedIds"); - model.refList("_rewardList", "_user.tasks", "_user.rewardIds"); - _.each(['habitIds', 'dailyIds', 'todoIds', 'rewardIds'], function(path) { - return user.set(path, _.uniq(user.get(path), true)); - }); - model.fn('_user._tnl', '_user.stats.lvl', function(lvl) { - return (lvl * 100) / 5; - }); - return page.render(); - }); -}); - -ready(function(model) { - var setupSortable, step, tour, type, _i, _j, _len, _len1, _ref1, _ref2; - scoring.setModel(model); - $('[rel=tooltip]').tooltip(); - $('[rel=popover]').popover(); - model.on('set', '*', function() { - $('[rel=tooltip]').tooltip(); - return $('[rel=popover]').popover(); - }); - if (!(model.get('_mobileDevice') === true)) { - setupSortable = function(type) { - return $("ul." + type + "s").sortable({ - dropOnEmpty: false, - cursor: "move", - items: "li", - opacity: 0.4, - scroll: true, - axis: 'y', - update: function(e, ui) { - var domId, id, item, to; - item = ui.item[0]; - domId = item.id; - id = item.getAttribute('data-id'); - to = $("ul." + type + "s").children().index(item); - return model.at("_" + type + "List").pass({ - ignore: domId - }).move({ - id: id - }, to); - } - }); - }; - _ref1 = ['habit', 'daily', 'todo', 'reward']; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - type = _ref1[_i]; - setupSortable(type); - } - } - tour = new Tour(); - _ref2 = content.tourSteps; - for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { - step = _ref2[_j]; - tour.addStep({ - element: step.element, - title: step.title, - content: step.content, - placement: step.placement - }); - } - tour.start(); - model.on('set', '_user.tasks.*.completed', function(i, completed, previous, isLocal, passed) { - var direction, from, fromIds, task, to, toIds, _ref3, _ref4; - if ((passed != null) && passed.cron) { - return; - } - direction = function() { - if (completed === true && previous === false) { - return 'up'; - } - if (completed === false && previous === true) { - return 'down'; - } - throw new Error("Direction neither 'up' nor 'down' on checkbox set."); - }; - task = model.at("_user.tasks." + i); - scoring.score(i, direction()); - if (task.get('type') === 'todo') { - _ref3 = direction() === 'up' ? ['todo', 'completed'] : ['completed', 'todo'], from = _ref3[0], to = _ref3[1]; - _ref4 = ["_user." + from + "Ids", "_user." + to + "Ids"], from = _ref4[0], to = _ref4[1]; - fromIds = model.get(from); - fromIds.splice(fromIds.indexOf(i), 1); - model.set(from, fromIds); - toIds = model.get(to); - toIds.push(i); - return model.set(to, toIds); - } - }); - exports.addTask = function(e, el, next) { - var list, newModel, text; - type = $(el).attr('data-task-type'); - list = model.at("_" + type + "List"); - newModel = model.at('_new' + type.charAt(0).toUpperCase() + type.slice(1)); - if (!(text = view.escapeHtml(newModel.get()))) { - return; - } - newModel.set(''); - switch (type) { - case 'habit': - return list.push({ - type: type, - text: text, - notes: '', - value: 0, - up: true, - down: true - }); - case 'reward': - return list.push({ - type: type, - text: text, - notes: '', - value: 20 - }); - case 'daily': - return list.push({ - type: type, - text: text, - notes: '', - value: 0, - repeat: { - su: true, - m: true, - t: true, - w: true, - th: true, - f: true, - s: true - }, - completed: false - }); - case 'todo': - return list.push({ - type: type, - text: text, - notes: '', - value: 0, - completed: false - }); - } - }; - exports.del = function(e, el) { - var history, result, task; - task = model.at(e.target); - history = task.get('history'); - if (history && history.length > 2) { - if (task.get('value') < 0) { - result = confirm("Are you sure? Deleting this task will hurt you (to prevent deleting, then re-creating red tasks)."); - if (result !== true) { - return; - } else { - task.set('type', 'habit'); - scoring.score(task.get('id'), { - direction: 'down' - }); - } - } else { - result = confirm("Are you sure you want to delete this task?"); - if (result !== true) { - return; - } - } - } - $('[rel=tooltip]').tooltip('hide'); - model.del('_user.tasks.' + task.get('id')); - return task.remove(); - }; - exports.clearCompleted = function(e, el) { - return _.each(model.get('_completedList'), function(task) { - model.del('_user.tasks.' + task.id); - return model.set('_user.completedIds', []); - }); - }; - exports.toggleDay = function(e, el) { - var task; - task = model.at(e.target); - if (/active/.test($(el).attr('class'))) { - return task.set('repeat.' + $(el).attr('data-day'), false); - } else { - return task.set('repeat.' + $(el).attr('data-day'), true); - } - }; - exports.toggleTaskEdit = function(e, el) { - var hideId, toggleId; - hideId = $(el).attr('data-hide-id'); - toggleId = $(el).attr('data-toggle-id'); - $(document.getElementById(hideId)).hide(); - return $(document.getElementById(toggleId)).toggle(); - }; - exports.toggleChart = function(e, el) { - var chart, chartSelector, data, date, hideSelector, historyPath, matrix, obj, options, readableDate, _k, _len2, _ref3; - hideSelector = $(el).attr('data-hide-id'); - chartSelector = $(el).attr('data-toggle-id'); - historyPath = $(el).attr('data-history-path'); - $(document.getElementById(hideSelector)).hide(); - $(document.getElementById(chartSelector)).toggle(); - matrix = [['Date', 'Score']]; - _ref3 = model.get(historyPath); - for (_k = 0, _len2 = _ref3.length; _k < _len2; _k++) { - obj = _ref3[_k]; - date = new Date(obj.date); - readableDate = moment(date).format('MM/DD'); - matrix.push([readableDate, obj.value]); - } - data = google.visualization.arrayToDataTable(matrix); - options = { - title: 'History', - backgroundColor: 'whiteSmoke' - }; - chart = new google.visualization.LineChart(document.getElementById(chartSelector)); - return chart.draw(data, options); - }; - exports.buyItem = function(e, el, next) { - var hp, index, money, user, value, _ref3; - user = model.at('_user'); - money = user.get('stats.money'); - _ref3 = [$(el).attr('data-type'), $(el).attr('data-value'), $(el).attr('data-index')], type = _ref3[0], value = _ref3[1], index = _ref3[2]; - if (money < value) { - return; - } - user.set('stats.money', money - value); - if (type === 'armor') { - user.set('items.armor', index); - return model.set('_items.armor', content.items.armor[parseInt(index) + 1]); - } else if (type === 'weapon') { - user.set('items.weapon', index); - return model.set('_items.weapon', content.items.weapon[parseInt(index) + 1]); - } else if (type === 'potion') { - hp = user.get('stats.hp'); - hp += 15; - if (hp > 50) { - hp = 50; - } - return user.set('stats.hp', hp); - } - }; - exports.score = function(e, el, next) { - var direction, task; - direction = $(el).attr('data-direction'); - if (direction === 'true/') { - direction = 'up'; - } - if (direction === 'false/') { - direction = 'down'; - } - task = model.at($(el).parents('li')[0]); - return scoring.score(task.get('id'), direction); - }; - exports.revive = function(e, el) { - var stats; - stats = model.at('_user.stats'); - stats.set('hp', 50); - stats.set('lvl', 1); - stats.set('exp', 0); - stats.set('money', 0); - model.set('_user.items.armor', 0); - model.set('_user.items.weapon', 0); - model.set('_items.armor', content.items.armor[1]); - model.set('_items.weapon', content.items.weapon[1]); - return model.set('_user.balance', model.get('_user.balance') - 0.50); - }; - exports.reset = function(e, el) { - model.set('_user.tasks', {}); - _.each(['habit', 'daily', 'todo', 'completed', 'reward'], function(type) { - model.set("_user." + type + "Ids", []); - return model.refList("_" + type + "List", "_user.tasks", "_user." + type + "Ids"); - }); - model.set('_user.stats.hp', 50); - model.set('_user.stats.money', 0); - model.set('_user.stats.exp', 0); - return model.set('_user.stats.lvl', 1); - }; - setTimeout(scoring.cron, 1); - setInterval(scoring.cron, 3600000); - return require('../server/private').app(exports, model); -}); diff --git a/lib/app/schema.js b/lib/app/schema.js deleted file mode 100644 index 216b3d5acf..0000000000 --- a/lib/app/schema.js +++ /dev/null @@ -1,94 +0,0 @@ -// Generated by CoffeeScript 1.4.0 -var content, moment, userSchema, _; - -content = require('./content'); - -moment = require('moment'); - -_ = require('underscore'); - -userSchema = { - balance: 2, - stats: { - money: 0, - exp: 0, - lvl: 1, - hp: 50 - }, - items: { - itemsEnabled: false, - armor: 0, - weapon: 0 - }, - tasks: {}, - habitIds: [], - dailyIds: [], - todoIds: [], - completedIds: [], - rewardIds: [] -}; - -module.exports.newUserObject = function() { - var guid, newUser, task, _i, _len, _ref; - newUser = require('clone')(userSchema, true); - _ref = content.defaultTasks; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - task = _ref[_i]; - guid = task.id = require('derby/node_modules/racer').uuid(); - newUser.tasks[guid] = task; - switch (task.type) { - case 'habit': - newUser.habitIds.push(guid); - break; - case 'daily': - newUser.dailyIds.push(guid); - break; - case 'todo': - newUser.todoIds.push(guid); - break; - case 'reward': - newUser.rewardIds.push(guid); - } - } - return newUser; -}; - -module.exports.updateSchema = function(model) { - return; - return model.fetch('users', function(err, users) { - return _.each(users.get(), function(userObj) { - var daysOld, sameTasks, user, userPath; - userPath = "users." + userObj._id; - user = model.at(userPath); - if (userObj.lastCron == null) { - model.del(userPath); - return; - } - daysOld = helpers.daysBetween(new Date(), userObj.lastCron); - if (daysOld > 30) { - sameTasks = _.filter(require('./content').defaultTasks, function(defaultTask) { - var foundSame; - foundSame = _.find(userObj.tasks, function(userTask) { - return userTask.text === defaultTask.text; - }); - return foundSame != null; - }); - if (_.size(sameTasks) > 5) { - model.del(userPath); - return; - } - } - user.set('history', { - exp: [], - todos: [] - }); - return _.each(userObj.tasks, function(taskObj) { - var task; - task = user.at("tasks." + taskObj.id); - if (task.get("history")) { - return task.set("history", []); - } - }); - }); - }); -}; diff --git a/lib/app/scoring.js b/lib/app/scoring.js deleted file mode 100644 index 92c4073411..0000000000 --- a/lib/app/scoring.js +++ /dev/null @@ -1,340 +0,0 @@ -// Generated by CoffeeScript 1.4.0 -var MODIFIER, async, content, cron, expModifier, helpers, hpModifier, model, moment, score, setModel, setupNotifications, taskDeltaFormula, updateStats, user, _; - -async = require('async'); - -moment = require('moment'); - -_ = require('underscore'); - -content = require('./content'); - -helpers = require('./helpers'); - -MODIFIER = .03; - -user = void 0; - -model = void 0; - -setModel = function(m) { - model = m; - user = model.at('_user'); - if (!model.get('_mobileDevice')) { - return setupNotifications(); - } -}; - -setupNotifications = function() { - var statsNotification; - if (typeof jQuery === "undefined" || jQuery === null) { - return; - } - statsNotification = function(html, type) { - if (user.get('stats.lvl') === 0) { - return; - } - return $.bootstrapGrowl(html, { - type: type, - top_offset: 20, - align: 'right', - width: 250, - delay: 3000, - allow_dismiss: true, - stackup_spacing: 10 - }); - }; - user.on('set', 'stats.hp', function(captures, args) { - var num, rounded; - num = captures - args; - rounded = Math.abs(num.toFixed(1)); - if (num < 0) { - return statsNotification("HP -" + rounded, 'error'); - } - }); - user.on('set', 'stats.money', function(captures, args) { - var num, rounded; - num = captures - args; - rounded = Math.abs(num.toFixed(1)); - if (num < 0) { - return statsNotification("GP -" + rounded, 'success'); - } else if (num > 0) { - num = Math.abs(num); - return statsNotification("Exp,GP +" + rounded, 'success'); - } - }); - return user.on('set', 'stats.lvl', function(captures, args) { - if (captures > args) { - return statsNotification(' Level Up!', 'info'); - } - }); -}; - -/* -Calculates Exp & GP modification based on weapon & lvl -{value} task.value for gain -{modifiers} may manually pass in stats as {weapon, exp}. This is used for testing -*/ - - -expModifier = function(value, modifiers) { - var dmg, lvl, modified, weapon; - if (modifiers == null) { - modifiers = {}; - } - weapon = modifiers.weapon || user.get('items.weapon'); - lvl = modifiers.lvl || user.get('stats.lvl'); - dmg = weapon * MODIFIER; - dmg += (lvl - 1) * MODIFIER; - modified = value + (value * dmg); - return modified; -}; - -/* -Calculates HP-loss modification based on armor & lvl -{value} task.value which is hurting us -{modifiers} may manually pass in modifier as {armor, lvl}. This is used for testing -*/ - - -hpModifier = function(value, modifiers) { - var ac, armor, lvl, modified; - if (modifiers == null) { - modifiers = {}; - } - armor = modifiers.armor || user.get('items.armor'); - lvl = modifiers.lvl || user.get('stats.lvl'); - ac = armor * MODIFIER; - ac += (lvl - 1) * MODIFIER; - modified = value - (value * ac); - return modified; -}; - -/* -Calculates the next task.value based on direction -For negative values, use a line: something like y=-.1x+1 -For positibe values, taper off with inverse log: y=.9^x -Would love to use inverse log for the whole thing, but after 13 fails it hits infinity. Revisit this formula later -{currentValue} the current value of the task, determines it's next value -{direction} 'up' or 'down' -*/ - - -taskDeltaFormula = function(currentValue, direction) { - var delta, sign; - sign = direction === "up" ? 1 : -1; - delta = currentValue < 0 ? (-0.1 * currentValue + 1) * sign : (Math.pow(0.9, currentValue)) * sign; - return delta; -}; - -updateStats = function(stats) { - var money, tnl; - if (user.get('stats.lvl') === 0) { - return; - } - if (stats.hp != null) { - if (stats.hp <= 0) { - user.set('stats.lvl', 0); - user.set('stast.hp', 0); - return; - } else { - user.set('stats.hp', stats.hp); - } - } - if (stats.exp != null) { - tnl = user.get('_tnl'); - if (stats.exp >= tnl) { - stats.exp -= tnl; - user.set('stats.lvl', user.get('stats.lvl') + 1); - user.set('stats.hp', 50); - } - if (!user.get('items.itemsEnabled') && stats.exp >= 15) { - user.set('items.itemsEnabled', true); - $('ul.items').popover({ - title: content.items.unlockedMessage.title, - placement: 'left', - trigger: 'manual', - html: true, - content: "
" + content.items.unlockedMessage.content + " [Close]
" - }); - $('ul.items').popover('show'); - } - user.set('stats.exp', stats.exp); - } - if (stats.money != null) { - if (!(typeof money !== "undefined" && money !== null) || money < 0) { - money = 0.0; - } - return user.set('stats.money', stats.money); - } -}; - -score = function(taskId, direction, options) { - var adjustvalue, delta, exp, hp, lvl, modified, money, num, task, taskObj, taskPath, type, userObj, value, _ref, _ref1, _ref2; - if (options == null) { - options = { - cron: false, - times: 1 - }; - } - taskPath = "_user.tasks." + taskId; - _ref = [model.at(taskPath), model.get(taskPath)], task = _ref[0], taskObj = _ref[1]; - type = taskObj.type, value = taskObj.value; - userObj = user.get(); - if (!task) { - _ref1 = userObj.stats, money = _ref1.money, hp = _ref1.hp, exp = _ref1.exp; - if (direction === "up") { - modified = expModifier(1); - money += modified; - exp += modified; - } else { - modified = hpModifier(1); - hp -= modified; - } - updateStats({ - hp: hp, - exp: exp, - money: money - }); - return; - } - adjustvalue = type !== 'reward'; - if ((type === 'habit') && (taskObj.up === false || taskObj.down === false)) { - adjustvalue = false; - } - delta = 0; - _.times(options.times, function(n) { - var nextDelta; - nextDelta = taskDeltaFormula(value, direction); - if (adjustvalue) { - value += nextDelta; - } - return delta += nextDelta; - }); - if (type === 'habit') { - if (taskObj.value !== value) { - task.push('history', { - date: new Date(), - value: value - }); - } - } - task.set('value', value); - if (options.cron) { - if (type === 'daily') { - return delta; - } else { - return 0; - } - } - _ref2 = userObj.stats, money = _ref2.money, hp = _ref2.hp, exp = _ref2.exp, lvl = _ref2.lvl; - if (type === 'reward') { - money -= task.get('value'); - num = parseFloat(task.get('value')).toFixed(2); - if (money < 0) { - hp += money; - money = 0; - } - } - if ((delta > 0 || (type === 'daily' || type === 'todo')) && !options.cron) { - modified = expModifier(delta); - exp += modified; - money += modified; - } else if (type !== 'reward' && type !== 'todo') { - modified = hpModifier(delta); - hp += modified; - } - updateStats({ - hp: hp, - exp: exp, - money: money - }); - return delta; -}; - -cron = function() { - var daysPassed, hpTally, lastCron, tallyTask, tasks, today, todoTally; - today = new Date(); - user.setNull('lastCron', today); - lastCron = user.get('lastCron'); - daysPassed = helpers.daysBetween(today, lastCron); - if (daysPassed > 0) { - todoTally = 0; - hpTally = 0; - tallyTask = function(taskObj, callback) { - var absVal, completed, daysFailed, id, repeat, task, type, value; - id = taskObj.id, type = taskObj.type, completed = taskObj.completed, repeat = taskObj.repeat; - if (id == null) { - return callback('a task had a null id during cron, this should not be happening'); - } - task = user.at("tasks." + id); - if (type === 'todo' || type === 'daily') { - if (!completed) { - daysFailed = daysPassed; - if (type === 'daily' && repeat) { - daysFailed = 0; - _.times(daysPassed, function(n) { - var thatDay; - thatDay = moment().subtract('days', n + 1); - if (repeat[helpers.dayMapping[thatDay.day()]] === true) { - return daysFailed++; - } - }); - } - hpTally += score(id, 'down', { - cron: true, - times: daysFailed - }); - } - value = task.get('value'); - if (type === 'daily') { - task.push("history", { - date: today, - value: value - }); - } else { - absVal = completed ? Math.abs(value) : value; - todoTally += absVal; - } - if (type === 'daily') { - task.pass({ - cron: true - }).set('completed', false); - } - } - return callback(); - }; - tasks = _.toArray(user.get('tasks')); - return async.forEach(tasks, tallyTask, function(err) { - var expTally, lvl; - user.push('history.todos', { - date: today, - value: todoTally - }); - expTally = user.get('stats.exp'); - lvl = 0; - while (lvl < (user.get('stats.lvl') - 1)) { - lvl++; - expTally += (lvl * 100) / 5; - } - user.push('history.exp', { - date: today, - value: expTally - }); - updateStats({ - hp: user.get('stats.hp') + hpTally - }); - return user.set('lastCron', today); - }); - } -}; - -module.exports = { - setModel: setModel, - MODIFIER: MODIFIER, - score: score, - cron: cron, - expModifier: expModifier, - hpModifier: hpModifier, - taskDeltaFormula: taskDeltaFormula -}; diff --git a/lib/server/index.js b/lib/server/index.js deleted file mode 100644 index a824ab706d..0000000000 --- a/lib/server/index.js +++ /dev/null @@ -1,103 +0,0 @@ -// Generated by CoffeeScript 1.4.0 -var MongoStore, ONE_YEAR, app, auth, derby, everyauth, express, expressApp, gzippo, habitrpgMiddleware, http, options, path, priv, publicPath, racer, root, server, serverError, store, strategies; - -http = require('http'); - -path = require('path'); - -express = require('express'); - -gzippo = require('gzippo'); - -derby = require('derby'); - -app = require('../app'); - -everyauth = require('everyauth'); - -serverError = require('./serverError'); - -MongoStore = require('connect-mongo')(express); - -auth = require('derby-auth'); - -priv = require('./private'); - -racer = require('derby/node_modules/racer'); - -racer.io.set('transports', ['xhr-polling']); - -if (process.env.NODE_ENV !== 'production') { - racer.use(racer.logPlugin); - derby.use(derby.logPlugin); -} - -expressApp = express(); - -server = http.createServer(expressApp); - -module.exports = server; - -derby.use(require('racer-db-mongo')); - -store = derby.createStore({ - db: { - type: 'Mongo', - uri: process.env.NODE_DB_URI - }, - listen: server -}); - -ONE_YEAR = 1000 * 60 * 60 * 24 * 365; - -root = path.dirname(path.dirname(__dirname)); - -publicPath = path.join(root, 'public'); - -habitrpgMiddleware = function(req, res, next) { - var model; - model = req.getModel(); - model.set('_mobileDevice', /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header('User-Agent'))); - model.set('_nodeEnv', process.env.NODE_ENV); - return next(); -}; - -strategies = { - facebook: { - strategy: require("passport-facebook").Strategy, - conf: { - clientID: process.env.FACEBOOK_KEY, - clientSecret: process.env.FACEBOOK_SECRET - } - } -}; - -options = { - domain: "http://localhost:3000", - allowPurl: true, - schema: require('../app/schema').newUserObject() -}; - -auth.init(expressApp, store, strategies, options); - -expressApp.use(express.favicon()).use(gzippo.staticGzip(publicPath, { - maxAge: ONE_YEAR -})).use(express.compress()).use(express.bodyParser()).use(express.methodOverride()).use(express.cookieParser()).use(store.sessionMiddleware({ - secret: process.env.SESSION_SECRET || 'YOUR SECRET HERE', - cookie: { - maxAge: ONE_YEAR - }, - store: new MongoStore({ - url: process.env.NODE_DB_URI - }) -})).use(store.modelMiddleware()).use(priv.middleware).use(habitrpgMiddleware).use(auth.middleware()).use(app.router()).use(expressApp.router).use(serverError(root)); - -auth.routes(); - -priv.routes(expressApp); - -require('./serverRoutes')(expressApp, root, derby); - -expressApp.all('*', function(req) { - throw "404: " + req.url; -}); diff --git a/lib/server/private.js b/lib/server/private.js deleted file mode 100644 index 0197b87658..0000000000 --- a/lib/server/private.js +++ /dev/null @@ -1,9 +0,0 @@ -// Generated by CoffeeScript 1.4.0 - -module.exports.middleware = function(req, res, next) { - return next(); -}; - -module.exports.app = function(appExports, model) {}; - -module.exports.routes = function(expressApp) {}; diff --git a/lib/server/serverError.js b/lib/server/serverError.js deleted file mode 100644 index bd667e8731..0000000000 --- a/lib/server/serverError.js +++ /dev/null @@ -1,27 +0,0 @@ -// Generated by CoffeeScript 1.4.0 -var derby, isProduction; - -derby = require('derby'); - -isProduction = derby.util.isProduction; - -module.exports = function(root) { - var staticPages; - staticPages = derby.createStatic(root); - return function(err, req, res, next) { - var message, status; - if (err == null) { - return next(); - } - console.log(err.stack ? err.stack : err); - message = err.message || err.toString(); - status = parseInt(message); - if (status === 404) { - return staticPages.render('404', res, { - url: req.url - }, 404); - } else { - return res.send((400 <= status && status < 600) ? status : 500); - } - }; -}; diff --git a/lib/server/serverRoutes.js b/lib/server/serverRoutes.js deleted file mode 100644 index 96067144fa..0000000000 --- a/lib/server/serverRoutes.js +++ /dev/null @@ -1,72 +0,0 @@ -// Generated by CoffeeScript 1.4.0 -var scoring, _; - -scoring = require('../app/scoring'); - -_ = require('underscore'); - -module.exports = function(expressApp, root, derby) { - var deprecatedMessage, staticPages; - staticPages = derby.createStatic(root); - expressApp.get('/privacy', function(req, res) { - return staticPages.render('privacy', res); - }); - expressApp.get('/terms', function(req, res) { - return staticPages.render('terms', res); - }); - deprecatedMessage = 'This REST resource is no longer supported, use /users/:uid/tasks/:taskId/:direction instead.'; - expressApp.get('/:uid/up/:score?', function(req, res) { - return res.send(200, deprecatedMessage); - }); - expressApp.get('/:uid/down/:score?', function(req, res) { - return res.send(200, deprecatedMessage); - }); - return expressApp.post('/users/:uid/tasks/:taskId/:direction', function(req, res) { - var direction, icon, model, service, taskId, title, uid, _ref, _ref1; - _ref = req.params, uid = _ref.uid, taskId = _ref.taskId, direction = _ref.direction; - _ref1 = req.body, title = _ref1.title, service = _ref1.service, icon = _ref1.icon; - console.log({ - params: req.params, - body: req.body - }); - if (direction !== 'up' && direction !== 'down') { - return res.send(500, ":direction must be 'up' or 'down'"); - } - model = req.getModel(); - model.session.userId = uid; - return model.fetch("users." + uid, function(err, user) { - var delta, result, userObj; - if (err) { - return res.send(500, err); - } - userObj = user.get(); - if (!(userObj && !_.isEmpty(userObj.stats))) { - console.log({ - taskId: taskId, - direction: direction, - user: userObj, - error: 'non-user attempted to score' - }); - return res.send(500, "User " + uid + " not found"); - } - model.ref('_user', user); - if (!model.get("_user.tasks." + taskId)) { - model.refList("_habitList", "_user.tasks", "_user.habitIds"); - model.at('_habitList').push({ - id: taskId, - type: 'habit', - text: title || taskId, - value: 0, - up: true, - down: true, - notes: "This task was created by a third-party service. Feel free to edit, it won't harm the connection to that service. Additionally, multiple services may piggy-back off this task." - }); - } - scoring.setModel(model); - delta = scoring.score(taskId, direction); - result = model.get('_user.stats'); - result.delta = delta; - return res.send(result); - }); - }); -}; diff --git a/package.json b/package.json index 21b8cb1860..c105628d9f 100644 --- a/package.json +++ b/package.json @@ -17,12 +17,10 @@ "stripe": "*", "async": "*", "underscore": "*", - "clone": "*" + "clone": "*", + "coffee-script": "*" }, "private": true, - "devDependencies": { - "coffee-script": ">=1.3.3" - }, "subdomain": "habitrpg", "domains": [ "habitrpg.com", diff --git a/server.js b/server.js index 4a47ca7429..02ebfebece 100644 --- a/server.js +++ b/server.js @@ -1,8 +1,5 @@ -var port = process.env.PORT || 3000; -if (process.env.NODE_ENV === 'debug' || process.env.NODE_ENV === 'production') { - // "up" module interferes with node debug & node-inspector. also, nodejitsu (aka, 'production') doesn't like up - console.log('Running in ' + process.env.NODE_ENV + ': require("./lib/server").listen(' + port + ');'); - require('./lib/server').listen(port); -} else { - require('derby').run(__dirname + '/lib/server', port); -} \ No newline at end of file +require('coffee-script') // remove intermediate compilation requirement +require('./src/server').listen(process.env.PORT || 3000); + +// Note: removed "up" module, which is default for development (but interferes with and production + PaaS) +// Restore to 5310bb0 if I want it back (see https://github.com/codeparty/derby/issues/165#issuecomment-10405693)