Skip to content

Commit 7957015

Browse files
author
Vincent Petry
authored
Merge pull request #28767 from owncloud/backbone-proppatch-waitmode
Make Backbone PROPPATCH work with options.wait mode
2 parents 5372290 + f819148 commit 7957015

File tree

2 files changed

+167
-90
lines changed

2 files changed

+167
-90
lines changed

core/js/oc-backbone-webdav.js

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,25 @@
180180
}
181181

182182
function callPropPatch(client, options, model, headers) {
183+
var changes = model.changed;
184+
if (options.wait && _.isEmpty(changes)) {
185+
// usually with "wait" mode, the changes aren't set yet,
186+
changes = options.data;
187+
188+
// if options.patch is not set, then data contains all the data
189+
// instead of just the properties to patch
190+
if (!options.patch) {
191+
// remove reserved properties
192+
delete changes.href;
193+
delete changes[_.result(model, 'idAttribute')];
194+
195+
// note: there is no way to diff with previous values here so
196+
// we just send everything
197+
}
198+
}
183199
return client.propPatch(
184200
options.url,
185-
convertModelAttributesToDavProperties(model.changed, options.davProperties),
201+
convertModelAttributesToDavProperties(changes, options.davProperties),
186202
headers
187203
).then(function(result) {
188204
if (result.status === 207 && result.body && result.body.length > 0) {
@@ -196,6 +212,11 @@
196212
}
197213

198214
if (isSuccessStatus(result.status)) {
215+
// with wait, we set the changes only after success
216+
if (options.wait) {
217+
model.set(changes, options);
218+
}
219+
199220
if (_.isFunction(options.success)) {
200221
// pass the object's own values because the server
201222
// does not return the updated model
@@ -236,7 +257,7 @@
236257
options.type,
237258
options.url,
238259
headers,
239-
options.data
260+
JSON.stringify(options.data)
240261
).then(function(result) {
241262
if (!isSuccessStatus(result.status)) {
242263
if (_.isFunction(options.error)) {
@@ -353,7 +374,7 @@
353374

354375
// Ensure that we have the appropriate request data.
355376
if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
356-
params.data = JSON.stringify(options.attrs || model.toJSON(options));
377+
params.data = options.attrs || model.toJSON(options);
357378
}
358379

359380
// Don't process data on a non-GET request.

core/js/tests/specs/oc-backbone-webdavSpec.js

Lines changed: 143 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -243,97 +243,164 @@ describe('Backbone Webdav extension', function() {
243243
});
244244
});
245245

246-
it('makes a PROPPATCH request to update model', function() {
247-
var model = new TestModel({
248-
id: '123',
249-
firstName: 'Hello',
250-
lastName: 'World',
251-
age: 32,
252-
married: false
253-
});
246+
describe('updating', function() {
247+
it('makes a PROPPATCH request to update model', function() {
248+
var model = new TestModel({
249+
id: '123',
250+
firstName: 'Hello',
251+
lastName: 'World',
252+
age: 32,
253+
married: false
254+
});
254255

255-
model.save({
256-
firstName: 'Hey',
257-
age: 33,
258-
married: true
256+
model.save({
257+
firstName: 'Hey',
258+
age: 33,
259+
married: true
260+
});
261+
262+
expect(davClientPropPatchStub.calledOnce).toEqual(true);
263+
expect(davClientPropPatchStub.getCall(0).args[0])
264+
.toEqual('http://example.com/owncloud/remote.php/test/123');
265+
expect(davClientPropPatchStub.getCall(0).args[1])
266+
.toEqual({
267+
'{http://owncloud.org/ns}first-name': 'Hey',
268+
'{http://owncloud.org/ns}age': '33',
269+
'{http://owncloud.org/ns}married': 'true'
270+
});
271+
expect(davClientPropPatchStub.getCall(0).args[2]['X-Requested-With'])
272+
.toEqual('XMLHttpRequest');
273+
274+
deferredRequest.resolve({
275+
status: 207,
276+
body: [{
277+
href: 'http://example.com/owncloud/remote.php/test/123',
278+
propStat: [{
279+
status: 'HTTP/1.1 200 OK',
280+
properties: {
281+
'{http://owncloud.org/ns}first-name': '',
282+
'{http://owncloud.org/ns}age-name': '',
283+
'{http://owncloud.org/ns}married': ''
284+
}
285+
}]
286+
}]
287+
});
288+
289+
expect(model.id).toEqual('123');
290+
expect(model.get('firstName')).toEqual('Hey');
291+
expect(model.get('age')).toEqual(33);
292+
expect(model.get('married')).toEqual(true);
259293
});
260294

261-
expect(davClientPropPatchStub.calledOnce).toEqual(true);
262-
expect(davClientPropPatchStub.getCall(0).args[0])
263-
.toEqual('http://example.com/owncloud/remote.php/test/123');
264-
expect(davClientPropPatchStub.getCall(0).args[1])
265-
.toEqual({
266-
'{http://owncloud.org/ns}first-name': 'Hey',
267-
'{http://owncloud.org/ns}age': '33',
268-
'{http://owncloud.org/ns}married': 'true'
295+
it('calls error callback with status code 422 in case of failed PROPPATCH properties', function() {
296+
var successHandler = sinon.stub();
297+
var errorHandler = sinon.stub();
298+
var model = new TestModel({
299+
id: '123',
300+
firstName: 'Hello',
301+
lastName: 'World',
302+
age: 32,
303+
married: false
269304
});
270-
expect(davClientPropPatchStub.getCall(0).args[2]['X-Requested-With'])
271-
.toEqual('XMLHttpRequest');
272305

273-
deferredRequest.resolve({
274-
status: 207,
275-
body: [{
276-
href: 'http://example.com/owncloud/remote.php/test/123',
277-
propStat: [{
278-
status: 'HTTP/1.1 200 OK',
279-
properties: {
280-
'{http://owncloud.org/ns}first-name': '',
281-
'{http://owncloud.org/ns}age-name': '',
282-
'{http://owncloud.org/ns}married': ''
283-
}
306+
model.save({
307+
firstName: 'Hey',
308+
lastName: 'low'
309+
}, {
310+
success: successHandler,
311+
error: errorHandler
312+
});
313+
314+
deferredRequest.resolve({
315+
status: 207,
316+
body: [{
317+
href: 'http://example.com/owncloud/remote.php/test/123',
318+
propStat: [{
319+
status: 'HTTP/1.1 200 OK',
320+
properties: {
321+
'{http://owncloud.org/ns}last-name': ''
322+
}
323+
}, {
324+
status: 'HTTP/1.1 403 Forbidden',
325+
properties: {
326+
'{http://owncloud.org/ns}first-name': ''
327+
}
328+
}]
284329
}]
285-
}]
286-
});
330+
});
287331

288-
expect(model.id).toEqual('123');
289-
expect(model.get('firstName')).toEqual('Hey');
290-
expect(model.get('age')).toEqual(33);
291-
expect(model.get('married')).toEqual(true);
292-
});
332+
expect(davClientPropPatchStub.calledOnce).toEqual(true);
293333

294-
it('calls error callback with status code 422 in case of failed PROPPATCH properties', function() {
295-
var successHandler = sinon.stub();
296-
var errorHandler = sinon.stub();
297-
var model = new TestModel({
298-
id: '123',
299-
firstName: 'Hello',
300-
lastName: 'World',
301-
age: 32,
302-
married: false
334+
expect(successHandler.notCalled).toEqual(true);
335+
expect(errorHandler.calledOnce).toEqual(true);
336+
expect(errorHandler.getCall(0).args[0]).toEqual(model);
337+
expect(errorHandler.getCall(0).args[1].status).toEqual(422);
303338
});
304339

305-
model.save({
306-
firstName: 'Hey',
307-
lastName: 'low'
308-
}, {
309-
success: successHandler,
310-
error: errorHandler
340+
it('calls error handler if error status in PROPPATCH response', function() {
341+
testMethodError(function(success, error) {
342+
var model = new TestModel();
343+
model.save({
344+
firstName: 'Hey'
345+
}, {
346+
success: success,
347+
error: error
348+
});
349+
});
311350
});
312351

313-
deferredRequest.resolve({
314-
status: 207,
315-
body: [{
316-
href: 'http://example.com/owncloud/remote.php/test/123',
317-
propStat: [{
318-
status: 'HTTP/1.1 200 OK',
319-
properties: {
320-
'{http://owncloud.org/ns}last-name': ''
321-
}
322-
}, {
323-
status: 'HTTP/1.1 403 Forbidden',
324-
properties: {
325-
'{http://owncloud.org/ns}first-name': ''
326-
}
352+
it('sends all data when using wait flag', function() {
353+
var successHandler = sinon.stub();
354+
var errorHandler = sinon.stub();
355+
var model = new TestModel({
356+
id: '123',
357+
firstName: 'Hello',
358+
lastName: 'World',
359+
age: 32,
360+
married: false
361+
});
362+
363+
model.save({
364+
firstName: 'Hey',
365+
lastName: 'low'
366+
}, {
367+
wait: true,
368+
success: successHandler,
369+
error: errorHandler
370+
});
371+
372+
// attributes not updated yet
373+
expect(model.get('firstName')).toEqual('Hello');
374+
375+
deferredRequest.resolve({
376+
status: 207,
377+
body: [{
378+
href: 'http://example.com/owncloud/remote.php/test/123',
379+
propStat: [{
380+
status: 'HTTP/1.1 200 OK',
381+
properties: {
382+
'{http://owncloud.org/ns}first-name': '',
383+
'{http://owncloud.org/ns}last-name': ''
384+
}
385+
}]
327386
}]
328-
}]
329-
});
387+
});
330388

331-
expect(davClientPropPatchStub.calledOnce).toEqual(true);
332389

333-
expect(successHandler.notCalled).toEqual(true);
334-
expect(errorHandler.calledOnce).toEqual(true);
335-
expect(errorHandler.getCall(0).args[0]).toEqual(model);
336-
expect(errorHandler.getCall(0).args[1].status).toEqual(422);
390+
expect(davClientPropPatchStub.calledOnce).toEqual(true);
391+
// just resends everything
392+
expect(davClientPropPatchStub.getCall(0).args[1])
393+
.toEqual({
394+
'{http://owncloud.org/ns}first-name': 'Hey',
395+
'{http://owncloud.org/ns}last-name': 'low',
396+
'{http://owncloud.org/ns}age': '32',
397+
'{http://owncloud.org/ns}married': 'false',
398+
});
399+
400+
expect(model.get('firstName')).toEqual('Hey');
401+
expect(successHandler.calledOnce).toEqual(true);
402+
expect(errorHandler.notCalled).toEqual(true);
403+
});
337404
});
338405

339406
it('uses PROPFIND to fetch single model', function() {
@@ -429,17 +496,6 @@ describe('Backbone Webdav extension', function() {
429496
});
430497
});
431498
});
432-
it('calls error handler if error status in PROPPATCH response', function() {
433-
testMethodError(function(success, error) {
434-
var model = new TestModel();
435-
model.save({
436-
firstName: 'Hey'
437-
}, {
438-
success: success,
439-
error: error
440-
});
441-
});
442-
});
443499
});
444500

445501

0 commit comments

Comments
 (0)