Changeset View
Changeset View
Standalone View
Standalone View
lib/subject/subject-types/single-resource-subject.js
"use strict"; | "use strict"; | ||||
const locreq = require("locreq")(__dirname); | const locreq = require("locreq")(__dirname); | ||||
const Promise = require("bluebird"); | const Promise = require("bluebird"); | ||||
const Subject = locreq("lib/subject/subject.js"); | const Subject = locreq("lib/subject/subject.js"); | ||||
const Errors = locreq("lib/response/error.js"); | const Errors = locreq("lib/response/error.js"); | ||||
const CollectionFieldSubject = require("./collection-field-subject.js"); | const CollectionFieldSubject = require("./collection-field-subject.js"); | ||||
const SingleResource = function(app, collection, resource_id){ | const SingleResource = function(app, collection, resource_id) { | ||||
this.collection = collection; | this.collection = collection; | ||||
this.resource_id = resource_id; | this.resource_id = resource_id; | ||||
this.name = "SingleResource"; | this.name = "SingleResource"; | ||||
this.get_resource = function(context, args){ | this.get_resource = function(context, args) { | ||||
const datastore = app.ChipManager.get_datastore_chip(); | const datastore = app.ChipManager.get_datastore_chip(); | ||||
return SingleResource.prototype.__get_resource(datastore, this.collection, this.resource_id, context, args); | return SingleResource.prototype.__get_resource( | ||||
datastore, | |||||
this.collection, | |||||
this.resource_id, | |||||
context, | |||||
args | |||||
); | |||||
}; | }; | ||||
this.delete_resource = function(context, args){ | this.delete_resource = function(context, args) { | ||||
const datastore = app.ChipManager.get_datastore_chip(); | const datastore = app.ChipManager.get_datastore_chip(); | ||||
const self = this; | const self = this; | ||||
return SingleResource.prototype.__delete_resource(datastore, self.collection, self.resource_id, context, args); | return SingleResource.prototype.__delete_resource( | ||||
datastore, | |||||
self.collection, | |||||
self.resource_id, | |||||
context, | |||||
args | |||||
); | |||||
}; | }; | ||||
this.edit_resource = function(context, values_to_patch, delete_empty_values){ | this.edit_resource = function(context, values_to_patch, delete_empty_values) { | ||||
const datastore = app.ChipManager.get_datastore_chip(); | const datastore = app.ChipManager.get_datastore_chip(); | ||||
const self = this; | const self = this; | ||||
return SingleResource.prototype.__edit_resource(datastore, self.collection, self.resource_id, context, values_to_patch, delete_empty_values); | return SingleResource.prototype.__edit_resource( | ||||
datastore, | |||||
self.collection, | |||||
self.resource_id, | |||||
context, | |||||
values_to_patch, | |||||
delete_empty_values | |||||
); | |||||
}; | }; | ||||
}; | }; | ||||
SingleResource.prototype = Object.create(Subject.prototype); | SingleResource.prototype = Object.create(Subject.prototype); | ||||
SingleResource.prototype.__get_resource = function(datastore, collection, resource_id, context, args){ | SingleResource.prototype.__get_resource = function( | ||||
datastore, | |||||
collection, | |||||
resource_id, | |||||
context, | |||||
args | |||||
) { | |||||
args = args || {}; | args = args || {}; | ||||
return datastore | |||||
return datastore.find(collection.name, {sealious_id: resource_id}, {}) | .find(collection.name, { sealious_id: resource_id }, {}) | ||||
.then(function(db_entries){ | .then(function(db_entries) { | ||||
if (db_entries[0] === undefined){ | if (db_entries[0] === undefined) { | ||||
throw new Errors.NotFound(`${collection.name}: id ${ resource_id } not found`); | throw new Errors.NotFound( | ||||
`${collection.name}: id ${resource_id} not found` | |||||
); | |||||
} else { | } else { | ||||
return collection.get_resource_representation(context, db_entries[0], args.format); | return collection.get_resource_representation( | ||||
context, | |||||
db_entries[0], | |||||
args.format | |||||
); | |||||
} | } | ||||
}).then(function(resource_representation){ | }) | ||||
return collection.check_if_action_is_allowed(context, "retrieve", resource_representation) | .then(function(resource_representation) { | ||||
return collection | |||||
.check_if_action_is_allowed( | |||||
context, | |||||
"retrieve", | |||||
resource_representation | |||||
) | |||||
.then(function(){ | .then(function() { | ||||
return resource_representation; | return resource_representation; | ||||
}); | }); | ||||
}); | }); | ||||
}; | }; | ||||
SingleResource.prototype.__edit_resource = function(datastore, collection, resource_id, context, values_to_patch, delete_empty_values){ | SingleResource.prototype.__edit_resource = function( | ||||
datastore, | |||||
collection, | |||||
resource_id, | |||||
context, | |||||
values_to_patch, | |||||
delete_empty_values | |||||
) { | |||||
// replaces just the provided values. Equivalent of PATCH request | // replaces just the provided values. Equivalent of PATCH request | ||||
delete_empty_values = (delete_empty_values === undefined? false : delete_empty_values); | delete_empty_values = | ||||
delete_empty_values === undefined ? false : delete_empty_values; | |||||
let resource_representation; | let resource_representation; | ||||
return SingleResource.prototype.__get_resource(datastore, collection, resource_id, context, {}) | return SingleResource.prototype | ||||
.__get_resource(datastore, collection, resource_id, context, {}) | |||||
.then(function(resource_data){ | .then(function(resource_data) { | ||||
resource_representation = resource_data; | resource_representation = resource_data; | ||||
return collection.check_if_action_is_allowed(context, "update", resource_representation); | return collection.check_if_action_is_allowed( | ||||
}).then(function(){ | context, | ||||
return collection.validate_field_values(context, delete_empty_values, values_to_patch, resource_representation.body); | "edit", | ||||
}).then(function(){ | resource_representation | ||||
return collection.encode_field_values(context, values_to_patch, resource_representation.body); | ); | ||||
}).then(function(encoded_values){ | }) | ||||
.then(function() { | |||||
return collection.validate_field_values( | |||||
context, | |||||
delete_empty_values, | |||||
values_to_patch, | |||||
resource_representation.body | |||||
); | |||||
}) | |||||
.then(function() { | |||||
return collection.encode_field_values( | |||||
context, | |||||
values_to_patch, | |||||
resource_representation.body | |||||
); | |||||
}) | |||||
.then(function(encoded_values) { | |||||
const query = {}; | const query = {}; | ||||
query.last_modified_context = context; | query.last_modified_context = context; | ||||
for (const field_name in encoded_values){ | for (const field_name in encoded_values) { | ||||
query[`body.${ field_name}`] = encoded_values[field_name]; | query[`body.${field_name}`] = encoded_values[field_name]; | ||||
} | } | ||||
return datastore.update(collection.name, {sealious_id: resource_id}, {$set: query}); | return datastore.update( | ||||
}).then(function(patch_result){ | collection.name, | ||||
{ sealious_id: resource_id }, | |||||
{ $set: query } | |||||
); | |||||
}) | |||||
.then(function(patch_result) { | |||||
if(patch_result.result.nModified !== 1){ | if (patch_result.result.nModified !== 1) { | ||||
throw new Error("Wrong amount of resources (!=1) modified"); | throw new Error("Wrong amount of resources (!=1) modified"); | ||||
} | } | ||||
return SingleResource.prototype.__get_resource(datastore, collection, resource_id, context, resource_id); | return SingleResource.prototype.__get_resource( | ||||
datastore, | |||||
collection, | |||||
resource_id, | |||||
context, | |||||
resource_id | |||||
); | |||||
}); | }); | ||||
}; | }; | ||||
SingleResource.prototype.__delete_resource = function(datastore, collection, resource_id, context, args){ | SingleResource.prototype.__delete_resource = function( | ||||
datastore, | |||||
collection, | |||||
resource_id, | |||||
context, | |||||
args | |||||
) { | |||||
// abstraction seems to be leaking here: should we use context or SuperContext here? | // abstraction seems to be leaking here: should we use context or SuperContext here? | ||||
return SingleResource.prototype.__get_resource(datastore, collection, resource_id, context, {}) | return SingleResource.prototype | ||||
.__get_resource(datastore, collection, resource_id, context, {}) | |||||
.then(function(resource_representation){ | .then(function(resource_representation) { | ||||
return collection.check_if_action_is_allowed(context, "delete", resource_representation); | return collection.check_if_action_is_allowed( | ||||
}).then(function(){ | context, | ||||
return datastore.remove(collection.name, { | "delete", | ||||
resource_representation | |||||
); | |||||
}) | |||||
.then(function() { | |||||
return datastore.remove( | |||||
collection.name, | |||||
{ | |||||
sealious_id: resource_id, | sealious_id: resource_id, | ||||
}, {}); | }, | ||||
{} | |||||
); | |||||
}) | }) | ||||
.then(function(data){ | .then(function(data) { | ||||
return Promise.resolve(); | return Promise.resolve(); | ||||
}); | }); | ||||
}; | }; | ||||
SingleResource.prototype.perform_action = function(context, action_name, args){ | SingleResource.prototype.perform_action = function(context, action_name, args) { | ||||
switch (action_name){ | switch (action_name) { | ||||
case "show": | case "show": | ||||
return this.get_resource(context, args); | return this.get_resource(context, args); | ||||
case "edit": | case "edit": | ||||
return this.edit_resource(context, args, false); | return this.edit_resource(context, args, false); | ||||
case "replace": | case "replace": | ||||
return this.edit_resource(context, args, true); | return this.edit_resource(context, args, true); | ||||
case "delete": | case "delete": | ||||
return this.delete_resource(context, args); | return this.delete_resource(context, args); | ||||
default: | default: | ||||
throw new Errors.DeveloperError(`Unknown action for '${this.collection.name}' resource: '${action_name}'`); | throw new Errors.DeveloperError( | ||||
`Unknown action for '${ | |||||
this.collection.name | |||||
}' resource: '${action_name}'` | |||||
); | |||||
} | } | ||||
}; | }; | ||||
SingleResource.prototype.get_child_subject = function(key){ | SingleResource.prototype.get_child_subject = function(key) { | ||||
if (this.collection.fields[key].type.is_subject){ | if (this.collection.fields[key].type.is_subject) { | ||||
return new CollectionFieldSubject(this.collection, this.resource_id, key); | return new CollectionFieldSubject(this.collection, this.resource_id, key); | ||||
} | } | ||||
}; | }; | ||||
module.exports = SingleResource; | module.exports = SingleResource; |