starts fixing default tasks and use discriminator

This commit is contained in:
Matteo Pagliazzi
2015-11-27 21:18:37 +01:00
parent 7d53a4fd54
commit cfa776fff3
3 changed files with 52 additions and 47 deletions

View File

@@ -10,10 +10,10 @@ var ChallengeSchema = new Schema({
shortName: String, shortName: String,
description: String, description: String,
official: {type: Boolean,'default':false}, official: {type: Boolean,'default':false},
habits: [TaskSchemas.HabitSchema], //habits: [TaskSchemas.HabitSchema],
dailys: [TaskSchemas.DailySchema], //dailys: [TaskSchemas.DailySchema],
todos: [TaskSchemas.TodoSchema], //todos: [TaskSchemas.TodoSchema],
rewards: [TaskSchemas.RewardSchema], //rewards: [TaskSchemas.RewardSchema],
leader: {type: String, ref: 'User'}, leader: {type: String, ref: 'User'},
group: {type: String, ref: 'Group'}, group: {type: String, ref: 'Group'},
timestamp: {type: Date, 'default': Date.now}, timestamp: {type: Date, 'default': Date.now},

View File

@@ -5,9 +5,10 @@ import baseModel from '../libs/api-v3/baseModel';
import _ from 'lodash'; import _ from 'lodash';
let Schema = mongoose.Schema; let Schema = mongoose.Schema;
let discriminatorOptions = () => { let discriminatorOptions = {
return {discriminatorKey: 'type'}; // the key that distinguishes task types discriminatorKey: 'type', // the key that distinguishes task types
}; };
let subDiscriminatorOptions = _.defaults(_.cloneDeep(discriminatorOptions), {_id: false});
// TODO make sure a task can only update the fields belonging to its type // TODO make sure a task can only update the fields belonging to its type
// We could use discriminators but it looks like when loading from the parent // We could use discriminators but it looks like when loading from the parent
@@ -29,10 +30,10 @@ export let TaskSchema = new Schema({
broken: String, // CHALLENGE_DELETED, TASK_DELETED, UNSUBSCRIBED, CHALLENGE_CLOSED TODO enum broken: String, // CHALLENGE_DELETED, TASK_DELETED, UNSUBSCRIBED, CHALLENGE_CLOSED TODO enum
winner: String, // user.profile.name TODO necessary? winner: String, // user.profile.name TODO necessary?
}, },
}, _.default({ }, _.defaults({
minimize: true, // So empty objects are returned minimize: true, // So empty objects are returned
strict: true, strict: true,
}, discriminatorOptions())); }, discriminatorOptions));
TaskSchema.plugin(baseModel, { TaskSchema.plugin(baseModel, {
noSet: [], noSet: [],
@@ -66,7 +67,7 @@ let dailyTodoSchema = () => {
export let Habit = Task.discriminator('Habit', new Schema(_.defaults({ export let Habit = Task.discriminator('Habit', new Schema(_.defaults({
up: {type: Boolean, default: true}, up: {type: Boolean, default: true},
down: {type: Boolean, default: true}, down: {type: Boolean, default: true},
}, habitDailySchema())), discriminatorOptions()); }, habitDailySchema()), subDiscriminatorOptions));
export let Daily = Task.discriminator('Daily', new Schema(_.defaults({ export let Daily = Task.discriminator('Daily', new Schema(_.defaults({
frequency: {type: String, default: 'weekly', enum: ['daily', 'weekly']}, frequency: {type: String, default: 'weekly', enum: ['daily', 'weekly']},
@@ -87,13 +88,13 @@ export let Daily = Task.discriminator('Daily', new Schema(_.defaults({
su: {type: Boolean, default: true}, su: {type: Boolean, default: true},
}, },
streak: {type: Number, default: 0}, streak: {type: Number, default: 0},
}, habitDailySchema(), dailyTodoSchema())), discriminatorOptions()); }, habitDailySchema(), dailyTodoSchema()), subDiscriminatorOptions));
export let Todo = Task.discriminator('Todo', new Schema(_.defaults({ export let Todo = Task.discriminator('Todo', new Schema(_.defaults({
dateCompleted: Date, dateCompleted: Date,
// FIXME we're getting parse errors, people have stored as "today" and "3/13". Need to run a migration & put this back to type: Date // FIXME we're getting parse errors, people have stored as "today" and "3/13". Need to run a migration & put this back to type: Date
// TODO change field name // TODO change field name
date: String, // due date for todos date: String, // due date for todos
}, dailyTodoSchema())), discriminatorOptions()); }, dailyTodoSchema()), subDiscriminatorOptions));
export let Reward = Task.discriminator('Reward', new Schema({}), discriminatorOptions()); export let Reward = Task.discriminator('Reward', new Schema({}, subDiscriminatorOptions));

View File

@@ -3,6 +3,7 @@ import shared from '../../../common';
import _ from 'lodash'; import _ from 'lodash';
import validator from 'validator'; import validator from 'validator';
import moment from 'moment'; import moment from 'moment';
import Q from 'q';
import { model as Task } from './task'; import { model as Task } from './task';
import baseModel from '../libs/api-v3/baseModel'; import baseModel from '../libs/api-v3/baseModel';
// import {model as Challenge} from './challenge'; // import {model as Challenge} from './challenge';
@@ -491,36 +492,37 @@ schema.post('init', function postInitUser (doc) {
}); });
function _populateDefaultTasks (user, taskTypes) { function _populateDefaultTasks (user, taskTypes) {
_.each(taskTypes, (taskType) => { if ('tags' in taskTypes) {
// TODO save in own documents user.tags = _.map(shared.content.userDefaults.tags, function(tag){
user[taskType] = _.map(shared.content.userDefaults[taskType], (taskDefaults) => { let newTag = _.cloneDeep(tag);
let newTask;
// Render task's text and notes in user's language // tasks automatically get _id=helpers.uuid() from TaskSchema id.default, but tags are Schema.Types.Mixed - so we need to manually invoke here
if (taskType === 'tags') { newTag.id = shared.uuid();
newTask = _.cloneDeep(taskDefaults); // Render tag's name in user's language
// tasks automatically get id=helpers.uuid() from TaskSchema id.default, but tags are Schema.Types.Mixed - so we need to manually invoke here newTag.name = newTag.name(user.preferences.language);
newTask.id = shared.uuid(); return newTag;
newTask.name = newTask.name(user.preferences.language); });
} else {
newTask = new Task(taskDefaults);
newTask.userId = user._id;
newTask.text = newTask.text(user.preferences.language);
if (newTask.notes) {
newTask.notes = newTask.notes(user.preferences.language);
} }
let tasksToCreate = [];
_.each(taskTypes, (taskType) => {
let tasksOfType = _.map(shared.content.userDefaults[taskType], (taskDefaults) => {
let newTask = new Task(taskDefaults);
newTask.userId = user._id;
newTask.text = newTask.text(user.preferences.language);
if (newTask.notes) newTask.notes = newTask.notes(user.preferences.language);
if (newTask.checklist) { if (newTask.checklist) {
newTask.checklist = _.map(newTask.checklist, (checklistItem) => { newTask.checklist = _.map(newTask.checklist, (checklistItem) => {
checklistItem.text = checklistItem.text(user.preferences.language); checklistItem.text = checklistItem.text(user.preferences.language);
return checklistItem; return checklistItem;
}); });
} }
} });
return newTask; tasksToCreate.push(...tasksOfType);
});
}); });
return Task.create(tasksToCreate);
} }
function _populateDefaultsForNewUser (user) { function _populateDefaultsForNewUser (user) {
@@ -543,7 +545,7 @@ function _populateDefaultsForNewUser (user) {
}); });
} }
_populateDefaultTasks(user, taskTypes); return _populateDefaultTasks(user, taskTypes);
} }
function _setProfileName (user) { function _setProfileName (user) {
@@ -556,13 +558,10 @@ function _setProfileName (user) {
return localUsername || facebookUsername || anonymous; return localUsername || facebookUsername || anonymous;
} }
schema.pre('save', function postSaveUser (next) { schema.pre('save', function postSaveUser (next, done) {
// Populate new users with default content next();
if (this.isNew) {
_populateDefaultsForNewUser(this);
}
// this.markModified('tasks'); // TODO remove all unnecessary checks
if (_.isNaN(this.preferences.dayStart) || this.preferences.dayStart < 0 || this.preferences.dayStart > 23) { if (_.isNaN(this.preferences.dayStart) || this.preferences.dayStart < 0 || this.preferences.dayStart > 23) {
this.preferences.dayStart = 0; this.preferences.dayStart = 0;
} }
@@ -611,7 +610,12 @@ schema.pre('save', function postSaveUser (next) {
if (_.isNaN(this._v) || !_.isNumber(this._v)) this._v = 0; if (_.isNaN(this._v) || !_.isNumber(this._v)) this._v = 0;
this._v++; this._v++;
next(); // Populate new users with default content
if (this.isNew) {
_populateDefaultsForNewUser(this)
.then((tasks) => done())
.catch(done);
}
}); });
schema.methods.unlink = function unlink (options, cb) { schema.methods.unlink = function unlink (options, cb) {