From 70233a5f692b8b316c2a83e95d126a9ece39050f Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Tue, 22 Aug 2017 11:48:18 +0200 Subject: [PATCH] Make Backbone PROPPATCH work with options.wait mode In options.wait mode, no model.changes are available as they haven't been set yet. So in this mode we simply get all properties and send these with PROPPATCH. --- core/js/oc-backbone-webdav.js | 27 +- core/js/tests/specs/oc-backbone-webdavSpec.js | 230 +++++++++++------- 2 files changed, 167 insertions(+), 90 deletions(-) diff --git a/core/js/oc-backbone-webdav.js b/core/js/oc-backbone-webdav.js index 724660ff93a2..0503abea8bda 100644 --- a/core/js/oc-backbone-webdav.js +++ b/core/js/oc-backbone-webdav.js @@ -180,9 +180,25 @@ } function callPropPatch(client, options, model, headers) { + var changes = model.changed; + if (options.wait && _.isEmpty(changes)) { + // usually with "wait" mode, the changes aren't set yet, + changes = options.data; + + // if options.patch is not set, then data contains all the data + // instead of just the properties to patch + if (!options.patch) { + // remove reserved properties + delete changes.href; + delete changes[_.result(model, 'idAttribute')]; + + // note: there is no way to diff with previous values here so + // we just send everything + } + } return client.propPatch( options.url, - convertModelAttributesToDavProperties(model.changed, options.davProperties), + convertModelAttributesToDavProperties(changes, options.davProperties), headers ).then(function(result) { if (result.status === 207 && result.body && result.body.length > 0) { @@ -196,6 +212,11 @@ } if (isSuccessStatus(result.status)) { + // with wait, we set the changes only after success + if (options.wait) { + model.set(changes, options); + } + if (_.isFunction(options.success)) { // pass the object's own values because the server // does not return the updated model @@ -236,7 +257,7 @@ options.type, options.url, headers, - options.data + JSON.stringify(options.data) ).then(function(result) { if (!isSuccessStatus(result.status)) { if (_.isFunction(options.error)) { @@ -353,7 +374,7 @@ // Ensure that we have the appropriate request data. if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) { - params.data = JSON.stringify(options.attrs || model.toJSON(options)); + params.data = options.attrs || model.toJSON(options); } // Don't process data on a non-GET request. diff --git a/core/js/tests/specs/oc-backbone-webdavSpec.js b/core/js/tests/specs/oc-backbone-webdavSpec.js index 6df6da4e6161..30b64fbdb5d7 100644 --- a/core/js/tests/specs/oc-backbone-webdavSpec.js +++ b/core/js/tests/specs/oc-backbone-webdavSpec.js @@ -243,97 +243,164 @@ describe('Backbone Webdav extension', function() { }); }); - it('makes a PROPPATCH request to update model', function() { - var model = new TestModel({ - id: '123', - firstName: 'Hello', - lastName: 'World', - age: 32, - married: false - }); + describe('updating', function() { + it('makes a PROPPATCH request to update model', function() { + var model = new TestModel({ + id: '123', + firstName: 'Hello', + lastName: 'World', + age: 32, + married: false + }); - model.save({ - firstName: 'Hey', - age: 33, - married: true + model.save({ + firstName: 'Hey', + age: 33, + married: true + }); + + expect(davClientPropPatchStub.calledOnce).toEqual(true); + expect(davClientPropPatchStub.getCall(0).args[0]) + .toEqual('http://example.com/owncloud/remote.php/test/123'); + expect(davClientPropPatchStub.getCall(0).args[1]) + .toEqual({ + '{http://owncloud.org/ns}first-name': 'Hey', + '{http://owncloud.org/ns}age': '33', + '{http://owncloud.org/ns}married': 'true' + }); + expect(davClientPropPatchStub.getCall(0).args[2]['X-Requested-With']) + .toEqual('XMLHttpRequest'); + + deferredRequest.resolve({ + status: 207, + body: [{ + href: 'http://example.com/owncloud/remote.php/test/123', + propStat: [{ + status: 'HTTP/1.1 200 OK', + properties: { + '{http://owncloud.org/ns}first-name': '', + '{http://owncloud.org/ns}age-name': '', + '{http://owncloud.org/ns}married': '' + } + }] + }] + }); + + expect(model.id).toEqual('123'); + expect(model.get('firstName')).toEqual('Hey'); + expect(model.get('age')).toEqual(33); + expect(model.get('married')).toEqual(true); }); - expect(davClientPropPatchStub.calledOnce).toEqual(true); - expect(davClientPropPatchStub.getCall(0).args[0]) - .toEqual('http://example.com/owncloud/remote.php/test/123'); - expect(davClientPropPatchStub.getCall(0).args[1]) - .toEqual({ - '{http://owncloud.org/ns}first-name': 'Hey', - '{http://owncloud.org/ns}age': '33', - '{http://owncloud.org/ns}married': 'true' + it('calls error callback with status code 422 in case of failed PROPPATCH properties', function() { + var successHandler = sinon.stub(); + var errorHandler = sinon.stub(); + var model = new TestModel({ + id: '123', + firstName: 'Hello', + lastName: 'World', + age: 32, + married: false }); - expect(davClientPropPatchStub.getCall(0).args[2]['X-Requested-With']) - .toEqual('XMLHttpRequest'); - deferredRequest.resolve({ - status: 207, - body: [{ - href: 'http://example.com/owncloud/remote.php/test/123', - propStat: [{ - status: 'HTTP/1.1 200 OK', - properties: { - '{http://owncloud.org/ns}first-name': '', - '{http://owncloud.org/ns}age-name': '', - '{http://owncloud.org/ns}married': '' - } + model.save({ + firstName: 'Hey', + lastName: 'low' + }, { + success: successHandler, + error: errorHandler + }); + + deferredRequest.resolve({ + status: 207, + body: [{ + href: 'http://example.com/owncloud/remote.php/test/123', + propStat: [{ + status: 'HTTP/1.1 200 OK', + properties: { + '{http://owncloud.org/ns}last-name': '' + } + }, { + status: 'HTTP/1.1 403 Forbidden', + properties: { + '{http://owncloud.org/ns}first-name': '' + } + }] }] - }] - }); + }); - expect(model.id).toEqual('123'); - expect(model.get('firstName')).toEqual('Hey'); - expect(model.get('age')).toEqual(33); - expect(model.get('married')).toEqual(true); - }); + expect(davClientPropPatchStub.calledOnce).toEqual(true); - it('calls error callback with status code 422 in case of failed PROPPATCH properties', function() { - var successHandler = sinon.stub(); - var errorHandler = sinon.stub(); - var model = new TestModel({ - id: '123', - firstName: 'Hello', - lastName: 'World', - age: 32, - married: false + expect(successHandler.notCalled).toEqual(true); + expect(errorHandler.calledOnce).toEqual(true); + expect(errorHandler.getCall(0).args[0]).toEqual(model); + expect(errorHandler.getCall(0).args[1].status).toEqual(422); }); - model.save({ - firstName: 'Hey', - lastName: 'low' - }, { - success: successHandler, - error: errorHandler + it('calls error handler if error status in PROPPATCH response', function() { + testMethodError(function(success, error) { + var model = new TestModel(); + model.save({ + firstName: 'Hey' + }, { + success: success, + error: error + }); + }); }); - deferredRequest.resolve({ - status: 207, - body: [{ - href: 'http://example.com/owncloud/remote.php/test/123', - propStat: [{ - status: 'HTTP/1.1 200 OK', - properties: { - '{http://owncloud.org/ns}last-name': '' - } - }, { - status: 'HTTP/1.1 403 Forbidden', - properties: { - '{http://owncloud.org/ns}first-name': '' - } + it('sends all data when using wait flag', function() { + var successHandler = sinon.stub(); + var errorHandler = sinon.stub(); + var model = new TestModel({ + id: '123', + firstName: 'Hello', + lastName: 'World', + age: 32, + married: false + }); + + model.save({ + firstName: 'Hey', + lastName: 'low' + }, { + wait: true, + success: successHandler, + error: errorHandler + }); + + // attributes not updated yet + expect(model.get('firstName')).toEqual('Hello'); + + deferredRequest.resolve({ + status: 207, + body: [{ + href: 'http://example.com/owncloud/remote.php/test/123', + propStat: [{ + status: 'HTTP/1.1 200 OK', + properties: { + '{http://owncloud.org/ns}first-name': '', + '{http://owncloud.org/ns}last-name': '' + } + }] }] - }] - }); + }); - expect(davClientPropPatchStub.calledOnce).toEqual(true); - expect(successHandler.notCalled).toEqual(true); - expect(errorHandler.calledOnce).toEqual(true); - expect(errorHandler.getCall(0).args[0]).toEqual(model); - expect(errorHandler.getCall(0).args[1].status).toEqual(422); + expect(davClientPropPatchStub.calledOnce).toEqual(true); + // just resends everything + expect(davClientPropPatchStub.getCall(0).args[1]) + .toEqual({ + '{http://owncloud.org/ns}first-name': 'Hey', + '{http://owncloud.org/ns}last-name': 'low', + '{http://owncloud.org/ns}age': '32', + '{http://owncloud.org/ns}married': 'false', + }); + + expect(model.get('firstName')).toEqual('Hey'); + expect(successHandler.calledOnce).toEqual(true); + expect(errorHandler.notCalled).toEqual(true); + }); }); it('uses PROPFIND to fetch single model', function() { @@ -429,17 +496,6 @@ describe('Backbone Webdav extension', function() { }); }); }); - it('calls error handler if error status in PROPPATCH response', function() { - testMethodError(function(success, error) { - var model = new TestModel(); - model.save({ - firstName: 'Hey' - }, { - success: success, - error: error - }); - }); - }); });