Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 37 additions & 17 deletions src/BinderApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export default class BinderApi {

constructor() {
this.__initializeCsrfHandling();

this.handleValidationErrors = this.handleValidationErrors.bind(this);
}

__initializeCsrfHandling() {
Expand Down Expand Up @@ -149,20 +151,22 @@ export default class BinderApi {
});
}

handleValidationErrors(err) {
if (err.response) {
err.valErrors = this.parseBackendValidationErrors(err.response);
}
throw err;
}

saveModel({ url, data, isNew, requestOptions }) {
const method = isNew ? 'post' : 'patch';
return this[method](url, data, requestOptions)
return (
this[method](url, data, requestOptions)
.then(newData => {
return { data: newData };
})
.catch(err => {
if (err.response) {
err.valErrors = this.parseBackendValidationErrors(
err.response
);
}
throw err;
});
.catch(this.handleValidationErrors)
);
}

saveAllModels({ url, data, model, requestOptions }) {
Expand All @@ -180,14 +184,7 @@ export default class BinderApi {
}
return res;
})
.catch(err => {
if (err.response) {
err.valErrors = this.parseBackendValidationErrors(
err.response
);
}
throw err;
});
.catch(this.handleValidationErrors);
}

deleteModel({ url, requestOptions }) {
Expand Down Expand Up @@ -221,4 +218,27 @@ export default class BinderApi {
};
});
}

saveModelFile({ url, name, file, requestOptions }) {
const data = new FormData();
data.append(name, file, file.name);

return (
this.api.post(url, data, {
...requestOptions,
headers: {
...(requestOptions.headers || {}),
'Content-Type': 'multipart/form-data',
},
})
.catch(this.handleValidationErrors)
);
}

deleteModelFile({ url, name, requestOptions }) {
return (
this.api.delete(url, {}, requestOptions)
.catch(this.handleValidationErrors)
);
}
}
68 changes: 31 additions & 37 deletions src/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export default class Model {
this.initialize();

this.saveFile = this.saveFile.bind(this);
this.handleValidationErrors = this.handleValidationErrors.bind(this);
}

@action
Expand Down Expand Up @@ -589,36 +590,33 @@ export default class Model {

saveFile(name) {
const snakeName = camelToSnake(name);
const url = `${this.url}${snakeName}/`;

if (this.__fileChanges[name]) {
const file = this.__fileChanges[name];

const data = new FormData();
data.append(name, file, file.name);

return (
this.api.post(
`${this.url}${snakeName}/`,
data,
{ headers: { 'Content-Type': 'multipart/form-data' } },
)
this.__getApi()
.saveModelFile({ url, name, file })
.then(action((res) => {
this.__fileExists[name] = true;
delete this.__fileChanges[name];
this.saveFromBackend(res);
}))
.catch((err) => this.handleValidationErrors(err, true))
);
} else if (this.__fileDeletions[name]) {
if (this.__fileExists[name]) {
return (
this.api.delete(`${this.url}${snakeName}/`)
this.__getApi()
.deleteModelFile({ url, name })
.then(action(() => {
this.__fileExists[name] = false;
delete this.__fileDeletions[name];
this.saveFromBackend({ data: {
[snakeName]: null,
} });
}))
.catch((err) => this.handleValidationErrors(err, true))
);
} else {
delete this.__fileDeletions[name];
Expand All @@ -632,19 +630,25 @@ export default class Model {
return Promise.all(this.fileFields().map(this.saveFile));
}

@action
save(options = {}) {
@action handleValidationErrors(err, append = false) {
if (err.valErrors) {
this.parseValidationErrors(err.valErrors, append);
}
throw err;
}

@action save(options = {}) {
this.clearValidationErrors();
return this.wrapPendingRequestCount(
this.__getApi()
.saveModel({
url: options.url || this.url,
data: this.toBackend({
data: options.data,
mapData: options.mapData,
fields: options.fields,
onlyChanges: options.onlyChanges,
}),
data: options.data,
mapData: options.mapData,
fields: options.fields,
onlyChanges: options.onlyChanges,
}),
isNew: this.isNew,
requestOptions: omit(options, 'url', 'data', 'mapData')
})
Expand All @@ -659,22 +663,15 @@ export default class Model {
return Promise.resolve(res);
});
}))
.catch(
action(err => {
if (err.valErrors) {
this.parseValidationErrors(err.valErrors);
}
throw err;
})
)
.catch(this.handleValidationErrors)
);
}

@action
setInput(name, value) {
invariant(
this.__attributes.includes(name) ||
this.__activeCurrentRelations.includes(name),
this.__activeCurrentRelations.includes(name),
`Field \`${name}\` does not exist on the model.`
);
if (this.fileFields().includes(name)) {
Expand Down Expand Up @@ -766,14 +763,7 @@ export default class Model {
return res;
});
}))
.catch(
action(err => {
if (err.valErrors) {
this.parseValidationErrors(err.valErrors);
}
throw err;
})
)
.catch(this.handleValidationErrors)
);
}

Expand All @@ -800,7 +790,7 @@ export default class Model {
}

@action
parseValidationErrors(valErrors) {
parseValidationErrors(valErrors, append = false) {
const bname = this.constructor.backendResourceName;

if (valErrors[bname]) {
Expand All @@ -818,12 +808,16 @@ export default class Model {
return valError.map(this.validationErrorFormatter);
}
);
this.__backendValidationErrors = formattedErrors;
if (append) {
this.__backendValidationErrors.push(...formattedErrors);
} else {
this.__backendValidationErrors = formattedErrors;
}
}
}

this.__activeCurrentRelations.forEach(currentRel => {
this[currentRel].parseValidationErrors(valErrors);
this[currentRel].parseValidationErrors(valErrors, append);
});
}

Expand Down
4 changes: 2 additions & 2 deletions src/Store.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,9 @@ export default class Store {
return this;
}

parseValidationErrors(valErrors) {
parseValidationErrors(valErrors, append = false) {
this.each(model => {
model.parseValidationErrors(valErrors);
model.parseValidationErrors(valErrors, append);
});
}

Expand Down