API: Allow specifying item ID for any item

pull/1195/head
Laurent Cozic 2019-02-06 22:36:39 +00:00
parent 0d6443c30a
commit 49f8d0c6d8
3 changed files with 32 additions and 12 deletions

View File

@ -170,6 +170,17 @@ describe('services_rest_Api', function() {
done();
});
it('should create folders with supplied ID', async (done) => {
const response = await api.route('POST', 'folders', null, JSON.stringify({
id: '12345678123456781234567812345678',
title: 'from api',
}));
expect(response.id).toBe('12345678123456781234567812345678');
done();
});
it('should create notes with images', async (done) => {
let response = null;
const f = await Folder.save({ title: "mon carnet" });

View File

@ -145,7 +145,7 @@ class ClipperServer {
const execRequest = async (request, body = '', files = []) => {
try {
const response = await this.api_.route(request.method, url.pathname, url.query, body, files);
writeResponse(200, response);
writeResponse(200, response ? response : '');
} catch (error) {
this.logger().error(error);
writeResponse(error.httpCode ? error.httpCode : 500, error.message);

View File

@ -103,7 +103,7 @@ class Api {
if (!this[parsedPath.callName]) throw new ErrorNotFound();
try {
return this[parsedPath.callName](request, id, link);
return await this[parsedPath.callName](request, id, link);
} catch (error) {
if (!error.httpCode) error.httpCode = 500;
throw error;
@ -118,8 +118,10 @@ class Api {
return this.logger_;
}
get readonlyProperties() {
return ['id', 'created_time', 'updated_time', 'encryption_blob_encrypted', 'encryption_applied', 'encryption_cipher_text'];
readonlyProperties(requestMethod) {
const output = ['created_time', 'updated_time', 'encryption_blob_encrypted', 'encryption_applied', 'encryption_cipher_text'];
if (requestMethod !== 'POST') output.splice(0, 0, 'id');
return output;
}
fields_(request, defaultFields) {
@ -174,7 +176,7 @@ class Api {
if (request.method === 'PUT' && id) {
const model = await getOneModel();
let newModel = Object.assign({}, model, request.bodyJson(this.readonlyProperties));
let newModel = Object.assign({}, model, request.bodyJson(this.readonlyProperties('PUT')));
newModel = await ModelClass.save(newModel, { userSideValidation: true });
return newModel;
}
@ -186,8 +188,11 @@ class Api {
}
if (request.method === 'POST') {
const model = request.bodyJson(this.readonlyProperties);
const result = await ModelClass.save(model, { userSideValidation: true });
const props = this.readonlyProperties('POST');
const idIdx = props.indexOf('id');
if (idIdx >= 0) props.splice(idIdx, 1);
const model = request.bodyJson(props);
const result = await ModelClass.save(model, this.defaultSaveOptions_(model, 'POST'));
return result;
}
@ -286,9 +291,8 @@ class Api {
if (request.method === 'POST') {
if (!request.files.length) throw new ErrorBadRequest('Resource cannot be created without a file');
const filePath = request.files[0].path;
const resource = await shim.createResourceFromPath(filePath);
const newResource = Object.assign({}, resource, request.bodyJson(this.readonlyProperties));
return await Resource.save(newResource);
const defaultProps = request.bodyJson(this.readonlyProperties('POST'));
return shim.createResourceFromPath(filePath, defaultProps);
}
return this.defaultAction_(BaseModel.TYPE_RESOURCE, request, id, link);
@ -301,6 +305,12 @@ class Api {
return options;
}
defaultSaveOptions_(model, requestMethod) {
const options = { userSideValidation: true };
if (requestMethod === 'POST' && model.id) options.isNew = true;
return options;
}
async action_notes(request, id = null, link = null) {
this.checkToken_(request);
@ -342,8 +352,7 @@ class Api {
this.logger().info('Request (' + requestId + '): Saving note...');
const saveOptions = {};
if (note.id) saveOptions.isNew = true;
const saveOptions = this.defaultSaveOptions_(note, 'POST');
note = await Note.save(note, saveOptions);
if (requestNote.tags) {