UNPKG

7.78 kBJavaScriptView Raw
1/* eslint-disable standard/no-callback-literal */
2module.exports = owner
3
4var npm = require('./npm.js')
5var log = require('npmlog')
6var mapToRegistry = require('./utils/map-to-registry.js')
7var readLocalPkg = require('./utils/read-local-package.js')
8var usage = require('./utils/usage')
9var output = require('./utils/output.js')
10
11owner.usage = usage(
12 'owner',
13 'npm owner add <user> [<@scope>/]<pkg>' +
14 '\nnpm owner rm <user> [<@scope>/]<pkg>' +
15 '\nnpm owner ls [<@scope>/]<pkg>'
16)
17owner.completion = function (opts, cb) {
18 var argv = opts.conf.argv.remain
19 if (argv.length > 4) return cb()
20 if (argv.length <= 2) {
21 var subs = ['add', 'rm']
22 if (opts.partialWord === 'l') subs.push('ls')
23 else subs.push('ls', 'list')
24 return cb(null, subs)
25 }
26
27 npm.commands.whoami([], true, function (er, username) {
28 if (er) return cb()
29
30 var un = encodeURIComponent(username)
31 var byUser, theUser
32 switch (argv[2]) {
33 case 'ls':
34 // FIXME: there used to be registry completion here, but it stopped
35 // making sense somewhere around 50,000 packages on the registry
36 return cb()
37
38 case 'rm':
39 if (argv.length > 3) {
40 theUser = encodeURIComponent(argv[3])
41 byUser = '-/by-user/' + theUser + '|' + un
42 return mapToRegistry(byUser, npm.config, function (er, uri, auth) {
43 if (er) return cb(er)
44
45 console.error(uri)
46 npm.registry.get(uri, { auth: auth }, function (er, d) {
47 if (er) return cb(er)
48 // return the intersection
49 return cb(null, d[theUser].filter(function (p) {
50 // kludge for server adminery.
51 return un === 'isaacs' || d[un].indexOf(p) === -1
52 }))
53 })
54 })
55 }
56 // else fallthrough
57 /* eslint no-fallthrough:0 */
58 case 'add':
59 if (argv.length > 3) {
60 theUser = encodeURIComponent(argv[3])
61 byUser = '-/by-user/' + theUser + '|' + un
62 return mapToRegistry(byUser, npm.config, function (er, uri, auth) {
63 if (er) return cb(er)
64
65 console.error(uri)
66 npm.registry.get(uri, { auth: auth }, function (er, d) {
67 console.error(uri, er || d)
68 // return mine that they're not already on.
69 if (er) return cb(er)
70 var mine = d[un] || []
71 var theirs = d[theUser] || []
72 return cb(null, mine.filter(function (p) {
73 return theirs.indexOf(p) === -1
74 }))
75 })
76 })
77 }
78 // just list all users who aren't me.
79 return mapToRegistry('-/users', npm.config, function (er, uri, auth) {
80 if (er) return cb(er)
81
82 npm.registry.get(uri, { auth: auth }, function (er, list) {
83 if (er) return cb()
84 return cb(null, Object.keys(list).filter(function (n) {
85 return n !== un
86 }))
87 })
88 })
89
90 default:
91 return cb()
92 }
93 })
94}
95
96function owner (args, cb) {
97 var action = args.shift()
98 switch (action) {
99 case 'ls': case 'list': return ls(args[0], cb)
100 case 'add': return add(args[0], args[1], cb)
101 case 'rm': case 'remove': return rm(args[0], args[1], cb)
102 default: return unknown(action, cb)
103 }
104}
105
106function ls (pkg, cb) {
107 if (!pkg) {
108 return readLocalPkg(function (er, pkg) {
109 if (er) return cb(er)
110 if (!pkg) return cb(owner.usage)
111 ls(pkg, cb)
112 })
113 }
114
115 mapToRegistry(pkg, npm.config, function (er, uri, auth) {
116 if (er) return cb(er)
117
118 npm.registry.get(uri, { auth: auth }, function (er, data) {
119 var msg = ''
120 if (er) {
121 log.error('owner ls', "Couldn't get owner data", pkg)
122 return cb(er)
123 }
124 var owners = data.maintainers
125 if (!owners || !owners.length) {
126 msg = 'admin party!'
127 } else {
128 msg = owners.map(function (o) {
129 return o.name + ' <' + o.email + '>'
130 }).join('\n')
131 }
132 output(msg)
133 cb(er, owners)
134 })
135 })
136}
137
138function add (user, pkg, cb) {
139 if (!user) return cb(owner.usage)
140 if (!pkg) {
141 return readLocalPkg(function (er, pkg) {
142 if (er) return cb(er)
143 if (!pkg) return cb(new Error(owner.usage))
144 add(user, pkg, cb)
145 })
146 }
147
148 log.verbose('owner add', '%s to %s', user, pkg)
149 mutate(pkg, user, function (u, owners) {
150 if (!owners) owners = []
151 for (var i = 0, l = owners.length; i < l; i++) {
152 var o = owners[i]
153 if (o.name === u.name) {
154 log.info(
155 'owner add',
156 'Already a package owner: ' + o.name + ' <' + o.email + '>'
157 )
158 return false
159 }
160 }
161 owners.push(u)
162 return owners
163 }, cb)
164}
165
166function rm (user, pkg, cb) {
167 if (!pkg) {
168 return readLocalPkg(function (er, pkg) {
169 if (er) return cb(er)
170 if (!pkg) return cb(new Error(owner.usage))
171 rm(user, pkg, cb)
172 })
173 }
174
175 log.verbose('owner rm', '%s from %s', user, pkg)
176 mutate(pkg, user, function (u, owners) {
177 var found = false
178 var m = owners.filter(function (o) {
179 var match = (o.name === user)
180 found = found || match
181 return !match
182 })
183
184 if (!found) {
185 log.info('owner rm', 'Not a package owner: ' + user)
186 return false
187 }
188
189 if (!m.length) {
190 return new Error(
191 'Cannot remove all owners of a package. Add someone else first.'
192 )
193 }
194
195 return m
196 }, cb)
197}
198
199function mutate (pkg, user, mutation, cb) {
200 if (user) {
201 var byUser = '-/user/org.couchdb.user:' + user
202 mapToRegistry(byUser, npm.config, function (er, uri, auth) {
203 if (er) return cb(er)
204
205 npm.registry.get(uri, { auth: auth }, mutate_)
206 })
207 } else {
208 mutate_(null, null)
209 }
210
211 function mutate_ (er, u) {
212 if (!er && user && (!u || u.error)) {
213 er = new Error(
214 "Couldn't get user data for " + user + ': ' + JSON.stringify(u)
215 )
216 }
217
218 if (er) {
219 log.error('owner mutate', 'Error getting user data for %s', user)
220 return cb(er)
221 }
222
223 if (u) u = { name: u.name, email: u.email }
224 mapToRegistry(pkg, npm.config, function (er, uri, auth) {
225 if (er) return cb(er)
226
227 npm.registry.get(uri, { auth: auth }, function (er, data) {
228 if (er) {
229 log.error('owner mutate', 'Error getting package data for %s', pkg)
230 return cb(er)
231 }
232
233 // save the number of maintainers before mutation so that we can figure
234 // out if maintainers were added or removed
235 var beforeMutation = data.maintainers.length
236
237 var m = mutation(u, data.maintainers)
238 if (!m) return cb() // handled
239 if (m instanceof Error) return cb(m) // error
240
241 data = {
242 _id: data._id,
243 _rev: data._rev,
244 maintainers: m
245 }
246 var dataPath = pkg.replace('/', '%2f') + '/-rev/' + data._rev
247 mapToRegistry(dataPath, npm.config, function (er, uri, auth) {
248 if (er) return cb(er)
249
250 var params = {
251 method: 'PUT',
252 body: data,
253 auth: auth
254 }
255 npm.registry.request(uri, params, function (er, data) {
256 if (!er && data.error) {
257 er = new Error('Failed to update package metadata: ' + JSON.stringify(data))
258 }
259
260 if (er) {
261 log.error('owner mutate', 'Failed to update package metadata')
262 } else if (m.length > beforeMutation) {
263 output('+ %s (%s)', user, pkg)
264 } else if (m.length < beforeMutation) {
265 output('- %s (%s)', user, pkg)
266 }
267
268 cb(er, data)
269 })
270 })
271 })
272 })
273 }
274}
275
276function unknown (action, cb) {
277 cb('Usage: \n' + owner.usage)
278}