{"_id":"mongoose-troop","_rev":"29-128c98f39bca467fb04b48a48b5de197","name":"mongoose-troop","description":"a collection of plugins for mongoose","dist-tags":{"latest":"0.0.8"},"versions":{"0.0.0":{"author":{"name":"Thomas Blobaum","email":"tblobaum@gmail.com","url":"https://github.com/tblobaum/"},"name":"mongoose-troop","description":"plugins for mongoose","version":"0.0.0","homepage":"http://analyticsmachine.com","repository":{"type":"git","url":"git://github.com/tblobaum/mongoose-troop.git"},"scripts":{"test":"npm test"},"engines":{"node":"*"},"dependencies":{"mongoose":"~2.4.1","redis":"~0.7.1","underscore":"~1.2.3","directory":"0.0.6"},"devDependencies":{},"_npmUser":{"name":"tblobaum","email":"tblobaum@gmail.com"},"_id":"mongoose-troop@0.0.0","_engineSupported":true,"_npmVersion":"1.0.105","_nodeVersion":"v0.6.1","_defaultsLoaded":true,"dist":{"shasum":"aa5456304d114b61811f1242a3759fa01be0de0c","tarball":"https://registry.npmjs.org/mongoose-troop/-/mongoose-troop-0.0.0.tgz","integrity":"sha512-cST8F1i3qmWrYVX0EIZ8OC4Ho96sO25izzaI+96Ch6Q5TJK9PiL+Vk4XtnWPlo04gyi5xFq2fqTCg+0htfM3KA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAy7G5y58TAyeEVLaTiGa6v6mTYwk6aqKorgFxyW0QHZAiBlhAYrpH0gl4/NPfx80kKA80ZKSJVa0/4jacjTcpgLUA=="}]},"maintainers":[{"name":"tblobaum","email":"tblobaum@gmail.com"}],"directories":{}},"0.0.1":{"author":{"name":"Thomas Blobaum","email":"tblobaum@gmail.com","url":"https://github.com/tblobaum/"},"contributors":[{"name":"Profulla Sadangi","url":"https://github.com/butu5/"},{"name":"Beau Sorensen","url":"https://github.com/sorensen/"}],"name":"mongoose-troop","description":"plugins for mongoose","version":"0.0.1","homepage":"http://analyticsmachine.com","repository":{"type":"git","url":"git://github.com/tblobaum/mongoose-troop.git"},"scripts":{"test":"npm test"},"engines":{"node":"*"},"dependencies":{"mongoose":"~2.4.5","redis":"~0.7.1","underscore":"~1.2.3","directory":"0.0.x"},"devDependencies":{"vows":"0.6.0"},"_npmUser":{"name":"tblobaum","email":"tblobaum@gmail.com"},"_id":"mongoose-troop@0.0.1","_engineSupported":true,"_npmVersion":"1.1.0-alpha-6","_nodeVersion":"v0.6.5","_defaultsLoaded":true,"dist":{"shasum":"5402b43c1a4e8e90543e2b93a97c5ac25998860d","tarball":"https://registry.npmjs.org/mongoose-troop/-/mongoose-troop-0.0.1.tgz","integrity":"sha512-NWm8Wg2n44sb3lp16Muq50dR/OfKI9QfA1iNZVpF124F2As9Yuv37QsERZulI67jLYoP0oGAiDbqlVv/i+z6cA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDX2SmQVAJH1vKdDFsN4n9oU0rkS6JOjnUGlYGLDl5+GwIgYRsrQEZsIRJf/W8w3jMUtHHr8L5hHBXwlG4lHFLnfPw="}]},"maintainers":[{"name":"tblobaum","email":"tblobaum@gmail.com"}],"directories":{}},"0.0.2":{"author":{"name":"Thomas Blobaum","email":"tblobaum@gmail.com","url":"https://github.com/tblobaum/"},"contributors":[{"name":"Profulla Sadangi","url":"https://github.com/butu5/"},{"name":"Beau Sorensen","url":"https://github.com/sorensen/"}],"name":"mongoose-troop","description":"plugins for mongoose","version":"0.0.2","homepage":"http://analyticsmachine.com","repository":{"type":"git","url":"git://github.com/tblobaum/mongoose-troop.git"},"scripts":{"test":"npm test"},"engines":{"node":"*"},"dependencies":{"underscore":"~1.2.3","directory":"0.0.x"},"devDependencies":{"vows":"0.6.0"},"_npmUser":{"name":"tblobaum","email":"tblobaum@gmail.com"},"_id":"mongoose-troop@0.0.2","_engineSupported":true,"_npmVersion":"1.1.0-alpha-6","_nodeVersion":"v0.6.5","_defaultsLoaded":true,"dist":{"shasum":"e956e24271fd78f302ceb87593bdf2dbbf0aaea1","tarball":"https://registry.npmjs.org/mongoose-troop/-/mongoose-troop-0.0.2.tgz","integrity":"sha512-1prt4SpAXVmkso/951xXumePAvtnn0D/Ub3LoydUzBWUh4wMHfBRjLgIEJcVCgZqHdcgXxNTV+oeMDoYjli0+A==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCGVHyHDYi3SY8qyRnt24JOg2BDcpe7Kc+eF7ndisL8DgIgH5cJt7/9fYtKctY4J4XZDMdR7a/fTdkZsWYqc9hyiv8="}]},"maintainers":[{"name":"tblobaum","email":"tblobaum@gmail.com"}],"directories":{}},"0.0.5":{"author":{"name":"Thomas Blobaum","email":"tblobaum@gmail.com","url":"https://github.com/tblobaum/"},"contributors":[{"name":"Profulla Sadangi","url":"https://github.com/butu5/"},{"name":"Beau Sorensen","url":"https://github.com/sorensen/"}],"name":"mongoose-troop","description":"plugins for mongoose","version":"0.0.5","homepage":"http://analyticsmachine.com","repository":{"type":"git","url":"git://github.com/tblobaum/mongoose-troop.git"},"scripts":{"test":"make test && make clean"},"engines":{"node":"0.x"},"dependencies":{"directory":"0.0.x","mongoose":"~2.4.10","bcrypt":"~0.5.0","redis":">= 0.7.1"},"devDependencies":{"mocha":"~0.10.0"},"_npmUser":{"name":"tblobaum","email":"tblobaum@gmail.com"},"_id":"mongoose-troop@0.0.5","_engineSupported":true,"_npmVersion":"1.1.0-beta-10","_nodeVersion":"v0.6.7","_defaultsLoaded":true,"dist":{"shasum":"3291a9222ccad18e9cea40ac3eb7c85c5c955393","tarball":"https://registry.npmjs.org/mongoose-troop/-/mongoose-troop-0.0.5.tgz","integrity":"sha512-mBD1lbmuWNgbwdVdlNOINKrgBs8zbsztucruGrdskU+LYDuvsYdvs0NEHy/WYBf6s9gj2KtaQGP1h9hQadzqMA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGz6rPtsS0cIBazPNYHvEz9/9iB5XIpWOgSwrq6V2zWJAiEA309qeQo8Qh1gtT5O2iLQw3szjD/Z1ElnY3AHQFzqaIk="}]},"readme":"\n# Mongoose Troop [![Build Status](https://secure.travis-ci.org/tblobaum/mongoose-troop.png)](http://travis-ci.org/tblobaum/mongoose-troop) \n\nA collection of handy plugins for mongoose\n\n## Contents\n* <a href=\"#Troop.acl\"> acl </a>\n* <a href=\"#Troop.basicAuth\"> basicAuth </a> (simple authentication and registration)\n* <a href=\"#Troop.timestamp\"> timestamp </a> (automatic created and modified timestamps)\n* <a href=\"#Troop.slugify\"> slugify </a> (url-friendly copies of string properties)\n* <a href=\"#Troop.keywords\"> keywords </a> (search-friendly array of stemmed words from string properties)\n* <a href=\"#Troop.pubsub\"> pubsub </a> (message passing)\n* <a href=\"#Troop.pagination\"> pagination </a> (query pagination)\n* <a href=\"#Troop.rest\"> rest </a> (http or rpc controller)\n* <a href=\"#Troop.obfuscate\"> obfuscate </a> (objectID encryption / decryption)\n* <a href=\"#Troop.utils\"> utils </a> (merge, removeDefaults, getdbrefs)\n\n***\n\n# <a name=\"Troop.acl\" href=\"#Troop.acl\">acl</a>\nSimple access control list\n\n## Methods\n\n### instance.addAccess(key)\n\nAdd `key` access to a Model instance\n\n### instance.removeAccess(key)\n\nRemove `key` access to a Model instance\n\n### instance.access(key [, callback])\n\nReturn or callback a boolean\n\n\n***\n\n# <a name=\"Troop.basicAuth\" href=\"#Troop.basicAuth\">basicAuth</a>\n\nSimple authentication plugin\n\n## Options\n\n* `loginPath` schema path for username/login (optional, default `username`)\n* `hashPath` schema path to hashed password (optional, default `hash`)\n* `workFactor` bcrypt work factor (optional, default `10`)\n\n## Methods\n\n### instance.authenticate(password, callback)\n\nAuthenticate a mongoose document\n\n### instance.setPassword(password, callback)\n\nSet the password for a mongoose document\n\n### model.authenticate(username, password, callback)\n\nAuthenticate a user on the model level\n\n### model.register(attributes, callback)\n\nCreate a new user with given attributes\n\n## Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n  , UserSchema = new mongoose.Schema()\n\nUserSchema.plugin(troop.basicAuth)\n\nvar User = mongoose.model('user', UserSchema)\n\nUser.register({\n  username: 'foo'\n, password: 'bar'\n}, function() {\n  // ...\n})\n\nUser.authenticate('foo', 'bar', function(err, doc) {\n  // ...\n})\n\nUser.findOne({ username: 'foo'}, function(err, doc) {\n  if (err || !doc) return\n  doc.setPassword('foobar', function(err) {\n    if (err) return\n    doc.authenticate('foobar', function() {\n      // ...\n    })\n  })\n})\n````\n\n\n***\n\n# <a name=\"Troop.timestamp\" href=\"#Troop.timestamp\">timestamp</a>\n\nAdds a `created` and `modified` property to the schema, updating the timestamps as expected.\n\n## Options\n\n* `createdPath` schema path for created timestamp (optional, default `created`)\n* `modifiedPath` schema path for modified timestamp (optional, default `modified`)\n* `useVirtual` use a virtual path for created timestamp based on ObjectId (optional, default `true`)\n\n## Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , FooSchema = new mongoose.Schema()\n\nFooSchema.plugin(troop.timestamp)\n````\n\n## Note\n\nUsing the virtual `created` timestamp you will lose the ability to run queries against it, \nas well as a loss in precision, as it will return a timestamp in seconds.\n\n\n***\n\n# <a name=\"Troop.slugify\" href=\"#Troop.slugify\">slugify</a>\n\nTurn a string based field into a url friendly slug\n\nConverts `this is a title` to `this-is-a-title`\n\n## Options\n\n* `target` schema path for slug destination (optional, default `slug`)\n* `source` schema path for slug content (optional, default `title`)\n* `maxLength` maximum slug length (optional, default `50`)\n* `spaceChar` space replacement character (optional, default `-`)\n* `invalidChar` invalid character replacement (optional, default ``)\n* `override` override slug field on source path change (optional, default `false`)\n\n## Methods\n\n### instance.slugify(string)\n\n### model.slugify(string)\n\n## Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , FooSchema = new mongoose.Schema()\n\nFooSchema.plugin(troop.slugify)\n\nvar instance = new FooSchema({title: 'well hello there!'})\n\ninstance.save(function(err, doc) {\n  console.log(doc.slug) // `well-hello-there`\n})\n````\n\n\n***\n\n# <a name=\"Troop.keywords\" href=\"#Troop.keywords\">keywords</a>\n\nKeyword extraction/creation plugin, can be used as a simple substitute of a full\nsearch indexing package.\n\nTurns `fooed bars` into `['foo', 'bar']`\n\n## Options\n\n* `target` schema path for keyword destination (optional, default `keywords`)\n* `source` schema path for extracting keywords, can be an array to specify multiple paths\n* `minLength` minimum string length to be used as a keyword (optional, default `2`)\n* `invalidChar` replacement char for invalid chars (optional, default ``)\n* `naturalize` specifies whether to use a porter stemmer for keywords (optional, default `false`)\n\n## Methods\n\n### instance.extractKeywords(str)\n\n### model.extractKeywords(str)\n\nManually calculate a keyword array with a given string\n\n## Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n\nvar FooSchema = new mongoose.Schema({\n  text: String\n})\n\nFooSchema.plugin(troop.keywords, {\n  source: 'text'\n})\n\nvar fooModel = mongoose.model('foo', FooSchema)\n  , instance = new FooSchema({text: 'i am the batman'})\n\nconsole.log(instance.keywords) // `['am', 'the', 'batman']`\n\nvar val = 'batman'\n\nfooModel.find({ keywords: { $in: fooModel.extractKeywords(val) }}, function(docs) {\n  // ...\n})\n````\n\n\n***\n\n# <a name=\"Troop.publish\" href=\"#Troop.publish\">publish</a>\n\nPlugin to publish/subscribe from a model or instance level, also enabling a model \nto automatically publish changes on `init`, `save`, and `remove` methods.  Both models \nand instances can be published/subscribed to.\n\n## Options\n\n* `auto` attach middleware based on the `hook` for `init`, `save`, and `remove` methods (optional, default `false`)\n* `hook` middleware method to attach auto middleware to (optional, default `post`)\n* `seperator` redis channel seperator (optional, default `:`)\n* `prefix` redis channel prefix, can be a string or function (optional, default ``)\n* `channel` channel for schema to publish/subscribe to, can be a string or function (optional, default `schema.constructor.modelName`)\n* `publish` redis instance to be used for publishing\n* `subscribe` redis instance to be used for subscribing\n\n## Methods\n\n### instance.publish(doc, options, callback)\n\n### instance.subscribe(callback)\n\n### instance.unsubscribe(callback)\n\n### instance.getChannel()\n\n### instance.on(event, callback)\n\n### model.subscribe(callback)\n\n### model.unsubscribe(callback)\n\n### model.getChannel()\n\n### model.on(event, callback)\n\n## Example\n\n```javascript\nvar redis = require('redis')\n  , publish = redis.createClient()\n  , subscribe = redis.createClient()\n  , mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n\nvar FooSchema = new mongoose.Schema({\n  name: String\n})\n\nFooSchema.plugin(troop.publish, {\n  publish: redis\n, subscribe: subscribe\n})\n\nvar FooModel = mongoose.model('foo', FooSchema)\n\nFooModel.subscribe() // channel: 'foos'\n\nFooModel.findOne({name: 'bar'}, function(err, instance) {\n  // ...\n})\n````\n\nOnce you have a mongoose instance you can now publish it, by default, a model or \ninstance will publish to it's own channel\n\n```javascript\ninstance.publish(null, {\n  method: 'save'\n}, function(err, count) {\n  // publishes to 'foos:4d6e5acebcd1b3fac9000007'\n})\n````\n\nYou can also publish other documents to other models or instances\n\n```javascript\nFooModel.publish(instance, function(err, count) {\n  // publishes to 'foos'\n})\n````\n\nor, if you have enabled `hooks`\n\n```javascript\ninstance.save()\n````\n\nYou can also subscribe on the instance level\n\n```javascript\ninstance.subscribe() // channel: 'foos:4d6e5acebcd1b3fac9000007'\n````\n\n\n***\n\n# <a name=\"Troop.pagination\" href=\"#Troop.pagination\">pagination</a>\n\nSimple query pagination routines.\n\n## Options\n\n* `defaultQuery` Query to use if not specified (optional, default `{}`)\n* `defaultLimit` Results per page to use if not specified (optional, default `10`)\n* `defaultFields` Fields to use if not specified (optional, default `[]`)\n* `remember` Remember the last options used for `query`, `limit`, and `fields` (optional, default `false`)\n\n## Methods\n\n### model.paginate(options, callback)\n\n### model.firstPage(options, callback)\n\n### model.lastPage(options, callback)\n\n## Example\n\nAssume that we have a collection with 55 records in it for the following example,\nwhere the `count` field is incremented by 1 for each record, starting at 1.\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n\nvar FooSchema = new mongoose.Schema({\n  name: String\n, count: Number\n})\n\nFooSchema.plugin(troop.pagination)\n\nvar FooModel = mongoose.model('foo', FooSchema)\n\nFooModel.paginate({ page: 1 }, function (err, docs, count, pages, current) {\n\n  // docs.length = 10\n  // count = 55\n  // pages = 6\n  // current = 1\n\n})\n````\n\nWhich, since using the default options, can also be written as:\n\n```javascript\nFooModel.firstPage(function (err, docs, count, pages, current) {\n  // ...\n})\n````\n\nOr, if you wanted the last page:\n\n```javascript\nFooModel.lastPage(function (err, docs, count, pages, current) {\n  // docs.length = 5\n  // current = 6\n})\n````\n\nA more verbose pagination call\n\n```javascript\nFooModel.paginate({\n  page: 2\n, query: { count: { $gt: 25 } }\n, limit: 25\n, fields: ['name']\n}, function(err, docs, count, pages, current) {\n  \n  // docs.length = 5\n  // count = 30\n  // pages = 2\n  // current = 2\n\n})\n````\n\n## Note\n\nIf using the `remember` option, the plugin will cache all of the options you give it \neach time you pass them in (except for the page), this can be handy if the params are \ngoing to be the same each time, if they are different you should not use this option.\n\nAlso, when on the last page, the plugin will return the trailing number of documents, \nin the example above the `lastPage` method returned 5 documents, it will never return \na full set specified by the `limit` when this is the case.\n\n\n***\n\n# <a name=\"Troop.rest\" href=\"#Troop.rest\">rest</a>\n\n## Options\n\n* `pagination` options to send to the pagination plugin above (optional, see plugin defaults above)\n\nCreate a REST-ful controller for your models for use with flatiron/director, express, dnode or socket.io\n\n\n***\n\n# <a name=\"Troop.obfuscate\" href=\"#Troop.obfuscate\">obfuscate</a>\n\nObjectID encrypt/decryption. Recursively traverses a document, encrypting or decrypting \nany ObjectID that is found to prevent leaking any server information contained in the ID, will \nwork with embedded documents as well as DBRefs.\n\n## Options\n\n* `encryptPath` Getter path for returning encrypted document (optional, default `obfuscate`)\n* `decryptPath` Setter path for decrypting an object and assigning it to the document (optional, default `deobfuscate`)\n* `algorithm` Encryption algorithm to use (optional, default `aes-256-cbc`)\n* `key` Encryption key to be used (optional, default `secret`)\n* `from` Encoding of the field to be encrypted (optional, default `utf8`)\n* `to` Encoding of the encrypted field (optional, default `hex`)\n\n## Methods\n\n###model.encrypt(string)\n\n###model.decrypt(string)\n\n###model.encode(object, boolean)\n\n###instance.encrypt(string)\n\n###instance.decrypt(string)\n\n## Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n\nvar BarSchema = new mongoose.Schema()\n  , UserSchema = new mongoose.Schema()\n  , SessionSchema = new mongoose.Schema()\n\n// A complicated schema\nvar FooSchema = new mongoose.Schema({\n  dbref: { type: ObjectId, ref: BarSchema }\n, dbrefArray: [{ type: ObjectId, ref: BarSchema }]\n, nested: {\n    dbref: { type: ObjectId, ref: BarSchema }\n  , dbrefArray: [{ type: ObjectId, ref: BarSchema }]\n  , embedded: [FooSchema]\n}\n, embedded: [FooSchema]\n, user: { \n    id: { type: Schema.ObjectId, ref: 'user' }\n  , session: {\n      sid: { type: Schema.ObjectId, ref: 'session' }\n    }\n  }\n})\n\nFooSchema.plugin(troop.obfuscate)\n\nvar FooModel = mongoose.model('foo', FooSchema)\n  , BarModel = mongoose.model('bar', BarSchema)\n  , UserModel = mongoose.model('user', UserSchema)\n  , SessionSchema = mongoose.model('session', SessionSchema)\n\nvar bar = new BarModel()\n  , user = new UserModel()\n  , session = new SessionModel()\n\nvar foo = new FooModel({\n  dbref: bar\n, dbrefArray: [foo2, foo3]\n, embeddedArray: [foo]\n, nested: {\n    dbref: foo\n  , dbrefArray: [foo2, foo3]\n  , nested: [foo]\n}\n, embedded: {\n    id: user._id\n  , session: { sid: session._id }\n  }\n})\n\nvar obfuscated = foo.obfuscate\n````\n\nNow we should have an obfuscated object like so\n\n```json\n{\n  _id: '0edaf91b2b5fa8c06413cdbf9ebed72a90a2c5ae4fe9b837d24865bd92c56ab2'\n, dbref: '0edaf91b2b5fa8c06413cdbf9ebed72a4735e5707b8423055431a1fe65adad6b'\n, dbrefArray: [\n    '0edaf91b2b5fa8c06413cdbf9ebed72a59ea2f1567c4ba640c02b02bb73f36d7'\n  , '0edaf91b2b5fa8c06413cdbf9ebed72aec369726048f7aa6cae9e8d20d7b2344'\n  ]\n, embedded: {\n    id: '0edaf91b2b5fa8c06413cdbf9ebed72a340f055306b64aeececd8835755008fc'\n  , session: {\n      sid: '0edaf91b2b5fa8c06413cdbf9ebed72a9f324d66d3a0e0d1c2fdd12d65efa3ea'\n    }\n  }\n, embeddedArray: [{\n    _id: '0edaf91b2b5fa8c06413cdbf9ebed72a4735e5707b8423055431a1fe65adad6b'\n  }]\n, nested: {\n    dbref: '0edaf91b2b5fa8c06413cdbf9ebed72a4735e5707b8423055431a1fe65adad6b'\n  , dbrefArray: [\n      '0edaf91b2b5fa8c06413cdbf9ebed72a59ea2f1567c4ba640c02b02bb73f36d7'\n    , '0edaf91b2b5fa8c06413cdbf9ebed72aec369726048f7aa6cae9e8d20d7b2344'\n    ]\n  , embeddedArray: [{\n      _id: '0edaf91b2b5fa8c06413cdbf9ebed72a4735e5707b8423055431a1fe65adad6b'\n    }]\n  }\n}\n````\n\nTo deobfuscate the object, we can assign it back to the original model, or to another.\n\n```javascript\nvar emptyFoo = new FooModel()\n\nemptyFoo.deobfuscate = obfuscated\n````\n\nWhich should give us back the original object\n\n```json\n{ \n  _id: 4f1b234afe789543a3000008\n, dbref: 4f1b234afe789543a3000003\n, dbrefArray: [ 4f1b234afe789543a3000004, 4f1b234afe789543a3000005 ] \n, embedded: { \n    id: 4f1b234afe789543a3000007\n  , session: { \n      sid: 4f1b234afe789543a3000006 \n    }\n  }\n, embeddedArray:  [{\n    _id: 4f1b234afe789543a3000003\n  }]\n, nested: { \n    dbref: 4f1b234afe789543a3000003\n  , dbrefArray: [ 4f1b234afe789543a3000004, 4f1b234afe789543a3000005 ] \n  , embeddedArray: [{\n      _id: 4f1b234afe789543a3000003\n    }]\n  }\n}\n````\n\n## Note\n\nThis plugin will not work with `Mixed` type schema paths, you will have to obfuscate\nthose manually\n\n\n***\n\n# <a name=\"Troop.utils\" href=\"#Troop.utils\">utils</a>\n\n## merge\n\nMerge JSON into your object more easily.\n\n```javascript\ninstance.merge({title:'A new title', description:'A new description'}).save()\n````\n\n### Options\n\n* `debug` verbose logging of current actions (optional, default `false`)\n\n## getdbrefs\n\nGet the dbrefs from a schema\n\n```javascript\ninstance.getdbrefs(function (refs) {\n  console.log(refs)\n  // ..\n  \n})\n\n```\n\n## removeDefaults\n\nRemove all of the default values from your model instance.\n\n`instance.removeDefaults().save()`\n\n### Options\n\n* `debug` verbose logging of current actions (optional, default `false`)\n\n\n## Contributing\n\nThis project is a work in progress and subject to API changes, please feel free to contribute\n\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2011-2012 Tom Blobaum <tblobaum@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","maintainers":[{"name":"tblobaum","email":"tblobaum@gmail.com"}],"directories":{}},"0.0.6":{"author":{"name":"Thomas Blobaum","email":"tblobaum@gmail.com","url":"https://github.com/tblobaum/"},"contributors":[{"name":"Profulla Sadangi","url":"https://github.com/butu5/"},{"name":"Beau Sorensen","url":"https://github.com/sorensen/"}],"name":"mongoose-troop","description":"plugins for mongoose","version":"0.0.6","homepage":"http://analyticsmachine.com","repository":{"type":"git","url":"git://github.com/tblobaum/mongoose-troop.git"},"scripts":{"test":"make test && make clean"},"engines":{"node":"0.x"},"dependencies":{"directory":"0.0.x","mongoose":"~2.4.10","bcrypt":"~0.5.0","redis":">= 0.7.1"},"devDependencies":{"mocha":"~0.10.0"},"_npmJsonOpts":{"file":"/home/tom/.npm/mongoose-troop/0.0.6/package/package.json","wscript":false,"contributors":false,"serverjs":false},"_id":"mongoose-troop@0.0.6","_engineSupported":true,"_npmVersion":"1.0.27","_nodeVersion":"v0.4.11","_defaultsLoaded":true,"dist":{"shasum":"2bf581daa0c677edb45672f08a702f9423bba18c","tarball":"https://registry.npmjs.org/mongoose-troop/-/mongoose-troop-0.0.6.tgz","integrity":"sha512-v27w2XztAOagaBsH78o01qJjm1FEE2Qsx6t/EtBBP1uODvX5x8nfWa0DNGoU9e1K3qri1/2Il57bx8zAx5Gj1Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDGV7ajgwI76TTqKFy9O0lBP+X8dPxf8l6iJJN/JwptEwIhAJI0I7U0wo2VPYuM+ArdSI70t5TUoxCdkEEYdooyVOjb"}]},"maintainers":[{"name":"tblobaum","email":"tblobaum@gmail.com"}],"directories":{}},"0.0.7":{"name":"mongoose-troop","version":"0.0.7","description":"a collection of plugins for mongoose","main":"index.js","bin":{},"directories":{"test":"test"},"scripts":{"test":"make test && make clean"},"optionalDependencies":{"bcrypt":"~0.5.0","redis":">= 0.7.1"},"dependencies":{"directory":"0.0.x","mongoose":"~2.4.10","bcrypt":"~0.5.0","redis":">= 0.7.1"},"devDependencies":{"mocha":"~0.10.0"},"repository":{"type":"git","url":"git://github.com/tblobaum/mongoose-troop.git"},"homepage":"https://github.com/tblobaum/mongoose-troop","keywords":["redis","stream"],"author":{"name":"Thomas Blobaum","email":"tblobaum@gmail.com","url":"https://github.com/tblobaum/"},"contributors":[{"name":"Profulla Sadangi","url":"https://github.com/butu5/"},{"name":"Beau Sorensen","url":"https://github.com/sorensen/"}],"license":"MIT","readme":"\n# Mongoose Troop [![Build Status](https://secure.travis-ci.org/tblobaum/mongoose-troop.png)](http://travis-ci.org/tblobaum/mongoose-troop) \n\nA collection of handy plugins for mongoose\n\n## Contents\n\n* [acl](#acl) (simple access control list)\n* [basicAuth](#basicauth) (simple authentication and registration)\n* [timestamp](#timestamp) (automatic created and modified timestamps)\n* [slugify](#slugify) (url-friendly copies of string properties)\n* [keywords](#keywords) (search-friendly array of stemmed words from string properties)\n* [pubsub](#pubsub) (message passing)\n* [pagination](#pagination) (query pagination)\n* [rest](#rest) (http or rpc controller)\n* [obfuscate](#obfuscate) (objectID encryption / decryption)\n* [merge](#merge) (merge a document into another)\n* [removeDefaults](#removedefaults) (remove default values from a document)\n* [getdbrefs](#getdbrefs) (find all document DBRefs)\n\nThe annotated source can be found [here](http://tblobaum.github.com/mongoose-troop/docs/)\n\n***\n\n## acl \nSimple access control list\n\n### Methods\n\n#### instance.addAccess(key)\n\nAdd `key` access to a Model instance\n\n#### instance.removeAccess(key)\n\nRemove `key` access to a Model instance\n\n#### instance.access(key [, callback])\n\nReturn or callback a boolean\n\n\n***\n\n## basicAuth \n\nSimple authentication plugin\n\n### Options\n\n* `loginPath` schema path for username/login (optional, default `username`)\n* `hashPath` schema path to hashed password (optional, default `hash`)\n* `workFactor` bcrypt work factor (optional, default `10`)\n\n### Methods\n\n#### instance.authenticate(password, callback)\n\nAuthenticate a mongoose document\n\n#### instance.setPassword(password, callback)\n\nSet the password for a mongoose document\n\n#### model.authenticate(username, password, callback)\n\nAuthenticate a user on the model level\n\n#### model.register(attributes, callback)\n\nCreate a new user with given attributes\n\n### Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n  , UserSchema = new mongoose.Schema()\n\nUserSchema.plugin(troop.basicAuth)\n\nvar User = mongoose.model('user', UserSchema)\n\nUser.register({\n  username: 'foo'\n, password: 'bar'\n}, function() {\n  // ...\n})\n\nUser.authenticate('foo', 'bar', function(err, doc) {\n  // ...\n})\n\nUser.findOne({ username: 'foo'}, function(err, doc) {\n  if (err || !doc) return\n  doc.setPassword('foobar', function(err) {\n    if (err) return\n    doc.authenticate('foobar', function() {\n      // ...\n    })\n  })\n})\n````\n\n\n***\n\n## timestamp \n\nAdds a `created` and `modified` property to the schema, updating the timestamps as expected.\n\n### Options\n\n* `createdPath` schema path for created timestamp (optional, default `created`)\n* `modifiedPath` schema path for modified timestamp (optional, default `modified`)\n* `useVirtual` use a virtual path for created timestamp based on ObjectId (optional, default `true`)\n\n### Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , FooSchema = new mongoose.Schema()\n\nFooSchema.plugin(troop.timestamp)\n````\n\n### Note\n\nUsing the virtual `created` timestamp you will lose the ability to run queries against it, \nas well as a loss in precision, as it will return a timestamp in seconds.\n\n\n***\n\n## slugify \n\nTurn a string based field into a url friendly slug\n\nConverts `this is a title` to `this-is-a-title`\n\n### Options\n\n* `target` schema path for slug destination (optional, default `slug`)\n* `source` schema path for slug content (optional, default `title`)\n* `maxLength` maximum slug length (optional, default `50`)\n* `spaceChar` space replacement character (optional, default `-`)\n* `invalidChar` invalid character replacement (optional, default ``)\n* `override` override slug field on source path change (optional, default `false`)\n\n### Methods\n\n#### instance.slugify(string)\n\n#### model.slugify(string)\n\n### Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , FooSchema = new mongoose.Schema()\n\nFooSchema.plugin(troop.slugify)\n\nvar instance = new FooSchema({title: 'well hello there!'})\n\ninstance.save(function(err, doc) {\n  console.log(doc.slug) // `well-hello-there`\n})\n````\n\n### Note\n\nThis plugin does not currently support nested paths\n\n\n***\n\n## keywords \n\nKeyword extraction/creation plugin, can be used as a simple substitute of a full\nsearch indexing package.\n\nTurns `fooed bars` into `['foo', 'bar']`\n\n### Options\n\n* `target` schema path for keyword destination (optional, default `keywords`)\n* `source` schema path for extracting keywords, can be an array to specify multiple paths\n* `minLength` minimum string length to be used as a keyword (optional, default `2`)\n* `invalidChar` replacement char for invalid chars (optional, default ``)\n* `naturalize` specifies whether to use a porter stemmer for keywords (optional, default `false`)\n\n### Methods\n\n#### instance.extractKeywords(str)\n\n#### model.extractKeywords(str)\n\nManually calculate a keyword array with a given string\n\n### Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n\nvar FooSchema = new mongoose.Schema({\n  text: String\n})\n\nFooSchema.plugin(troop.keywords, {\n  source: 'text'\n})\n\nvar fooModel = mongoose.model('foo', FooSchema)\n  , instance = new FooSchema({ text: 'i am the batman' })\n\nconsole.log(instance.keywords) // `['am', 'the', 'batman']`\n\nfooModel.find({ \n  keywords: { $in: fooModel.extractKeywords('batman') }\n}, function(docs) {\n  // ...\n})\n````\n\n### Note\n\nThis plugin does not currently support nested paths\n\n\n***\n\n## publish \n\nPlugin to publish/subscribe from a model or instance level, also enabling a model \nto automatically publish changes on `init`, `save`, and `remove` methods.  Both models \nand instances can be published/subscribed to.\n\n### Options\n\n* `auto` attach middleware based on the `hook` for `init`, `save`, and `remove` methods (optional, default `false`)\n* `hook` middleware method to attach auto middleware to (optional, default `post`)\n* `seperator` redis channel seperator (optional, default `:`)\n* `prefix` redis channel prefix, can be a string or function (optional, default ``)\n* `channel` channel for schema to publish/subscribe to, can be a string or function (optional, default `schema.constructor.modelName`)\n* `publish` redis instance to be used for publishing\n* `subscribe` redis instance to be used for subscribing\n\n### Methods\n\n#### instance.publish(doc, options, callback)\n\n#### instance.subscribe(callback)\n\n#### instance.unsubscribe(callback)\n\n#### instance.getChannel()\n\n#### instance.on(event, callback)\n\n#### model.subscribe(callback)\n\n#### model.unsubscribe(callback)\n\n#### model.getChannel()\n\n#### model.on(event, callback)\n\n### Example\n\n```javascript\nvar redis = require('redis')\n  , publish = redis.createClient()\n  , subscribe = redis.createClient()\n  , mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n\nvar FooSchema = new mongoose.Schema({\n  name: String\n})\n\nFooSchema.plugin(troop.publish, {\n  publish: redis\n, subscribe: subscribe\n})\n\nvar FooModel = mongoose.model('foo', FooSchema)\n\nFooModel.subscribe() // channel: 'foos'\n\nFooModel.findOne({name: 'bar'}, function(err, instance) {\n  // ...\n})\n````\n\nOnce you have a mongoose instance you can now publish it, by default, a model or \ninstance will publish to it's own channel\n\n```javascript\ninstance.publish(null, {\n  method: 'save'\n}, function(err, count) {\n  // publishes to 'foos:4d6e5acebcd1b3fac9000007'\n})\n````\n\nYou can also publish other documents to other models or instances\n\n```javascript\nFooModel.publish(instance, function(err, count) {\n  // publishes to 'foos'\n})\n````\n\nor, if you have enabled `hooks`\n\n```javascript\ninstance.save()\n````\n\nYou can also subscribe on the instance level\n\n```javascript\ninstance.subscribe() // channel: 'foos:4d6e5acebcd1b3fac9000007'\n````\n\n\n***\n\n## pagination \n\nSimple query pagination routines.\n\n### Options\n\n* `defaultQuery` Query to use if not specified (optional, default `{}`)\n* `defaultLimit` Results per page to use if not specified (optional, default `10`)\n* `defaultFields` Fields to use if not specified (optional, default `[]`)\n* `remember` Remember the last options used for `query`, `limit`, and `fields` (optional, default `false`)\n\n### Methods\n\n#### model.paginate(options, callback)\n\n#### model.firstPage(options, callback)\n\n#### model.lastPage(options, callback)\n\n### Example\n\nAssume that we have a collection with 55 records in it for the following example,\nwhere the `count` field is incremented by 1 for each record, starting at 1.\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n\nvar FooSchema = new mongoose.Schema({\n  name: String\n, count: Number\n})\n\nFooSchema.plugin(troop.pagination)\n\nvar FooModel = mongoose.model('foo', FooSchema)\n\nFooModel.paginate({ page: 1 }, function (err, docs, count, pages, current) {\n\n  // docs.length = 10\n  // count = 55\n  // pages = 6\n  // current = 1\n\n})\n````\n\nWhich, since using the default options, can also be written as:\n\n```javascript\nFooModel.firstPage(function (err, docs, count, pages, current) {\n  // ...\n})\n````\n\nOr, if you wanted the last page:\n\n```javascript\nFooModel.lastPage(function (err, docs, count, pages, current) {\n  // docs.length = 5\n  // current = 6\n})\n````\n\nA more verbose pagination call\n\n```javascript\nFooModel.paginate({\n  page: 2\n, query: { count: { $gt: 25 } }\n, limit: 25\n, fields: 'field1, field2'\n}, function(err, docs, count, pages, current) {\n  \n  // docs.length = 5\n  // count = 30\n  // pages = 2\n  // current = 2\n\n})\n````\n\n### Note\n\nIf using the `remember` option, the plugin will cache all of the options you give it \neach time you pass them in (except for the page), this can be handy if the params are \ngoing to be the same each time, if they are different you should not use this option.\n\nAlso, when on the last page, the plugin will return the trailing number of documents, \nin the example above the `lastPage` method returned 5 documents, it will never return \na full set specified by the `limit` when this is the case.\n\n\n***\n\n## rest \n\n### Options\n\n* `pagination` options to send to the pagination plugin above (optional, see plugin defaults above)\n\nCreate a REST-ful controller for your models for use with flatiron/director, express, dnode or socket.io\n\n\n***\n\n## obfuscate \n\nObjectID encrypt/decryption. Recursively traverses a document, encrypting or decrypting \nany ObjectID that is found to prevent leaking any server information contained in the ID, will \nwork with embedded documents as well as DBRefs.\n\n### Options\n\n* `encryptPath` Getter path for returning encrypted document (optional, default `obfuscate`)\n* `decryptPath` Setter path for decrypting an object and assigning it to the document (optional, default `deobfuscate`)\n* `algorithm` Encryption algorithm to use (optional, default `aes-256-cbc`)\n* `key` Encryption key to be used (optional, default `secret`)\n* `from` Encoding of the field to be encrypted (optional, default `utf8`)\n* `to` Encoding of the encrypted field (optional, default `hex`)\n\n### Methods\n\n####model.encrypt(string)\n\n####model.decrypt(string)\n\n####model.encode(object, boolean)\n\n####instance.encrypt(string)\n\n####instance.decrypt(string)\n\n### Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n\nvar BarSchema = new mongoose.Schema()\n  , UserSchema = new mongoose.Schema()\n  , SessionSchema = new mongoose.Schema()\n\n// A complicated schema\nvar FooSchema = new mongoose.Schema({\n  dbref: { type: ObjectId, ref: BarSchema }\n, dbrefArray: [{ type: ObjectId, ref: BarSchema }]\n, nested: {\n    dbref: { type: ObjectId, ref: BarSchema }\n  , dbrefArray: [{ type: ObjectId, ref: BarSchema }]\n  , embedded: [FooSchema]\n}\n, embedded: [FooSchema]\n, user: { \n    id: { type: Schema.ObjectId, ref: 'user' }\n  , session: {\n      sid: { type: Schema.ObjectId, ref: 'session' }\n    }\n  }\n})\n\nFooSchema.plugin(troop.obfuscate)\n\nvar FooModel = mongoose.model('foo', FooSchema)\n  , BarModel = mongoose.model('bar', BarSchema)\n  , UserModel = mongoose.model('user', UserSchema)\n  , SessionSchema = mongoose.model('session', SessionSchema)\n\nvar bar = new BarModel()\n  , user = new UserModel()\n  , session = new SessionModel()\n\nvar foo = new FooModel({\n  dbref: bar\n, dbrefArray: [foo2, foo3]\n, embeddedArray: [foo]\n, nested: {\n    dbref: foo\n  , dbrefArray: [foo2, foo3]\n  , nested: [foo]\n}\n, embedded: {\n    id: user._id\n  , session: { sid: session._id }\n  }\n})\n\nvar obfuscated = foo.obfuscate\n````\n\nNow we should have an obfuscated object like so\n\n``` js\n{\n  _id: '0edaf91b2b5fa8c06413cdbf9ebed72a90a2c5ae4fe9b837d24865bd92c56ab2'\n, dbref: '0edaf91b2b5fa8c06413cdbf9ebed72a4735e5707b8423055431a1fe65adad6b'\n, dbrefArray: [\n    '0edaf91b2b5fa8c06413cdbf9ebed72a59ea2f1567c4ba640c02b02bb73f36d7'\n  , '0edaf91b2b5fa8c06413cdbf9ebed72aec369726048f7aa6cae9e8d20d7b2344'\n  ]\n, embedded: {\n    id: '0edaf91b2b5fa8c06413cdbf9ebed72a340f055306b64aeececd8835755008fc'\n  , session: {\n      sid: '0edaf91b2b5fa8c06413cdbf9ebed72a9f324d66d3a0e0d1c2fdd12d65efa3ea'\n    }\n  }\n, embeddedArray: [{\n    _id: '0edaf91b2b5fa8c06413cdbf9ebed72a4735e5707b8423055431a1fe65adad6b'\n  }]\n, nested: {\n    dbref: '0edaf91b2b5fa8c06413cdbf9ebed72a4735e5707b8423055431a1fe65adad6b'\n  , dbrefArray: [\n      '0edaf91b2b5fa8c06413cdbf9ebed72a59ea2f1567c4ba640c02b02bb73f36d7'\n    , '0edaf91b2b5fa8c06413cdbf9ebed72aec369726048f7aa6cae9e8d20d7b2344'\n    ]\n  , embeddedArray: [{\n      _id: '0edaf91b2b5fa8c06413cdbf9ebed72a4735e5707b8423055431a1fe65adad6b'\n    }]\n  }\n}\n````\n\nTo deobfuscate the object, we can assign it back to the original model, or to another.\n\n```javascript\nvar emptyFoo = new FooModel()\n\nemptyFoo.deobfuscate = obfuscated\n````\n\nWhich should give us back the original object\n\n``` js\n{ \n  _id: 4f1b234afe789543a3000008\n, dbref: 4f1b234afe789543a3000003\n, dbrefArray: [ 4f1b234afe789543a3000004, 4f1b234afe789543a3000005 ] \n, embedded: { \n    id: 4f1b234afe789543a3000007\n  , session: { \n      sid: 4f1b234afe789543a3000006 \n    }\n  }\n, embeddedArray:  [{\n    _id: 4f1b234afe789543a3000003\n  }]\n, nested: { \n    dbref: 4f1b234afe789543a3000003\n  , dbrefArray: [ 4f1b234afe789543a3000004, 4f1b234afe789543a3000005 ] \n  , embeddedArray: [{\n      _id: 4f1b234afe789543a3000003\n    }]\n  }\n}\n````\n\n### Note\n\nThis plugin will not work with `Mixed` type schema paths, you will have to obfuscate\nthose manually\n\n\n***\n\n## merge \n\nMerge JSON into your object more easily.\n\n```javascript\ninstance.merge({title:'A new title', description:'A new description'}).save()\n````\n\n\n***\n\n## getdbrefs \n\nGet the dbrefs from a schema\n\n```javascript\ninstance.getdbrefs(function (refs) {\n  // ...\n})\n```\n\n### Note\n\nThis plugin does not currently support nested paths\n\n\n***\n\n## removeDefaults \n\nRemove all of the default values from your model instance.\n\n`instance.removeDefaults().save()`\n\n\n### Note\n\nThis plugin does not currently support nested paths\n\n\n***\n\n## Contributing\n\nThis project is a work in progress and subject to API changes, please feel free to contribute\n\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2011-2012 Tom Blobaum <tblobaum@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","_id":"mongoose-troop@0.0.7","dist":{"shasum":"88094aa9ac9da556c9a97db458e4e6464552f66b","tarball":"https://registry.npmjs.org/mongoose-troop/-/mongoose-troop-0.0.7.tgz","integrity":"sha512-27KxIb32dx/+duP45IqrbrB7NxcD5P+e4epurQSy6A4565y/fNx5mO/d4Ey1xt5FEiLEgFqCEEQmoXbNbHS5gQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCuOnL2/yE4Ni8Un0yHPUrxl91ccKAw4hgdXlfvgVUICQIgfvX5n0o7vI65Iimi1SKtwd3qiVHzh65DcT9+coSs8/o="}]},"maintainers":[{"name":"tblobaum","email":"tblobaum@gmail.com"}]},"0.0.8":{"name":"mongoose-troop","version":"0.0.8","description":"a collection of plugins for mongoose","main":"index.js","bin":{},"directories":{"test":"test"},"scripts":{"test":"make test && make clean"},"optionalDependencies":{"bcrypt":"~0.7.0","redis":">= 0.7.1"},"dependencies":{"directory":"0.0.x","mongoose":"~3.5.8","bcrypt":"~0.7.0","redis":">= 0.7.1"},"devDependencies":{"mocha":"~1.8.2"},"repository":{"type":"git","url":"git://github.com/tblobaum/mongoose-troop.git"},"homepage":"https://github.com/tblobaum/mongoose-troop","keywords":["mongoose","troop","acl","auth","slugify","keywords","search","paginate","pagination","obfuscate","merge","getdbrefs"],"author":{"name":"Thomas Blobaum","email":"tblobaum@gmail.com","url":"https://github.com/tblobaum/"},"contributors":[{"name":"Profulla Sadangi","url":"https://github.com/butu5/"},{"name":"Beau Sorensen","url":"https://github.com/sorensen/"}],"license":"MIT","readme":"\n# Mongoose Troop [![Build Status](https://secure.travis-ci.org/tblobaum/mongoose-troop.png)](http://travis-ci.org/tblobaum/mongoose-troop) \n\nA collection of handy plugins for mongoose\n\n## Contents\n\n* [acl](#acl) (simple access control list)\n* [basicAuth](#basicauth) (simple authentication and registration)\n* [timestamp](#timestamp) (automatic created and modified timestamps)\n* [slugify](#slugify) (url-friendly copies of string properties)\n* [keywords](#keywords) (search-friendly array of stemmed words from string properties)\n* [pubsub](#pubsub) (message passing)\n* [pagination](#pagination) (query pagination)\n* [rest](#rest) (http or rpc controller)\n* [obfuscate](#obfuscate) (objectID encryption / decryption)\n* [merge](#merge) (merge a document into another)\n* [removeDefaults](#removedefaults) (remove default values from a document)\n* [getdbrefs](#getdbrefs) (find all document DBRefs)\n\n<!-- The annotated source can be found [here](http://tblobaum.github.com/mongoose-troop/docs/) -->\n\n***\n\n## acl \nSimple access control list\n\n### Methods\n\n#### instance.addAccess(key)\n\nAdd `key` access to a Model instance\n\n#### instance.removeAccess(key)\n\nRemove `key` access to a Model instance\n\n#### instance.access(key [, callback])\n\nReturn or callback a boolean\n\n\n***\n\n## basicAuth \n\nSimple authentication plugin\n\n### Options\n\n* `loginPath` schema path for username/login (optional, default `username`)\n* `hashPath` schema path to hashed password (optional, default `hash`)\n* `workFactor` bcrypt work factor (optional, default `10`)\n\n### Methods\n\n#### instance.authenticate(password, callback)\n\nAuthenticate a mongoose document\n\n#### instance.setPassword(password, callback)\n\nSet the password for a mongoose document\n\n#### model.authenticate(username, password, callback)\n\nAuthenticate a user on the model level\n\n#### model.register(attributes, callback)\n\nCreate a new user with given attributes\n\n### Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n  , UserSchema = new mongoose.Schema()\n\nUserSchema.plugin(troop.basicAuth)\n\nvar User = mongoose.model('user', UserSchema)\n\nUser.register({\n  username: 'foo'\n, password: 'bar'\n}, function() {\n  // ...\n})\n\nUser.authenticate('foo', 'bar', function(err, doc) {\n  // ...\n})\n\nUser.findOne({ username: 'foo'}, function(err, doc) {\n  if (err || !doc) return\n  doc.setPassword('foobar', function(err) {\n    if (err) return\n    doc.authenticate('foobar', function() {\n      // ...\n    })\n  })\n})\n````\n\n\n***\n\n## timestamp \n\nAdds a `created` and `modified` property to the schema, updating the timestamps as expected.\n\n### Options\n\n* `createdPath` schema path for created timestamp (optional, default `created`)\n* `modifiedPath` schema path for modified timestamp (optional, default `modified`)\n* `useVirtual` use a virtual path for created timestamp based on ObjectId (optional, default `true`)\n\n### Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , FooSchema = new mongoose.Schema()\n\nFooSchema.plugin(troop.timestamp)\n````\n\n### Note\n\nUsing the virtual `created` timestamp you will lose the ability to run queries against it, \nas well as a loss in precision, as it will return a timestamp in seconds.\n\n\n***\n\n## slugify \n\nTurn a string based field into a url friendly slug\n\nConverts `this is a title` to `this-is-a-title`\n\n### Options\n\n* `target` schema path for slug destination (optional, default `slug`)\n* `source` schema path for slug content (optional, default `title`)\n* `maxLength` maximum slug length (optional, default `50`)\n* `spaceChar` space replacement character (optional, default `-`)\n* `invalidChar` invalid character replacement (optional, default ``)\n* `override` override slug field on source path change (optional, default `false`)\n\n### Methods\n\n#### instance.slugify(string)\n\n#### model.slugify(string)\n\n### Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , FooSchema = new mongoose.Schema()\n\nFooSchema.plugin(troop.slugify)\n\nvar instance = new FooSchema({title: 'well hello there!'})\n\ninstance.save(function(err, doc) {\n  console.log(doc.slug) // `well-hello-there`\n})\n````\n\n### Note\n\nThis plugin does not currently support nested paths\n\n\n***\n\n## keywords \n\nKeyword extraction/creation plugin, can be used as a simple substitute of a full\nsearch indexing package.\n\nTurns `fooed bars` into `['foo', 'bar']`\n\n### Options\n\n* `target` schema path for keyword destination (optional, default `keywords`)\n* `source` schema path for extracting keywords, can be an array to specify multiple paths\n* `minLength` minimum string length to be used as a keyword (optional, default `2`)\n* `invalidChar` replacement char for invalid chars (optional, default ``)\n* `naturalize` specifies whether to use a porter stemmer for keywords (optional, default `false`)\n\n### Methods\n\n#### instance.extractKeywords(str)\n\n#### model.extractKeywords(str)\n\nManually calculate a keyword array with a given string\n\n### Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n\nvar FooSchema = new mongoose.Schema({\n  text: String\n})\n\nFooSchema.plugin(troop.keywords, {\n  source: 'text'\n})\n\nvar fooModel = mongoose.model('foo', FooSchema)\n  , instance = new FooSchema({ text: 'i am the batman' })\n\nconsole.log(instance.keywords) // `['am', 'the', 'batman']`\n\nfooModel.find({ \n  keywords: { $in: fooModel.extractKeywords('batman') }\n}, function(docs) {\n  // ...\n})\n````\n\n### Note\n\nThis plugin does not currently support nested paths\n\n\n***\n\n## publish \n\nPlugin to publish/subscribe from a model or instance level, also enabling a model \nto automatically publish changes on `init`, `save`, and `remove` methods.  Both models \nand instances can be published/subscribed to.\n\n### Options\n\n* `auto` attach middleware based on the `hook` for `init`, `save`, and `remove` methods (optional, default `false`)\n* `hook` middleware method to attach auto middleware to (optional, default `post`)\n* `seperator` redis channel seperator (optional, default `:`)\n* `prefix` redis channel prefix, can be a string or function (optional, default ``)\n* `channel` channel for schema to publish/subscribe to, can be a string or function (optional, default `schema.constructor.modelName`)\n* `publish` redis instance to be used for publishing\n* `subscribe` redis instance to be used for subscribing\n\n### Methods\n\n#### instance.publish(doc, options, callback)\n\n#### instance.subscribe(callback)\n\n#### instance.unsubscribe(callback)\n\n#### instance.getChannel()\n\n#### instance.on(event, callback)\n\n#### model.subscribe(callback)\n\n#### model.unsubscribe(callback)\n\n#### model.getChannel()\n\n#### model.on(event, callback)\n\n### Example\n\n```javascript\nvar redis = require('redis')\n  , publish = redis.createClient()\n  , subscribe = redis.createClient()\n  , mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n\nvar FooSchema = new mongoose.Schema({\n  name: String\n})\n\nFooSchema.plugin(troop.publish, {\n  publish: redis\n, subscribe: subscribe\n})\n\nvar FooModel = mongoose.model('foo', FooSchema)\n\nFooModel.subscribe() // channel: 'foos'\n\nFooModel.findOne({name: 'bar'}, function(err, instance) {\n  // ...\n})\n````\n\nOnce you have a mongoose instance you can now publish it, by default, a model or \ninstance will publish to it's own channel\n\n```javascript\ninstance.publish(null, {\n  method: 'save'\n}, function(err, count) {\n  // publishes to 'foos:4d6e5acebcd1b3fac9000007'\n})\n````\n\nYou can also publish other documents to other models or instances\n\n```javascript\nFooModel.publish(instance, function(err, count) {\n  // publishes to 'foos'\n})\n````\n\nor, if you have enabled `hooks`\n\n```javascript\ninstance.save()\n````\n\nYou can also subscribe on the instance level\n\n```javascript\ninstance.subscribe() // channel: 'foos:4d6e5acebcd1b3fac9000007'\n````\n\n\n***\n\n## pagination \n\nSimple query pagination routines.\n\n### Options\n\n* `defaultQuery` Query to use if not specified (optional, default `{}`)\n* `defaultLimit` Results per page to use if not specified (optional, default `10`)\n* `defaultFields` Fields to use if not specified (optional, default `{}`)\n* `remember` Remember the last options used for `query`, `limit`, and `fields` (optional, default `false`)\n\n### Methods\n\n#### model.paginate(options, callback)\n\n#### model.firstPage(options, callback)\n\n#### model.lastPage(options, callback)\n\n### Example\n\nAssume that we have a collection with 55 records in it for the following example,\nwhere the `count` field is incremented by 1 for each record, starting at 1.\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n\nvar FooSchema = new mongoose.Schema({\n  name: String\n, count: Number\n})\n\nFooSchema.plugin(troop.pagination)\n\nvar FooModel = mongoose.model('foo', FooSchema)\n\nFooModel.paginate({ page: 1 }, function (err, docs, count, pages, current) {\n\n  // docs.length = 10\n  // count = 55\n  // pages = 6\n  // current = 1\n\n})\n````\n\nWhich, since using the default options, can also be written as:\n\n```javascript\nFooModel.firstPage(function (err, docs, count, pages, current) {\n  // ...\n})\n````\n\nOr, if you wanted the last page:\n\n```javascript\nFooModel.lastPage(function (err, docs, count, pages, current) {\n  // docs.length = 5\n  // current = 6\n})\n````\n\nA more verbose pagination call\n\n```javascript\nFooModel.paginate({\n  page: 2\n, query: { count: { $gt: 25 } }\n, limit: 25\n, fields: { 'field1: 1, field2': 1 }\n}, function(err, docs, count, pages, current) {\n  \n  // docs.length = 5\n  // count = 30\n  // pages = 2\n  // current = 2\n\n})\n````\n\n### Note\n\nIf using the `remember` option, the plugin will cache all of the options you give it \neach time you pass them in (except for the page), this can be handy if the params are \ngoing to be the same each time, if they are different you should not use this option.\n\nAlso, when on the last page, the plugin will return the trailing number of documents, \nin the example above the `lastPage` method returned 5 documents, it will never return \na full set specified by the `limit` when this is the case.\n\n\n***\n\n## rest \n\n### Options\n\n* `pagination` options to send to the pagination plugin above (optional, see plugin defaults above)\n\nCreate a REST-ful controller for your models for use with flatiron/director, express, dnode or socket.io\n\n\n***\n\n## obfuscate \n\nObjectID encrypt/decryption. Recursively traverses a document, encrypting or decrypting \nany ObjectID that is found to prevent leaking any server information contained in the ID, will \nwork with embedded documents as well as DBRefs.\n\n### Options\n\n* `encryptPath` Getter path for returning encrypted document (optional, default `obfuscate`)\n* `decryptPath` Setter path for decrypting an object and assigning it to the document (optional, default `deobfuscate`)\n* `algorithm` Encryption algorithm to use (optional, default `aes-256-cbc`)\n* `key` Encryption key to be used (optional, default `secret`)\n* `from` Encoding of the field to be encrypted (optional, default `utf8`)\n* `to` Encoding of the encrypted field (optional, default `hex`)\n\n### Methods\n\n####model.encrypt(string)\n\n####model.decrypt(string)\n\n####model.encode(object, boolean)\n\n####instance.encrypt(string)\n\n####instance.decrypt(string)\n\n### Example\n\n```javascript\nvar mongoose = require('mongoose')\n  , troop = require('mongoose-troop')\n  , db = mongoose.connect()\n\nvar BarSchema = new mongoose.Schema()\n  , UserSchema = new mongoose.Schema()\n  , SessionSchema = new mongoose.Schema()\n\n// A complicated schema\nvar FooSchema = new mongoose.Schema({\n  dbref: { type: ObjectId, ref: BarSchema }\n, dbrefArray: [{ type: ObjectId, ref: BarSchema }]\n, nested: {\n    dbref: { type: ObjectId, ref: BarSchema }\n  , dbrefArray: [{ type: ObjectId, ref: BarSchema }]\n  , embedded: [FooSchema]\n}\n, embedded: [FooSchema]\n, user: { \n    id: { type: Schema.ObjectId, ref: 'user' }\n  , session: {\n      sid: { type: Schema.ObjectId, ref: 'session' }\n    }\n  }\n})\n\nFooSchema.plugin(troop.obfuscate)\n\nvar FooModel = mongoose.model('foo', FooSchema)\n  , BarModel = mongoose.model('bar', BarSchema)\n  , UserModel = mongoose.model('user', UserSchema)\n  , SessionSchema = mongoose.model('session', SessionSchema)\n\nvar bar = new BarModel()\n  , user = new UserModel()\n  , session = new SessionModel()\n\nvar foo = new FooModel({\n  dbref: bar\n, dbrefArray: [foo2, foo3]\n, embeddedArray: [foo]\n, nested: {\n    dbref: foo\n  , dbrefArray: [foo2, foo3]\n  , nested: [foo]\n}\n, embedded: {\n    id: user._id\n  , session: { sid: session._id }\n  }\n})\n\nvar obfuscated = foo.obfuscate\n````\n\nNow we should have an obfuscated object like so\n\n``` js\n{\n  _id: '0edaf91b2b5fa8c06413cdbf9ebed72a90a2c5ae4fe9b837d24865bd92c56ab2'\n, dbref: '0edaf91b2b5fa8c06413cdbf9ebed72a4735e5707b8423055431a1fe65adad6b'\n, dbrefArray: [\n    '0edaf91b2b5fa8c06413cdbf9ebed72a59ea2f1567c4ba640c02b02bb73f36d7'\n  , '0edaf91b2b5fa8c06413cdbf9ebed72aec369726048f7aa6cae9e8d20d7b2344'\n  ]\n, embedded: {\n    id: '0edaf91b2b5fa8c06413cdbf9ebed72a340f055306b64aeececd8835755008fc'\n  , session: {\n      sid: '0edaf91b2b5fa8c06413cdbf9ebed72a9f324d66d3a0e0d1c2fdd12d65efa3ea'\n    }\n  }\n, embeddedArray: [{\n    _id: '0edaf91b2b5fa8c06413cdbf9ebed72a4735e5707b8423055431a1fe65adad6b'\n  }]\n, nested: {\n    dbref: '0edaf91b2b5fa8c06413cdbf9ebed72a4735e5707b8423055431a1fe65adad6b'\n  , dbrefArray: [\n      '0edaf91b2b5fa8c06413cdbf9ebed72a59ea2f1567c4ba640c02b02bb73f36d7'\n    , '0edaf91b2b5fa8c06413cdbf9ebed72aec369726048f7aa6cae9e8d20d7b2344'\n    ]\n  , embeddedArray: [{\n      _id: '0edaf91b2b5fa8c06413cdbf9ebed72a4735e5707b8423055431a1fe65adad6b'\n    }]\n  }\n}\n````\n\nTo deobfuscate the object, we can assign it back to the original model, or to another.\n\n```javascript\nvar emptyFoo = new FooModel()\n\nemptyFoo.deobfuscate = obfuscated\n````\n\nWhich should give us back the original object\n\n``` js\n{ \n  _id: 4f1b234afe789543a3000008\n, dbref: 4f1b234afe789543a3000003\n, dbrefArray: [ 4f1b234afe789543a3000004, 4f1b234afe789543a3000005 ] \n, embedded: { \n    id: 4f1b234afe789543a3000007\n  , session: { \n      sid: 4f1b234afe789543a3000006 \n    }\n  }\n, embeddedArray:  [{\n    _id: 4f1b234afe789543a3000003\n  }]\n, nested: { \n    dbref: 4f1b234afe789543a3000003\n  , dbrefArray: [ 4f1b234afe789543a3000004, 4f1b234afe789543a3000005 ] \n  , embeddedArray: [{\n      _id: 4f1b234afe789543a3000003\n    }]\n  }\n}\n````\n\n### Note\n\nThis plugin will not work with `Mixed` type schema paths, you will have to obfuscate\nthose manually\n\n\n***\n\n## merge \n\nMerge JSON into your object more easily.\n\n```javascript\ninstance.merge({title:'A new title', description:'A new description'}).save()\n````\n\n\n***\n\n## getdbrefs \n\nGet the dbrefs from a schema\n\n```javascript\ninstance.getdbrefs(function (refs) {\n  // ...\n})\n```\n\n### Note\n\nThis plugin does not currently support nested paths\n\n\n***\n\n## removeDefaults \n\nRemove all of the default values from your model instance.\n\n`instance.removeDefaults().save()`\n\n\n### Note\n\nThis plugin does not currently support nested paths\n\n\n***\n\n## Contributing\n\nThis project is a work in progress and subject to API changes, please feel free to contribute\n\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2011-2012 Tom Blobaum <tblobaum@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","_id":"mongoose-troop@0.0.8","dist":{"shasum":"2c948a0dea1725a6102637a4995cd5013625c254","tarball":"https://registry.npmjs.org/mongoose-troop/-/mongoose-troop-0.0.8.tgz","integrity":"sha512-AFdNJjL4xRdkbuISd3D/inh8UqtSx/YwrTmgVCTQNstT+hsnGp4enmwUhhTjmCnlA82Mpdw57NMoapPDjqGVNQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCmcP6eGL2IFzZbyogiTzUe7oKxu7V2ye9de9ZcKwBtCQIhAOcHrY413MFfSKZneea5PHYDmhAi+W6lNSfgc7ZlpCMQ"}]},"_npmVersion":"1.1.62","_npmUser":{"name":"tblobaum","email":"tblobaum@gmail.com"},"maintainers":[{"name":"tblobaum","email":"tblobaum@gmail.com"}]}},"readme":"","maintainers":[{"name":"tblobaum","email":"tblobaum@gmail.com"}],"time":{"modified":"2022-06-20T07:58:19.617Z","created":"2011-12-11T16:27:02.568Z","0.0.0":"2011-12-11T16:27:03.690Z","0.0.1":"2011-12-16T03:19:32.743Z","0.0.2":"2011-12-16T03:56:16.051Z","0.0.5":"2012-01-23T00:54:54.807Z","0.0.6":"2012-02-06T08:47:46.556Z","0.0.7":"2012-07-29T20:19:03.490Z","0.0.8":"2013-03-13T22:50:28.909Z"},"author":{"name":"Thomas Blobaum","email":"tblobaum@gmail.com","url":"https://github.com/tblobaum/"},"repository":{"type":"git","url":"git://github.com/tblobaum/mongoose-troop.git"},"users":{"fgribreau":true,"hoitmort":true,"kolomiichenko":true}}