Files
habitica/documentation/docs/user.html
T
2013-09-26 18:10:28 -04:00

623 lines
20 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>User.js</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
<link rel="stylesheet" media="all" href="docco.css" />
</head>
<body>
<div id="container">
<div id="background"></div>
<ul id="jump_to">
<li>
<a class="large" href="javascript:void(0);">Jump To &hellip;</a>
<a class="small" href="javascript:void(0);">+</a>
<div id="jump_wrapper">
<div id="jump_page">
<a class="source" href="group.html">
group.js
</a>
<a class="source" href="user.html">
user.js
</a>
</div>
</li>
</ul>
<ul class="sections">
<li id="section-1">
<div class="annotation">
<div class="pilwrap for-h1">
<a class="pilcrow" href="#section-1">&#182;</a>
</div>
<h1>User.js</h1>
</div>
</li>
<li id="section-2">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-2">&#182;</a>
</div>
<p>Defines the user data model (schema) for use via the API.</p>
<h2>Dependencies</h2>
</div>
</li>
<li id="section-3">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-3">&#182;</a>
</div>
</div>
<div class="content"><div class='highlight'><pre><span class="keyword">var</span> mongoose = require(<span class="string">"mongoose"</span>);
<span class="keyword">var</span> Schema = mongoose.Schema;
<span class="keyword">var</span> helpers = require(<span class="string">'habitrpg-shared/script/helpers'</span>);
<span class="keyword">var</span> _ = require(<span class="string">'lodash'</span>);</pre></div></div>
</li>
<li id="section-4">
<div class="annotation">
<div class="pilwrap for-h2">
<a class="pilcrow" href="#section-4">&#182;</a>
</div>
<h2>User Schema</h2>
</div>
</li>
<li id="section-5">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-5">&#182;</a>
</div>
</div>
<div class="content"><div class='highlight'><pre><span class="keyword">var</span> UserSchema = <span class="keyword">new</span> Schema({</pre></div></div>
</li>
<li id="section-6">
<div class="annotation">
<div class="pilwrap for-h3">
<a class="pilcrow" href="#section-6">&#182;</a>
</div>
<h3>UUID and API Token</h3>
</div>
<div class="content"><div class='highlight'><pre> _id: {
type: String,
<span class="string">'default'</span>: helpers.uuid
},
apiToken: {
type: String,
<span class="string">'default'</span>: helpers.uuid
},</pre></div></div>
</li>
<li id="section-7">
<div class="annotation">
<div class="pilwrap for-h3">
<a class="pilcrow" href="#section-7">&#182;</a>
</div>
<h3>Mongoode Update Object</h3>
<p>We want to know <em>every</em> time an object updates. Mongoose uses __v to designate when an object contains arrays which
have been updated (<a href="http://goo.gl/gQLz41">http://goo.gl/gQLz41</a>), but we want <em>every</em> update</p>
</div>
<div class="content"><div class='highlight'><pre> _v: {
type: Number,
<span class="string">'default'</span>: <span class="number">0</span>
},
achievements: {
originalUser: Boolean,
helpedHabit: Boolean,
ultimateGear: Boolean,
beastMaster: Boolean,
streak: Number
},
auth: {
facebook: Schema.Types.Mixed,
local: {
email: String,
hashed_password: String,
salt: String,
username: String
},
timestamps: {
created: {
type: Date,
<span class="string">'default'</span>: Date.now
},
loggedin: Date
}
},
backer: {
tier: Number,
admin: Boolean,
npc: String,
contributor: String,
tokensApplied: Boolean
},
balance: Number,
habitIds: Array,
dailyIds: Array,
todoIds: Array,
rewardIds: Array,
filters: {type: Schema.Types.Mixed, <span class="string">'default'</span>: {}},
flags: {
showTour: {type: Boolean, <span class="string">'default'</span>: <span class="literal">true</span>},
ads: {type: String, <span class="string">'default'</span>: <span class="string">'show'</span>}, <span class="comment">// FIXME make this a boolean, run migration</span>
dropsEnabled: {type: Boolean, <span class="string">'default'</span>: <span class="literal">false</span>},
itemsEnabled: {type: Boolean, <span class="string">'default'</span>: <span class="literal">false</span>},
newStuff: {type: String, <span class="string">'default'</span>: <span class="string">'hide'</span>}, <span class="comment">//FIXME to boolean (currently show/hide)</span>
rewrite: {type: Boolean, <span class="string">'default'</span>: <span class="literal">true</span>},
partyEnabled: Boolean, <span class="comment">// FIXME do we need this?</span>
petsEnabled: {type: Boolean, <span class="string">'default'</span>: <span class="literal">false</span>},
rest: {type: Boolean, <span class="string">'default'</span>: <span class="literal">false</span>} <span class="comment">// fixme - change to preferences.resting once we're off derby</span>
},
history: {
exp: [
{
date: Date,
value: Number
}
],
todos: [
{
data: Date,
value: Number
}
]
},
<span class="comment">/* FIXME remove?*/</span>
invitations: {
guilds: {type: Array, <span class="string">'default'</span>: []},
party: Schema.Types.Mixed
},
items: {
armor: Number,
weapon: Number,
head: Number,
shield: Number,
<span class="comment">/*FIXME - tidy this up, not the best way to store current pet*/</span>
currentPet: {
<span class="comment">/*Cactus*/</span>
text: String,
<span class="comment">/*Cactus*/</span>
name: String,
<span class="comment">/*3*/</span>
value: Number,
<span class="comment">/*"Find a hatching potion to pour on this egg, and one day it will hatch into a loyal pet.",*/</span>
notes: String,
<span class="comment">/*Skeleton*/</span>
modifier: String,
<span class="comment">/*Cactus-Skeleton*/</span>
str: String
},
eggs: [
{</pre></div></div>
</li>
<li id="section-8">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-8">&#182;</a>
</div>
<p>example: You&#39;ve found a Wolf Egg! Find a hatching potion to pour on this egg, and one day it will hatch into a loyal pet</p>
</div>
<div class="content"><div class='highlight'><pre> dialog: String,</pre></div></div>
</li>
<li id="section-9">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-9">&#182;</a>
</div>
<p>example: Wolf</p>
</div>
<div class="content"><div class='highlight'><pre> name: String,</pre></div></div>
</li>
<li id="section-10">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-10">&#182;</a>
</div>
<p>example: Find a hatching potion to pour on this egg, and one day it will hatch into a loyal pet.</p>
</div>
<div class="content"><div class='highlight'><pre> notes: String,</pre></div></div>
</li>
<li id="section-11">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-11">&#182;</a>
</div>
<p>example: Wolf </p>
</div>
<div class="content"><div class='highlight'><pre> text: String,
<span class="comment">/* type: String, //Egg // this is forcing mongoose to return object as "[object Object]", but I don't think this is needed anyway? */</span></pre></div></div>
</li>
<li id="section-12">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-12">&#182;</a>
</div>
<p>example: 3</p>
</div>
<div class="content"><div class='highlight'><pre> value: Number
}
],
hatchingPotions: Array, <span class="comment">// ["Base", "Skeleton",...]</span>
lastDrop: {
date: {type: Date, <span class="string">'default'</span>: Date.now},
count: {type: Number, <span class="string">'default'</span>: <span class="number">0</span>}
},</pre></div></div>
</li>
<li id="section-13">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-13">&#182;</a>
</div>
<p>[&quot;BearCub-Base&quot;, &quot;Cactus-Base&quot;, ...]</p>
</div>
<div class="content"><div class='highlight'><pre> pets: Array
},</pre></div></div>
</li>
<li id="section-14">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-14">&#182;</a>
</div>
<p>FIXME store as Date?</p>
</div>
<div class="content"><div class='highlight'><pre> lastCron: {
type: Date,
<span class="string">'default'</span>: Date.now
},</pre></div></div>
</li>
<li id="section-15">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-15">&#182;</a>
</div>
<p>FIXME remove?</p>
</div>
<div class="content"><div class='highlight'><pre> party: {</pre></div></div>
</li>
<li id="section-16">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-16">&#182;</a>
</div>
<p>party._id // FIXME make these populate docs?</p>
</div>
<div class="content"><div class='highlight'><pre> current: String, <span class="comment">// party._id</span>
invitation: String, <span class="comment">// party._id</span>
lastMessageSeen: String,
leader: Boolean
},
preferences: {
armorSet: String,
dayStart: {type:Number, <span class="string">'default'</span>: <span class="number">0</span>},
gender: {type:String, <span class="string">'default'</span>: <span class="string">'m'</span>},
hair: {type:String, <span class="string">'default'</span>:<span class="string">'blond'</span>},
hideHeader: {type:Boolean, <span class="string">'default'</span>:<span class="literal">false</span>},
showHelm: {type:Boolean, <span class="string">'default'</span>:<span class="literal">true</span>},
skin: {type:String, <span class="string">'default'</span>:<span class="string">'white'</span>},
timezoneOffset: Number
},
profile: {
blurb: String,
imageUrl: String,
name: String,
websites: Array <span class="comment">// styled like --&gt; ["http://ocdevel.com" ]</span>
},
stats: {
hp: Number,
exp: Number,
gp: Number,
lvl: Number
},
tags: [
{</pre></div></div>
</li>
<li id="section-17">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-17">&#182;</a>
</div>
<p>FIXME use refs?</p>
</div>
<div class="content"><div class='highlight'><pre> id: String,
name: String
}
],</pre></div></div>
</li>
<li id="section-18">
<div class="annotation">
<div class="pilwrap for-h3">
<a class="pilcrow" href="#section-18">&#182;</a>
</div>
<h3>Tasks Definition</h3>
<p>We can&#39;t define <code>tasks</code> until we move off Derby, since Derby requires dictionary of objects. When we&#39;re off, migrate
to array of subdocs</p>
</div>
<div class="content"><div class='highlight'><pre> tasks: Schema.Types.Mixed
<span class="comment">/*
# history: {date, value}
# id
# notes
# tags { "4ddf03d9-54bd-41a3-b011-ca1f1d2e9371" : true },
# text
# type
# up
# down
# value
# completed
# priority: '!!'
# repeat {m: true, t: true}
# streak
*/</span>
}, {
strict: <span class="literal">true</span>
});</pre></div></div>
</li>
<li id="section-19">
<div class="annotation">
<div class="pilwrap for-h2">
<a class="pilcrow" href="#section-19">&#182;</a>
</div>
<h2>Legacy Derby Function?</h2>
</div>
</li>
<li id="section-20">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-20">&#182;</a>
</div>
<p>Derby requires a strange storage format for somethign called &quot;refLists&quot;. Here we hook into loading the data, so we
can provide a more &quot;expected&quot; storage format for our various helper methods. Since the attributes are passed by reference,
the underlying data will be modified too - so when we save back to the database, it saves it in the way Derby likes.
This will go away after the rewrite is complete</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">transformTaskLists</span><span class="params">(doc)</span> {</span>
_.each([<span class="string">'habit'</span>, <span class="string">'daily'</span>, <span class="string">'todo'</span>, <span class="string">'reward'</span>], <span class="keyword">function</span>(type) {</pre></div></div>
</li>
<li id="section-21">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-21">&#182;</a>
</div>
<p>we use <em>.transform instead of a simple </em>.where in order to maintain sort-order</p>
</div>
<div class="content"><div class='highlight'><pre> doc[type + <span class="string">"s"</span>] = _.reduce(doc[type + <span class="string">"Ids"</span>], <span class="keyword">function</span>(m, tid) {
<span class="keyword">if</span> (!doc.tasks[tid]) <span class="keyword">return</span> m; <span class="comment">// FIXME tmp hotfix, people still have null tasks?</span>
<span class="keyword">if</span> (!doc.tasks[tid].tags) doc.tasks[tid].tags = {}; <span class="comment">// FIXME remove this when we switch tasks to subdocs and can define tags default in schema</span>
m.push(doc.tasks[tid]);
<span class="keyword">return</span> m;
}, []);
});
}
UserSchema.post(<span class="string">'init'</span>, <span class="keyword">function</span>(doc) {
transformTaskLists(doc);
});
UserSchema.methods.toJSON = <span class="keyword">function</span>() {
<span class="keyword">var</span> doc = <span class="keyword">this</span>.toObject();
doc.id = doc._id;
transformTaskLists(doc); <span class="comment">// we need to also transform for our server-side routes</span></pre></div></div>
</li>
<li id="section-22">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-22">&#182;</a>
</div>
<p>FIXME? Is this a reference to <code>doc.filters</code> or just disabled code? Remove?</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="comment">/*</pre></div></div>
</li>
<li id="section-23">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-23">&#182;</a>
</div>
<p>Remove some unecessary data as far as client consumers are concerned
_.each([&#39;habit&#39;, &#39;daily&#39;, &#39;todo&#39;, &#39;reward&#39;], function(type) {
delete doc[&quot;#{type}Ids&quot;]
});
delete doc.tasks</p>
</div>
<div class="content"><div class='highlight'><pre> */
doc.filters = {};
return doc;
};</pre></div></div>
</li>
<li id="section-24">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-24">&#182;</a>
</div>
<p>FIXME - since we&#39;re using special @post(&#39;init&#39;) above, we need to flag when the original path was modified.
Custom setter/getter virtuals?</p>
</div>
<div class="content"><div class='highlight'><pre>UserSchema.pre(<span class="string">'save'</span>, <span class="keyword">function</span>(next) {
<span class="keyword">this</span>.markModified(<span class="string">'tasks'</span>);</pre></div></div>
</li>
<li id="section-25">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-25">&#182;</a>
</div>
<p>our own version incrementer</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="keyword">this</span>._v++;
next();
});
module.exports.schema = UserSchema;
module.exports.model = mongoose.model(<span class="string">"User"</span>, UserSchema);</pre></div></div>
</li>
</ul>
</div>
</body>
</html>