From acb26ce528c7ff792f548ff0c2c579b6e99943f8 Mon Sep 17 00:00:00 2001
From: Vincent Bechu <vincent.bechu@nexedi.com>
Date: Tue, 3 Oct 2017 08:43:06 +0000
Subject: [PATCH] [erp5_web_renderjs_ui][erp5_core] Release Jio Version 3.24.0

---
 .../web_page_module/rjs_jio_js.js             | 278 +++++++++++-------
 .../web_page_module/rjs_jio_js.xml            |   6 +-
 .../portal_skins/erp5_core/jio.js.js          | 278 +++++++++++-------
 3 files changed, 341 insertions(+), 221 deletions(-)

diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_jio_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_jio_js.js
index 17627b006a..7739990486 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_jio_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_jio_js.js
@@ -10297,27 +10297,18 @@ return new Parser;
  * JIO Dropbox Storage. Type = "dropbox".
  * Dropbox "database" storage.
  */
-/*global Blob, jIO, RSVP, UriTemplate*/
+/*global Blob, jIO, RSVP*/
 /*jslint nomen: true*/
 
-(function (jIO, RSVP, Blob, UriTemplate) {
+(function (jIO, RSVP, Blob, JSON) {
   "use strict";
-  var UPLOAD_URL = "https://content.dropboxapi.com/1/files_put/" +
-      "{+root}{+id}{+name}{?access_token}",
-    upload_template = UriTemplate.parse(UPLOAD_URL),
-    CREATE_DIR_URL = "https://api.dropboxapi.com/1/fileops/create_folder" +
-      "{?access_token,root,path}",
-    create_dir_template = UriTemplate.parse(CREATE_DIR_URL),
-    REMOVE_URL = "https://api.dropboxapi.com/1/fileops/delete/" +
-      "{?access_token,root,path}",
-    remote_template = UriTemplate.parse(REMOVE_URL),
-    GET_URL = "https://content.dropboxapi.com/1/files" +
-      "{/root,id}{+name}{?access_token}",
-    get_template = UriTemplate.parse(GET_URL),
-    //LIST_URL = 'https://api.dropboxapi.com/1/metadata/sandbox/';
-    METADATA_URL = "https://api.dropboxapi.com/1/metadata" +
-      "{/root}{+id}{?access_token}",
-    metadata_template = UriTemplate.parse(METADATA_URL);
+  var GET_URL = "https://content.dropboxapi.com/2/files/download",
+    UPLOAD_URL = "https://content.dropboxapi.com/2/files/upload",
+    REMOVE_URL = "https://api.dropboxapi.com/2/files/delete_v2",
+    CREATE_DIR_URL = "https://api.dropboxapi.com/2/files/create_folder_v2",
+    METADATA_URL = "https://api.dropboxapi.com/2/files/get_metadata",
+    LIST_FOLDER_URL = "https://api.dropboxapi.com/2/files/list_folder",
+    LIST_MORE_URL = "https://api.dropboxapi.com/2/files/list_folder/continue";
 
   function restrictDocumentId(id) {
     if (id.indexOf("/") !== 0) {
@@ -10328,7 +10319,7 @@ return new Parser;
       throw new jIO.util.jIOError("id " + id + " is forbidden (no end /)",
                                   400);
     }
-    return id;
+    return id.slice(0, -1);
   }
 
   function restrictAttachmentId(id) {
@@ -10338,6 +10329,66 @@ return new Parser;
     }
   }
 
+  function recursiveAllAttachments(result, token, id, cursor) {
+    var data,
+      url;
+    if (cursor === undefined) {
+      data = {
+        "path": id,
+        "recursive": false,
+        "include_media_info": false,
+        "include_deleted": false,
+        "include_has_explicit_shared_members": false,
+        "include_mounted_folders": true
+      };
+      url = LIST_FOLDER_URL;
+    } else {
+      data = {"cursor": cursor};
+      url = LIST_MORE_URL;
+    }
+    return new RSVP.Queue()
+      .push(function () {
+        return jIO.util.ajax({
+          type: "POST",
+          url: url,
+          headers: {
+            "Authorization": "Bearer " + token,
+            "Content-Type": "application/json"
+          },
+          data: JSON.stringify(data)
+        });
+      })
+      .push(function (evt) {
+        var obj = JSON.parse(evt.target.response || evt.target.responseText),
+          i;
+        for (i = 0; i < obj.entries.length; i += 1) {
+          if (obj.entries[i][".tag"] === "file") {
+            result[obj.entries[i].name] = {};
+          }
+        }
+        if (obj.has_more) {
+          return recursiveAllAttachments(result, token, id, obj.cursor);
+        }
+        return result;
+      }, function (error) {
+        if (error.target !== undefined && error.target.status === 409) {
+          var err_content = JSON.parse(error.target.response ||
+                                       error.target.responseText);
+          if ((err_content.error['.tag'] === 'path') &&
+              (err_content.error.path['.tag'] === 'not_folder')) {
+            throw new jIO.util.jIOError("Not a directory: " + id + "/",
+                                        404);
+          }
+          if ((err_content.error['.tag'] === 'path') &&
+              (err_content.error.path['.tag'] === 'not_found')) {
+            throw new jIO.util.jIOError("Cannot find document: " + id + "/",
+                                        404);
+          }
+        }
+        throw error;
+      });
+  }
+
   /**
    * The JIO Dropbox Storage extension
    *
@@ -10349,12 +10400,7 @@ return new Parser;
       throw new TypeError("Access Token' must be a string " +
                           "which contains more than one character.");
     }
-    if (typeof spec.root !== 'string' || !spec.root ||
-        (spec.root !== "dropbox" && spec.root !== "sandbox")) {
-      throw new TypeError("root must be 'dropbox' or 'sandbox'");
-    }
     this._access_token = spec.access_token;
-    this._root = spec.root;
   }
 
   DropboxStorage.prototype.put = function (id, param) {
@@ -10369,18 +10415,24 @@ return new Parser;
       .push(function () {
         return jIO.util.ajax({
           type: "POST",
-          url: create_dir_template.expand({
-            access_token: that._access_token,
-            root: that._root,
-            path: id
-          })
+          url: CREATE_DIR_URL,
+          headers: {
+            "Authorization": "Bearer " + that._access_token,
+            "Content-Type": "application/json"
+          },
+          data: JSON.stringify({"path": id, "autorename": false})
         });
       })
       .push(undefined, function (err) {
         if ((err.target !== undefined) &&
-            (err.target.status === 405)) {
-          // Directory already exists, no need to fail
-          return;
+            (err.target.status === 409)) {
+          var err_content = JSON.parse(err.target.response ||
+                                       err.target.responseText);
+          if ((err_content.error['.tag'] === 'path') &&
+              (err_content.error.path['.tag'] === 'conflict')) {
+            // Directory already exists, no need to fail
+            return;
+          }
         }
         throw err;
       });
@@ -10390,11 +10442,12 @@ return new Parser;
     id = restrictDocumentId(id);
     return jIO.util.ajax({
       type: "POST",
-      url: remote_template.expand({
-        access_token: this._access_token,
-        root: this._root,
-        path: id
-      })
+      url: REMOVE_URL,
+      headers: {
+        "Authorization": "Bearer " + this._access_token,
+        "Content-Type": "application/json"
+      },
+      data: JSON.stringify({"path": id})
     });
   };
 
@@ -10409,64 +10462,39 @@ return new Parser;
     return new RSVP.Queue()
       .push(function () {
         return jIO.util.ajax({
-          type: "GET",
-          url: metadata_template.expand({
-            access_token: that._access_token,
-            root: that._root,
-            id: id
-          })
+          type: "POST",
+          url: METADATA_URL,
+          headers: {
+            "Authorization": "Bearer " + that._access_token,
+            "Content-Type": "application/json"
+          },
+          data: JSON.stringify({"path": id})
         });
       })
       .push(function (evt) {
         var obj = JSON.parse(evt.target.response ||
                              evt.target.responseText);
-        if (obj.is_dir) {
+        if (obj[".tag"] === "folder") {
           return {};
         }
-        throw new jIO.util.jIOError("Not a directory: " + id, 404);
+        throw new jIO.util.jIOError("Not a directory: " + id + "/", 404);
       }, function (error) {
-        if (error.target !== undefined && error.target.status === 404) {
-          throw new jIO.util.jIOError("Cannot find document: " + id, 404);
+        if (error.target !== undefined && error.target.status === 409) {
+          var err_content = JSON.parse(error.target.response ||
+                                       error.target.responseText);
+          if ((err_content.error['.tag'] === 'path') &&
+              (err_content.error.path['.tag'] === 'not_found')) {
+            throw new jIO.util.jIOError("Cannot find document: " + id + "/",
+                                        404);
+          }
         }
         throw error;
       });
   };
 
   DropboxStorage.prototype.allAttachments = function (id) {
-
-    var that = this;
     id = restrictDocumentId(id);
-
-    return new RSVP.Queue()
-      .push(function () {
-        return jIO.util.ajax({
-          type: "GET",
-          url: metadata_template.expand({
-            access_token: that._access_token,
-            root: that._root,
-            id: id
-          })
-        });
-      })
-      .push(function (evt) {
-        var obj = JSON.parse(evt.target.response || evt.target.responseText),
-          i,
-          result = {};
-        if (!obj.is_dir) {
-          throw new jIO.util.jIOError("Not a directory: " + id, 404);
-        }
-        for (i = 0; i < obj.contents.length; i += 1) {
-          if (!obj.contents[i].is_dir) {
-            result[obj.contents[i].path.split("/").pop()] = {};
-          }
-        }
-        return result;
-      }, function (error) {
-        if (error.target !== undefined && error.target.status === 404) {
-          throw new jIO.util.jIOError("Cannot find document: " + id, 404);
-        }
-        throw error;
-      });
+    return recursiveAllAttachments({}, this._access_token, id);
   };
 
   //currently, putAttachment will fail with files larger than 150MB,
@@ -10481,20 +10509,24 @@ return new Parser;
     restrictAttachmentId(name);
 
     return jIO.util.ajax({
-      type: "PUT",
-      url: upload_template.expand({
-        root: this._root,
-        id: id,
-        name: name,
-        access_token: this._access_token
-      }),
-      dataType: blob.type,
+      type: "POST",
+      url: UPLOAD_URL,
+      headers: {
+        "Authorization": "Bearer " + this._access_token,
+        "Content-Type": "application/octet-stream",
+        "Dropbox-API-Arg": JSON.stringify({
+          "path": id + "/" + name,
+          "mode": "overwrite",
+          "autorename": false,
+          "mute": false
+        })
+      },
       data: blob
     });
   };
 
   DropboxStorage.prototype.getAttachment = function (id, name) {
-    var that = this;
+    var context = this;
 
     id = restrictDocumentId(id);
     restrictAttachmentId(name);
@@ -10502,26 +10534,48 @@ return new Parser;
     return new RSVP.Queue()
       .push(function () {
         return jIO.util.ajax({
-          type: "GET",
+          url: GET_URL,
+          type: "POST",
           dataType: "blob",
-          url: get_template.expand({
-            root: that._root,
-            id: id,
-            name: name,
-            access_token: that._access_token
-          })
+          headers: {
+            "Authorization": "Bearer " + context._access_token,
+            "Dropbox-API-Arg": JSON.stringify({"path": id + "/" + name})
+          }
         });
       })
       .push(function (evt) {
+        if (evt.target.response instanceof Blob) {
+          return evt.target.response;
+        }
         return new Blob(
-          [evt.target.response || evt.target.responseText],
+          [evt.target.responseText],
           {"type": evt.target.getResponseHeader('Content-Type') ||
             "application/octet-stream"}
         );
       }, function (error) {
-        if (error.target !== undefined && error.target.status === 404) {
-          throw new jIO.util.jIOError("Cannot find attachment: " +
-                                      id + ", " + name, 404);
+        if (error.target !== undefined && error.target.status === 409) {
+          if (!(error.target.response instanceof Blob)) {
+            var err_content = JSON.parse(error.target.responseText);
+            if ((err_content.error['.tag'] === 'path') &&
+                (err_content.error.path['.tag'] === 'not_found')) {
+              throw new jIO.util.jIOError("Cannot find attachment: " +
+                                          id + "/, " + name, 404);
+            }
+            throw error;
+          }
+          return new RSVP.Queue()
+            .push(function () {
+              return jIO.util.readBlobAsText(error.target.response);
+            })
+            .push(function (evt) {
+              var err_content = JSON.parse(evt.target.result);
+              if ((err_content.error['.tag'] === 'path') &&
+                  (err_content.error.path['.tag'] === 'not_found')) {
+                throw new jIO.util.jIOError("Cannot find attachment: " +
+                                            id + "/, " + name, 404);
+              }
+              throw error;
+            });
         }
         throw error;
       });
@@ -10538,16 +10592,22 @@ return new Parser;
       .push(function () {
         return jIO.util.ajax({
           type: "POST",
-          url: remote_template.expand({
-            access_token: that._access_token,
-            root: that._root,
-            path: id + name
-          })
+          url: REMOVE_URL,
+          headers: {
+            "Authorization": "Bearer " + that._access_token,
+            "Content-Type": "application/json"
+          },
+          data: JSON.stringify({"path": id + "/" + name})
         });
       }).push(undefined, function (error) {
-        if (error.target !== undefined && error.target.status === 404) {
-          throw new jIO.util.jIOError("Cannot find attachment: " +
-                                      id + ", " + name, 404);
+        if (error.target !== undefined && error.target.status === 409) {
+          var err_content = JSON.parse(error.target.response ||
+                                       error.target.responseText);
+          if ((err_content.error['.tag'] === 'path_lookup') &&
+              (err_content.error.path_lookup['.tag'] === 'not_found')) {
+            throw new jIO.util.jIOError("Cannot find attachment: " +
+                                        id + "/, " + name, 404);
+          }
         }
         throw error;
       });
@@ -10555,7 +10615,7 @@ return new Parser;
 
   jIO.addStorage('dropbox', DropboxStorage);
 
-}(jIO, RSVP, Blob, UriTemplate));
+}(jIO, RSVP, Blob, JSON));
 ;/*
  * Copyright 2013, Nexedi SA
  * Released under the LGPL license.
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_jio_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_jio_js.xml
index a92a1b6ed7..8160a20bd1 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_jio_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_jio_js.xml
@@ -222,7 +222,7 @@
             </item>
             <item>
                 <key> <string>actor</string> </key>
-                <value> <string>vincentb</string> </value>
+                <value> <string>vincent</string> </value>
             </item>
             <item>
                 <key> <string>comment</string> </key>
@@ -236,7 +236,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>962.14277.44425.47445</string> </value>
+                <value> <string>962.34068.22248.54801</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -254,7 +254,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1506330877.9</float>
+                        <float>1507020010.09</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/jio.js.js b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/jio.js.js
index 17627b006a..7739990486 100644
--- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/jio.js.js
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/jio.js.js
@@ -10297,27 +10297,18 @@ return new Parser;
  * JIO Dropbox Storage. Type = "dropbox".
  * Dropbox "database" storage.
  */
-/*global Blob, jIO, RSVP, UriTemplate*/
+/*global Blob, jIO, RSVP*/
 /*jslint nomen: true*/
 
-(function (jIO, RSVP, Blob, UriTemplate) {
+(function (jIO, RSVP, Blob, JSON) {
   "use strict";
-  var UPLOAD_URL = "https://content.dropboxapi.com/1/files_put/" +
-      "{+root}{+id}{+name}{?access_token}",
-    upload_template = UriTemplate.parse(UPLOAD_URL),
-    CREATE_DIR_URL = "https://api.dropboxapi.com/1/fileops/create_folder" +
-      "{?access_token,root,path}",
-    create_dir_template = UriTemplate.parse(CREATE_DIR_URL),
-    REMOVE_URL = "https://api.dropboxapi.com/1/fileops/delete/" +
-      "{?access_token,root,path}",
-    remote_template = UriTemplate.parse(REMOVE_URL),
-    GET_URL = "https://content.dropboxapi.com/1/files" +
-      "{/root,id}{+name}{?access_token}",
-    get_template = UriTemplate.parse(GET_URL),
-    //LIST_URL = 'https://api.dropboxapi.com/1/metadata/sandbox/';
-    METADATA_URL = "https://api.dropboxapi.com/1/metadata" +
-      "{/root}{+id}{?access_token}",
-    metadata_template = UriTemplate.parse(METADATA_URL);
+  var GET_URL = "https://content.dropboxapi.com/2/files/download",
+    UPLOAD_URL = "https://content.dropboxapi.com/2/files/upload",
+    REMOVE_URL = "https://api.dropboxapi.com/2/files/delete_v2",
+    CREATE_DIR_URL = "https://api.dropboxapi.com/2/files/create_folder_v2",
+    METADATA_URL = "https://api.dropboxapi.com/2/files/get_metadata",
+    LIST_FOLDER_URL = "https://api.dropboxapi.com/2/files/list_folder",
+    LIST_MORE_URL = "https://api.dropboxapi.com/2/files/list_folder/continue";
 
   function restrictDocumentId(id) {
     if (id.indexOf("/") !== 0) {
@@ -10328,7 +10319,7 @@ return new Parser;
       throw new jIO.util.jIOError("id " + id + " is forbidden (no end /)",
                                   400);
     }
-    return id;
+    return id.slice(0, -1);
   }
 
   function restrictAttachmentId(id) {
@@ -10338,6 +10329,66 @@ return new Parser;
     }
   }
 
+  function recursiveAllAttachments(result, token, id, cursor) {
+    var data,
+      url;
+    if (cursor === undefined) {
+      data = {
+        "path": id,
+        "recursive": false,
+        "include_media_info": false,
+        "include_deleted": false,
+        "include_has_explicit_shared_members": false,
+        "include_mounted_folders": true
+      };
+      url = LIST_FOLDER_URL;
+    } else {
+      data = {"cursor": cursor};
+      url = LIST_MORE_URL;
+    }
+    return new RSVP.Queue()
+      .push(function () {
+        return jIO.util.ajax({
+          type: "POST",
+          url: url,
+          headers: {
+            "Authorization": "Bearer " + token,
+            "Content-Type": "application/json"
+          },
+          data: JSON.stringify(data)
+        });
+      })
+      .push(function (evt) {
+        var obj = JSON.parse(evt.target.response || evt.target.responseText),
+          i;
+        for (i = 0; i < obj.entries.length; i += 1) {
+          if (obj.entries[i][".tag"] === "file") {
+            result[obj.entries[i].name] = {};
+          }
+        }
+        if (obj.has_more) {
+          return recursiveAllAttachments(result, token, id, obj.cursor);
+        }
+        return result;
+      }, function (error) {
+        if (error.target !== undefined && error.target.status === 409) {
+          var err_content = JSON.parse(error.target.response ||
+                                       error.target.responseText);
+          if ((err_content.error['.tag'] === 'path') &&
+              (err_content.error.path['.tag'] === 'not_folder')) {
+            throw new jIO.util.jIOError("Not a directory: " + id + "/",
+                                        404);
+          }
+          if ((err_content.error['.tag'] === 'path') &&
+              (err_content.error.path['.tag'] === 'not_found')) {
+            throw new jIO.util.jIOError("Cannot find document: " + id + "/",
+                                        404);
+          }
+        }
+        throw error;
+      });
+  }
+
   /**
    * The JIO Dropbox Storage extension
    *
@@ -10349,12 +10400,7 @@ return new Parser;
       throw new TypeError("Access Token' must be a string " +
                           "which contains more than one character.");
     }
-    if (typeof spec.root !== 'string' || !spec.root ||
-        (spec.root !== "dropbox" && spec.root !== "sandbox")) {
-      throw new TypeError("root must be 'dropbox' or 'sandbox'");
-    }
     this._access_token = spec.access_token;
-    this._root = spec.root;
   }
 
   DropboxStorage.prototype.put = function (id, param) {
@@ -10369,18 +10415,24 @@ return new Parser;
       .push(function () {
         return jIO.util.ajax({
           type: "POST",
-          url: create_dir_template.expand({
-            access_token: that._access_token,
-            root: that._root,
-            path: id
-          })
+          url: CREATE_DIR_URL,
+          headers: {
+            "Authorization": "Bearer " + that._access_token,
+            "Content-Type": "application/json"
+          },
+          data: JSON.stringify({"path": id, "autorename": false})
         });
       })
       .push(undefined, function (err) {
         if ((err.target !== undefined) &&
-            (err.target.status === 405)) {
-          // Directory already exists, no need to fail
-          return;
+            (err.target.status === 409)) {
+          var err_content = JSON.parse(err.target.response ||
+                                       err.target.responseText);
+          if ((err_content.error['.tag'] === 'path') &&
+              (err_content.error.path['.tag'] === 'conflict')) {
+            // Directory already exists, no need to fail
+            return;
+          }
         }
         throw err;
       });
@@ -10390,11 +10442,12 @@ return new Parser;
     id = restrictDocumentId(id);
     return jIO.util.ajax({
       type: "POST",
-      url: remote_template.expand({
-        access_token: this._access_token,
-        root: this._root,
-        path: id
-      })
+      url: REMOVE_URL,
+      headers: {
+        "Authorization": "Bearer " + this._access_token,
+        "Content-Type": "application/json"
+      },
+      data: JSON.stringify({"path": id})
     });
   };
 
@@ -10409,64 +10462,39 @@ return new Parser;
     return new RSVP.Queue()
       .push(function () {
         return jIO.util.ajax({
-          type: "GET",
-          url: metadata_template.expand({
-            access_token: that._access_token,
-            root: that._root,
-            id: id
-          })
+          type: "POST",
+          url: METADATA_URL,
+          headers: {
+            "Authorization": "Bearer " + that._access_token,
+            "Content-Type": "application/json"
+          },
+          data: JSON.stringify({"path": id})
         });
       })
       .push(function (evt) {
         var obj = JSON.parse(evt.target.response ||
                              evt.target.responseText);
-        if (obj.is_dir) {
+        if (obj[".tag"] === "folder") {
           return {};
         }
-        throw new jIO.util.jIOError("Not a directory: " + id, 404);
+        throw new jIO.util.jIOError("Not a directory: " + id + "/", 404);
       }, function (error) {
-        if (error.target !== undefined && error.target.status === 404) {
-          throw new jIO.util.jIOError("Cannot find document: " + id, 404);
+        if (error.target !== undefined && error.target.status === 409) {
+          var err_content = JSON.parse(error.target.response ||
+                                       error.target.responseText);
+          if ((err_content.error['.tag'] === 'path') &&
+              (err_content.error.path['.tag'] === 'not_found')) {
+            throw new jIO.util.jIOError("Cannot find document: " + id + "/",
+                                        404);
+          }
         }
         throw error;
       });
   };
 
   DropboxStorage.prototype.allAttachments = function (id) {
-
-    var that = this;
     id = restrictDocumentId(id);
-
-    return new RSVP.Queue()
-      .push(function () {
-        return jIO.util.ajax({
-          type: "GET",
-          url: metadata_template.expand({
-            access_token: that._access_token,
-            root: that._root,
-            id: id
-          })
-        });
-      })
-      .push(function (evt) {
-        var obj = JSON.parse(evt.target.response || evt.target.responseText),
-          i,
-          result = {};
-        if (!obj.is_dir) {
-          throw new jIO.util.jIOError("Not a directory: " + id, 404);
-        }
-        for (i = 0; i < obj.contents.length; i += 1) {
-          if (!obj.contents[i].is_dir) {
-            result[obj.contents[i].path.split("/").pop()] = {};
-          }
-        }
-        return result;
-      }, function (error) {
-        if (error.target !== undefined && error.target.status === 404) {
-          throw new jIO.util.jIOError("Cannot find document: " + id, 404);
-        }
-        throw error;
-      });
+    return recursiveAllAttachments({}, this._access_token, id);
   };
 
   //currently, putAttachment will fail with files larger than 150MB,
@@ -10481,20 +10509,24 @@ return new Parser;
     restrictAttachmentId(name);
 
     return jIO.util.ajax({
-      type: "PUT",
-      url: upload_template.expand({
-        root: this._root,
-        id: id,
-        name: name,
-        access_token: this._access_token
-      }),
-      dataType: blob.type,
+      type: "POST",
+      url: UPLOAD_URL,
+      headers: {
+        "Authorization": "Bearer " + this._access_token,
+        "Content-Type": "application/octet-stream",
+        "Dropbox-API-Arg": JSON.stringify({
+          "path": id + "/" + name,
+          "mode": "overwrite",
+          "autorename": false,
+          "mute": false
+        })
+      },
       data: blob
     });
   };
 
   DropboxStorage.prototype.getAttachment = function (id, name) {
-    var that = this;
+    var context = this;
 
     id = restrictDocumentId(id);
     restrictAttachmentId(name);
@@ -10502,26 +10534,48 @@ return new Parser;
     return new RSVP.Queue()
       .push(function () {
         return jIO.util.ajax({
-          type: "GET",
+          url: GET_URL,
+          type: "POST",
           dataType: "blob",
-          url: get_template.expand({
-            root: that._root,
-            id: id,
-            name: name,
-            access_token: that._access_token
-          })
+          headers: {
+            "Authorization": "Bearer " + context._access_token,
+            "Dropbox-API-Arg": JSON.stringify({"path": id + "/" + name})
+          }
         });
       })
       .push(function (evt) {
+        if (evt.target.response instanceof Blob) {
+          return evt.target.response;
+        }
         return new Blob(
-          [evt.target.response || evt.target.responseText],
+          [evt.target.responseText],
           {"type": evt.target.getResponseHeader('Content-Type') ||
             "application/octet-stream"}
         );
       }, function (error) {
-        if (error.target !== undefined && error.target.status === 404) {
-          throw new jIO.util.jIOError("Cannot find attachment: " +
-                                      id + ", " + name, 404);
+        if (error.target !== undefined && error.target.status === 409) {
+          if (!(error.target.response instanceof Blob)) {
+            var err_content = JSON.parse(error.target.responseText);
+            if ((err_content.error['.tag'] === 'path') &&
+                (err_content.error.path['.tag'] === 'not_found')) {
+              throw new jIO.util.jIOError("Cannot find attachment: " +
+                                          id + "/, " + name, 404);
+            }
+            throw error;
+          }
+          return new RSVP.Queue()
+            .push(function () {
+              return jIO.util.readBlobAsText(error.target.response);
+            })
+            .push(function (evt) {
+              var err_content = JSON.parse(evt.target.result);
+              if ((err_content.error['.tag'] === 'path') &&
+                  (err_content.error.path['.tag'] === 'not_found')) {
+                throw new jIO.util.jIOError("Cannot find attachment: " +
+                                            id + "/, " + name, 404);
+              }
+              throw error;
+            });
         }
         throw error;
       });
@@ -10538,16 +10592,22 @@ return new Parser;
       .push(function () {
         return jIO.util.ajax({
           type: "POST",
-          url: remote_template.expand({
-            access_token: that._access_token,
-            root: that._root,
-            path: id + name
-          })
+          url: REMOVE_URL,
+          headers: {
+            "Authorization": "Bearer " + that._access_token,
+            "Content-Type": "application/json"
+          },
+          data: JSON.stringify({"path": id + "/" + name})
         });
       }).push(undefined, function (error) {
-        if (error.target !== undefined && error.target.status === 404) {
-          throw new jIO.util.jIOError("Cannot find attachment: " +
-                                      id + ", " + name, 404);
+        if (error.target !== undefined && error.target.status === 409) {
+          var err_content = JSON.parse(error.target.response ||
+                                       error.target.responseText);
+          if ((err_content.error['.tag'] === 'path_lookup') &&
+              (err_content.error.path_lookup['.tag'] === 'not_found')) {
+            throw new jIO.util.jIOError("Cannot find attachment: " +
+                                        id + "/, " + name, 404);
+          }
         }
         throw error;
       });
@@ -10555,7 +10615,7 @@ return new Parser;
 
   jIO.addStorage('dropbox', DropboxStorage);
 
-}(jIO, RSVP, Blob, UriTemplate));
+}(jIO, RSVP, Blob, JSON));
 ;/*
  * Copyright 2013, Nexedi SA
  * Released under the LGPL license.
-- 
2.30.9