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-30 18:38:53 +00:00
export let tasksTypes = [ 'habit' , 'daily' , 'todo' , 'reward' ] ;
2015-02-10 22:03:59 +00:00
2015-11-27 18:06:26 +00:00
export let TaskSchema = new Schema ( {
2015-11-30 18:38:53 +00:00
type : { type : String , enum : tasksTypes , required : true , default : tasksTypes [ 0 ] } ,
2015-11-28 12:46:53 +00:00
text : { type : String , required : true } ,
2015-11-27 18:06:26 +00:00
notes : { type : String , default : '' } ,
2015-12-03 18:19:53 +00:00
tags : [ {
type : String ,
validate : [ validator . isUUID , 'Invalid uuid.' ] ,
} ] ,
2015-12-29 17:35:34 +00:00
value : { type : Number , default : 0 , required : true } , // redness or cost for rewards Required because it must be settable (for rewards)
2015-12-03 18:19:53 +00:00
priority : { type : Number , default : 1 , required : true } , // TODO enum?
2015-11-27 18:06:26 +00:00
attribute : { type : String , default : 'str' , enum : [ 'str' , 'con' , 'int' , 'per' ] } ,
2015-12-28 09:46:34 +00:00
userId : { type : String , ref : 'User' , validate : [ validator . isUUID , 'Invalid uuid.' ] } , // When not set it belongs to a challenge
2015-11-27 18:06:26 +00:00
2015-02-10 22:03:59 +00:00
challenge : {
2015-12-29 17:35:34 +00:00
id : { type : String , ref : 'Challenge' , validate : [ validator . isUUID , 'Invalid uuid.' ] } , // When set (and userId not set) it's the original task
2016-01-05 19:19:55 +00:00
taskId : { type : String , ref : 'Task' , validate : [ validator . isUUID , 'Invalid uuid.' ] } , // When not set but challenge.id defined it's the original task TODO unique index?
2015-12-28 09:46:34 +00:00
broken : { type : String , enum : [ 'CHALLENGE_DELETED' , 'TASK_DELETED' , 'UNSUBSCRIBED' , 'CHALLENGE_CLOSED' ] } ,
2015-11-27 18:06:26 +00:00
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-12-06 16:07:29 +00:00
// TODO checklist fields editable?
// TODO value should be settable only for rewards
noSet : [ 'challenge' , 'userId' , 'completed' , 'history' , 'streak' , 'dateCompleted' ] ,
2015-11-27 18:06:26 +00:00
private : [ ] ,
timestamps : true ,
} ) ;
2015-02-10 22:03:59 +00:00
2015-12-03 17:15:22 +00:00
// A list of additional fields that cannot be set on creation (but can be set on updare)
2015-12-06 16:29:14 +00:00
let noCreate = [ 'completed' ] ; // TODO completed should be removed for updates too?
2015-12-03 17:15:22 +00:00
TaskSchema . statics . sanitizeCreate = function sanitizeCreate ( createObj ) {
return Task . sanitize ( createObj , noCreate ) ; // eslint-disable-line no-use-before-define
} ;
2015-11-29 18:05:24 +00:00
// A list of additional fields that cannot be updated (but can be set on creation)
2015-12-06 16:29:14 +00:00
let noUpdate = [ '_id' , 'type' ] ;
2015-11-29 18:05:24 +00:00
TaskSchema . statics . sanitizeUpdate = function sanitizeUpdate ( updateObj ) {
2015-11-30 18:38:53 +00:00
return Task . sanitize ( updateObj , noUpdate ) ; // eslint-disable-line no-use-before-define
2015-11-29 18:05:24 +00:00
} ;
2015-02-10 22:03:59 +00:00
2015-12-16 11:29:03 +00:00
// Sanitize checklist objects (disallowing _id)
TaskSchema . statics . sanitizeChecklist = function sanitizeChecklist ( checklistObj ) {
delete checklistObj . _id ;
return checklistObj ;
} ;
2015-11-30 18:38:53 +00:00
export let Task = mongoose . model ( 'Task' , TaskSchema ) ;
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 ) ;
2015-12-02 10:22:53 +00:00
export let habit = Task . 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 ) ;
2015-12-02 10:22:53 +00:00
export let daily = Task . 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 ) ;
2015-12-02 10:22:53 +00:00
export let todo = Task . 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 ) ;
2015-12-02 10:22:53 +00:00
export let reward = Task . discriminator ( 'reward' , RewardSchema ) ;