2015-11-27 18:06:26 +00:00
|
|
|
import mongoose from 'mongoose';
|
|
|
|
|
import shared from '../../../common';
|
2015-11-28 12:46:53 +00:00
|
|
|
import validator from 'validator';
|
2015-11-27 18:06:26 +00:00
|
|
|
import moment from 'moment';
|
|
|
|
|
import baseModel from '../libs/api-v3/baseModel';
|
|
|
|
|
import _ from 'lodash';
|
2015-02-10 22:03:59 +00:00
|
|
|
|
2015-11-27 18:06:26 +00:00
|
|
|
let Schema = mongoose.Schema;
|
2015-11-27 20:18:37 +00:00
|
|
|
let discriminatorOptions = {
|
|
|
|
|
discriminatorKey: 'type', // the key that distinguishes task types
|
2015-11-27 18:06:26 +00:00
|
|
|
};
|
2015-11-27 20:18:37 +00:00
|
|
|
let subDiscriminatorOptions = _.defaults(_.cloneDeep(discriminatorOptions), {_id: false});
|
2015-02-10 22:03:59 +00:00
|
|
|
|
2015-11-27 18:06:26 +00:00
|
|
|
// 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
|
|
|
|
|
// Task model the subclasses are not applied - check twice
|
2015-02-10 22:03:59 +00:00
|
|
|
|
2015-11-27 18:06:26 +00:00
|
|
|
export let TaskSchema = new Schema({
|
2015-11-28 12:46:53 +00:00
|
|
|
type: {type: String, enum: ['Habit', 'Todo', 'Daily', 'Reward'], required: true, default: 'Habit'},
|
|
|
|
|
text: {type: String, required: true},
|
2015-11-27 18:06:26 +00:00
|
|
|
notes: {type: String, default: ''},
|
2015-11-28 12:46:53 +00:00
|
|
|
tags: {type: Schema.Types.Mixed, default: {}}, // TODO dictionary? { "4ddf03d9-54bd-41a3-b011-ca1f1d2e9371" : true }, validate
|
2015-11-27 18:06:26 +00:00
|
|
|
value: {type: Number, default: 0}, // redness
|
|
|
|
|
priority: {type: Number, default: 1},
|
|
|
|
|
attribute: {type: String, default: 'str', enum: ['str', 'con', 'int', 'per']},
|
|
|
|
|
userId: {type: String, ref: 'User'}, // When null it belongs to a challenge
|
|
|
|
|
|
2015-02-10 22:03:59 +00:00
|
|
|
challenge: {
|
2015-11-27 18:06:26 +00:00
|
|
|
id: {type: String, ref: 'Challenge'},
|
|
|
|
|
taskId: {type: String, ref: 'Task'}, // When null but challenge.id defined it's the original task
|
|
|
|
|
broken: String, // CHALLENGE_DELETED, TASK_DELETED, UNSUBSCRIBED, CHALLENGE_CLOSED TODO enum
|
|
|
|
|
winner: String, // user.profile.name TODO necessary?
|
|
|
|
|
},
|
2015-11-27 20:18:37 +00:00
|
|
|
}, _.defaults({
|
2015-11-27 18:06:26 +00:00
|
|
|
minimize: true, // So empty objects are returned
|
|
|
|
|
strict: true,
|
2015-11-27 20:18:37 +00:00
|
|
|
}, discriminatorOptions));
|
2015-02-10 22:03:59 +00:00
|
|
|
|
2015-11-27 18:06:26 +00:00
|
|
|
TaskSchema.plugin(baseModel, {
|
2015-11-28 12:46:53 +00:00
|
|
|
noSet: ['challenge', 'userId', 'value', 'completed', 'history', 'streak', 'dateCompleted'], // TODO checklist fields editable?
|
2015-11-27 18:06:26 +00:00
|
|
|
private: [],
|
|
|
|
|
timestamps: true,
|
|
|
|
|
});
|
2015-02-10 22:03:59 +00:00
|
|
|
|
2015-11-28 12:46:53 +00:00
|
|
|
export let TaskModel = mongoose.model('Task', TaskSchema);
|
2015-02-10 22:03:59 +00:00
|
|
|
|
2015-11-27 18:06:26 +00:00
|
|
|
// TODO discriminators: it's very important to check that the options and plugins of the parent schema are used in the sub-schemas too
|
2015-02-10 22:03:59 +00:00
|
|
|
|
2015-11-27 18:06:26 +00:00
|
|
|
// habits and dailies shared fields
|
|
|
|
|
let habitDailySchema = () => {
|
|
|
|
|
return {history: Array}; // [{date:Date, value:Number}], // this causes major performance problems TODO revisit
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// dailys and todos shared fields
|
|
|
|
|
let dailyTodoSchema = () => {
|
|
|
|
|
return {
|
|
|
|
|
completed: {type: Boolean, default: false},
|
|
|
|
|
// Checklist fields (dailies and todos)
|
|
|
|
|
collapseChecklist: {type: Boolean, default: false},
|
|
|
|
|
checklist: [{
|
|
|
|
|
completed: {type: Boolean, default: false},
|
2015-11-28 12:46:53 +00:00
|
|
|
text: {type: String, required: true},
|
|
|
|
|
_id: {type: String, default: shared.uuid, validate: [validator.isUUID, 'Invalid uuid.']},
|
2015-11-27 18:06:26 +00:00
|
|
|
}],
|
|
|
|
|
};
|
|
|
|
|
};
|
2015-02-10 22:03:59 +00:00
|
|
|
|
2015-11-28 12:46:53 +00:00
|
|
|
export let HabitSchema = new Schema(_.defaults({
|
2015-11-27 18:06:26 +00:00
|
|
|
up: {type: Boolean, default: true},
|
|
|
|
|
down: {type: Boolean, default: true},
|
2015-11-28 12:46:53 +00:00
|
|
|
}, habitDailySchema()), subDiscriminatorOptions);
|
|
|
|
|
export let HabitModel = TaskModel.discriminator('Habit', HabitSchema);
|
2015-11-27 18:06:26 +00:00
|
|
|
|
2015-11-28 12:46:53 +00:00
|
|
|
export let DailySchema = new Schema(_.defaults({
|
2015-11-27 18:06:26 +00:00
|
|
|
frequency: {type: String, default: 'weekly', enum: ['daily', 'weekly']},
|
|
|
|
|
everyX: {type: Number, default: 1}, // e.g. once every X weeks
|
|
|
|
|
startDate: {
|
|
|
|
|
type: Date,
|
|
|
|
|
default () {
|
|
|
|
|
return moment().startOf('day').toDate();
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
repeat: { // used only for 'weekly' frequency,
|
|
|
|
|
m: {type: Boolean, default: true},
|
|
|
|
|
t: {type: Boolean, default: true},
|
|
|
|
|
w: {type: Boolean, default: true},
|
|
|
|
|
th: {type: Boolean, default: true},
|
|
|
|
|
f: {type: Boolean, default: true},
|
|
|
|
|
s: {type: Boolean, default: true},
|
|
|
|
|
su: {type: Boolean, default: true},
|
|
|
|
|
},
|
|
|
|
|
streak: {type: Number, default: 0},
|
2015-11-28 12:46:53 +00:00
|
|
|
}, habitDailySchema(), dailyTodoSchema()), subDiscriminatorOptions);
|
|
|
|
|
export let DailyModel = TaskModel.discriminator('Daily', DailySchema);
|
2015-02-10 22:03:59 +00:00
|
|
|
|
2015-11-28 12:46:53 +00:00
|
|
|
export let TodoSchema = new Schema(_.defaults({
|
2015-11-27 18:06:26 +00:00
|
|
|
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
|
|
|
|
|
// TODO change field name
|
|
|
|
|
date: String, // due date for todos
|
2015-11-28 12:46:53 +00:00
|
|
|
}, dailyTodoSchema()), subDiscriminatorOptions);
|
|
|
|
|
export let TodoModel = TaskModel.discriminator('Todo', TodoSchema);
|
2015-02-10 22:03:59 +00:00
|
|
|
|
2015-11-28 12:46:53 +00:00
|
|
|
export let RewardSchema = new Schema({}, subDiscriminatorOptions);
|
|
|
|
|
export let RewardModel = TaskModel.discriminator('Reward', RewardSchema);
|