diff --git a/src/i18n/en.json b/src/i18n/en.json index abeeaad8a..3b50d92ee 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -34,7 +34,7 @@ "invalidEditRolesArguments": "Either permissions or channels must be provided.", "invalidEditStepArguments": "Either name, type, content or permissions must be provided.", "invalidEditWorkflowArguments": "Either name or steps must be provided.", - "invalidEmailsInput": "Wrong format detected. Please provide valid emails.", + "invalidEmailsInput": "Wrong format detected. Following emails are invalid: {{emails}}", "invalidPaginationArguments": "Please provider valid integers for first and offset arguments.", "invalidPublishNotificationArguments": "Action, content and channel arguments must all be provided.", "invalidSeeNotificationArguments": "Notification ID must be provided.", diff --git a/src/i18n/test.json b/src/i18n/test.json index 0c949cdff..8181cfe43 100644 --- a/src/i18n/test.json +++ b/src/i18n/test.json @@ -34,7 +34,7 @@ "invalidEditRolesArguments": "******", "invalidEditStepArguments": "******", "invalidEditWorkflowArguments": "******", - "invalidEmailsInput": "******", + "invalidEmailsInput": "****** {{emails}}", "invalidPaginationArguments": "******", "invalidPublishNotificationArguments": "******", "invalidSeeNotificationArguments": "******", diff --git a/src/routes/upload/index.ts b/src/routes/upload/index.ts index 546221849..96b6b3ea5 100644 --- a/src/routes/upload/index.ts +++ b/src/routes/upload/index.ts @@ -61,8 +61,11 @@ async function insertRecords( // } if (canCreate) { const records: Record[] = []; - const dataSets: { data: any; positionAttributes: PositionAttribute[] }[] = - []; + const dataSets: Promise<{ + data: any; + positionAttributes: PositionAttribute[]; + user: mongoose.Types.ObjectId; + }>[] = []; const workbook = new Workbook(); await workbook.xlsx.load(file.data); const worksheet = workbook.getWorksheet(1); @@ -75,8 +78,13 @@ async function insertRecords( dataSets.push(loadRow(columns, values)); } }); + const resolvedDataSets: { + data: any; + positionAttributes: PositionAttribute[]; + user: mongoose.Types.ObjectId; + }[] = await Promise.all(dataSets); // Create records one by one so the incrementalId works correctly - for (const dataSet of dataSets) { + for (const dataSet of resolvedDataSets) { records.push( new Record({ incrementalId: await getNextId( @@ -89,6 +97,7 @@ async function insertRecords( resource: form.resource ? form.resource : null, createdBy: { positionAttributes: dataSet.positionAttributes, + user: dataSet.user, }, }) ); diff --git a/src/schema/mutation/addUsers.ts b/src/schema/mutation/addUsers.ts index 01ec5be97..c6fb07653 100644 --- a/src/schema/mutation/addUsers.ts +++ b/src/schema/mutation/addUsers.ts @@ -39,8 +39,13 @@ export default { ); } } - if (args.users.filter((x) => !validateEmail(x.email)).length > 0) { - throw new GraphQLError(context.i18next.t('errors.invalidEmailsInput')); + const invalidEmails = args.users.filter((x) => !validateEmail(x.email)); + if (invalidEmails.length > 0) { + throw new GraphQLError( + context.i18next.t('errors.invalidEmailsInput', { + emails: invalidEmails.map((x) => x.email), + }) + ); } // Separate registered users and new users const invitedUsers: User[] = []; diff --git a/src/utils/files/getUploadColumns.ts b/src/utils/files/getUploadColumns.ts index 251560b31..9e81a9961 100644 --- a/src/utils/files/getUploadColumns.ts +++ b/src/utils/files/getUploadColumns.ts @@ -146,6 +146,7 @@ export const getUploadColumns = (fields: any[], headers: any[]): any[] => { } } } + // Create position attributes columns for (const name of headers.filter((x) => x && x.startsWith('$attribute.'))) { const index = headers.indexOf(name); columns.push({ @@ -155,5 +156,14 @@ export const getUploadColumns = (fields: any[], headers: any[]): any[] => { category: name.replace('$attribute.', ''), }); } + // Create user column + for (const name of headers.filter((x: string) => x && x === '$user')) { + const index = headers.indexOf(name); + columns.push({ + name, + index, + type: '$user', + }); + } return columns; }; diff --git a/src/utils/files/loadRow.ts b/src/utils/files/loadRow.ts index a70a603a2..e809c660d 100644 --- a/src/utils/files/loadRow.ts +++ b/src/utils/files/loadRow.ts @@ -1,6 +1,7 @@ import { isArray } from 'lodash'; import set from 'lodash/set'; -import { PositionAttribute } from '../../models'; +import { PositionAttribute, User } from '../../models'; +import mongoose from 'mongoose'; /** * Transforms uploaded row into record data, using fiels definition. @@ -9,14 +10,19 @@ import { PositionAttribute } from '../../models'; * @param row list of records * @returns list of export rows. */ -export const loadRow = ( +export const loadRow = async ( columns: any[], row: any -): { data: any; positionAttributes: PositionAttribute[] } => { +): Promise<{ + data: any; + positionAttributes: PositionAttribute[]; + user: mongoose.Types.ObjectId; +}> => { const data = {}; const positionAttributes = []; + let user; for (const column of columns) { - const value = row[column.index]; + let value = row[column.index]; if (value !== undefined) { switch (column.type) { case 'boolean': { @@ -71,6 +77,26 @@ export const loadRow = ( }); break; } + case '$user': { + if (typeof value === 'object' && value.text) { + value = value.text; + } + let filter; + if (mongoose.Types.ObjectId.isValid(value)) { + filter = { + $or: [ + { username: value }, + { + _id: mongoose.Types.ObjectId(value), + }, + ], + }; + } else { + filter = { username: value }; + } + user = (await User.findOne(filter, '_id'))._id; + break; + } default: { data[column.field] = value; break; @@ -78,5 +104,5 @@ export const loadRow = ( } } } - return { data, positionAttributes }; + return { data, positionAttributes, user }; };