From ae852f9a2e8d1ef165a51bdab8b895d2a5c35638 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 8 Jan 2016 17:47:08 +0100 Subject: [PATCH] complete preening and enable for challenges too --- common/script/index.js | 4 +- common/script/preenUserHistory.js | 105 +++++++++++++------------ test/common/preenUserHistory.test.js | 2 +- website/src/controllers/api-v2/user.js | 8 +- 4 files changed, 64 insertions(+), 55 deletions(-) diff --git a/common/script/index.js b/common/script/index.js index 42d8953eae..7f07df6a9b 100644 --- a/common/script/index.js +++ b/common/script/index.js @@ -7,7 +7,7 @@ import { MAX_LEVEL, MAX_STAT_POINTS, } from './constants'; -import preenUserHistory from './preenUserHistory'; +import { preenHistory, preenUserHistory } from './preenUserHistory'; import * as statHelpers from './statHelpers'; var $w, _, api, content, i18n, moment, sortOrder, @@ -32,6 +32,8 @@ api.maxHealth = MAX_HEALTH; api.tnl = statHelpers.toNextLevel; api.diminishingReturns = statHelpers.diminishingReturns; +api.preenHistory = preenHistory; + $w = api.$w = function(s) { return s.split(' '); }; diff --git a/common/script/preenUserHistory.js b/common/script/preenUserHistory.js index 5979720e12..801048c4c0 100644 --- a/common/script/preenUserHistory.js +++ b/common/script/preenUserHistory.js @@ -1,68 +1,69 @@ import _ from 'lodash'; import moment from 'moment'; -/* - Preen history for users and tasks. This code runs only on the server. +// Aggregate entries +function _aggregate (history, aggregateBy) { + return _.chain(history) + .groupBy(entry => { // group entries by aggregateBy + return moment(entry.date).format(aggregateBy); + }) + .sortBy((entry, key) => key) // sort by date + .reverse() // sort from most to least recent + .map(entries => { + return { + date: Number(entries[0].date), + value: _.reduce(entries, (previousValue, entry) => { + return previousValue + entry.value; + }, 0) / entries.length, + }; + }) + .value(); +} - Free users: - - 1 value for each day of the past 60 days (no compression) - - 1 value each month for the previous 10 months - - 1 value each year for the previous years +/* Preen an array of history entries - Subscribers: - - 1 value for each day of the past 365 days (no compression) - - 1 value each month for the previous 12 months - - 1 value each year for the previous years +Free users: +- 1 value for each day of the past 60 days (no compression) +- 1 value each month for the previous 10 months +- 1 value each year for the previous years + +Subscribers and challenges: +- 1 value for each day of the past 365 days (no compression) +- 1 value each month for the previous 12 months +- 1 value each year for the previous years */ +export function preenHistory (history, isSubscribed, timezoneOffset) { + history = _.filter(history, historyEntry => Boolean(historyEntry)); // Filter missing entries + let now = timezoneOffset ? moment().zone(timezoneOffset) : moment(); + // Date after which to begin compressing data + let cutOff = now.subtract(isSubscribed ? 365 : 60, 'days').startOf('day'); + // Keep uncompressed entries (modifies history) + let newHistory = _.remove(history, entry => { + return moment(entry.date).isSameOrAfter(cutOff); + }); -function _preenHistory (history, isSubscribed) { - history = _.filter(history, historyEntry => return Boolean(historyEntry)); // Filter missing entries - let newHistory = []; - - // Steps - // Take first 365 or 60 entries and keep them unmodified - only if of consecutive days? In the long term we want history to be continuous not with big jumps - // Group the rest by month and keep 10 or 12 - // Group the rest by year - - function _preen (amount, groupBy) { - let groups = _.chain(history).groupBy(h => { - return moment(h.date).format(groupBy); - }).sortBy((h, k) => { - return k; - }).value(); - groups = groups.slice(-amount); - groups.pop(); - - return _.each(groups, group => { - newHistory.push({ - date: moment(group[0].date).toDate(), - value: _.reduce(group, (m, obj) => { - return m + obj.value; - }, 0) / group.length, - }); - }); - } - - _preen(50, 'YYYY'); - _preen(moment().format('MM'), 'YYYYMM'); - - let thisMonth = moment().format('YYYYMM'); - newHistory = newHistory.concat(_.filter(history, h => { - return moment(h.date).format('YYYYMM') === thisMonth; - })); + // Date after which to begin compressing data by year + let monthsCutOff = cutOff.subtract(isSubscribed ? 12 : 10, 'months').startOf('day'); + let aggregateByMonth = _.remove(history, entry => { + return moment(entry.date).isSameOrAfter(monthsCutOff); + }); + // Aggregate remaining entries by month and year + newHistory.push(..._aggregate(aggregateByMonth, 'YYYYMM')); + newHistory.push(..._aggregate(history, 'YYYY')); return newHistory; } -export default function (user) { +// Preen history for users and tasks. This code runs only on the server. +export function preenUserHistory (user) { let isSubscribed = user.purchased && user.purchased.plan && user.purchased.plan.customerId; let minHistoryLength = isSubscribed ? 365 : 60; _.each(user.habits.concat(user.dailys), (task, index) => { if (task.history && task.history.length > minHistoryLength) { - task.history = _preenHistory(task.history, isSubscribed); - user.markModified(`user.${task.type}s.${index}.history`); + task.history = preenHistory(task.history, isSubscribed); + if (user.markModified) user.markModified(`${task.type}s.${index}.history`); } }); @@ -72,12 +73,12 @@ export default function (user) { }); if (user.history.exp.length > minHistoryLength) { - user.history.exp = _preenHistory(user.history.exp, isSubscribed); - user.markModified('user.history.exp'); + user.history.exp = preenHistory(user.history.exp, isSubscribed); + user.markModified('history.exp'); } if (user.history.todos.length > minHistoryLength) { - user.history.todos = _preenHistory(user.history.todos, isSubscribed); - user.markModified('user.history.todos'); + user.history.todos = preenHistory(user.history.todos, isSubscribed); + user.markModified('history.todos'); } } diff --git a/test/common/preenUserHistory.test.js b/test/common/preenUserHistory.test.js index 2bb799e4f7..fd5ff3b37f 100644 --- a/test/common/preenUserHistory.test.js +++ b/test/common/preenUserHistory.test.js @@ -1,4 +1,4 @@ -import preenUserHistory from '../../common/script/preenUserHistory'; // eslint-disable-line no-unused-vars +import preenUserHistory from '../../common/script/preenUserHistory'; describe('preenUserHistory', () => { describe('preen tasks history', () => { diff --git a/website/src/controllers/api-v2/user.js b/website/src/controllers/api-v2/user.js index d472d14df8..d112bb2837 100644 --- a/website/src/controllers/api-v2/user.js +++ b/website/src/controllers/api-v2/user.js @@ -135,8 +135,14 @@ api.score = function(req, res, next) { } t.value += delta; - if (t.type == 'habit' || t.type == 'daily') + if (t.type == 'habit' || t.type == 'daily') { t.history.push({value: t.value, date: +new Date}); + if (t.history.length > 365) { + var tIndex = chal[`${t.type}`].indexOf(t); + t.history = shared.preenHistory(t.history, true); // true means the challenge will retain as much entries as a subscribed user + chal.markModified(`${t.type}s.${tIndex}.history`); // Setting habits/dailys as modified because we don't know the index of the task + } + } chal.save(); clearMemory(); });