From ab108a6f9370407bc6fd7c269c5a54b08d380b51 Mon Sep 17 00:00:00 2001 From: Aurelsicoko Date: Tue, 27 Feb 2018 11:52:18 +0100 Subject: [PATCH] Create & handle association between File upload and others models --- .../admin/src/containers/EditPage/saga.js | 11 ++--- .../config/queries/mongoose.js | 36 ++++++++++++---- .../controllers/ContentManager.js | 2 + .../services/ContentManager.js | 43 +++++++++++++++++++ .../config/queries/mongoose.js | 25 ++++++----- .../controllers/Upload.js | 2 +- .../strapi-plugin-upload/services/Upload.js | 6 +-- packages/strapi-utils/lib/models.js | 8 +++- 8 files changed, 104 insertions(+), 29 deletions(-) diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditPage/saga.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditPage/saga.js index 815745fd77..4615d624c4 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditPage/saga.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditPage/saga.js @@ -49,13 +49,11 @@ export function* submit() { const isCreating = yield select(makeSelectIsCreating()); try { - const recordCleaned = Object.keys(recordJSON).reduce((acc, current) => { - acc[current] = cleanData(recordJSON[current], 'value', 'id'); + acc.append(current, cleanData(recordJSON[current], 'value', 'id')); return acc; - }, {}); - + }, new FormData()); const id = isCreating ? '' : recordCleaned.id; const params = { source }; @@ -65,9 +63,12 @@ export function* submit() { // Call our request helper (see 'utils/request') yield call(request, requestUrl, { method: isCreating ? 'POST' : 'PUT', + headers: { + 'X-Forwarded-Host': 'strapi', + }, body: recordCleaned, params, - }); + }, false, false); strapi.notification.success('content-manager.success.record.save'); yield put(submitSuccess()); diff --git a/packages/strapi-plugin-content-manager/config/queries/mongoose.js b/packages/strapi-plugin-content-manager/config/queries/mongoose.js index a53668c8c1..e071244845 100755 --- a/packages/strapi-plugin-content-manager/config/queries/mongoose.js +++ b/packages/strapi-plugin-content-manager/config/queries/mongoose.js @@ -23,20 +23,40 @@ module.exports = { }, create: async function (params) { - const entry = await this.create(Object.keys(params.values).reduce((acc, current) => { + // Exclude relationships. + const values = Object.keys(params.values).reduce((acc, current) => { if (this._attributes[current].type) { acc[current] = params.values[current]; } return acc; - }, {})) - .catch((err) => { - const message = err.message.split('index:'); - const field = _.words(_.last(message).split('_')[0]); - const error = { message: `This ${field} is already taken`, field }; + }, {}); - throw error; - }); + this.associations + .filter(association => association.nature.toLowerCase().indexOf('morphto') !== -1) + .map(association => { + values[association.alias] = params.values[association.alias] + .map(obj => { + const globalId = obj.source && obj.source !== 'content-manager' ? + strapi.plugins[obj.source].models[obj.model].globalId: + strapi.models[obj.model].globalId; + + return { + ref: obj.ref, + kind: globalId, + [association.filter]: obj.field + } + }) + }); + + const entry = await this.create(values) + .catch((err) => { + const message = err.message.split('index:'); + const field = _.words(_.last(message).split('_')[0]); + const error = { message: `This ${field} is already taken`, field }; + + throw error; + }); return module.exports.update.call(this, { [this.primaryKey]: entry[this.primaryKey], diff --git a/packages/strapi-plugin-content-manager/controllers/ContentManager.js b/packages/strapi-plugin-content-manager/controllers/ContentManager.js index a90e275b33..74fe5a0dc2 100755 --- a/packages/strapi-plugin-content-manager/controllers/ContentManager.js +++ b/packages/strapi-plugin-content-manager/controllers/ContentManager.js @@ -73,6 +73,7 @@ module.exports = { // Create an entry using `queries` system ctx.body = await strapi.plugins['content-manager'].services['contentmanager'].add(ctx.params, ctx.request.body, source); } catch(error) { + strapi.log.error(error); ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: error.message, field: error.field }] }] : error.message); } }, @@ -85,6 +86,7 @@ module.exports = { ctx.body = await strapi.plugins['content-manager'].services['contentmanager'].edit(ctx.params, ctx.request.body, source); } catch(error) { // TODO handle error update + strapi.log.error(error); ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: error.message, field: error.field }] }] : error.message); } }, diff --git a/packages/strapi-plugin-content-manager/services/ContentManager.js b/packages/strapi-plugin-content-manager/services/ContentManager.js index 21aa130921..c5685a1d4c 100644 --- a/packages/strapi-plugin-content-manager/services/ContentManager.js +++ b/packages/strapi-plugin-content-manager/services/ContentManager.js @@ -38,6 +38,49 @@ module.exports = { }, edit: async (params, values, source) => { + // Multipart/form-data. + if (values.hasOwnProperty('fields') && values.hasOwnProperty('files')) { + const fields = await strapi.query(params.model, source).update({ + id: params.id, + values + }); + + // Request plugin upload. + if (strapi.plugins.upload) { + const config = await strapi.store({ + environment: strapi.config.environment, + type: 'plugin', + name: 'upload' + }).get({ key: 'provider' }); + + const arrayOfPromise = await Promise.all( + Object.keys(values.files) + .map(async attribute => { + // Bufferize files per attribute. + const buffers = await strapi.plugins.upload.services.upload.bufferize(values.files[attribute]); + const files = buffers.map(file => { + // Add related information to be able to make + // the relationships later. + file.related = [{ + ref: params.id, + model: params.model, + source, + field: attribute, + }]; + + return file; + }); + + // Make upload async. + return await strapi.plugins.upload.services.upload.upload(files, config); + }) + ); + } + + return fields; + } + + // Raw JSON. return strapi.query(params.model, source).update({ id: params.id, values diff --git a/packages/strapi-plugin-upload/config/queries/mongoose.js b/packages/strapi-plugin-upload/config/queries/mongoose.js index 59d53bef8d..4a7af68c85 100644 --- a/packages/strapi-plugin-upload/config/queries/mongoose.js +++ b/packages/strapi-plugin-upload/config/queries/mongoose.js @@ -32,24 +32,27 @@ module.exports = { }, create: async function (params) { - return this.create(Object.keys(params).reduce((acc, current) => { + // Exclude relationships. + const values = Object.keys(params).reduce((acc, current) => { if (_.get(this._attributes, [current, 'type']) || _.get(this._attributes, [current, 'model'])) { acc[current] = params[current]; } return acc; - }, {})) - .catch((err) => { - if (err.message.indexOf('index:') !== -1) { - const message = err.message.split('index:'); - const field = _.words(_.last(message).split('_')[0]); - const error = { message: `This ${field} is already taken`, field }; + }, {}); - throw error; - } + return this.create(values) + .catch((err) => { + if (err.message.indexOf('index:') !== -1) { + const message = err.message.split('index:'); + const field = _.words(_.last(message).split('_')[0]); + const error = { message: `This ${field} is already taken`, field }; - throw err; - }); + throw error; + } + + throw err; + }); }, update: async function (search, params = {}) { diff --git a/packages/strapi-plugin-upload/controllers/Upload.js b/packages/strapi-plugin-upload/controllers/Upload.js index 0b25860ba7..8013053e4b 100644 --- a/packages/strapi-plugin-upload/controllers/Upload.js +++ b/packages/strapi-plugin-upload/controllers/Upload.js @@ -30,7 +30,7 @@ module.exports = { const Service = strapi.plugins['upload'].services.upload; // transform stream files to buffer - const files = await Service.bufferize(ctx.request.body.files); + const files = await Service.bufferize(ctx.request.body.files.files); for (var i = 0; i < files.length; i++) { if (files[i].size > config.sizeLimit) { diff --git a/packages/strapi-plugin-upload/services/Upload.js b/packages/strapi-plugin-upload/services/Upload.js index fd7a2d02d6..c2347f8233 100644 --- a/packages/strapi-plugin-upload/services/Upload.js +++ b/packages/strapi-plugin-upload/services/Upload.js @@ -13,13 +13,13 @@ const toArray = require('stream-to-array'); const uuid = require('uuid/v4'); module.exports = { - bufferize: async values => { - if (_.size(values.files) === 0) { + bufferize: async files => { + if (_.isEmpty(files) === 0) { throw 'Missing files.'; } // files is always an array to map on - const files = _.isArray(values.files) ? values.files : [values.files]; + files = _.isArray(files) ? files : [files]; // transform all files in buffer return Promise.all( diff --git a/packages/strapi-utils/lib/models.js b/packages/strapi-utils/lib/models.js index e1a2299102..e19cc500fc 100755 --- a/packages/strapi-utils/lib/models.js +++ b/packages/strapi-utils/lib/models.js @@ -121,6 +121,10 @@ module.exports = { } else if (association.hasOwnProperty('via') && association.hasOwnProperty('collection')) { const relatedAttribute = models[association.collection].attributes[association.via]; + if (!relatedAttribute) { + throw new Error(`The attribute \`${association.via}\` is missing in the model ${_.upperFirst(association.collection)} ${association.plugin ? '(plugin - ' + association.plugin + ')' : '' }`); + } + types.current = 'collection'; if (relatedAttribute.hasOwnProperty('collection') && relatedAttribute.collection !== '*' && relatedAttribute.hasOwnProperty('via')) { @@ -329,7 +333,9 @@ module.exports = { const infos = this.getNature(association, key, undefined, model.toLowerCase()); if (globalName !== '*') { - details = _.get(strapi.models, `${globalName}.attributes.${association.via}`, {}); + details = association.plugin ? + _.get(strapi.plugins, `${association.plugin}.models.${globalName}.attributes.${association.via}`, {}): + _.get(strapi.models, `${globalName}.attributes.${association.via}`, {}); } // Build associations object