tags from text -function removeTags(text) { - return text ? text.replace(tagsRegex, "") : text -} - -function addInfo(projectJson) { - let info = {} - info["title"] = projectJson.title || projectJson.name - info["version"] = projectJson.version - info["description"] = projectJson.description - return info -} - -/** - * Extracts paths provided in json format - * post, patch, put request parameters are extracted in body - * get and delete are extracted to path parameters - * @param apidocJson - * @returns {{}} - */ -function extractPaths(apidocJson) { - let apiPaths = groupByUrl(apidocJson) - let paths = {} - for (let i = 0; i < apiPaths.length; i++) { - let verbs = apiPaths[i].verbs - let url = verbs[0].url - let pattern = pathToRegexp(url, null) - let matches = pattern.exec(url) - - // Surrounds URL parameters with curly brackets -> :email with {email} - let pathKeys = [] - for (let j = 1; j < matches.length; j++) { - let key = matches[j].slice(1) - url = url.replace(matches[j], "{" + key + "}") - pathKeys.push(key) - } - - for (let j = 0; j < verbs.length; j++) { - let verb = verbs[j] - let type = verb.type - - let obj = (paths[url] = paths[url] || {}) - - if (type === "post" || type === "patch" || type === "put") { - _.extend( - obj, - createPostPushPutOutput(verb, swagger.definitions, pathKeys) - ) - } else { - _.extend(obj, createGetDeleteOutput(verb, swagger.definitions)) - } - } - } - return paths -} - -function createPostPushPutOutput(verbs, definitions, pathKeys) { - let pathItemObject = {} - let verbDefinitionResult = createVerbDefinitions(verbs, definitions) - - let params = [] - let pathParams = createPathParameters(verbs, pathKeys) - pathParams = _.filter(pathParams, function (param) { - let hasKey = pathKeys.indexOf(param.name) !== -1 - return !(param.in === "path" && !hasKey) - }) - - params = params.concat(pathParams) - let required = - verbs.parameter && - verbs.parameter.fields && - verbs.parameter.fields.Parameter && - verbs.parameter.fields.Parameter.length > 0 - - params.push({ - in: "body", - name: "body", - description: removeTags(verbs.description), - required: required, - schema: { - $ref: "#/definitions/" + verbDefinitionResult.topLevelParametersRef, - }, - }) - - pathItemObject[verbs.type] = { - tags: [verbs.group], - summary: removeTags(verbs.description), - consumes: ["application/json"], - produces: ["application/json"], - parameters: params, - } - - if (verbDefinitionResult.topLevelSuccessRef) { - pathItemObject[verbs.type].responses = { - 200: { - description: "successful operation", - schema: { - type: verbDefinitionResult.topLevelSuccessRefType, - items: { - $ref: "#/definitions/" + verbDefinitionResult.topLevelSuccessRef, - }, - }, - }, - } - } - - return pathItemObject -} - -function createVerbDefinitions(verbs, definitions) { - let result = { - topLevelParametersRef: null, - topLevelSuccessRef: null, - topLevelSuccessRefType: null, - } - let defaultObjectName = verbs.name - - let fieldArrayResult = {} - if (verbs && verbs.parameter && verbs.parameter.fields) { - fieldArrayResult = createFieldArrayDefinitions( - verbs.parameter.fields.Parameter, - definitions, - verbs.name, - defaultObjectName - ) - result.topLevelParametersRef = fieldArrayResult.topLevelRef - } - - if (verbs && verbs.success && verbs.success.fields) { - fieldArrayResult = createFieldArrayDefinitions( - verbs.success.fields["Success 200"], - definitions, - verbs.name, - defaultObjectName - ) - result.topLevelSuccessRef = fieldArrayResult.topLevelRef - result.topLevelSuccessRefType = fieldArrayResult.topLevelRefType - } - - return result -} - -function createFieldArrayDefinitions( - fieldArray, - definitions, - topLevelRef, - defaultObjectName -) { - let result = { - topLevelRef: topLevelRef, - topLevelRefType: null, - } - - if (!fieldArray) { - return result - } - - for (let i = 0; i < fieldArray.length; i++) { - let parameter = fieldArray[i] - - let nestedName = createNestedName(parameter.field) - let objectName = nestedName.objectName - if (!objectName) { - objectName = defaultObjectName - } - let type = parameter.type - if (i === 0) { - result.topLevelRefType = type - if (parameter.type === "Object") { - objectName = nestedName.propertyName - nestedName.propertyName = null - } else if (parameter.type === "Array") { - objectName = nestedName.propertyName - nestedName.propertyName = null - result.topLevelRefType = "array" - } - result.topLevelRef = objectName - } - - definitions[objectName] = definitions[objectName] || { - properties: {}, - required: [], - } - - if (nestedName.propertyName) { - let prop = { - type: (parameter.type || "").toLowerCase(), - description: removeTags(parameter.description), - } - if (parameter.type === "Object") { - prop.$ref = "#/definitions/" + parameter.field - } - - let typeIndex = type.indexOf("[]") - if (typeIndex !== -1 && typeIndex === type.length - 2) { - prop.type = "array" - prop.items = { - type: type.slice(0, type.length - 2), - } - } - - definitions[objectName]["properties"][nestedName.propertyName] = prop - if (!parameter.optional) { - let arr = definitions[objectName]["required"] - if (arr.indexOf(nestedName.propertyName) === -1) { - arr.push(nestedName.propertyName) - } - } - } - } - - return result -} - -function createNestedName(field) { - let propertyName = field - let objectName - let propertyNames = field.split(".") - if (propertyNames && propertyNames.length > 1) { - propertyName = propertyNames[propertyNames.length - 1] - propertyNames.pop() - objectName = propertyNames.join(".") - } - - return { - propertyName: propertyName, - objectName: objectName, - } -} - -/** - * Generate get, delete method output - * @param verbs - * @param definitions - * @returns {{}} - */ -function createGetDeleteOutput(verbs, definitions) { - let pathItemObject = {} - verbs.type = verbs.type === "del" ? "delete" : verbs.type - - let verbDefinitionResult = createVerbDefinitions(verbs, definitions) - pathItemObject[verbs.type] = { - tags: [verbs.group], - summary: removeTags(verbs.description), - consumes: ["application/json"], - produces: ["application/json"], - parameters: createPathParameters(verbs), - } - if (verbDefinitionResult.topLevelSuccessRef) { - pathItemObject[verbs.type].responses = { - 200: { - description: "successful operation", - schema: { - type: verbDefinitionResult.topLevelSuccessRefType, - items: { - $ref: "#/definitions/" + verbDefinitionResult.topLevelSuccessRef, - }, - }, - }, - } - } - return pathItemObject -} - -/** - * Iterate through all method parameters and create array of parameter objects which are stored as path parameters - * @param verbs - * @returns {Array} - */ -function createPathParameters(verbs) { - let pathItemObject = [] - if (verbs.parameter && verbs.parameter.fields.Parameter) { - for (let i = 0; i < verbs.parameter.fields.Parameter.length; i++) { - let param = verbs.parameter.fields.Parameter[i] - let field = param.field - let type = param.type - pathItemObject.push({ - name: field, - in: type === "file" ? "formData" : "path", - required: !param.optional, - type: param.type.toLowerCase(), - description: removeTags(param.description), - }) - } - } - return pathItemObject -} - -function groupByUrl(apidocJson) { - return _.chain(apidocJson) - .groupBy("url") - .toPairs() - .map(function (element) { - return _.zipObject(["url", "verbs"], element) - }) - .value() -} - -module.exports = toSwagger diff --git a/packages/server/specs/openapi.json b/packages/server/specs/openapi.json index 8baba62a62..a6900adea7 100644 --- a/packages/server/specs/openapi.json +++ b/packages/server/specs/openapi.json @@ -859,7 +859,8 @@ "json", "internal", "barcodeqr", - "bigint" + "bigint", + "bb_reference" ], "description": "Defines the type of the column, most explain themselves, a link column is a relationship." }, @@ -1064,7 +1065,8 @@ "json", "internal", "barcodeqr", - "bigint" + "bigint", + "bb_reference" ], "description": "Defines the type of the column, most explain themselves, a link column is a relationship." }, @@ -1280,7 +1282,8 @@ "json", "internal", "barcodeqr", - "bigint" + "bigint", + "bb_reference" ], "description": "Defines the type of the column, most explain themselves, a link column is a relationship." }, diff --git a/packages/server/specs/openapi.yaml b/packages/server/specs/openapi.yaml index 0673794fb0..ad02a3cd9c 100644 --- a/packages/server/specs/openapi.yaml +++ b/packages/server/specs/openapi.yaml @@ -782,6 +782,7 @@ components: - internal - barcodeqr - bigint + - bb_reference description: Defines the type of the column, most explain themselves, a link column is a relationship. constraints: @@ -946,6 +947,7 @@ components: - internal - barcodeqr - bigint + - bb_reference description: Defines the type of the column, most explain themselves, a link column is a relationship. constraints: @@ -1117,6 +1119,7 @@ components: - internal - barcodeqr - bigint + - bb_reference description: Defines the type of the column, most explain themselves, a link column is a relationship. constraints: diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 4b1bc65793..0a80253210 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1580,6 +1580,9 @@ describe.each([ (row: Row) => ({ _id: row._id, primaryDisplay: row.email, + email: row.email, + firstName: row.firstName, + lastName: row.lastName, }), ], ])("links - %s", (__, relSchema, dataGenerator, resultMapper) => { diff --git a/packages/server/src/definitions/openapi.ts b/packages/server/src/definitions/openapi.ts index a813f0f135..34014ba626 100644 --- a/packages/server/src/definitions/openapi.ts +++ b/packages/server/src/definitions/openapi.ts @@ -279,7 +279,8 @@ export interface components { | "json" | "internal" | "barcodeqr" - | "bigint"; + | "bigint" + | "bb_reference"; /** @description A constraint can be applied to the column which will be validated against when a row is saved. */ constraints?: { /** @enum {string} */ @@ -386,7 +387,8 @@ export interface components { | "json" | "internal" | "barcodeqr" - | "bigint"; + | "bigint" + | "bb_reference"; /** @description A constraint can be applied to the column which will be validated against when a row is saved. */ constraints?: { /** @enum {string} */ @@ -495,7 +497,8 @@ export interface components { | "json" | "internal" | "barcodeqr" - | "bigint"; + | "bigint" + | "bb_reference"; /** @description A constraint can be applied to the column which will be validated against when a row is saved. */ constraints?: { /** @enum {string} */ diff --git a/packages/server/src/utilities/rowProcessor/bbReferenceProcessor.ts b/packages/server/src/utilities/rowProcessor/bbReferenceProcessor.ts index c126530b8d..c7b8998bad 100644 --- a/packages/server/src/utilities/rowProcessor/bbReferenceProcessor.ts +++ b/packages/server/src/utilities/rowProcessor/bbReferenceProcessor.ts @@ -82,6 +82,9 @@ export async function processOutputBBReferences( return users.map(u => ({ _id: u._id, primaryDisplay: u.email, + email: u.email, + firstName: u.firstName, + lastName: u.lastName, })) default: diff --git a/packages/server/src/utilities/rowProcessor/tests/bbReferenceProcessor.spec.ts b/packages/server/src/utilities/rowProcessor/tests/bbReferenceProcessor.spec.ts index 10d339f6b4..b6174861d4 100644 --- a/packages/server/src/utilities/rowProcessor/tests/bbReferenceProcessor.spec.ts +++ b/packages/server/src/utilities/rowProcessor/tests/bbReferenceProcessor.spec.ts @@ -180,6 +180,9 @@ describe("bbReferenceProcessor", () => { { _id: user._id, primaryDisplay: user.email, + email: user.email, + firstName: user.firstName, + lastName: user.lastName, }, ]) expect(cacheGetUsersSpy).toBeCalledTimes(1) @@ -204,6 +207,9 @@ describe("bbReferenceProcessor", () => { [user1, user2].map(u => ({ _id: u._id, primaryDisplay: u.email, + email: u.email, + firstName: u.firstName, + lastName: u.lastName, })) ) ) diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 6780840ed3..d9f56442a0 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -29,7 +29,7 @@ "dayjs": "^1.10.8", "handlebars": "^4.7.6", "lodash": "^4.17.20", - "vm2": "^3.9.15" + "vm2": "^3.9.19" }, "devDependencies": { "@rollup/plugin-commonjs": "^17.1.0", diff --git a/yarn.lock b/yarn.lock index d8e1d41d56..81c2815663 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21750,10 +21750,10 @@ vlq@^0.2.2: resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26" integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow== -vm2@3.9.17, vm2@^3.9.15, vm2@^3.9.8: - version "3.9.17" - resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.17.tgz#251b165ff8a0e034942b5181057305e39570aeab" - integrity sha512-AqwtCnZ/ERcX+AVj9vUsphY56YANXxRuqMb7GsDtAr0m0PcQX3u0Aj3KWiXM0YAHy7i6JEeHrwOnwXbGYgRpAw== +vm2@^3.9.19: + version "3.9.19" + resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.19.tgz#be1e1d7a106122c6c492b4d51c2e8b93d3ed6a4a" + integrity sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg== dependencies: acorn "^8.7.0" acorn-walk "^8.2.0"