habitica/src/models/user.js

248 lines
6.2 KiB
JavaScript
Raw Normal View History

2013-09-19 19:51:51 +00:00
// User.js
// =======
// Defines the user data model (schema) for use via the API.
// Dependencies
// ------------
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var helpers = require('habitrpg-shared/script/helpers');
var _ = require('lodash');
var TaskSchema = require('./task').schema;
2013-09-19 19:51:51 +00:00
// User Schema
// -----------
var UserSchema = new Schema({
2013-09-19 19:51:51 +00:00
// ### UUID and API Token
_id: {
type: String,
'default': helpers.uuid
},
apiToken: {
type: String,
'default': helpers.uuid
},
2013-09-19 20:30:22 +00:00
// ### Mongoose Update Object
2013-09-19 19:51:51 +00:00
// We want to know *every* time an object updates. Mongoose uses __v to designate when an object contains arrays which
// have been updated (http://goo.gl/gQLz41), but we want *every* update
_v: {
type: Number,
'default': 0
},
achievements: {
originalUser: Boolean,
helpedHabit: Boolean,
ultimateGear: Boolean,
beastMaster: Boolean,
veteran: Boolean,
streak: Number,
challenges: Array
},
auth: {
facebook: Schema.Types.Mixed,
local: {
email: String,
hashed_password: String,
salt: String,
username: String
},
timestamps: {
created: {type: Date,'default': Date.now},
loggedin: {type: Date,'default': Date.now}
}
},
backer: {
tier: Number,
admin: Boolean,
npc: String,
contributor: String,
tokensApplied: Boolean
},
balance: Number,
filters: {type: Schema.Types.Mixed, 'default': {}},
purchased: {
ads: {type: Boolean, 'default': false},
skin: {type: Schema.Types.Mixed, 'default': {}}, // eg, {skeleton: true, pumpkin: true, eb052b: true}
hair: {type: Schema.Types.Mixed, 'default': {}}
},
flags: {
customizationsNotification: {type: Boolean, 'default': false},
showTour: {type: Boolean, 'default': true},
dropsEnabled: {type: Boolean, 'default': false},
itemsEnabled: {type: Boolean, 'default': false},
newStuff: {type: Boolean, 'default': false},
rewrite: {type: Boolean, 'default': true},
partyEnabled: Boolean, // FIXME do we need this?
petsEnabled: {type: Boolean, 'default': false},
rest: {type: Boolean, 'default': false} // fixme - change to preferences.resting once we're off derby
},
history: {
exp: [{date: Date, value: Number}],
todos: [{data: Date, value: Number}]
},
/* FIXME remove?*/
invitations: {
guilds: {type: Array, 'default': []},
party: Schema.Types.Mixed
},
items: {
armor: Number,
weapon: Number,
head: Number,
shield: Number,
/*FIXME - tidy this up, not the best way to store current pet*/
currentPet: {
/*Cactus*/
text: String,
/*Cactus*/
name: String,
/*3*/
value: Number,
/*"Find a hatching potion to pour on this egg, and one day it will hatch into a loyal pet.",*/
notes: String,
/*Skeleton*/
modifier: String,
/*Cactus-Skeleton*/
str: String
},
2013-09-02 19:54:32 +00:00
eggs: [
{
2013-09-19 19:51:51 +00:00
// example: You've found a Wolf Egg! Find a hatching potion to pour on this egg, and one day it will hatch into a loyal pet
dialog: String,
// example: Wolf
name: String,
// example: Find a hatching potion to pour on this egg, and one day it will hatch into a loyal pet.
notes: String,
// example: Wolf
text: String,
/* type: String, //Egg // this is forcing mongoose to return object as "[object Object]", but I don't think this is needed anyway? */
// example: 3
value: Number
}
],
2013-09-19 19:51:51 +00:00
hatchingPotions: Array, // ["Base", "Skeleton",...]
lastDrop: {
date: {type: Date, 'default': Date.now},
count: {type: Number, 'default': 0}
},
2013-09-19 19:51:51 +00:00
// ["BearCub-Base", "Cactus-Base", ...]
pets: Array
},
lastCron: {
type: Date,
'default': Date.now
},
// FIXME remove?
party: {
2013-09-19 19:51:51 +00:00
//party._id // FIXME make these populate docs?
current: String, // party._id
invitation: String, // party._id
lastMessageSeen: String,
leader: Boolean
},
preferences: {
armorSet: String,
dayStart: {type:Number, 'default': 0},
gender: {type:String, 'default': 'm'},
hair: {type:String, 'default':'blond'},
hideHeader: {type:Boolean, 'default':false},
showHelm: {type:Boolean, 'default':true},
skin: {type:String, 'default':'white'},
timezoneOffset: Number
},
profile: {
blurb: String,
imageUrl: String,
name: String,
2013-09-19 19:51:51 +00:00
websites: Array // styled like --> ["http://ocdevel.com" ]
},
stats: {
hp: Number,
exp: Number,
gp: Number,
lvl: Number
},
tags: [
{
2013-09-19 19:51:51 +00:00
// FIXME use refs?
id: String,
name: String
}
],
2013-09-19 19:51:51 +00:00
challenges: [{type: 'String', ref:'Challenge'}],
habits: [TaskSchema],
dailys: [TaskSchema],
todos: [TaskSchema],
rewards: [TaskSchema],
}, {
2013-10-27 09:49:32 +00:00
strict: true,
2013-10-27 09:55:43 +00:00
minimize: false // So empty objects are returned
});
UserSchema.methods.toJSON = function() {
var doc = this.toObject();
doc.id = doc._id;
// FIXME? Is this a reference to `doc.filters` or just disabled code? Remove?
2013-09-09 04:13:11 +00:00
doc.filters = {};
2013-09-17 16:16:16 +00:00
doc._tmp = this._tmp; // be sure to send down drop notifs
// TODO why isnt' this happening automatically given the TaskSchema.methods.toJSON above?
_.each(['habits','dailys','todos','rewards'], function(type){
_.each(doc[type],function(task){
task.id = task._id;
})
})
return doc;
};
UserSchema.virtual('tasks').get(function () {
var tasks = this.habits.concat(this.dailys).concat(this.todos).concat(this.rewards);
var tasks = _.object(_.pluck(tasks,'id'), tasks);
return tasks;
});
2013-09-19 19:51:51 +00:00
// FIXME - since we're using special @post('init') above, we need to flag when the original path was modified.
// Custom setter/getter virtuals?
UserSchema.pre('save', function(next) {
//this.markModified('tasks');
if (!this.profile.name) {
var fb = this.auth.facebook;
this.profile.name =
(this.auth.local && this.auth.local.username) ||
(fb && (fb.displayName || fb.name || fb.username || (fb.first_name && fb.first_name + ' ' + fb.last_name))) ||
'Anonymous';
}
//our own version incrementer
this._v++;
next();
});
module.exports.schema = UserSchema;
module.exports.model = mongoose.model("User", UserSchema);