contents.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. define(function(requirejs) {
  4. "use strict";
  5. var $ = requirejs('jquery');
  6. var utils = requirejs('base/js/utils');
  7. var Contents = function(options) {
  8. /**
  9. * Constructor
  10. *
  11. * Preliminary documentation for the REST API is at
  12. * https://github.com/ipython/ipython/wiki/IPEP-27%3A-Contents-Service
  13. *
  14. * A contents handles passing file operations
  15. * to the back-end. This includes checkpointing
  16. * with the normal file operations.
  17. *
  18. * Parameters:
  19. * options: dictionary
  20. * Dictionary of keyword arguments.
  21. * base_url: string
  22. */
  23. this.base_url = options.base_url;
  24. };
  25. /** Error type */
  26. Contents.DIRECTORY_NOT_EMPTY_ERROR = 'DirectoryNotEmptyError';
  27. Contents.DirectoryNotEmptyError = function() {
  28. // Constructor
  29. //
  30. // An error representing the result of attempting to delete a non-empty
  31. // directory.
  32. this.message = 'A directory must be empty before being deleted.';
  33. };
  34. Contents.DirectoryNotEmptyError.prototype = Object.create(Error.prototype);
  35. Contents.DirectoryNotEmptyError.prototype.name =
  36. Contents.DIRECTORY_NOT_EMPTY_ERROR;
  37. Contents.prototype.api_url = function() {
  38. var url_parts = [
  39. this.base_url, 'api/contents',
  40. utils.url_join_encode.apply(null, arguments),
  41. ];
  42. return utils.url_path_join.apply(null, url_parts);
  43. };
  44. /**
  45. * Creates a basic error handler that wraps a jqXHR error as an Error.
  46. *
  47. * Takes a callback that accepts an Error, and returns a callback that can
  48. * be passed directly to $.ajax, which will wrap the error from jQuery
  49. * as an Error, and pass that to the original callback.
  50. *
  51. * @method create_basic_error_handler
  52. * @param{Function} callback
  53. * @return{Function}
  54. */
  55. Contents.prototype.create_basic_error_handler = function(callback) {
  56. if (!callback) {
  57. return utils.log_ajax_error;
  58. }
  59. return function(xhr, status, error) {
  60. callback(utils.wrap_ajax_error(xhr, status, error));
  61. };
  62. };
  63. /**
  64. * File Functions (including notebook operations)
  65. */
  66. /**
  67. * Get a file.
  68. *
  69. * @method get
  70. * @param {String} path
  71. * @param {Object} options
  72. * type : 'notebook', 'file', or 'directory'
  73. * format: 'text' or 'base64'; only relevant for type: 'file'
  74. * content: true or false; // whether to include the content
  75. */
  76. Contents.prototype.get = function (path, options) {
  77. /**
  78. * We do the call with settings so we can set cache to false.
  79. */
  80. var settings = {
  81. processData : false,
  82. cache : false,
  83. type : "GET",
  84. dataType : "json",
  85. };
  86. var url = this.api_url(path);
  87. var params = {};
  88. if (options.type) { params.type = options.type; }
  89. if (options.format) { params.format = options.format; }
  90. if (options.content === false) { params.content = '0'; }
  91. return utils.promising_ajax(url + '?' + $.param(params), settings);
  92. };
  93. /**
  94. * Creates a new untitled file or directory in the specified directory path.
  95. *
  96. * @method new
  97. * @param {String} path: the directory in which to create the new file/directory
  98. * @param {Object} options:
  99. * ext: file extension to use
  100. * type: model type to create ('notebook', 'file', or 'directory')
  101. */
  102. Contents.prototype.new_untitled = function(path, options) {
  103. var data = JSON.stringify({
  104. ext: options.ext,
  105. type: options.type
  106. });
  107. var settings = {
  108. processData : false,
  109. type : "POST",
  110. data: data,
  111. contentType: 'application/json',
  112. dataType : "json",
  113. };
  114. return utils.promising_ajax(this.api_url(path), settings);
  115. };
  116. Contents.prototype.delete = function(path) {
  117. var settings = {
  118. processData : false,
  119. type : "DELETE",
  120. dataType : "json",
  121. };
  122. var url = this.api_url(path);
  123. return utils.promising_ajax(url, settings).catch(
  124. // Translate certain errors to more specific ones.
  125. function(error) {
  126. // TODO: update IPEP27 to specify errors more precisely, so
  127. // that error types can be detected here with certainty.
  128. if (error.xhr.status === 400) {
  129. throw new Contents.DirectoryNotEmptyError();
  130. }
  131. throw error;
  132. }
  133. );
  134. };
  135. Contents.prototype.rename = function(path, new_path) {
  136. var data = {path: new_path};
  137. var settings = {
  138. processData : false,
  139. type : "PATCH",
  140. data : JSON.stringify(data),
  141. dataType: "json",
  142. contentType: 'application/json',
  143. };
  144. var url = this.api_url(path);
  145. return utils.promising_ajax(url, settings);
  146. };
  147. Contents.prototype.trust = function(path) {
  148. var settings = {
  149. processData : false,
  150. type : "POST",
  151. contentType: 'application/json',
  152. };
  153. var url = this.api_url(path, "trust");
  154. return utils.promising_ajax(url, settings);
  155. }
  156. Contents.prototype.save = function(path, model) {
  157. /**
  158. * We do the call with settings so we can set cache to false.
  159. */
  160. var settings = {
  161. processData : false,
  162. type : "PUT",
  163. dataType: "json",
  164. data : JSON.stringify(model),
  165. contentType: 'application/json',
  166. };
  167. var url = this.api_url(path);
  168. return utils.promising_ajax(url, settings);
  169. };
  170. Contents.prototype.copy = function(from_file, to_dir) {
  171. /**
  172. * Copy a file into a given directory via POST
  173. * The server will select the name of the copied file
  174. */
  175. var url = this.api_url(to_dir);
  176. var settings = {
  177. processData : false,
  178. type: "POST",
  179. data: JSON.stringify({copy_from: from_file}),
  180. contentType: 'application/json',
  181. dataType : "json",
  182. };
  183. return utils.promising_ajax(url, settings);
  184. };
  185. /**
  186. * Checkpointing Functions
  187. */
  188. Contents.prototype.create_checkpoint = function(path) {
  189. var url = this.api_url(path, 'checkpoints');
  190. var settings = {
  191. type : "POST",
  192. contentType: false, // no data
  193. dataType : "json",
  194. };
  195. return utils.promising_ajax(url, settings);
  196. };
  197. Contents.prototype.list_checkpoints = function(path) {
  198. var url = this.api_url(path, 'checkpoints');
  199. var settings = {
  200. type : "GET",
  201. cache: false,
  202. dataType: "json",
  203. };
  204. return utils.promising_ajax(url, settings);
  205. };
  206. Contents.prototype.restore_checkpoint = function(path, checkpoint_id) {
  207. var url = this.api_url(path, 'checkpoints', checkpoint_id);
  208. var settings = {
  209. type : "POST",
  210. contentType: false, // no data
  211. };
  212. return utils.promising_ajax(url, settings);
  213. };
  214. Contents.prototype.delete_checkpoint = function(path, checkpoint_id) {
  215. var url = this.api_url(path, 'checkpoints', checkpoint_id);
  216. var settings = {
  217. type : "DELETE",
  218. };
  219. return utils.promising_ajax(url, settings);
  220. };
  221. /**
  222. * File management functions
  223. */
  224. /**
  225. * List notebooks and directories at a given path
  226. *
  227. * On success, load_callback is called with an array of dictionaries
  228. * representing individual files or directories. Each dictionary has
  229. * the keys:
  230. * type: "notebook" or "directory"
  231. * created: created date
  232. * last_modified: last modified dat
  233. * @method list_notebooks
  234. * @param {String} path The path to list notebooks in
  235. */
  236. Contents.prototype.list_contents = function(path) {
  237. return this.get(path, {type: 'directory'});
  238. };
  239. return {'Contents': Contents};
  240. });