Guest User

Untitled

a guest
Jul 18th, 2018
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.17 KB | None | 0 0
  1. (function (exports) {
  2. if (typeof JSON === "undefined") {
  3. throw new Error("JSON is required. Plesae include json2.js if you are running this in the browser");
  4. }
  5.  
  6. var
  7. Q = require("promised-io/promise"),
  8. HttpClient = require("promised-io/http-client").Client,
  9. Trait = require("traits").Trait,
  10. base64 = require("./base64"),
  11. when = Q.when,
  12. defineProperty = Object.defineProperty,
  13. httpMethod = {
  14. POST: "POST",
  15. GET: "GET",
  16. DELETE: "DELETE",
  17. PUT: "PUT"
  18. };
  19.  
  20. exports.createClient = function(opts) {
  21. opts = opts || {};
  22.  
  23. var
  24. client = new HttpClient(),
  25. couchClient = new CouchClient(client); // add this line
  26. // this line is throwing the error -> couchClient = Trait.create(new CouchClient(client), Trait(opts));
  27.  
  28. return couchClient;
  29. };
  30.  
  31. function CouchClient(httpClient){
  32. this.httpClient = httpClient;
  33. }
  34.  
  35. /**
  36. * Get options for http client request
  37. *
  38. * @api private
  39. * @return {Object} Request options
  40. */
  41. CouchClient.prototype.getRequestOptions = function(opts) {
  42. var defaults = {
  43. hostname: this.host,
  44. port: this.port,
  45. headers: { "Content-Type": "application/json" }
  46. };
  47.  
  48. opts = complete(opts, defaults);
  49. if (opts.headers["Content-Type"] === undefined || opts.headers["Content-Type"] === null) {
  50. opts.headers["Content-Type"] = "application/json";
  51. }
  52.  
  53. if (this.user) {
  54. opts.headers["Authorization"] = "Basic "+base64.encode(this.user+":"+this.password);
  55. } else if (this.authSession) {
  56. if (opts.headers.cookie) {
  57. opts.headers.cookie += ";";
  58. } else {
  59. opts.headers.cookie = "";
  60. }
  61. opts.headers.cookie += "AuthSession="+this.authSession;
  62. }
  63.  
  64. if (typeof opts.body === "string") {
  65. opts.body = [opts.body];
  66. }
  67.  
  68. return opts;
  69. };
  70.  
  71. var parseBody = exports.parseBody = function(resp) {
  72. var body = "";
  73. return when(resp.body.forEach(function(chunk) { body += chunk; }), function() {
  74. var val;
  75.  
  76. try {
  77. val = JSON.parse(body);
  78. } catch (err) {
  79. console.log("parse error:" + body);
  80. throw { error: 'ParseError', reason: body };
  81. }
  82.  
  83. if (resp.status >= 400) {
  84. val.status = resp.status;
  85. throw val;
  86. }
  87.  
  88. return val;
  89. });
  90. }
  91.  
  92. CouchClient.prototype.requestRaw = function(opts) {
  93. var opts = this.getRequestOptions(opts);
  94.  
  95. return this.httpClient.request(opts);
  96. };;
  97.  
  98. CouchClient.prototype.request = function(opts) {
  99. var opts = this.getRequestOptions(opts);
  100.  
  101. return when(this.httpClient.request(opts), function success(resp) {
  102. var body = "";
  103. return parseBody(resp);
  104. });
  105. };
  106.  
  107. CouchClient.prototype.prepareUserDoc = function(doc, password) {
  108. doc._id = doc._id || USER_PREFIX+doc.name;
  109. doc.type = "user";
  110. doc.roles = doc.roles || [];
  111.  
  112. if (password) {
  113. return when(this.uuids(1), function(uuids) {
  114. doc.salt = uuids[0];
  115. doc.password_sha = require("./sha1").hex_sha1(password + doc.salt);
  116.  
  117. return doc;
  118. });
  119.  
  120. }
  121. return doc;
  122. };
  123.  
  124. /**
  125. * Get the users DB for this CouchDB Server
  126. * @returns {Promise} A promise that resolves to the users database
  127. */
  128. CouchClient.prototype.userDb = function() {
  129. var self = this;
  130.  
  131. return when(this.session(), function(resp) {
  132. var
  133. userDbName = resp.info.authentication_db,
  134. userDb = self.db(userDbName);
  135.  
  136. userDb.hasUser = function(name) {
  137. return this.exists(USER_PREFIX+name);
  138. };
  139.  
  140. return userDb;
  141. });
  142. };
  143.  
  144. CouchClient.prototype.signup = function(user, newPassword, opts) {
  145. var self = this;
  146.  
  147. opts = opts || {};
  148.  
  149. return when(this.userDb(), function(db) {
  150. return when(self.prepareUserDoc(user, newPassword), function(doc) {
  151. return db.saveDoc(doc);
  152. });
  153. });
  154. };
  155.  
  156. CouchClient.prototype.login = function(name, password) {
  157. return this.requestRaw({
  158. pathInfo: "/_session",
  159. method: httpMethod.POST,
  160. headers: { "Content-Type": "application/x-www-form-urlencoded", "X-CouchDB-WWW-Authenticate": "Cookie" },
  161. body: "name="+encodeURIComponent(name)+"&password="+encodeURIComponent(password)
  162. });
  163. };
  164.  
  165. CouchClient.prototype.logout = CouchClient.prototype.logoff = function() {
  166. return this.request({
  167. pathInfo: "/_session",
  168. method: httpMethod.DELETE,
  169. headers: {
  170. "Content-Type": "application/x-www-form-urlencoded",
  171. "X-CouchDB-WWW-Authenticate": "Cookie"
  172. }
  173. });
  174. };
  175.  
  176. CouchClient.prototype.allDbs = function() {
  177. return this.request({
  178. pathInfo: "/_all_dbs"
  179. });
  180. };
  181.  
  182. CouchClient.prototype.config = function() {
  183. return this.request({
  184. pathInfo: "/_config"
  185. });
  186. };
  187.  
  188. CouchClient.prototype.session = function() {
  189. return this.request({
  190. pathInfo: "/_session"
  191. });
  192. };
  193.  
  194. /**
  195. * Retrieve unique identifiers generated by CouchDB
  196. *
  197. * @param {Number|Function} count If this is a function, it becomes the callback. If it is a number, it is the number of unique identifiers to retrieve
  198. * @param {Function} cb Callback
  199. * @api public
  200. */
  201. CouchClient.prototype.uuids = function(count) {
  202. var jsgiRequest = {
  203. pathInfo: "/_uuids"
  204. };
  205.  
  206. if (count) {
  207. jsgiRequest.queryString = "count="+count;
  208. }
  209.  
  210. return when(this.request(jsgiRequest), function(resp) {
  211. return resp.uuids;
  212. });
  213. };
  214.  
  215. CouchClient.prototype.replicate = function(source, target, opts) {
  216. opts = complete({}, {
  217. source: source,
  218. target: target
  219. }, opts);
  220.  
  221. var req = {
  222. method: httpMethod.POST,
  223. pathInfo: "/_replicate",
  224. body: [JSON.stringify(opts)]
  225. };
  226.  
  227. if (opts.queryString) {
  228. req.queryString = opts.queryString;
  229. delete opts.queryString;
  230. }
  231.  
  232. return this.request(req);
  233. };
  234.  
  235. CouchClient.prototype.stats = function() {
  236. var args = Array.prototype.slice.call(arguments);
  237.  
  238. return this.request({
  239. pathInfo: "/_stats" + ((args && args.length > 0) ? "/" + args.join("/") : "")
  240. });
  241. };
  242.  
  243. CouchClient.prototype.activeTasks = function() {
  244. return this.request({
  245. path: "/_active_tasks"
  246. });
  247. };
  248.  
  249. CouchClient.prototype.session = function() {
  250. return this.request({
  251. pathInfo: "/_session"
  252. });
  253. };
  254.  
  255. CouchClient.prototype.db = function(name) {
  256. if (name === undefined || name === null || name === "") {
  257. throw new Error("Name must contain a value");
  258. }
  259.  
  260. var
  261. couchClient = this;
  262. db = Object.create(new Database(),
  263. {
  264. "name": {
  265. get: function() { return name; }
  266. },
  267. "client": {
  268. get: function() { return couchClient; }
  269. }
  270. });
  271.  
  272. db.request = function(opts) {
  273. opts = opts || {};
  274. opts.pathInfo = "/"+name+(opts.path || "");
  275.  
  276. return couchClient.request(opts);
  277. };
  278. db.view = function(designDoc, viewName, opts){
  279. opts = opts || {};
  280. opts.pathInfo = "/" + this.name +"/_design/" + designDoc + "/_view/" + viewName + encodeOptions(opts);
  281. return couchClient.request(opts);
  282. };
  283. return db;
  284. };
  285.  
  286. var Database = exports.Database = function() {};
  287.  
  288. Database.prototype.exists = function() {
  289. return when(this.request({ pathInfo: "" }), function(resp) {
  290. return true;
  291. }, function(err) {
  292. return !(err.error && err.error === "not_found");
  293. });
  294. };
  295.  
  296. Database.prototype.info = function() {
  297. return this.request({}, cb);
  298. };
  299.  
  300. Database.prototype.create = function() {
  301. return this.request({
  302. method: httpMethod.PUT
  303. });
  304. };
  305.  
  306. /**
  307. * Permanently delete database
  308. *
  309. * @return {Promise} a promise
  310. * @api public
  311. */
  312. Database.prototype.remove = function() {
  313. return this.request({
  314. method: httpMethod.DELETE
  315. });
  316. };
  317.  
  318. Database.prototype.allDocs = function() {
  319. return this.request({
  320. path: "/_all_docs"
  321. });
  322. };
  323.  
  324. /**
  325. * Retrieve document by unique identifier
  326. *
  327. * @param {String} id Unique identifier of the document
  328. * @param {Function} cb Callback
  329. * @api public
  330. */
  331. Database.prototype.getDoc = Database.prototype.openDoc = function(id) {
  332. return when(this.request({
  333. path: "/"+id
  334. }), function(doc) {
  335. return doc;
  336. }, function(err) {
  337. if (err.status === 404) {
  338. return null;
  339. }
  340.  
  341. throw err;
  342. });
  343. };
  344.  
  345.  
  346.  
  347. Database.prototype.getAttachmentResponse = function(doc, attachmentName){
  348. return this.request({
  349. method:httpMethod.GET,
  350. path:"/"+this.name + "/" + doc._id + "/" + attachmentName
  351. })
  352. };
  353.  
  354. Database.prototype.saveDoc = function(doc, opts) {
  355. var
  356. method = httpMethod.PUT
  357. , path = "/";
  358.  
  359. if (doc._id === undefined) {
  360. method = httpMethod.POST;
  361. } else {
  362. path += doc._id;
  363. }
  364.  
  365. return this.request({
  366. method: method,
  367. path: path,
  368. body: typeof doc === "string" ? [doc] : [JSON.stringify(doc)]
  369. });
  370. };
  371.  
  372. Database.prototype.removeDoc = function(id, rev) {
  373. return this.request({
  374. method: httpMethod.DELETE,
  375. path: "/"+id,
  376. queryString: "rev="+rev
  377. });
  378. };
  379.  
  380. Database.prototype.security = function(obj) {
  381. if (obj === undefined || obj === null) {
  382. return this.request({
  383. method: httpMethod.GET,
  384. path: "/_security"
  385. });
  386. }
  387.  
  388. return this.request({
  389. method: httpMethod.PUT,
  390. path: "/_security",
  391. body: [ JSON.stringify(obj) ]
  392. });
  393. };
  394.  
  395. /**
  396. * @api private
  397. */
  398. function getRequestOptions(args) {
  399. args = Array.prototype.slice.call(args);
  400.  
  401. var
  402. cb = args.pop(),
  403. method = args.shift(),
  404. path = args.shift(),
  405. data = args.shift(),
  406. opts;
  407.  
  408.  
  409. if (typeof method === "object") {
  410. opts = method;
  411. } else if (typeof method === "string" && typeof path !== "string") {
  412. opts = {
  413. path: method,
  414. query: path
  415. };
  416. } else {
  417. opts = {
  418. method: method,
  419. path: path,
  420. data: data
  421. };
  422. }
  423.  
  424. opts.cb = cb;
  425.  
  426. return opts;
  427. }
  428.  
  429. function removeAttr(attr) {
  430. var val = this[attr];
  431. delete this[attr];
  432.  
  433. return val;
  434. }
  435.  
  436. /**
  437. * Stringify function embedded inside of objects. Useful for couch views.
  438. * @api private
  439. */
  440. function toJSON(data) {
  441. return JSON.stringify(data, function(key, val) {
  442. if (typeof val == 'function') {
  443. return val.toString();
  444. }
  445. return val;
  446. });
  447. }
  448.  
  449. // Convert a options object to an url query string.
  450. // ex: {key:'value',key2:'value2'} becomes '?key="value"&key2="value2"'
  451. function encodeOptions(options) {
  452. var buf = [];
  453. if (typeof(options) == "object" && options !== null) {
  454. for (var name in options) {
  455. if (options.hasOwnProperty(name)) {
  456. var value = options[name];
  457. if (name == "key" || name == "startkey" || name == "endkey") {
  458. value = toJSON(value);
  459. }
  460. buf.push(encodeURIComponent(name) + "=" + encodeURIComponent(value));
  461. }
  462. }
  463. }
  464. if (!buf.length) {
  465. return "";
  466. }
  467. return "?" + buf.join("&");
  468. }
  469.  
  470. /**
  471. * Updates an object with the properties of another object(s) if those
  472. * properties are not already defined for the target object. First argument is
  473. * the object to complete, the remaining arguments are considered sources to
  474. * complete from. If multiple sources contain the same property, the value of
  475. * the first source with that property will be the one inserted in to the
  476. * target.
  477. *
  478. * example usage:
  479. * util.complete({}, { hello: "world" }); // -> { hello: "world" }
  480. * util.complete({ hello: "narwhal" }, { hello: "world" }); // -> { hello: "narwhal" }
  481. * util.complete({}, { hello: "world" }, { hello: "le monde" }); // -> { hello: "world" }
  482. *
  483. * @returns Completed object
  484. * @type Object
  485. * @api private
  486. */
  487. function complete() {
  488. return variadicHelper(arguments, function(target, source) {
  489. var key;
  490. for (key in source) {
  491. if (
  492. Object.prototype.hasOwnProperty.call(source, key) &&
  493. !Object.prototype.hasOwnProperty.call(target, key)
  494. ) {
  495. target[key] = source[key];
  496. }
  497. }
  498. });
  499. }
  500.  
  501. /**
  502. * @param args Arguments list of the calling function
  503. * First argument should be a callback that takes target and source parameters.
  504. * Second argument should be target.
  505. * Remaining arguments are treated a sources.
  506. *
  507. * @returns Target
  508. * @type Object
  509. * @api private
  510. */
  511. function variadicHelper(args, callback) {
  512. var sources = Array.prototype.slice.call(args);
  513. var target = sources.shift();
  514.  
  515. sources.forEach(function(source) {
  516. callback(target, source);
  517. });
  518.  
  519. return target;
  520. }
  521.  
  522. var USER_PREFIX = exports.USER_PREFIX = "org.couchdb.user:";
  523.  
  524. })(exports);
Add Comment
Please, Sign In to add comment