UNPKG

4.82 kBJavaScriptView Raw
1'use strict';
2
3var normalize = require('../normalize');
4
5/**
6 * Access users based request information.
7 *
8 * @constructor
9 * @param {Registry} api Reference to the wrapping registry.
10 * @api private
11 */
12function Users(api) {
13 this.api = api;
14 this.send = api.send.bind(api);
15 this.view = api.view.bind(api);
16}
17
18/**
19 * Add a user as maintainer of a package.
20 *
21 * @param {String} name The user's name who needs to own the package.
22 * @param {String} pkg The module it should become an owner off.
23 * @param {Function} fn The callback.
24 * @returns {Assign}
25 * @api public
26 */
27Users.prototype.add = function add(name, pkg, fn) {
28 return this.send(name, {
29 method: 'PUT',
30 json: {}
31 }, fn);
32};
33
34/**
35 * Create a new npm account.
36 *
37 * @param {String} username The desired user name.
38 * @param {String} email Accounts email.
39 * @param {String} password Account password.
40 * @param {Function} fn Callback.
41 * @returns {Assign}
42 * @api public
43 */
44Users.prototype.create = function create(username, email, password, fn) {
45 password = (password || '').toString().trim();
46 username = (username || '').toString().trim();
47 email = (email || '').toString().trim();
48
49 //
50 // @TODO this will break our Assign return flow, making chaining impossible.
51 //
52 if (!password) return fn(new Error('Missing password'));
53 if (!~password.indexOf(':')) return fn(new Error('Password cannot contain a `:`'));
54 if (!email) return fn(new Error('Missing email'));
55 if (!~email.indexOf('@')) return fn(new Error('Invalid email address'));
56 if (!username) return fn(new Error('Missing username'));
57
58 return this.send('/-/user/org.couchdb.user:'+ encodeURIComponent(username), {
59 method: 'PUT',
60 json: {
61 _id: 'org.couchdb.user:'+ username
62 , date: (new Date()).toISOString()
63 , email: email
64 , name: username
65 , password: password
66 , roles: []
67 , type: 'user'
68 }
69 }, fn);
70};
71
72/**
73 * Update the user.
74 *
75 * @param {String} username The user's name.
76 * @param {Object} fields The fields we want to add.
77 * @param {Function} fn Completion callback.
78 * @returns {Assign}
79 * @api public
80 */
81Users.prototype.update = function update(username, fields, fn) {
82 username = '/-/user/org.couchdb.user:'+ encodeURIComponent(username);
83
84 var users = this;
85
86 /**
87 * Small helper function to handle revisions in CouchDB.
88 *
89 * @param {Error} err An optional error object.
90 * @param {String} _rev The current rev in the CouchDB.
91 * @param {Object} data Optional data.
92 * @api private
93 */
94 function rev(err, _rev, data) {
95 if (err) return fn(err);
96
97 return users.send(username +'/-rev/'+ _rev, {
98 method: 'PUT',
99 json: users.api.merge(data || {}, fields)
100 }, fn);
101 }
102
103 if ('_rev' in fields) return rev(undefined, fields._rev);
104 return this.send(username, rev);
105};
106
107/**
108 * List all packages for the given name.
109 *
110 * @param {String} name The user's name who's packages we want to list.
111 * @param {Function} fn The callback.
112 * @returns {Assign}
113 * @api public
114 */
115Users.prototype.list = function list(name, fn) {
116 return this.view('browseAuthors', {
117 key: name
118 }, fn)
119 .map(this.api.map.simple)
120 .filter(Boolean);
121};
122
123/**
124 * List all packages that the user has starred.
125 *
126 * @param {String} name The user's name
127 * @param {Function} fn The callback.
128 * @returns {Assign}
129 * @api public
130 */
131Users.prototype.starred = function starred(name, fn) {
132 return this.view('browseStarUser', {
133 key: name
134 }, fn)
135 .map(this.api.map.simple)
136 .filter(Boolean);
137};
138
139/**
140 * Get profile information.
141 *
142 * @param {String} username The user's name.
143 * @param {Function} fn The callback.
144 * @returns {Assign}
145 * @api public
146 */
147Users.prototype.get = function get(username, fn) {
148 username = '/-/user/org.couchdb.user:'+ encodeURIComponent(username);
149
150 return this.send(username, fn).map(normalize.users);
151};
152
153/**
154 * Sync ownership of npm modules with another account. This is useful if you
155 * have one base owner of modules like a corporate account and you want to
156 * on-board a new user.
157 *
158 * @param {String} source The user's packages that needs to be synced.
159 * @param {String} target The user who needs to have ownership.
160 * @param {Object} options Configuration of the sync process.
161 * @returns {Assign}
162 * @api public
163 */
164Users.prototype.sync = function sync(source, target, options, fn) {
165 if ('function' === typeof options) {
166 fn = options;
167 options = null;
168 }
169
170 options = options || {};
171 options.add = 'add' in options ? options.add : true;
172 options.packages = 'packages' in options ? options.packages : false;
173
174 var user = this;
175
176 this.list(source, function (err, packages) {
177 user.api.async.each(packages, function (name, next) {
178 user.add(target, name, next);
179 }, fn);
180 });
181};
182
183//
184// Expose module.
185//
186module.exports = Users;