diff --git a/core/js/oc-backbone-webdav.js b/core/js/oc-backbone-webdav.js index 4e3f11ce09111..4637c2ed2f5b2 100644 --- a/core/js/oc-backbone-webdav.js +++ b/core/js/oc-backbone-webdav.js @@ -128,7 +128,7 @@ // so we take the part before that } while (!result && parts.length > 0); - return result; + return decodeURIComponent(result); } function isSuccessStatus(status) { diff --git a/core/js/tests/specs/oc-backbone-webdavSpec.js b/core/js/tests/specs/oc-backbone-webdavSpec.js index 97281e982ce10..65d279146b85f 100644 --- a/core/js/tests/specs/oc-backbone-webdavSpec.js +++ b/core/js/tests/specs/oc-backbone-webdavSpec.js @@ -229,7 +229,7 @@ describe('Backbone Webdav extension', function() { 'married': '{http://owncloud.org/ns}married', // bool }, url: function() { - return 'http://example.com/owncloud/remote.php/test/' + this.id; + return 'http://example.com/owncloud/remote.php/test/' + encodeURIComponent(this.id); }, parse: function(data) { return { @@ -386,5 +386,401 @@ describe('Backbone Webdav extension', function() { }); }); }); + + describe('WebdavNode', function() { + var NodeModel; + + beforeEach(function() { + NodeModel = OC.Backbone.WebdavNode.extend({ + url: function() { + return 'http://example.com/owncloud/remote.php/dav/endpoint/nodemodel/' + encodeURIComponent(this.id); + }, + davProperties: { + 'firstName': '{http://owncloud.org/ns}first-name', + 'lastName': '{http://owncloud.org/ns}last-name' + } + }); + }); + it('isNew at creation time even with an id set', function() { + var model = new NodeModel({ + id: 'someuri' + }); + expect(model.isNew()).toEqual(true); + }); + it('is not new as soon as fetched', function() { + var model = new NodeModel({ + id: 'someuri' + }); + model.fetch(); + + expect(davClientPropFindStub.calledOnce).toEqual(true); + expect(davClientPropFindStub.getCall(0).args[0]) + .toEqual('http://example.com/owncloud/remote.php/dav/endpoint/nodemodel/someuri'); + expect(davClientPropFindStub.getCall(0).args[1]) + .toEqual([ + '{http://owncloud.org/ns}first-name', + '{http://owncloud.org/ns}last-name' + ]); + expect(davClientPropFindStub.getCall(0).args[2]) + .toEqual(0); + expect(davClientPropFindStub.getCall(0).args[3]['X-Requested-With']) + .toEqual('XMLHttpRequest'); + + deferredRequest.resolve({ + status: 207, + body: { + href: 'http://example.org/owncloud/remote.php/dav/endpoint/nodemodel/someuri', + propStat: [{ + status: 'HTTP/1.1 200 OK', + properties: { + '{http://owncloud.org/ns}first-name': 'Hello', + '{http://owncloud.org/ns}last-name': 'World' + } + }] + } + }); + expect(model.isNew()).toEqual(false); + }); + it('saves new model with PUT', function() { + var model = new NodeModel({ + id: 'someuri' + }); + model.save({ + firstName: 'Hello', + lastName: 'World', + }); + + // PUT + expect(davClientRequestStub.calledOnce).toEqual(true); + expect(davClientRequestStub.getCall(0).args[0]) + .toEqual('PUT'); + expect(davClientRequestStub.getCall(0).args[1]) + .toEqual('http://example.com/owncloud/remote.php/dav/endpoint/nodemodel/someuri'); + expect(davClientRequestStub.getCall(0).args[2]['X-Requested-With']) + .toEqual('XMLHttpRequest'); + expect(davClientRequestStub.getCall(0).args[3]) + .toEqual(JSON.stringify({ + id: 'someuri', + firstName: 'Hello', + lastName: 'World' + })); + + deferredRequest.resolve({ + status: 201, + body: '', + xhr: { + getResponseHeader: _.noop + } + }); + + expect(model.id).toEqual('someuri'); + expect(model.isNew()).toEqual(false); + }); + it('updates existing model with PROPPATCH', function() { + var model = new NodeModel({ + id: 'someuri' + }); + + model.fetch(); + + // from here, the model will exist + expect(davClientPropFindStub.calledOnce).toEqual(true); + expect(davClientPropFindStub.getCall(0).args[0]) + .toEqual('http://example.com/owncloud/remote.php/dav/endpoint/nodemodel/someuri'); + expect(davClientPropFindStub.getCall(0).args[1]) + .toEqual([ + '{http://owncloud.org/ns}first-name', + '{http://owncloud.org/ns}last-name' + ]); + expect(davClientPropFindStub.getCall(0).args[2]) + .toEqual(0); + expect(davClientPropFindStub.getCall(0).args[3]['X-Requested-With']) + .toEqual('XMLHttpRequest'); + + deferredRequest.resolve({ + status: 207, + body: { + href: 'http://example.com/owncloud/remote.php/dav/endpoint/nodemodel/someuri', + propStat: [{ + status: 'HTTP/1.1 200 OK', + properties: { + '{http://owncloud.org/ns}first-name': 'Hello', + '{http://owncloud.org/ns}last-name': 'World' + } + }] + } + }); + + expect(model.isNew()).toEqual(false); + + model.save({ + firstName: 'Hey', + }); + + expect(davClientPropPatchStub.calledOnce).toEqual(true); + expect(davClientPropPatchStub.getCall(0).args[0]) + .toEqual('http://example.com/owncloud/remote.php/dav/endpoint/nodemodel/someuri'); + expect(davClientPropPatchStub.getCall(0).args[1]) + .toEqual({ + '{http://owncloud.org/ns}first-name': 'Hey' + }); + expect(davClientPropPatchStub.getCall(0).args[2]['X-Requested-With']) + .toEqual('XMLHttpRequest'); + + deferredRequest.resolve({ + status: 201, + body: '', + xhr: { + getResponseHeader: _.noop + } + }); + + expect(model.isNew()).toEqual(false); + }); + }); + + describe('WebdavCollectionNode and WebdavChildrenCollection', function() { + var NodeModel; + var ChildrenCollection; + + beforeEach(function() { + ChildModel = OC.Backbone.WebdavNode.extend({ + url: function() { + return 'http://example.com/owncloud/remote.php/dav/davcol/' + encodeURIComponent(this.id); + }, + davProperties: { + 'firstName': '{http://owncloud.org/ns}first-name', + 'lastName': '{http://owncloud.org/ns}last-name' + } + }); + ChildrenCollection = OC.Backbone.WebdavChildrenCollection.extend({ + model: ChildModel + }); + + NodeModel = OC.Backbone.WebdavCollectionNode.extend({ + childrenCollectionClass: ChildrenCollection, + url: function() { + return 'http://example.com/owncloud/remote.php/dav/' + encodeURIComponent(this.id); + }, + davProperties: { + 'firstName': '{http://owncloud.org/ns}first-name', + 'lastName': '{http://owncloud.org/ns}last-name' + } + }); + }); + + it('returns the children collection pointing to the same url', function() { + var model = new NodeModel({ + id: 'davcol' + }); + + var collection = model.getChildrenCollection(); + expect(collection instanceof ChildrenCollection).toEqual(true); + + collection.instanceCheck = true; + + // returns the same instance + var collection2 = model.getChildrenCollection(); + expect(collection2.instanceCheck).toEqual(true); + + expect(collection.url()).toEqual(model.url()); + }); + + it('resets isNew to false for every model after fetching', function() { + var model = new NodeModel({ + id: 'davcol' + }); + + var collection = model.getChildrenCollection(); + collection.fetch(); + + expect(davClientPropFindStub.calledOnce).toEqual(true); + expect(davClientPropFindStub.getCall(0).args[0]) + .toEqual('http://example.com/owncloud/remote.php/dav/davcol'); + expect(davClientPropFindStub.getCall(0).args[1]) + .toEqual([ + '{http://owncloud.org/ns}first-name', + '{http://owncloud.org/ns}last-name' + ]); + expect(davClientPropFindStub.getCall(0).args[2]) + .toEqual(1); + expect(davClientPropFindStub.getCall(0).args[3]['X-Requested-With']) + .toEqual('XMLHttpRequest'); + + deferredRequest.resolve({ + status: 207, + body: [ + // root element + { + href: 'http://example.com/owncloud/remote.php/dav/davcol/', + propStat: [] + }, + // first model + { + href: 'http://example.com/owncloud/remote.php/dav/davcol/hello', + propStat: [{ + status: 'HTTP/1.1 200 OK', + properties: { + '{http://owncloud.org/ns}first-name': 'Hello', + '{http://owncloud.org/ns}last-name': 'World' + } + }] + }, + // second model + { + href: 'http://example.com/owncloud/remote.php/dav/davcol/test', + propStat: [{ + status: 'HTTP/1.1 200 OK', + properties: { + '{http://owncloud.org/ns}first-name': 'Test', + '{http://owncloud.org/ns}last-name': 'Person' + } + }] + } + ] + }); + + expect(collection.length).toEqual(2); + + expect(collection.at(0).url()).toEqual('http://example.com/owncloud/remote.php/dav/davcol/hello'); + expect(collection.at(0).isNew()).toEqual(false); + expect(collection.at(1).url()).toEqual('http://example.com/owncloud/remote.php/dav/davcol/test'); + expect(collection.at(1).isNew()).toEqual(false); + }); + + it('parses id from href if no id was queried', function() { + var model = new NodeModel({ + id: 'davcol' + }); + + var collection = model.getChildrenCollection(); + collection.fetch(); + + deferredRequest.resolve({ + status: 207, + body: [ + // root element + { + href: 'http://example.com/owncloud/remote.php/dav/davcol/', + propStat: [] + }, + // first model + { + href: 'http://example.com/owncloud/remote.php/dav/davcol/sub%40thing', + propStat: [{ + status: 'HTTP/1.1 200 OK', + properties: { + '{http://owncloud.org/ns}first-name': 'Hello', + '{http://owncloud.org/ns}last-name': 'World' + } + }] + } + ] + }); + + expect(collection.length).toEqual(1); + + expect(collection.at(0).id).toEqual('sub@thing'); + expect(collection.at(0).url()).toEqual('http://example.com/owncloud/remote.php/dav/davcol/sub%40thing'); + }); + + it('creates the Webdav collection with MKCOL', function() { + var mkcolStub = sinon.stub(dav.Client.prototype, 'mkcol'); + mkcolStub.returns(deferredRequest.promise()); + var model = new NodeModel({ + id: 'davcol' + }); + model.save({ + firstName: 'Hello', + lastName: 'World', + }); + + expect(mkcolStub.calledOnce).toEqual(true); + expect(mkcolStub.getCall(0).args[0]) + .toEqual('http://example.com/owncloud/remote.php/dav/davcol'); + expect(mkcolStub.getCall(0).args[1]) + .toEqual({ + '{http://owncloud.org/ns}first-name': 'Hello', + '{http://owncloud.org/ns}last-name': 'World', + '{DAV:}resourcetype': '' + }); + expect(mkcolStub.getCall(0).args[2]['X-Requested-With']) + .toEqual('XMLHttpRequest'); + + deferredRequest.resolve({ + status: 201, + body: '', + xhr: { + getResponseHeader: _.noop + } + }); + + expect(model.id).toEqual('davcol'); + expect(model.isNew()).toEqual(false); + + mkcolStub.restore(); + }); + it('updates Webdav collection properties with PROPPATCH', function() { + var model = new NodeModel({ + id: 'davcol' + }); + + model.fetch(); + + // from here, the model will exist + expect(davClientPropFindStub.calledOnce).toEqual(true); + expect(davClientPropFindStub.getCall(0).args[0]) + .toEqual('http://example.com/owncloud/remote.php/dav/davcol'); + expect(davClientPropFindStub.getCall(0).args[1]) + .toEqual([ + '{http://owncloud.org/ns}first-name', + '{http://owncloud.org/ns}last-name' + ]); + expect(davClientPropFindStub.getCall(0).args[2]) + .toEqual(0); + expect(davClientPropFindStub.getCall(0).args[3]['X-Requested-With']) + .toEqual('XMLHttpRequest'); + + deferredRequest.resolve({ + status: 207, + body: { + href: 'http://example.com/owncloud/remote.php/dav/davcol', + propStat: [{ + status: 'HTTP/1.1 200 OK', + properties: { + '{http://owncloud.org/ns}first-name': 'Hello', + '{http://owncloud.org/ns}last-name': 'World' + } + }] + } + }); + + expect(model.isNew()).toEqual(false); + + model.save({ + firstName: 'Hey', + }); + + expect(davClientPropPatchStub.calledOnce).toEqual(true); + expect(davClientPropPatchStub.getCall(0).args[0]) + .toEqual('http://example.com/owncloud/remote.php/dav/davcol'); + expect(davClientPropPatchStub.getCall(0).args[1]) + .toEqual({ + '{http://owncloud.org/ns}first-name': 'Hey' + }); + expect(davClientPropPatchStub.getCall(0).args[2]['X-Requested-With']) + .toEqual('XMLHttpRequest'); + + deferredRequest.resolve({ + status: 201, + body: '', + xhr: { + getResponseHeader: _.noop + } + }); + + expect(model.isNew()).toEqual(false); + }); + }); });