acl.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. // Copyright 2019 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import { promisifyAll } from '@google-cloud/promisify';
  15. /**
  16. * Attach functionality to a {@link Storage.acl} instance. This will add an
  17. * object for each role group (owners, readers, and writers), with each object
  18. * containing methods to add or delete a type of entity.
  19. *
  20. * As an example, here are a few methods that are created.
  21. *
  22. * myBucket.acl.readers.deleteGroup('groupId', function(err) {});
  23. *
  24. * myBucket.acl.owners.addUser('email@example.com', function(err, acl) {});
  25. *
  26. * myBucket.acl.writers.addDomain('example.com', function(err, acl) {});
  27. *
  28. * @private
  29. */
  30. class AclRoleAccessorMethods {
  31. constructor() {
  32. this.owners = {};
  33. this.readers = {};
  34. this.writers = {};
  35. /**
  36. * An object of convenience methods to add or delete owner ACL permissions
  37. * for a given entity.
  38. *
  39. * The supported methods include:
  40. *
  41. * - `myFile.acl.owners.addAllAuthenticatedUsers`
  42. * - `myFile.acl.owners.deleteAllAuthenticatedUsers`
  43. * - `myFile.acl.owners.addAllUsers`
  44. * - `myFile.acl.owners.deleteAllUsers`
  45. * - `myFile.acl.owners.addDomain`
  46. * - `myFile.acl.owners.deleteDomain`
  47. * - `myFile.acl.owners.addGroup`
  48. * - `myFile.acl.owners.deleteGroup`
  49. * - `myFile.acl.owners.addProject`
  50. * - `myFile.acl.owners.deleteProject`
  51. * - `myFile.acl.owners.addUser`
  52. * - `myFile.acl.owners.deleteUser`
  53. *
  54. * @name Acl#owners
  55. *
  56. * @example
  57. * ```
  58. * const storage = require('@google-cloud/storage')();
  59. * const myBucket = storage.bucket('my-bucket');
  60. * const myFile = myBucket.file('my-file');
  61. *
  62. * //-
  63. * // Add a user as an owner of a file.
  64. * //-
  65. * const myBucket = gcs.bucket('my-bucket');
  66. * const myFile = myBucket.file('my-file');
  67. * myFile.acl.owners.addUser('email@example.com', function(err, aclObject)
  68. * {});
  69. *
  70. * //-
  71. * // For reference, the above command is the same as running the following.
  72. * //-
  73. * myFile.acl.add({
  74. * entity: 'user-email@example.com',
  75. * role: gcs.acl.OWNER_ROLE
  76. * }, function(err, aclObject) {});
  77. *
  78. * //-
  79. * // If the callback is omitted, we'll return a Promise.
  80. * //-
  81. * myFile.acl.owners.addUser('email@example.com').then(function(data) {
  82. * const aclObject = data[0];
  83. * const apiResponse = data[1];
  84. * });
  85. * ```
  86. */
  87. this.owners = {};
  88. /**
  89. * An object of convenience methods to add or delete reader ACL permissions
  90. * for a given entity.
  91. *
  92. * The supported methods include:
  93. *
  94. * - `myFile.acl.readers.addAllAuthenticatedUsers`
  95. * - `myFile.acl.readers.deleteAllAuthenticatedUsers`
  96. * - `myFile.acl.readers.addAllUsers`
  97. * - `myFile.acl.readers.deleteAllUsers`
  98. * - `myFile.acl.readers.addDomain`
  99. * - `myFile.acl.readers.deleteDomain`
  100. * - `myFile.acl.readers.addGroup`
  101. * - `myFile.acl.readers.deleteGroup`
  102. * - `myFile.acl.readers.addProject`
  103. * - `myFile.acl.readers.deleteProject`
  104. * - `myFile.acl.readers.addUser`
  105. * - `myFile.acl.readers.deleteUser`
  106. *
  107. * @name Acl#readers
  108. *
  109. * @example
  110. * ```
  111. * const storage = require('@google-cloud/storage')();
  112. * const myBucket = storage.bucket('my-bucket');
  113. * const myFile = myBucket.file('my-file');
  114. *
  115. * //-
  116. * // Add a user as a reader of a file.
  117. * //-
  118. * myFile.acl.readers.addUser('email@example.com', function(err, aclObject)
  119. * {});
  120. *
  121. * //-
  122. * // For reference, the above command is the same as running the following.
  123. * //-
  124. * myFile.acl.add({
  125. * entity: 'user-email@example.com',
  126. * role: gcs.acl.READER_ROLE
  127. * }, function(err, aclObject) {});
  128. *
  129. * //-
  130. * // If the callback is omitted, we'll return a Promise.
  131. * //-
  132. * myFile.acl.readers.addUser('email@example.com').then(function(data) {
  133. * const aclObject = data[0];
  134. * const apiResponse = data[1];
  135. * });
  136. * ```
  137. */
  138. this.readers = {};
  139. /**
  140. * An object of convenience methods to add or delete writer ACL permissions
  141. * for a given entity.
  142. *
  143. * The supported methods include:
  144. *
  145. * - `myFile.acl.writers.addAllAuthenticatedUsers`
  146. * - `myFile.acl.writers.deleteAllAuthenticatedUsers`
  147. * - `myFile.acl.writers.addAllUsers`
  148. * - `myFile.acl.writers.deleteAllUsers`
  149. * - `myFile.acl.writers.addDomain`
  150. * - `myFile.acl.writers.deleteDomain`
  151. * - `myFile.acl.writers.addGroup`
  152. * - `myFile.acl.writers.deleteGroup`
  153. * - `myFile.acl.writers.addProject`
  154. * - `myFile.acl.writers.deleteProject`
  155. * - `myFile.acl.writers.addUser`
  156. * - `myFile.acl.writers.deleteUser`
  157. *
  158. * @name Acl#writers
  159. *
  160. * @example
  161. * ```
  162. * const storage = require('@google-cloud/storage')();
  163. * const myBucket = storage.bucket('my-bucket');
  164. * const myFile = myBucket.file('my-file');
  165. *
  166. * //-
  167. * // Add a user as a writer of a file.
  168. * //-
  169. * myFile.acl.writers.addUser('email@example.com', function(err, aclObject)
  170. * {});
  171. *
  172. * //-
  173. * // For reference, the above command is the same as running the following.
  174. * //-
  175. * myFile.acl.add({
  176. * entity: 'user-email@example.com',
  177. * role: gcs.acl.WRITER_ROLE
  178. * }, function(err, aclObject) {});
  179. *
  180. * //-
  181. * // If the callback is omitted, we'll return a Promise.
  182. * //-
  183. * myFile.acl.writers.addUser('email@example.com').then(function(data) {
  184. * const aclObject = data[0];
  185. * const apiResponse = data[1];
  186. * });
  187. * ```
  188. */
  189. this.writers = {};
  190. AclRoleAccessorMethods.roles.forEach(this._assignAccessMethods.bind(this));
  191. }
  192. _assignAccessMethods(role) {
  193. const accessMethods = AclRoleAccessorMethods.accessMethods;
  194. const entities = AclRoleAccessorMethods.entities;
  195. const roleGroup = role.toLowerCase() + 's';
  196. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  197. this[roleGroup] = entities.reduce((acc, entity) => {
  198. const isPrefix = entity.charAt(entity.length - 1) === '-';
  199. accessMethods.forEach(accessMethod => {
  200. let method = accessMethod + entity[0].toUpperCase() + entity.substring(1);
  201. if (isPrefix) {
  202. method = method.replace('-', '');
  203. }
  204. // Wrap the parent accessor method (e.g. `add` or `delete`) to avoid the
  205. // more complex API of specifying an `entity` and `role`.
  206. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  207. acc[method] = (entityId, options, callback) => {
  208. let apiEntity;
  209. if (typeof options === 'function') {
  210. callback = options;
  211. options = {};
  212. }
  213. if (isPrefix) {
  214. apiEntity = entity + entityId;
  215. }
  216. else {
  217. // If the entity is not a prefix, it is a special entity group
  218. // that does not require further details. The accessor methods
  219. // only accept a callback.
  220. apiEntity = entity;
  221. callback = entityId;
  222. }
  223. options = Object.assign({
  224. entity: apiEntity,
  225. role,
  226. }, options);
  227. const args = [options];
  228. if (typeof callback === 'function') {
  229. args.push(callback);
  230. }
  231. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  232. return this[accessMethod].apply(this, args);
  233. };
  234. });
  235. return acc;
  236. }, {});
  237. }
  238. }
  239. AclRoleAccessorMethods.accessMethods = ['add', 'delete'];
  240. AclRoleAccessorMethods.entities = [
  241. // Special entity groups that do not require further specification.
  242. 'allAuthenticatedUsers',
  243. 'allUsers',
  244. // Entity groups that require specification, e.g. `user-email@example.com`.
  245. 'domain-',
  246. 'group-',
  247. 'project-',
  248. 'user-',
  249. ];
  250. AclRoleAccessorMethods.roles = ['OWNER', 'READER', 'WRITER'];
  251. /**
  252. * Cloud Storage uses access control lists (ACLs) to manage object and
  253. * bucket access. ACLs are the mechanism you use to share objects with other
  254. * users and allow other users to access your buckets and objects.
  255. *
  256. * An ACL consists of one or more entries, where each entry grants permissions
  257. * to an entity. Permissions define the actions that can be performed against an
  258. * object or bucket (for example, `READ` or `WRITE`); the entity defines who the
  259. * permission applies to (for example, a specific user or group of users).
  260. *
  261. * Where an `entity` value is accepted, we follow the format the Cloud Storage
  262. * API expects.
  263. *
  264. * Refer to
  265. * https://cloud.google.com/storage/docs/json_api/v1/defaultObjectAccessControls
  266. * for the most up-to-date values.
  267. *
  268. * - `user-userId`
  269. * - `user-email`
  270. * - `group-groupId`
  271. * - `group-email`
  272. * - `domain-domain`
  273. * - `project-team-projectId`
  274. * - `allUsers`
  275. * - `allAuthenticatedUsers`
  276. *
  277. * Examples:
  278. *
  279. * - The user "liz@example.com" would be `user-liz@example.com`.
  280. * - The group "example@googlegroups.com" would be
  281. * `group-example@googlegroups.com`.
  282. * - To refer to all members of the Google Apps for Business domain
  283. * "example.com", the entity would be `domain-example.com`.
  284. *
  285. * For more detailed information, see
  286. * {@link http://goo.gl/6qBBPO| About Access Control Lists}.
  287. *
  288. * @constructor Acl
  289. * @mixin
  290. * @param {object} options Configuration options.
  291. */
  292. class Acl extends AclRoleAccessorMethods {
  293. constructor(options) {
  294. super();
  295. this.pathPrefix = options.pathPrefix;
  296. this.request_ = options.request;
  297. }
  298. /**
  299. * @typedef {array} AddAclResponse
  300. * @property {object} 0 The Acl Objects.
  301. * @property {object} 1 The full API response.
  302. */
  303. /**
  304. * @callback AddAclCallback
  305. * @param {?Error} err Request error, if any.
  306. * @param {object} acl The Acl Objects.
  307. * @param {object} apiResponse The full API response.
  308. */
  309. /**
  310. * Add access controls on a {@link Bucket} or {@link File}.
  311. *
  312. * See {@link https://cloud.google.com/storage/docs/json_api/v1/bucketAccessControls/insert| BucketAccessControls: insert API Documentation}
  313. * See {@link https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls/insert| ObjectAccessControls: insert API Documentation}
  314. *
  315. * @param {object} options Configuration options.
  316. * @param {string} options.entity Whose permissions will be added.
  317. * @param {string} options.role Permissions allowed for the defined entity.
  318. * See {@link https://cloud.google.com/storage/docs/access-control Access
  319. * Control}.
  320. * @param {number} [options.generation] **File Objects Only** Select a specific
  321. * revision of this file (as opposed to the latest version, the default).
  322. * @param {string} [options.userProject] The ID of the project which will be
  323. * billed for the request.
  324. * @param {AddAclCallback} [callback] Callback function.
  325. * @returns {Promise<AddAclResponse>}
  326. *
  327. * @example
  328. * ```
  329. * const storage = require('@google-cloud/storage')();
  330. * const myBucket = storage.bucket('my-bucket');
  331. * const myFile = myBucket.file('my-file');
  332. *
  333. * const options = {
  334. * entity: 'user-useremail@example.com',
  335. * role: gcs.acl.OWNER_ROLE
  336. * };
  337. *
  338. * myBucket.acl.add(options, function(err, aclObject, apiResponse) {});
  339. *
  340. * //-
  341. * // For file ACL operations, you can also specify a `generation` property.
  342. * // Here is how you would grant ownership permissions to a user on a
  343. * specific
  344. * // revision of a file.
  345. * //-
  346. * myFile.acl.add({
  347. * entity: 'user-useremail@example.com',
  348. * role: gcs.acl.OWNER_ROLE,
  349. * generation: 1
  350. * }, function(err, aclObject, apiResponse) {});
  351. *
  352. * //-
  353. * // If the callback is omitted, we'll return a Promise.
  354. * //-
  355. * myBucket.acl.add(options).then(function(data) {
  356. * const aclObject = data[0];
  357. * const apiResponse = data[1];
  358. * });
  359. *
  360. * ```
  361. * @example <caption>include:samples/acl.js</caption>
  362. * region_tag:storage_add_file_owner
  363. * Example of adding an owner to a file:
  364. *
  365. * @example <caption>include:samples/acl.js</caption>
  366. * region_tag:storage_add_bucket_owner
  367. * Example of adding an owner to a bucket:
  368. *
  369. * @example <caption>include:samples/acl.js</caption>
  370. * region_tag:storage_add_bucket_default_owner
  371. * Example of adding a default owner to a bucket:
  372. */
  373. add(options, callback) {
  374. const query = {};
  375. if (options.generation) {
  376. query.generation = options.generation;
  377. }
  378. if (options.userProject) {
  379. query.userProject = options.userProject;
  380. }
  381. this.request({
  382. method: 'POST',
  383. uri: '',
  384. qs: query,
  385. maxRetries: 0, //explicitly set this value since this is a non-idempotent function
  386. json: {
  387. entity: options.entity,
  388. role: options.role.toUpperCase(),
  389. },
  390. }, (err, resp) => {
  391. if (err) {
  392. callback(err, null, resp);
  393. return;
  394. }
  395. callback(null, this.makeAclObject_(resp), resp);
  396. });
  397. }
  398. /**
  399. * @typedef {array} RemoveAclResponse
  400. * @property {object} 0 The full API response.
  401. */
  402. /**
  403. * @callback RemoveAclCallback
  404. * @param {?Error} err Request error, if any.
  405. * @param {object} apiResponse The full API response.
  406. */
  407. /**
  408. * Delete access controls on a {@link Bucket} or {@link File}.
  409. *
  410. * See {@link https://cloud.google.com/storage/docs/json_api/v1/bucketAccessControls/delete| BucketAccessControls: delete API Documentation}
  411. * See {@link https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls/delete| ObjectAccessControls: delete API Documentation}
  412. *
  413. * @param {object} options Configuration object.
  414. * @param {string} options.entity Whose permissions will be revoked.
  415. * @param {int} [options.generation] **File Objects Only** Select a specific
  416. * revision of this file (as opposed to the latest version, the default).
  417. * @param {string} [options.userProject] The ID of the project which will be
  418. * billed for the request.
  419. * @param {RemoveAclCallback} callback The callback function.
  420. * @returns {Promise<RemoveAclResponse>}
  421. *
  422. * @example
  423. * ```
  424. * const storage = require('@google-cloud/storage')();
  425. * const myBucket = storage.bucket('my-bucket');
  426. * const myFile = myBucket.file('my-file');
  427. *
  428. * myBucket.acl.delete({
  429. * entity: 'user-useremail@example.com'
  430. * }, function(err, apiResponse) {});
  431. *
  432. * //-
  433. * // For file ACL operations, you can also specify a `generation` property.
  434. * //-
  435. * myFile.acl.delete({
  436. * entity: 'user-useremail@example.com',
  437. * generation: 1
  438. * }, function(err, apiResponse) {});
  439. *
  440. * //-
  441. * // If the callback is omitted, we'll return a Promise.
  442. * //-
  443. * myFile.acl.delete().then(function(data) {
  444. * const apiResponse = data[0];
  445. * });
  446. *
  447. * ```
  448. * @example <caption>include:samples/acl.js</caption>
  449. * region_tag:storage_remove_bucket_owner
  450. * Example of removing an owner from a bucket:
  451. *
  452. * @example <caption>include:samples/acl.js</caption>
  453. * region_tag:storage_remove_bucket_default_owner
  454. * Example of removing a default owner from a bucket:
  455. *
  456. * @example <caption>include:samples/acl.js</caption>
  457. * region_tag:storage_remove_file_owner
  458. * Example of removing an owner from a bucket:
  459. */
  460. delete(options, callback) {
  461. const query = {};
  462. if (options.generation) {
  463. query.generation = options.generation;
  464. }
  465. if (options.userProject) {
  466. query.userProject = options.userProject;
  467. }
  468. this.request({
  469. method: 'DELETE',
  470. uri: '/' + encodeURIComponent(options.entity),
  471. qs: query,
  472. }, (err, resp) => {
  473. callback(err, resp);
  474. });
  475. }
  476. /**
  477. * @typedef {array} GetAclResponse
  478. * @property {object|object[]} 0 Single or array of Acl Objects.
  479. * @property {object} 1 The full API response.
  480. */
  481. /**
  482. * @callback GetAclCallback
  483. * @param {?Error} err Request error, if any.
  484. * @param {object|object[]} acl Single or array of Acl Objects.
  485. * @param {object} apiResponse The full API response.
  486. */
  487. /**
  488. * Get access controls on a {@link Bucket} or {@link File}. If
  489. * an entity is omitted, you will receive an array of all applicable access
  490. * controls.
  491. *
  492. * See {@link https://cloud.google.com/storage/docs/json_api/v1/bucketAccessControls/get| BucketAccessControls: get API Documentation}
  493. * See {@link https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls/get| ObjectAccessControls: get API Documentation}
  494. *
  495. * @param {object|function} [options] Configuration options. If you want to
  496. * receive a list of all access controls, pass the callback function as
  497. * the only argument.
  498. * @param {string} options.entity Whose permissions will be fetched.
  499. * @param {number} [options.generation] **File Objects Only** Select a specific
  500. * revision of this file (as opposed to the latest version, the default).
  501. * @param {string} [options.userProject] The ID of the project which will be
  502. * billed for the request.
  503. * @param {GetAclCallback} [callback] Callback function.
  504. * @returns {Promise<GetAclResponse>}
  505. *
  506. * @example
  507. * ```
  508. * const storage = require('@google-cloud/storage')();
  509. * const myBucket = storage.bucket('my-bucket');
  510. * const myFile = myBucket.file('my-file');
  511. *
  512. * myBucket.acl.get({
  513. * entity: 'user-useremail@example.com'
  514. * }, function(err, aclObject, apiResponse) {});
  515. *
  516. * //-
  517. * // Get all access controls.
  518. * //-
  519. * myBucket.acl.get(function(err, aclObjects, apiResponse) {
  520. * // aclObjects = [
  521. * // {
  522. * // entity: 'user-useremail@example.com',
  523. * // role: 'owner'
  524. * // }
  525. * // ]
  526. * });
  527. *
  528. * //-
  529. * // For file ACL operations, you can also specify a `generation` property.
  530. * //-
  531. * myFile.acl.get({
  532. * entity: 'user-useremail@example.com',
  533. * generation: 1
  534. * }, function(err, aclObject, apiResponse) {});
  535. *
  536. * //-
  537. * // If the callback is omitted, we'll return a Promise.
  538. * //-
  539. * myBucket.acl.get().then(function(data) {
  540. * const aclObject = data[0];
  541. * const apiResponse = data[1];
  542. * });
  543. *
  544. * ```
  545. * @example <caption>include:samples/acl.js</caption>
  546. * region_tag:storage_print_file_acl
  547. * Example of printing a file's ACL:
  548. *
  549. * @example <caption>include:samples/acl.js</caption>
  550. * region_tag:storage_print_file_acl_for_user
  551. * Example of printing a file's ACL for a specific user:
  552. *
  553. * @example <caption>include:samples/acl.js</caption>
  554. * region_tag:storage_print_bucket_acl
  555. * Example of printing a bucket's ACL:
  556. *
  557. * @example <caption>include:samples/acl.js</caption>
  558. * region_tag:storage_print_bucket_acl_for_user
  559. * Example of printing a bucket's ACL for a specific user:
  560. */
  561. get(optionsOrCallback, cb) {
  562. const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : null;
  563. const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
  564. let path = '';
  565. const query = {};
  566. if (options) {
  567. path = '/' + encodeURIComponent(options.entity);
  568. if (options.generation) {
  569. query.generation = options.generation;
  570. }
  571. if (options.userProject) {
  572. query.userProject = options.userProject;
  573. }
  574. }
  575. this.request({
  576. uri: path,
  577. qs: query,
  578. }, (err, resp) => {
  579. if (err) {
  580. callback(err, null, resp);
  581. return;
  582. }
  583. let results;
  584. if (resp.items) {
  585. results = resp.items.map(this.makeAclObject_);
  586. }
  587. else {
  588. results = this.makeAclObject_(resp);
  589. }
  590. callback(null, results, resp);
  591. });
  592. }
  593. /**
  594. * @typedef {array} UpdateAclResponse
  595. * @property {object} 0 The updated Acl Objects.
  596. * @property {object} 1 The full API response.
  597. */
  598. /**
  599. * @callback UpdateAclCallback
  600. * @param {?Error} err Request error, if any.
  601. * @param {object} acl The updated Acl Objects.
  602. * @param {object} apiResponse The full API response.
  603. */
  604. /**
  605. * Update access controls on a {@link Bucket} or {@link File}.
  606. *
  607. * See {@link https://cloud.google.com/storage/docs/json_api/v1/bucketAccessControls/update| BucketAccessControls: update API Documentation}
  608. * See {@link https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls/update| ObjectAccessControls: update API Documentation}
  609. *
  610. * @param {object} options Configuration options.
  611. * @param {string} options.entity Whose permissions will be updated.
  612. * @param {string} options.role Permissions allowed for the defined entity.
  613. * See {@link Storage.acl}.
  614. * @param {number} [options.generation] **File Objects Only** Select a specific
  615. * revision of this file (as opposed to the latest version, the default).
  616. * @param {string} [options.userProject] The ID of the project which will be
  617. * billed for the request.
  618. * @param {UpdateAclCallback} [callback] Callback function.
  619. * @returns {Promise<UpdateAclResponse>}
  620. *
  621. * @example
  622. * ```
  623. * const storage = require('@google-cloud/storage')();
  624. * const myBucket = storage.bucket('my-bucket');
  625. * const myFile = myBucket.file('my-file');
  626. *
  627. * const options = {
  628. * entity: 'user-useremail@example.com',
  629. * role: gcs.acl.WRITER_ROLE
  630. * };
  631. *
  632. * myBucket.acl.update(options, function(err, aclObject, apiResponse) {});
  633. *
  634. * //-
  635. * // For file ACL operations, you can also specify a `generation` property.
  636. * //-
  637. * myFile.acl.update({
  638. * entity: 'user-useremail@example.com',
  639. * role: gcs.acl.WRITER_ROLE,
  640. * generation: 1
  641. * }, function(err, aclObject, apiResponse) {});
  642. *
  643. * //-
  644. * // If the callback is omitted, we'll return a Promise.
  645. * //-
  646. * myFile.acl.update(options).then(function(data) {
  647. * const aclObject = data[0];
  648. * const apiResponse = data[1];
  649. * });
  650. * ```
  651. */
  652. update(options, callback) {
  653. const query = {};
  654. if (options.generation) {
  655. query.generation = options.generation;
  656. }
  657. if (options.userProject) {
  658. query.userProject = options.userProject;
  659. }
  660. this.request({
  661. method: 'PUT',
  662. uri: '/' + encodeURIComponent(options.entity),
  663. qs: query,
  664. json: {
  665. role: options.role.toUpperCase(),
  666. },
  667. }, (err, resp) => {
  668. if (err) {
  669. callback(err, null, resp);
  670. return;
  671. }
  672. callback(null, this.makeAclObject_(resp), resp);
  673. });
  674. }
  675. /**
  676. * Transform API responses to a consistent object format.
  677. *
  678. * @private
  679. */
  680. makeAclObject_(accessControlObject) {
  681. const obj = {
  682. entity: accessControlObject.entity,
  683. role: accessControlObject.role,
  684. };
  685. if (accessControlObject.projectTeam) {
  686. obj.projectTeam = accessControlObject.projectTeam;
  687. }
  688. return obj;
  689. }
  690. /**
  691. * Patch requests up to the bucket's request object.
  692. *
  693. * @private
  694. *
  695. * @param {string} method Action.
  696. * @param {string} path Request path.
  697. * @param {*} query Request query object.
  698. * @param {*} body Request body contents.
  699. * @param {function} callback Callback function.
  700. */
  701. request(reqOpts, callback) {
  702. reqOpts.uri = this.pathPrefix + reqOpts.uri;
  703. this.request_(reqOpts, callback);
  704. }
  705. }
  706. /*! Developer Documentation
  707. *
  708. * All async methods (except for streams) will return a Promise in the event
  709. * that a callback is omitted.
  710. */
  711. promisifyAll(Acl, {
  712. exclude: ['request'],
  713. });
  714. export { Acl, AclRoleAccessorMethods };