diff --git a/cosealious-src/index.js b/cosealious-src/index.js --- a/cosealious-src/index.js +++ b/cosealious-src/index.js @@ -13,4 +13,5 @@ APIs: { SingleResourceAPI: require("./lib/api/single-resource-api.js"), }, + form: require("./lib/mixins/form"), }; diff --git a/cosealious-src/lib/ResourceDropdown.jsx b/cosealious-src/lib/ResourceDropdown.jsx --- a/cosealious-src/lib/ResourceDropdown.jsx +++ b/cosealious-src/lib/ResourceDropdown.jsx @@ -18,7 +18,7 @@ function getAttr(name, resource, props) { const propname = name + "Attr"; if (typeof props[propname] === "string") { - return resource[props[propname]] || resource.body[props[propname]]; + return resource[props[propname]]; } else if (typeof props[propname] === "function") { return props[propname](resource); } diff --git a/cosealious-src/lib/mixins/form.jsx b/cosealious-src/lib/mixins/form.jsx new file mode 100644 --- /dev/null +++ b/cosealious-src/lib/mixins/form.jsx @@ -0,0 +1,85 @@ +import React from "react"; +import Promise from "bluebird"; + +function form(fields, onSubmit, component, default_values, clear_on_submit) { + if (!default_values) default_values = {}; + class FormComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + body: this.getInitialBody(), + submitting: false, + }; + } + getInitialBody() { + return Object.values(fields).reduce((acc, field) => { + acc[field] = default_values[field] || ""; + return acc; + }, {}); + } + getChangeFieldFn(field_name) { + const self = this; + return function(event) { + let new_value = ""; + if (event.target && event.target.type === "file") { + //here we asynchronously append a base64 representation of the image so we can display it before upload + const file = event.target.files[0]; + const reader = new FileReader(); + + reader.addEventListener( + "load", + function() { + file.base64 = reader.result; + self.setState({ + [field_name]: file, + }); + }, + false + ); + + if (file) { + reader.readAsDataURL(file); + } + new_value = event.target.files[0]; + } else if (event.target && event.target.type === "checkbox") { + new_value = event.target.checked; + } else if (event.target && event.target.type !== "checkbox") { + new_value = event.target.value; + } else { + new_value = event; + } + const current_body = self.state.body; + current_body[field_name] = new_value; + self.setState({ + body: current_body, + }); + }; + } + render() { + const self = this; + const props = { ...this.state.body }; + props._handlers = {}; + for (const i in fields) { + props._handlers[fields[i]] = this.getChangeFieldFn(fields[i]); + } + props.onSubmit = function(e) { + e.preventDefault(); + self.setState({ submitting: true }); + return Promise.method(onSubmit)(self.state.body) + .then(function() { + if (clear_on_submit) { + self.setState({ + body: self.getInitialBody(), + }); + } + }) + .finally(() => self.setState({ submitting: false })); + }; + props._submitting = self.state.submitting; + return React.createElement(component, props); + } + } + return FormComponent; +} + +module.exports = form; diff --git a/getting_started/getting_started.md b/getting_started/getting_started.md --- a/getting_started/getting_started.md +++ b/getting_started/getting_started.md @@ -71,18 +71,18 @@ const path = require("path"); const config = { - datastore_mongo: { - port: 27018, - }, - upload_path: path.resolve("./uploaded_files"), + datastore_mongo: { + port: 27018, + }, + upload_path: path.resolve("./uploaded_files"), }; const manifest = { - name: "What Seal Do?", - logo: path.resolve(__dirname, "./img/logo.jpg"), - version: "1.0", - default_language: "pl", - base_url: "http://localhost:8080", - admin_email: "mr.seal.api.admin@sealcode.org", + name: "What Seal Do?", + logo: path.resolve(__dirname, "./img/logo.jpg"), + version: "1.0", + default_language: "pl", + base_url: "http://localhost:8080", + admin_email: "mr.seal.api.admin@sealcode.org", }; const app = new Sealious.App(config, manifest); @@ -100,12 +100,12 @@ ```js const tasks = app.createChip(Sealious.Collection, { - name: "tasks", - fields: [ - { name: "title", type: "text", required: true }, - { name: "done", type: "boolean", required: true }, - ], - access_strategy: { default: "owner", create: "logged_in" }, + name: "tasks", + fields: [ + { name: "title", type: "text", required: true }, + { name: "done", type: "boolean", required: true }, + ], + access_strategy: { default: "owner", create: "logged_in" }, }); ``` @@ -150,10 +150,10 @@ ```js ... access_strategy: { - edit: "owner", - show: "owner", - delete: "owner", - create: "logged_in", + edit: "owner", + show: "owner", + delete: "owner", + create: "logged_in", } ``` @@ -176,7 +176,7 @@ ``` ... 15:28:19.570 (1.3s) - warning: Creating an admin account for mr.seal.api.admin@sealcode.org -15:28:19.616 (1.3s) - info: +15:28:19.616 (1.3s) - info: - message: "Would send an email here" - to: "mr.seal.api.admin@sealcode.org" - subject: {} @@ -231,7 +231,7 @@ ``` ... -15:30:34.101 (2m 15.8s) - info: +15:30:34.101 (2m 15.8s) - info: - message: "Would send an email here" - to: "seal_user_1@sealcode.org" - subject: {} @@ -323,26 +323,27 @@ vary: accept-encoding { - "body": { - "done": false, - "title": "Przetestować API" - }, - "calculated_fields": {}, - "collection_name": "tasks", - "created_context": { - "anonymous_user_id": "1n4eYyW_o", - "ip": "127.0.0.1", - "timestamp": 1532958162953, - "total": 1, - "user_id": "kYxtJ2-pe" - }, + + "done": false, + "title": "Przetestować API" "id": "fhNxgSoJp", - "last_modified_context": { - "anonymous_user_id": "1n4eYyW_o", - "ip": "127.0.0.1", - "timestamp": 1532958162953, - "total": 1, - "user_id": "kYxtJ2-pe" + "calculated_fields": {}, + "_metadata": { + "collection_name": "tasks", + "created_context": { + "anonymous_user_id": "1n4eYyW_o", + "ip": "127.0.0.1", + "timestamp": 1532958162953, + "total": 1, + "user_id": "kYxtJ2-pe" + }, + "last_modified_context": { + "anonymous_user_id": "1n4eYyW_o", + "ip": "127.0.0.1", + "timestamp": 1532958162953, + "total": 1, + "user_id": "kYxtJ2-pe" + } } } ``` diff --git a/lib/app/base-chips/access-strategy-types/not.subtest.js b/lib/app/base-chips/access-strategy-types/not.subtest.js --- a/lib/app/base-chips/access-strategy-types/not.subtest.js +++ b/lib/app/base-chips/access-strategy-types/not.subtest.js @@ -59,22 +59,20 @@ }); } - let numbers = await Promise.map([0, 1, 2, 3, 4], n => - app.run_action( + for (let i of [0, 1, 2, 3, 4]) { + const { id } = await app.run_action( new app.Sealious.SuperContext(), ["collections", "numbers"], "create", - { number: n } - ) - ); + { number: i } + ); - for (const number of numbers) { await Promise.map(collections, ({ name }) => app.run_action( new app.Sealious.SuperContext(), ["collections", name], "create", - { number: number.id } + { number: id } ) ); } @@ -87,18 +85,18 @@ const query = new app.Query(); const id = query.lookup({ from: "numbers", - localField: "body.number", + localField: "number", foreignField: "sealious_id", }); query.match({ - [`${id}.body.number`]: { + [`${id}.number`]: { $lt: number, }, }); return query; }, checker_function: async function(context, params, item) { - if (item.body.number.body.number >= number) { + if (item.number.number >= number) { return Promise.reject( `Given value is not lower than ${number}` ); @@ -127,7 +125,7 @@ await setup(app); const numbers = (await rest_api.get( "/api/v1/collections/collection-not(noone)?format%5Bnumber%5D=expand" - )).items.map(n => n.body.number.body.number); + )).items.map(n => n.number.number); assert.deepEqual(numbers, [0, 1, 2, 3, 4]); })); @@ -137,7 +135,7 @@ await setup(app); const numbers = (await rest_api.get( "/api/v1/collections/collection-not(less-than(2))?format%5Bnumber%5D=expand" - )).items.map(n => n.body.number.body.number); + )).items.map(n => n.number.number); assert.deepEqual(numbers, [2, 3, 4]); })); @@ -147,7 +145,7 @@ await setup(app); const numbers = (await rest_api.get( "/api/v1/collections/collection-not(less-than(6))?format%5Bnumber%5D=expand" - )).items.map(n => n.body.number.body.number); + )).items.map(n => n.number.number); assert.deepEqual(numbers, []); })); diff --git a/lib/app/base-chips/access-strategy-types/owner.js b/lib/app/base-chips/access-strategy-types/owner.js --- a/lib/app/base-chips/access-strategy-types/owner.js +++ b/lib/app/base-chips/access-strategy-types/owner.js @@ -7,7 +7,7 @@ getRestrictingQuery: async function(context, params) { if (context.user_id) { return Query.fromSingleMatch({ - "created_context.user_id": { $eq: context.user_id }, + "_metadata.created_context.user_id": { $eq: context.user_id }, }); } return new Query.DenyAll(); @@ -15,7 +15,7 @@ checker_function: function(context, params, item) { if ( context.user_id && - context.user_id === item.created_context.user_id + context.user_id === item._metadata.created_context.user_id ) { return Promise.resolve(); } else { diff --git a/lib/app/base-chips/access-strategy-types/roles.js b/lib/app/base-chips/access-strategy-types/roles.js --- a/lib/app/base-chips/access-strategy-types/roles.js +++ b/lib/app/base-chips/access-strategy-types/roles.js @@ -6,7 +6,7 @@ ["collections", "user-roles"], "show", { filter: { user: user_id } } - )).items.map(role_resource => role_resource.body.role); + )).items.map(role_resource => role_resource.role); return allowed_roles.filter(allowed_role => user_roles.includes(allowed_role) diff --git a/lib/app/base-chips/access-strategy-types/same-anon.js b/lib/app/base-chips/access-strategy-types/same-anon.js --- a/lib/app/base-chips/access-strategy-types/same-anon.js +++ b/lib/app/base-chips/access-strategy-types/same-anon.js @@ -6,7 +6,8 @@ getRestrictingQuery: async function(context, params) { if (context.anonymous_user_id) { return Query.fromSingleMatch({ - "created_context.anonymous_user_id": context.anonymous_user_id, + "_metadata.created_context.anonymous_user_id": + context.anonymous_user_id, }); } return new Query.AllowAll(); @@ -16,7 +17,8 @@ return Promise.reject(); } if ( - context.anonymous_user_id === item.created_context.anonymous_user_id + context.anonymous_user_id === + item._metadata.created_context.anonymous_user_id ) { return Promise.resolve(); } else { diff --git a/lib/app/base-chips/access-strategy-types/same-as-for-resource-in-field.js b/lib/app/base-chips/access-strategy-types/same-as-for-resource-in-field.js --- a/lib/app/base-chips/access-strategy-types/same-as-for-resource-in-field.js +++ b/lib/app/base-chips/access-strategy-types/same-as-for-resource-in-field.js @@ -31,7 +31,7 @@ const query = new Query(); const parent_prefix = query.lookup({ from: referenced_collection, - localField: `body.${field}`, + localField: field, foreignField: "sealious_id", }); @@ -66,7 +66,7 @@ const referenced_item = await app.run_action( new app.Sealious.SuperContext(), - ["collections", referenced_collection, item.body[field]], + ["collections", referenced_collection, item[field]], "show" ); diff --git a/lib/app/base-chips/access-strategy-types/user-referenced-in-field.js b/lib/app/base-chips/access-strategy-types/user-referenced-in-field.js --- a/lib/app/base-chips/access-strategy-types/user-referenced-in-field.js +++ b/lib/app/base-chips/access-strategy-types/user-referenced-in-field.js @@ -3,13 +3,12 @@ getRestrictingQuery: async (context, field_name) => { if (!context.user_id) return new app.Query.DenyAll(); return app.Query.fromSingleMatch({ - [`body.${field_name}`]: context.user_id, + [field_name]: context.user_id, }); }, checker_function: (context, field_name, item) => { if (!context.user_id) return Promise.reject("You're not logged in!"); - else if (context.user_id === item.body[field_name]) - return Promise.resolve(); + else if (context.user_id === item[field_name]) return Promise.resolve(); else return Promise.reject("Access not allowed for this user"); }, item_sensitive: true, diff --git a/lib/app/base-chips/access-strategy-types/user-referenced-in-field.subtest.js b/lib/app/base-chips/access-strategy-types/user-referenced-in-field.subtest.js --- a/lib/app/base-chips/access-strategy-types/user-referenced-in-field.subtest.js +++ b/lib/app/base-chips/access-strategy-types/user-referenced-in-field.subtest.js @@ -51,6 +51,6 @@ alice_session ); assert.equal(items.length, 1); - assert.equal(items[0].body.name, "Alice's pet"); + assert.equal(items[0].name, "Alice's pet"); })); }); diff --git a/lib/app/base-chips/access-strategy-types/when.js b/lib/app/base-chips/access-strategy-types/when.js --- a/lib/app/base-chips/access-strategy-types/when.js +++ b/lib/app/base-chips/access-strategy-types/when.js @@ -67,7 +67,7 @@ ); query.match({ sealious_id: item.id }); const results = await app.Datastore.aggregate( - item.collection_name, + item._metadata.collection_name, query.toPipeline() ); if (!results.length) { diff --git a/lib/app/base-chips/access-strategy-types/when.subtest.js b/lib/app/base-chips/access-strategy-types/when.subtest.js --- a/lib/app/base-chips/access-strategy-types/when.subtest.js +++ b/lib/app/base-chips/access-strategy-types/when.subtest.js @@ -52,12 +52,12 @@ }); const { items: resources_when_logged_in } = await rest_api.get( - "/api/v1/collections/numbers?sort[body.number]=asc", + "/api/v1/collections/numbers?sort[number]=asc", session ); assert.equal(resources_when_logged_in.length, 3); - assert.equal(resources_when_logged_in[0].body.number, -1); + assert.equal(resources_when_logged_in[0].number, -1); })); it("should only use 'when_false' access strategy when the item doesn't pass the filter", async () => @@ -65,7 +65,7 @@ await create_resources(app); const { items: public_resources } = await rest_api.get( - "/api/v1/collections/numbers?sort[body.number]=asc" + "/api/v1/collections/numbers?sort[number]=asc" ); assert.equal(public_resources.length, 2); diff --git a/lib/app/base-chips/collections/password-reset-intents.js b/lib/app/base-chips/collections/password-reset-intents.js --- a/lib/app/base-chips/collections/password-reset-intents.js +++ b/lib/app/base-chips/collections/password-reset-intents.js @@ -31,10 +31,10 @@ new app.Sealious.SuperContext(metadata.context), ["collections", "password-reset-intents", intent.id], "show" - )).body.token; + )).token; const message = await app.MailTemplates.PasswordReset(app, { - email_address: intent.body.email, + email_address: intent.email, token, }); await message.send(app); diff --git a/lib/app/base-chips/collections/password-reset-intents.subtest.js b/lib/app/base-chips/collections/password-reset-intents.subtest.js --- a/lib/app/base-chips/collections/password-reset-intents.subtest.js +++ b/lib/app/base-chips/collections/password-reset-intents.subtest.js @@ -42,16 +42,19 @@ it("allows anyone to create an intent, if the email exists", async () => with_running_app(async ({ app, base_url }) => { await create_a_user(app); - const data = (await axios.post( + const { email, token } = (await axios.post( `${base_url}/api/v1/collections/password-reset-intents`, { email: "user@example.com", } )).data; - assert.deepEqual(data.body, { - email: "user@example.com", - token: "it's a secret to everybody", - }); + assert.deepEqual( + { email, token }, + { + email: "user@example.com", + token: "it's a secret to everybody", + } + ); })); it("tells you if the email address is malformed", async () => diff --git a/lib/app/base-chips/collections/registration-intents.js b/lib/app/base-chips/collections/registration-intents.js --- a/lib/app/base-chips/collections/registration-intents.js +++ b/lib/app/base-chips/collections/registration-intents.js @@ -50,9 +50,9 @@ new app.Sealious.SuperContext(emitted_event.metadata.context), ["collections", "registration-intents", intent.id], "show" - )).body.token; + )).token; const message = await app.MailTemplates.RegistrationIntent(app, { - email_address: intent.body.email, + email_address: intent.email, token, }); await message.send(app); diff --git a/lib/app/base-chips/collections/registration-intents.subtest.js b/lib/app/base-chips/collections/registration-intents.subtest.js --- a/lib/app/base-chips/collections/registration-intents.subtest.js +++ b/lib/app/base-chips/collections/registration-intents.subtest.js @@ -64,13 +64,13 @@ role: "admin", } )).data; - assert.equal(intent.body.role, "admin"); + assert.equal(intent.role, "admin"); const response = await app.run_action( new app.Sealious.SuperContext(), ["collections", "registration-intents", intent.id], "show" ); - assert.equal(response.body.role, "admin"); + assert.equal(response.role, "admin"); } )); }); diff --git a/lib/app/base-chips/collections/users.subtest.js b/lib/app/base-chips/collections/users.subtest.js --- a/lib/app/base-chips/collections/users.subtest.js +++ b/lib/app/base-chips/collections/users.subtest.js @@ -14,7 +14,7 @@ { filter: { email: app.manifest.admin_email } } ); assert.equal(registration_intents.length, 1); - assert.equal(registration_intents[0].body.role, "admin"); + assert.equal(registration_intents[0].role, "admin"); })); it("should properly handle route to account cration", async () => @@ -28,7 +28,7 @@ { filter: { email: app.manifest.admin_email } } ); - const { email, token } = registration_intent.body; + const { email, token } = registration_intent; const response = await rest_api.get( `/account-creation-details?token=${token}&email=${email}` ); diff --git a/lib/app/base-chips/field-types/cached-value.js b/lib/app/base-chips/field-types/cached-value.js --- a/lib/app/base-chips/field-types/cached-value.js +++ b/lib/app/base-chips/field-types/cached-value.js @@ -117,7 +117,7 @@ ["collections", referenced_collection_name], "show", { - sort: { "last_modified_context.timestamp": "desc" }, + sort: { "last_modified_context._metadata.timestamp": "desc" }, pagination: { items: 1 }, } )).items[0]; @@ -127,7 +127,7 @@ } const last_modified_timestamp = - last_modified_resource.last_modified_context.timestamp; + last_modified_resource._metadata.last_modified_context.timestamp; const outdated_resources = await app.Datastore.aggregate( collection.name, @@ -136,11 +136,11 @@ $match: { $or: [ { - [`body.${field_name}.timestamp`]: { + [`${field_name}.timestamp`]: { $lt: last_modified_timestamp, }, }, - { [`body.${field_name}`]: { $exists: false } }, + { [field_name]: { $exists: false } }, ], }, }, @@ -161,7 +161,7 @@ await app.Datastore.update( collection.name, { sealious_id: resource.sealious_id }, - { $set: { [`body.${field_name}`]: cache_value } } + { $set: { [field_name]: cache_value } } ); } }, diff --git a/lib/app/base-chips/field-types/cached-value.subtest.js b/lib/app/base-chips/field-types/cached-value.subtest.js --- a/lib/app/base-chips/field-types/cached-value.subtest.js +++ b/lib/app/base-chips/field-types/cached-value.subtest.js @@ -96,15 +96,15 @@ [ { $match: { - "body.account": resource_id, + account: resource_id, }, }, { $group: { - _id: "$body.name", + _id: "$name", timestamp: { $max: - "$last_modified_context.timestamp", + "$_metadata.last_modified_context.timestamp", }, }, }, @@ -231,7 +231,7 @@ it("Respects filters of base field type", async () => with_running_app(async ({ app, rest_api }) => { create_collections(app); - const ids = await add_a_few_accounts(app); + await add_a_few_accounts(app); const { items: accounts } = await rest_api.get( "/api/v1/collections/accounts?filter[number][>]=3" @@ -251,7 +251,7 @@ ); const actual_datetime = (await rest_api.get( `/api/v1/collections/accounts/${id}?format[date_time]=human_readable` - )).body.date_time; + )).date_time; assert.equal(actual_datetime, expected_datetime); })); @@ -279,7 +279,7 @@ number_id ) => { const { - body: { number }, + number, } = await app.run_action( context, [ @@ -330,8 +330,7 @@ collection_name: "actions", action: "create", }), - resource_id_getter: (emitted_event, resource) => - resource.body.account, + resource_id_getter: (emitted_event, resource) => resource.account, }, { event_matcher: new app.Sealious.EventMatchers.Resource({ @@ -339,15 +338,14 @@ collection_name: "actions", action: "edit", }), - resource_id_getter: (emitted_event, resource) => - resource.body.account, + resource_id_getter: (emitted_event, resource) => resource.account, }, ]; } async function assert_status_equals(rest_api, account_id, expected_status) { - const account = (await rest_api.get( + const account = await rest_api.get( `/api/v1/collections/accounts/${account_id}` - )).body; + ); assert.equal(account.status, expected_status); } diff --git a/lib/app/base-chips/field-types/control-access.subtest.js b/lib/app/base-chips/field-types/control-access.subtest.js --- a/lib/app/base-chips/field-types/control-access.subtest.js +++ b/lib/app/base-chips/field-types/control-access.subtest.js @@ -109,7 +109,7 @@ ); ssh_keys.forEach(key => { - assert.deepEqual(key.body.private, ""); + assert.deepEqual(key.private, ""); }); })); @@ -123,7 +123,7 @@ ); ssh_keys.forEach(key => { - assert(key.body.private.length >= 3); + assert(key.private.length >= 3); }); })); @@ -170,7 +170,7 @@ sessions.admin ); - assert.deepEqual(updated_key.body.private, "654321"); + assert.deepEqual(updated_key.private, "654321"); })); it("Doesn't allow regular-user to update a protected field", async () => diff --git a/lib/app/base-chips/field-types/derived-value.js b/lib/app/base-chips/field-types/derived-value.js --- a/lib/app/base-chips/field-types/derived-value.js +++ b/lib/app/base-chips/field-types/derived-value.js @@ -98,7 +98,7 @@ subject_path.split("."), "show" ); - return resource.body[current_field]; + return resource[current_field]; } ); const derived_value = await derived_fn(...derived_fn_args); diff --git a/lib/app/base-chips/field-types/derived-value.subtest.js b/lib/app/base-chips/field-types/derived-value.subtest.js --- a/lib/app/base-chips/field-types/derived-value.subtest.js +++ b/lib/app/base-chips/field-types/derived-value.subtest.js @@ -120,7 +120,7 @@ surname: "Kowalski", }); - assert.deepEqual("Jan Kowalski", person.body.name_and_surname); + assert.deepEqual("Jan Kowalski", person.name_and_surname); })); it("properly reacts to pre:edit handler", async () => @@ -136,7 +136,7 @@ surname: "Kowalski", }); - assert.deepEqual("Jan Kowalski", person.body.name_and_surname); + assert.deepEqual("Jan Kowalski", person.name_and_surname); const updated_person = await rest_api.patch( `/api/v1/collections/people/${person.id}`, @@ -145,9 +145,9 @@ } ); - assert.deepEqual(updated_person.body.username, "Janusz"); + assert.deepEqual(updated_person.username, "Janusz"); assert.deepEqual( - updated_person.body.name_and_surname, + updated_person.name_and_surname, "Janusz Kowalski" ); @@ -158,9 +158,9 @@ surname: "Doe", } ); - assert.deepEqual(updated_person2.body.username, "John"); - assert.deepEqual(updated_person2.body.surname, "Doe"); - assert.deepEqual(updated_person2.body.name_and_surname, "John Doe"); + assert.deepEqual(updated_person2.username, "John"); + assert.deepEqual(updated_person2.surname, "Doe"); + assert.deepEqual(updated_person2.name_and_surname, "John Doe"); })); it("value isn't undefined after edit on fields other than the ones conerning derived_value", async () => @@ -177,7 +177,7 @@ age: 60, }); - assert.deepEqual(60, person.body.age); + assert.deepEqual(60, person.age); const updated_person = await rest_api.patch( `/api/v1/collections/people/${person.id}`, @@ -186,11 +186,8 @@ } ); - assert.deepEqual(updated_person.body.age, 22); - assert.deepEqual( - updated_person.body.name_and_surname, - "Jan Kowalski" - ); + assert.deepEqual(updated_person.age, 22); + assert.deepEqual(updated_person.name_and_surname, "Jan Kowalski"); })); it("throws when the value returned from derived_fn is unnacceptable by target_field_type of derived-value", async () => with_running_app(async ({ app, rest_api }) => { diff --git a/lib/app/base-chips/field-types/json-object.subtest.js b/lib/app/base-chips/field-types/json-object.subtest.js --- a/lib/app/base-chips/field-types/json-object.subtest.js +++ b/lib/app/base-chips/field-types/json-object.subtest.js @@ -38,17 +38,19 @@ "/api/v1/collections/seals", item ); - assert.deepEqual( - item, - (await rest_api.get(`/api/v1/collections/seals/${id}`)).body + let { name, metadata } = await rest_api.get( + `/api/v1/collections/seals/${id}` ); + assert.deepEqual({ name, metadata }, item); item.metadata.weight = 320; await rest_api.patch(`/api/v1/collections/seals/${id}`, item); - assert.deepEqual( - item, - (await rest_api.get(`/api/v1/collections/seals/${id}`)).body - ); + + ({ name, metadata } = await rest_api.get( + `/api/v1/collections/seals/${id}` + )); + + assert.deepEqual({ name, metadata }, item); })); it("Doesn't allow to post a primitive", async () => @@ -92,14 +94,14 @@ seals = (await rest_api.get( "/api/v1/collections/seals?filter[name]=Hoover" )).items; - assert.equal(seals[0].body.name, "Hoover"); + assert.equal(seals[0].name, "Hoover"); seals = (await rest_api.get( "/api/v1/collections/seals?filter[metadata][weight]=280" )).items; assert.equal(seals.length, 1); - assert.equal(seals[0].body.name, "Maksiu"); + assert.equal(seals[0].name, "Maksiu"); })); it("Respects filter passed to query when value can be parsed as number", async () => @@ -135,7 +137,7 @@ ); assert.equal(actual_seals.length, 1); - assert.equal(actual_seals[0].body.name, seal.name); + assert.equal(actual_seals[0].name, seal.name); } })); }); diff --git a/lib/app/base-chips/field-types/password.subtest.js b/lib/app/base-chips/field-types/password.subtest.js --- a/lib/app/base-chips/field-types/password.subtest.js +++ b/lib/app/base-chips/field-types/password.subtest.js @@ -33,7 +33,7 @@ !(await rest_api.get( `/api/v1/collections/users/${user_id}`, session - )).body.password + )).password ); assert.ok( @@ -41,7 +41,7 @@ new app.Sealious.SuperContext(), ["collections", "users", user_id], "show" - )).body.password + )).password ); })); @@ -51,7 +51,7 @@ const hashed_password = (await app.Datastore.find("users", { sealious_id: user_id, - }))[0].body.password; + }))[0].password; assert.ok(await SecureHasher.matches(password, hashed_password)); assert.ok( diff --git a/lib/app/base-chips/field-types/reverse-single-reference.js b/lib/app/base-chips/field-types/reverse-single-reference.js --- a/lib/app/base-chips/field-types/reverse-single-reference.js +++ b/lib/app/base-chips/field-types/reverse-single-reference.js @@ -25,7 +25,7 @@ pipeline = [ { $match: { - [`body.${referencing_field_name}`]: { $in: resource_ids }, + [referencing_field_name]: { $in: resource_ids }, }, }, ]; @@ -34,8 +34,8 @@ } pipeline.push({ $group: { - _id: `$body.${referencing_field_name}`, - referenced_by: { $push: `$sealious_id` }, + _id: `$${referencing_field_name}`, + referenced_by: { $push: "$sealious_id" }, }, }); const to_update = await app.Datastore.aggregate( @@ -53,7 +53,7 @@ await app.Datastore.update( collection.name, { sealious_id: entry._id }, - { $set: { [`body.${field_name}`]: entry.referenced_by } } + { $set: { [field_name]: entry.referenced_by } } ); } } @@ -146,13 +146,15 @@ ["collections", params.collection.name], "show", { - sort: { "last_modified_context.timestamp": "desc" }, + sort: { + "_metadata.last_modified_context.timestamp": "desc", + }, pagination: { items: 1 }, } )).items[0]; if (last_modified_resource_in_reference_collection) { const last_modified_resource_timestamp = - last_modified_resource_in_reference_collection + last_modified_resource_in_reference_collection._metadata .last_modified_context.timestamp; const last_field_cache_update = (await app.Metadata.get( @@ -178,7 +180,7 @@ action: "create", }), async (emitted_event, resource) => { - const referenced_id = resource.body[params.field_name]; + const referenced_id = resource[params.field_name]; await update_cache(app, collection, field_name, params, [ referenced_id, ]); @@ -194,7 +196,7 @@ async (emitted_event, data) => { const deleted_id = emitted_event.subject_path.split(".")[2]; const affected = await app.Datastore.find(collection.name, { - [`body.${field_name}`]: deleted_id, + [field_name]: deleted_id, }); const affected_ids = affected.map( document => document.sealious_id @@ -222,7 +224,7 @@ const no_longer_referenced = await app.Datastore.find( collection.name, { - [`body.${field_name}`]: edited_id, + [field_name]: edited_id, } ); const affected_ids = no_longer_referenced.map( diff --git a/lib/app/base-chips/field-types/reverse-single-reference.subtest.js b/lib/app/base-chips/field-types/reverse-single-reference.subtest.js --- a/lib/app/base-chips/field-types/reverse-single-reference.subtest.js +++ b/lib/app/base-chips/field-types/reverse-single-reference.subtest.js @@ -39,16 +39,19 @@ async function create_resources(app) { const numbers = [1, 2, 3]; - const bs = await Promise.map(numbers, number => - app.run_action( - new app.Sealious.SuperContext(), - ["collections", "B"], - "create", - { number } - ) - ); + const bs = []; + for (let number of numbers) { + bs.push( + await app.run_action( + new app.Sealious.SuperContext(), + ["collections", "B"], + "create", + { number } + ) + ); + } for (let b of bs) { - for (let i = 1; i <= b.body.number; i++) { + for (let i = 1; i <= b.number; i++) { await app.run_action( new app.Sealious.SuperContext(), ["collections", "A"], @@ -84,13 +87,13 @@ const { items: [result], } = await rest_api.get("/api/v1/collections/B?filter[number]=1"); - assert(result.body.references_in_a); - assert.equal(result.body.references_in_a.length, 1); + assert(result.references_in_a); + assert.equal(result.references_in_a.length, 1); const { items: [result2], } = await rest_api.get("/api/v1/collections/B?filter[number]=2"); - assert(result2.body.references_in_a); - assert.equal(result2.body.references_in_a.length, 2); + assert(result2.references_in_a); + assert.equal(result2.references_in_a.length, 2); }); }); @@ -102,8 +105,8 @@ const { items: [result], } = await rest_api.get("/api/v1/collections/B?filter[number]=2"); - assert(result.body.references_in_a instanceof Array); - assert.equal(result.body.references_in_a.length, 2); + assert(result.references_in_a instanceof Array); + assert.equal(result.references_in_a.length, 2); }); }); @@ -112,12 +115,12 @@ const { items: [result], } = await rest_api.get("/api/v1/collections/B?filter[number]=2"); - const referencing_id = result.body.references_in_a[0]; + const referencing_id = result.references_in_a[0]; await rest_api.delete(`/api/v1/collections/A/${referencing_id}`); const { items: [new_result2], } = await rest_api.get("/api/v1/collections/B?filter[number]=2"); - assert.equal(new_result2.body.references_in_a.length, 1); + assert.equal(new_result2.references_in_a.length, 1); })); it("updates the cached value when an old reference is edited to a new one", async () => @@ -128,7 +131,7 @@ const { items: [result2], } = await rest_api.get("/api/v1/collections/B?filter[number]=2"); - const referencing_id = result2.body.references_in_a[0]; + const referencing_id = result2.references_in_a[0]; await rest_api.patch(`/api/v1/collections/A/${referencing_id}`, { reference_to_b: result1.id, @@ -136,11 +139,11 @@ const { items: [new_result2], } = await rest_api.get("/api/v1/collections/B?filter[number]=2"); - assert.equal(new_result2.body.references_in_a.length, 1); + assert.equal(new_result2.references_in_a.length, 1); const { items: [new_result1], } = await rest_api.get("/api/v1/collections/B?filter[number]=1"); - assert.equal(new_result1.body.references_in_a.length, 2); + assert.equal(new_result1.references_in_a.length, 2); })); it("updates the cached value when an old reference is edited to an empty one", async () => @@ -151,7 +154,7 @@ const { items: [result2], } = await rest_api.get("/api/v1/collections/B?filter[number]=2"); - const referencing_id = result2.body.references_in_a[0]; + const referencing_id = result2.references_in_a[0]; await rest_api.patch(`/api/v1/collections/A/${referencing_id}`, { reference_to_b: "", @@ -159,7 +162,7 @@ const { items: [new_result2], } = await rest_api.get("/api/v1/collections/B?filter[number]=2"); - assert.equal(new_result2.body.references_in_a.length, 1); + assert.equal(new_result2.references_in_a.length, 1); })); it("allows to filter by a value of the referencing resource", async () => @@ -183,6 +186,6 @@ let { items } = await rest_api.get( "/api/v1/collections/B?format[references_in_a]=expand" ); - assert(items[0].body.references_in_a[0].body); + assert(items[0].references_in_a[0]); })); }); diff --git a/lib/app/base-chips/field-types/settable-by.subtest.js b/lib/app/base-chips/field-types/settable-by.subtest.js --- a/lib/app/base-chips/field-types/settable-by.subtest.js +++ b/lib/app/base-chips/field-types/settable-by.subtest.js @@ -62,12 +62,12 @@ any: 1, } )).data; - assert.equal(response.body.any, 1); + assert.equal(response.any, 1); const response2 = await rest_api.get( `/api/v1/collections/allowed-collection/${response.id}` ); - assert.equal(response2.body.any, 1); + assert.equal(response2.any, 1); })); it("should not allow invalid value when access strategy allows", async () => diff --git a/lib/app/base-chips/field-types/single_reference.js b/lib/app/base-chips/field-types/single_reference.js --- a/lib/app/base-chips/field-types/single_reference.js +++ b/lib/app/base-chips/field-types/single_reference.js @@ -149,7 +149,7 @@ field_name ); filter[ - `${temp_field_name}.0.body.${field_name}` + `${temp_field_name}.0.${field_name}` ] = field.filter_to_query(context, request_filter[field_name]); } return Promise.props(filter).then(function(_filter) { diff --git a/lib/app/base-chips/field-types/single_reference.subtest.js b/lib/app/base-chips/field-types/single_reference.subtest.js --- a/lib/app/base-chips/field-types/single_reference.subtest.js +++ b/lib/app/base-chips/field-types/single_reference.subtest.js @@ -97,7 +97,7 @@ `${A}?filter[reference_to_b][number]=3&format[reference_to_b]=expand` ); assert.deepEqual(items.length, 1); - assert.deepEqual(items[0].body.reference_to_b.body.number, 3); + assert.deepEqual(items[0].reference_to_b.number, 3); })); it("should be filterable by referenced collection field of referenced collection field", async () => @@ -156,10 +156,7 @@ .catch(console.error); assert.deepEqual(items.length, 1); - assert.deepEqual( - items[0].body.reference_to_b.body.reference_to_c.body.number, - 3 - ); + assert.deepEqual(items[0].reference_to_b.reference_to_c.number, 3); })); }); diff --git a/lib/app/base-chips/special_filters/IsReferencedByResourcesMatching.js b/lib/app/base-chips/special_filters/IsReferencedByResourcesMatching.js --- a/lib/app/base-chips/special_filters/IsReferencedByResourcesMatching.js +++ b/lib/app/base-chips/special_filters/IsReferencedByResourcesMatching.js @@ -28,10 +28,10 @@ const lookup_id = query.lookup({ from: this.params.collection.name, localField: "sealious_id", - foreignField: `body.${this.params.referencing_field}`, + foreignField: this.params.referencing_field, }); query.match({ - [`${lookup_id}.body.${this.params.field_to_check}`]: { + [`${lookup_id}.${this.params.field_to_check}`]: { $in: this.params.allowed_values, }, }); diff --git a/lib/app/base-chips/special_filters/IsReferencedByResourcesMatching.subtest.js b/lib/app/base-chips/special_filters/IsReferencedByResourcesMatching.subtest.js --- a/lib/app/base-chips/special_filters/IsReferencedByResourcesMatching.subtest.js +++ b/lib/app/base-chips/special_filters/IsReferencedByResourcesMatching.subtest.js @@ -2,12 +2,10 @@ const locreq = require("locreq")(__dirname); const Promise = require("bluebird"); -const { create_resource_as } = locreq("test_utils"); const { with_running_app } = locreq("test_utils/with-test-app.js"); describe("IsReferencedByResourcesMatching", () => { - async function setup(app) { - const port = app.ConfigManager.get("www-server.port"); + async function setup(app, rest_api) { const Users = app.ChipManager.get_chip("collection", "users"); Users.set_access_strategy({ create: "public", @@ -63,29 +61,21 @@ }, ]; - const created_users = await Promise.map(users, user => - create_resource_as({ - collection: "users", - resource: user, - port, - }) - ); - - await Promise.map(created_users, user => - create_resource_as({ - collection: "users-roles", - resource: { - user: user.id, - role: user.body.username, - }, - port, - }) - ); + for (let user of users) { + const { id, username } = await rest_api.post( + "/api/v1/collections/users", + user + ); + await rest_api.post("/api/v1/collections/users-roles", { + user: id, + role: username, + }); + } } it("returns only users with role matching `allowed_values`", () => with_running_app(async ({ app, rest_api }) => { - await setup(app); + await setup(app, rest_api); return rest_api .get("/api/v1/collections/users/@staff") @@ -93,8 +83,8 @@ assert(items.length > 0); items.forEach(user => assert( - user.body.username === "admin" || - user.body.username === "moderator" + user.username === "admin" || + user.username === "moderator" ) ); }); diff --git a/lib/app/base-chips/special_filters/matches.subtest.js b/lib/app/base-chips/special_filters/matches.subtest.js --- a/lib/app/base-chips/special_filters/matches.subtest.js +++ b/lib/app/base-chips/special_filters/matches.subtest.js @@ -2,11 +2,10 @@ const locreq = require("locreq")(__dirname); const Promise = require("bluebird"); -const { create_resource_as } = locreq("test_utils"); const { with_running_app } = locreq("test_utils/with-test-app.js"); describe("Matches", () => { - async function setup(app) { + async function setup(app, rest_api) { const port = app.ConfigManager.get("www-server.port"); app.createChip(Sealious.Collection, { name: "numbers", @@ -23,48 +22,41 @@ }); const numbers = [-2, -1, 0, 1, 2]; - await Promise.map(numbers, n => - create_resource_as({ - collection: "numbers", - resource: { number: n }, - port, - }) - ); + for (let number of numbers) { + await rest_api.post("/api/v1/collections/numbers", { number }); + } } it("returns only positive numbers when using filter", () => with_running_app(async ({ app, rest_api }) => { - await setup(app); + await setup(app, rest_api); const result = await app.run_action( new app.Sealious.SuperContext(), ["collections", "numbers", "@positive"], "show" ); - assert.deepEqual( - result.items.map(resource => resource.body.number), - [1, 2] - ); + assert.deepEqual(result.items.map(resource => resource.number), [ + 1, + 2, + ]); })); it("returns only positive numbers when using @positive filter", () => with_running_app(async ({ app, rest_api }) => { - await setup(app); + await setup(app, rest_api); const { items } = await rest_api.get( - "/api/v1/collections/numbers/@positive?sort[body.number]=asc" + "/api/v1/collections/numbers/@positive?sort[number]=asc" ); - assert.deepEqual(items.map(resource => resource.body.number), [ - 1, - 2, - ]); + assert.deepEqual(items.map(resource => resource.number), [1, 2]); })); it("returns empty array when using both @positive and @negative filters", () => with_running_app(async ({ app, rest_api }) => { - await setup(app); + await setup(app, rest_api); const { items } = await rest_api.get( "/api/v1/collections/numbers/@positive/@negative" ); - assert.deepEqual(items.map(resource => resource.body.number), []); + assert.deepEqual(items.map(resource => resource.number), []); })); }); diff --git a/lib/chip-types/collection.js b/lib/chip-types/collection.js --- a/lib/chip-types/collection.js +++ b/lib/chip-types/collection.js @@ -410,7 +410,7 @@ const decoded_values = await Collection.pure.decode_values( fields, context, - db_document.body + db_document ); return Collection.pure.format_decoded_values( fields, @@ -438,7 +438,7 @@ } return Promise.props(ret); }, - get_resource_representation: function( + get_resource_representation: async function( fields, field_type_name, context, @@ -448,20 +448,17 @@ calculate ) { if (calculate === undefined) calculate = true; - const representation = {}; - representation.created_context = db_document.created_context; - representation.last_modified_context = - db_document.last_modified_context; - representation.id = db_document.sealious_id; - representation.collection_name = field_type_name; - representation.body = Collection.pure._get_body( + const representation = await Collection.pure._get_body( fields, context, db_document, format ); + representation.id = db_document.sealious_id; + representation._metadata = db_document._metadata; + representation._metadata.collection_name = field_type_name; if (calculate) { - representation.calculated_fields = Collection.pure._get_calculated_fields( + representation.calculated_fields = await Collection.pure._get_calculated_fields( context, calculated_fields, representation, @@ -469,7 +466,7 @@ calculate ); } - return Promise.props(representation); + return representation; }, check_if_action_is_allowed: function( access_strategy_map, diff --git a/lib/chip-types/datastore.js b/lib/chip-types/datastore.js --- a/lib/chip-types/datastore.js +++ b/lib/chip-types/datastore.js @@ -159,7 +159,7 @@ // Should handle dot-notation nested queries return self .find(test_collection_name, { - "body.name": complex_object.body.name, + name: complex_object.name, }) .then(function(response) { assert.deepEqual( @@ -174,7 +174,7 @@ return self .find(test_collection_name, { body: { - name: complex_object.body.name, + name: complex_object.name, }, }) .then(function(response) { @@ -188,7 +188,7 @@ }) .then(function(complex_object) { // .update should modify document values with dot notation - complex_object.body.name = "Hanna"; + complex_object.name = "Hanna"; return self .update( test_collection_name, @@ -196,7 +196,7 @@ id: complex_object.id, }, { - "body.name": complex_object.body.name, + name: complex_object.name, } ) .then(function() { @@ -215,7 +215,7 @@ }) .then(function(complex_object) { // .update should modify document values using nested object as a query - complex_object.body.name = "Marzanna"; + complex_object.name = "Marzanna"; return self .update( test_collection_name, @@ -224,7 +224,7 @@ }, { body: { - name: complex_object.body.name, + name: complex_object.name, }, } ) @@ -244,7 +244,7 @@ }) .then(function(complex_object) { // .update should insert new value to a field that previously had no value (undefined) - complex_object.body.other = "Focca"; + complex_object.other = "Focca"; return self .update( test_collection_name, @@ -253,7 +253,7 @@ }, { body: { - other: complex_object.body.other, + other: complex_object.other, }, } ) diff --git a/lib/chip-types/field.js b/lib/chip-types/field.js --- a/lib/chip-types/field.js +++ b/lib/chip-types/field.js @@ -7,8 +7,7 @@ this.name = declaration.name; this.declaration = declaration; this.type = new FieldType(app, declaration.type); - this.value_path = - "body." + this.name + (this.type.value_path_after_field_name || ""); + this.value_path = this.name + (this.type.value_path_after_field_name || ""); this.required = declaration.required || false; this.params = declaration.params || {}; this.type.init(collection, declaration.name, this.params); diff --git a/lib/datastore/mongo-api-abstract.js b/lib/datastore/mongo-api-abstract.js --- a/lib/datastore/mongo-api-abstract.js +++ b/lib/datastore/mongo-api-abstract.js @@ -21,7 +21,7 @@ for (var field_name in collection.fields) { indexes.push( Promise.all([ - "body." + field_name, + field_name, collection.fields[field_name].has_index(), ]) ); diff --git a/lib/email/templates/password-reset.js b/lib/email/templates/password-reset.js --- a/lib/email/templates/password-reset.js +++ b/lib/email/templates/password-reset.js @@ -12,11 +12,11 @@ return SimpleTemplate(app, { subject: app.i18n("password_reset_email_subject", app.manifest.name), - to: `${user.body.username}<${email_address}>`, + to: `${user.username}<${email_address}>`, text: ` ${app.i18n("password_reset_email_text", [ app.manifest.name, - user.body.username, + user.username, ])}`, buttons: [ { diff --git a/lib/http/extract-context.js b/lib/http/extract-context.js --- a/lib/http/extract-context.js +++ b/lib/http/extract-context.js @@ -50,8 +50,8 @@ let anonymous_user_id = null; await get_anonymous_data.then(function(anon_session) { - anonymous_session_id = anon_session.body["anonymous-session-id"]; - anonymous_user_id = anon_session.body["anonymous-user-id"]; + anonymous_session_id = anon_session["anonymous-session-id"]; + anonymous_user_id = anon_session["anonymous-user-id"]; }); const { items: results } = await app.run_action( @@ -67,7 +67,7 @@ if (results.length === 0) { session_id = undefined; } else { - user = results[0].body.user; + user = results[0].user; } return new Sealious.Context( timestamp, diff --git a/lib/http/routes/finalize-password-reset.js b/lib/http/routes/finalize-password-reset.js --- a/lib/http/routes/finalize-password-reset.js +++ b/lib/http/routes/finalize-password-reset.js @@ -18,7 +18,7 @@ } else if (matches.length > 1) { throw new Error("Something went wrong."); } - const user_email = matches[0].body.email; + const user_email = matches[0].email; const { items: [user], } = await app.run_action( diff --git a/lib/http/routes/finalize-registration-intent.js b/lib/http/routes/finalize-registration-intent.js --- a/lib/http/routes/finalize-registration-intent.js +++ b/lib/http/routes/finalize-registration-intent.js @@ -27,15 +27,15 @@ { password: params.password, username: params.username, - email: intent.body.email, + email: intent.email, } ); - if (intent.body.role) { + if (intent.role) { await app.run_action( new app.Sealious.SuperContext(), ["collections", "user-roles"], "create", - { user: user.id, role: intent.body.role } + { user: user.id, role: intent.role } ); } await app.run_action( diff --git a/lib/http/routes/finalize-registration-intent.subtest.js b/lib/http/routes/finalize-registration-intent.subtest.js --- a/lib/http/routes/finalize-registration-intent.subtest.js +++ b/lib/http/routes/finalize-registration-intent.subtest.js @@ -47,8 +47,8 @@ "/api/v1/users/me?format[roles]=expand", options ); - assert(user_data.body.roles); - assert.equal(user_data.body.roles.length, 1); - assert.equal(user_data.body.roles[0].body.role, "admin"); + assert(user_data.roles); + assert.equal(user_data.roles.length, 1); + assert.equal(user_data.roles[0].role, "admin"); })); }); diff --git a/lib/subject/predefined-subjects/sessions-subject.js b/lib/subject/predefined-subjects/sessions-subject.js --- a/lib/subject/predefined-subjects/sessions-subject.js +++ b/lib/subject/predefined-subjects/sessions-subject.js @@ -10,14 +10,14 @@ async function validate_auth_data(app, username, password) { const [user] = await app.Datastore.find("users", { - "body.username.safe": username, + "username.safe": username, }); if (!user) { throw new Errors.InvalidCredentials("Incorrect username!"); } - const is_valid = await SecureHasher.matches(password, user.body.password); + const is_valid = await SecureHasher.matches(password, user.password); if (!is_valid) { throw new Errors.InvalidCredentials("Incorrect password!"); } @@ -48,7 +48,7 @@ { last_login_context: context } ); - return new Responses.NewSession(session.body["session-id"]); + return new Responses.NewSession(session["session-id"]); }); } diff --git a/lib/subject/subject-types/_batch_action.js b/lib/subject/subject-types/_batch_action.js --- a/lib/subject/subject-types/_batch_action.js +++ b/lib/subject/subject-types/_batch_action.js @@ -45,9 +45,7 @@ if (field_in_collection === "id") { return resource.id; } else { - return resource.body[ - field_in_collection - ]; + return resource[field_in_collection]; } }) ); diff --git a/lib/subject/subject-types/collection-subject.js b/lib/subject/subject-types/collection-subject.js --- a/lib/subject/subject-types/collection-subject.js +++ b/lib/subject/subject-types/collection-subject.js @@ -132,7 +132,7 @@ body ) { return collection - .check_if_action_is_allowed(context, "create", { body: body }) + .check_if_action_is_allowed(context, "create", body) .then(function() { return collection.validate_field_values(context, true, body); }) @@ -142,11 +142,13 @@ .then(function(encoded_body) { const newID = shortid(); const resource_data = { + _metadata: { + collection: collection.name, + created_context: context, + last_modified_context: context, + }, sealious_id: newID, - collection: collection.name, - body: encoded_body, - created_context: context, - last_modified_context: context, + ...encoded_body, }; return datastore.insert(collection.name, resource_data, {}); }) diff --git a/lib/subject/subject-types/image-format.js b/lib/subject/subject-types/image-format.js --- a/lib/subject/subject-types/image-format.js +++ b/lib/subject/subject-types/image-format.js @@ -99,22 +99,19 @@ return app.Datastore.aggregate("formatted-images", [ { $match: { - "body.original_photo_file": { $eq: file_id }, + original_photo_file: { $eq: file_id }, }, }, { $match: { - $or: [ - { "body.format.original": hash }, - { "body.format.safe": hash }, - ], + $or: [{ "format.original": hash }, { "format.safe": hash }], }, }, ]).then(function(results) { return ( results[0] && - results[0].body && { - id: results[0].body.formatted_photo_file, + results[0] && { + id: results[0].formatted_photo_file, original_name: format_filename(file_name, format_name), } ); diff --git a/lib/subject/subject-types/single-resource-subject.js b/lib/subject/subject-types/single-resource-subject.js --- a/lib/subject/subject-types/single-resource-subject.js +++ b/lib/subject/subject-types/single-resource-subject.js @@ -121,21 +121,21 @@ context, delete_empty_values, values_to_patch, - resource_representation.body + resource_representation ); }) .then(function() { return collection.encode_field_values( context, values_to_patch, - resource_representation.body + resource_representation ); }) .then(function(encoded_values) { - const query = {}; - query.last_modified_context = context; + const query = { _metadata: resource_representation._metadata }; + query._metadata.last_modified_context = context; for (const field_name in encoded_values) { - query[`body.${field_name}`] = encoded_values[field_name]; + query[field_name] = encoded_values[field_name]; } return datastore.update( collection.name, diff --git a/test_utils/access-strategy-types/create_strategies_with_complex_pipeline.js b/test_utils/access-strategy-types/create_strategies_with_complex_pipeline.js --- a/test_utils/access-strategy-types/create_strategies_with_complex_pipeline.js +++ b/test_utils/access-strategy-types/create_strategies_with_complex_pipeline.js @@ -14,7 +14,7 @@ const query = new App.Query(); const id = query.lookup({ from: "numbers", - localField: "body.number", + localField: "number", foreignField: "sealious_id", }); query.match({