couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j..@apache.org
Subject svn commit: r674334 - in /incubator/couchdb/trunk: share/www/script/couch.js share/www/script/couch_tests.js src/couchdb/couch_httpd.erl
Date Sun, 06 Jul 2008 18:52:56 GMT
Author: jan
Date: Sun Jul  6 11:52:56 2008
New Revision: 674334

URL: http://svn.apache.org/viewvc?rev=674334&view=rev
Log:
Add RESTful API for document attachments as per http://groups.google.com/group/couchdb/browse_thread/thread/c84c5f35afb5db2a
with not yet comprehensive tests.

Modified:
    incubator/couchdb/trunk/share/www/script/couch.js
    incubator/couchdb/trunk/share/www/script/couch_tests.js
    incubator/couchdb/trunk/src/couchdb/couch_httpd.erl

Modified: incubator/couchdb/trunk/share/www/script/couch.js
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/share/www/script/couch.js?rev=674334&r1=674333&r2=674334&view=diff
==============================================================================
--- incubator/couchdb/trunk/share/www/script/couch.js [utf-8] (original)
+++ incubator/couchdb/trunk/share/www/script/couch.js [utf-8] Sun Jul  6 11:52:56 2008
@@ -80,6 +80,16 @@
     return result;
   }
 
+  // Deletes an attachment from a document
+  this.deleteDocAttachment = function(doc, attachment_name) {
+    var req = request("DELETE", this.uri + encodeURIComponent(doc._id) + "/" + attachment_name
+ "?rev=" + doc._rev);
+    var result = JSON.parse(req.responseText);
+    if (req.status != 200)
+      throw result;
+    doc._rev = result.rev; //record rev in input document
+    return result;
+  }
+  
   this.bulkSave = function(docs, options) {
     var req = request("POST", this.uri + "_bulk_docs" + encodeOptions(options), {
       body: JSON.stringify({"docs": docs})

Modified: incubator/couchdb/trunk/share/www/script/couch_tests.js
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/share/www/script/couch_tests.js?rev=674334&r1=674333&r2=674334&view=diff
==============================================================================
--- incubator/couchdb/trunk/share/www/script/couch_tests.js [utf-8] (original)
+++ incubator/couchdb/trunk/share/www/script/couch_tests.js [utf-8] Sun Jul  6 11:52:56 2008
@@ -556,8 +556,59 @@
     T(db.save(binAttDoc).ok);
 
     var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt");
-    T(xhr.responseText == "This is a base64 encoded text")
-    T(xhr.getResponseHeader("Content-Type") == "text/plain")
+    T(xhr.responseText == "This is a base64 encoded text");
+    T(xhr.getResponseHeader("Content-Type") == "text/plain");
+    
+    // test RESTful doc API
+    
+    // test without rev, should fail
+    var xhr = CouchDB.request("DELETE", "/test_suite_db/bin_doc/foo.txt");
+    T(xhr.status == 412);
+    
+    db.deleteDocAttachment({_id:"bin_doc"}, "foo.txt");
+    var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt");
+    T(xhr.status == 404);
+    
+    var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc/foo.txt", {
+      body: "This is not base64 encoded text",
+      headers:{"Content-Type":"text/plain;charset=utf-8"}
+    });
+    T(xhr.status == 201);
+
+    var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt");
+    T(xhr.responseText == "This is not base64 encoded text");
+    T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");
+
+    // test binary data
+    var xhr = CouchDB.request("GET", "/favicon.ico");
+    var bin_data = xhr.responseText;
+    // bin_data = 123;
+    var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc/favicon.ico", {
+      headers:{"Content-Type":"image/vnd.microsoft.icon"},
+      body:bin_data
+    });
+    T(xhr.status == 201);
+    var rev = JSON.parse(xhr.responseText).rev;
+
+    var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/favicon.ico");
+    T(xhr.responseText == bin_data);
+    T(xhr.getResponseHeader("Content-Type") == "image/vnd.microsoft.icon");
+    
+     var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc/favicon.ico", {
+      headers:{"Content-Type":"image/vnd.microsoft.icon"},
+      body:bin_data
+    });
+    T(xhr.status == 412);
+
+    var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc/favicon.ico?rev="+rev, {
+      headers:{"Content-Type":"image/vnd.microsoft.icon"},
+      body:bin_data
+    });
+    T(xhr.status == 201);
+    var rev = JSON.parse(xhr.responseText).rev;
+
+    var xhr = CouchDB.request("DELETE", "/test_suite_db/bin_doc/foo.txt?rev="+rev);
+    T(xhr.status == 200);
   },
 
   content_negotiation: function(debug) {

Modified: incubator/couchdb/trunk/src/couchdb/couch_httpd.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/couchdb/couch_httpd.erl?rev=674334&r1=674333&r2=674334&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/couchdb/couch_httpd.erl (original)
+++ incubator/couchdb/trunk/src/couchdb/couch_httpd.erl Sun Jul  6 11:52:56 2008
@@ -633,8 +633,114 @@
         throw(Error)
     end;
 
+handle_attachment_request(Req, 'DELETE', _DbName, Db, DocId, FileName) ->
+    QueryRev = proplists:get_value("rev", Req:parse_qs()),
+    Etag = case Req:get_header_value("If-Match") of
+        undefined ->
+            undefined;
+        Tag ->
+            string:strip(Tag, both, $")
+    end,
+    case {QueryRev, Etag} of
+    {undefined, undefined} ->
+        throw({missing_rev, "Document rev/etag must be specified to delete"});
+    {_, undefined} ->
+        QueryRev;
+    {undefined, _} ->
+        Etag;
+    _ when QueryRev == Etag ->
+        Etag;
+    _ ->
+        throw({bad_request, "Document rev and etag have different values"})
+    end,
+    
+    case couch_db:open_doc(Db, DocId, []) of
+    {ok, Doc} ->
+        #doc{attachments=Attachments,revs=Revs} = Doc,
+        case proplists:get_value(FileName, Attachments) of
+        undefined ->
+            throw({not_found, missing});
+        {_Type, _Bin} ->
+
+            NewAttachmentList = proplists:delete(FileName, Attachments),
+
+            {ok, NewRev} = couch_db:update_doc(Db, Doc#doc{
+                id=DocId,
+                revs=Revs,
+                attachments=NewAttachmentList
+            }, []),
+            
+            send_json(Req, 200, {obj, [
+                {ok, true},
+                {id, DocId},
+                {rev, NewRev}
+            ]})
+        end;
+    Error ->
+        throw(Error)
+    end;   
+    
+handle_attachment_request(Req, 'PUT', _DbName, Db, DocId, FileName) ->
+    case couch_db:open_doc(Db, DocId, []) of
+    {ok, Doc} ->
+        #doc{attachments=Attachments,revs=OldRevs} = Doc,
+
+        NewAttachments = 
+        case proplists:get_value(FileName, Attachments) of
+            undefined -> % new attachment, just append to list
+                Revs = OldRevs,
+                lists:append(Attachments, [{FileName, {
+                    Req:get_header_value("Content-Type"),
+                    Req:recv_body()
+                }}]);
+
+            {_Type, _Bin} -> % update of an existing attachment, delete and re-add
+                QueryRev = proplists:get_value("rev", Req:parse_qs()),
+                Etag = case Req:get_header_value("If-Match") of
+                    undefined ->
+                        undefined;
+                    Tag ->
+                        string:strip(Tag, both, $")
+                end,
+                Revs = case {QueryRev, Etag} of
+                {undefined, undefined} ->
+                    throw({missing_rev, "Document rev/etag must be specified to delete"});
+                {_, undefined} ->
+                    [QueryRev];
+                {undefined, _} ->
+                    [Etag];
+                _ when QueryRev == Etag ->
+                    [Etag];
+                _ ->
+                    throw({bad_request, "Document rev and etag have different values"})
+                end,
+
+                lists:append(
+                    proplists:delete(FileName, Attachments),
+                    [{FileName, {
+                        Req:get_header_value("Content-Type"),
+                        Req:recv_body()
+                    }
+                }])
+        end,
+
+        {ok, NewRev} = couch_db:update_doc(Db, Doc#doc{
+            id=DocId,
+            revs=Revs,
+            attachments=NewAttachments
+        }, []),
+
+        send_json(Req, 201, {obj, [
+            {ok, true},
+            {id, DocId},
+            {rev, NewRev}
+        ]});
+    Error ->
+        throw(Error)
+    end;   
+
 handle_attachment_request(_Req, _Method, _DbName, _Db, _DocId, _FileName) ->
-    throw({method_not_allowed, "GET,HEAD"}).
+    throw({method_not_allowed, "GET,HEAD,DELETE,PUT"}).
 
 % View request handling internals
 



Mime
View raw message