diff --git a/packages/nc-gui/components/project/spreadsheet/components/spreadsheetNavDrawer.vue b/packages/nc-gui/components/project/spreadsheet/components/spreadsheetNavDrawer.vue index 700b9b7cee..9ade88a856 100644 --- a/packages/nc-gui/components/project/spreadsheet/components/spreadsheetNavDrawer.vue +++ b/packages/nc-gui/components/project/spreadsheet/components/spreadsheetNavDrawer.vue @@ -758,7 +758,8 @@ export default { fields: Object.keys(this.showFields) .filter(f => this.showFields[f]) .join(','), - extraViewParams: this.extraViewParams + extraViewParams: this.extraViewParams, + selectedViewId: this.selectedViewId }, type: this.selectedView.type, show_as: this.selectedView.show_as, diff --git a/packages/nocodb/src/lib/noco/common/BaseModel.ts b/packages/nocodb/src/lib/noco/common/BaseModel.ts index 264ab72e7d..b1321d49bd 100644 --- a/packages/nocodb/src/lib/noco/common/BaseModel.ts +++ b/packages/nocodb/src/lib/noco/common/BaseModel.ts @@ -1,20 +1,18 @@ -import Handlebars from "handlebars"; -import {IWebhookNotificationAdapter} from "nc-plugin"; -import ejs from "ejs"; -import IEmailAdapter from "../../../interface/IEmailAdapter"; -import {BaseModelSql} from "../../dataMapper"; +import Handlebars from 'handlebars'; +import { IWebhookNotificationAdapter } from 'nc-plugin'; +import ejs from 'ejs'; +import IEmailAdapter from '../../../interface/IEmailAdapter'; +import { BaseModelSql } from '../../dataMapper'; // import axios from "axios"; -import BaseApiBuilder from "./BaseApiBuilder"; -import formSubmissionEmailTemplate from "./formSubmissionEmailTemplate"; +import BaseApiBuilder from './BaseApiBuilder'; +import formSubmissionEmailTemplate from './formSubmissionEmailTemplate'; -Handlebars.registerHelper('json', function (context) { +Handlebars.registerHelper('json', function(context) { return JSON.stringify(context); }); class BaseModel> extends BaseModelSql { - - private builder: T; constructor(args: any, builder: T) { @@ -23,72 +21,82 @@ class BaseModel> extends BaseModelSql { } public async beforeInsert(data: any, _trx: any, req): Promise { - await this.handleHooks('before.insert', data, req) + await this.handleHooks('before.insert', data, req); } - public async afterInsert(data: any, _trx: any, req): Promise { await this.handleHooks('after.insert', data, req); if (req?.headers?.['xc-gui']) { const id = this._extractPksValues(data); - this.builder.getXcMeta().audit( - this.builder?.getProjectId(), - this.builder?.getDbAlias(), - 'nc_audit', - { - model_name: this._tn, - model_id: id, - op_type: 'DATA', - op_sub_type: 'INSERT', - description: `${id} inserted into ${this._tn}`, - // details: JSON.stringify(data), - ip: req?.clientIp, - user: req?.user?.email - } - ) + this.builder + .getXcMeta() + .audit( + this.builder?.getProjectId(), + this.builder?.getDbAlias(), + 'nc_audit', + { + model_name: this._tn, + model_id: id, + op_type: 'DATA', + op_sub_type: 'INSERT', + description: `${id} inserted into ${this._tn}`, + // details: JSON.stringify(data), + ip: req?.clientIp, + user: req?.user?.email + } + ); } } public async beforeUpdate(data: any, _trx: any, req): Promise { - await this.handleHooks('before.update', data, req) + await this.handleHooks('before.update', data, req); } public async afterUpdate(data: any, _trx: any, req): Promise { - await this.handleHooks('after.update', data, req) + await this.handleHooks('after.update', data, req); } public async beforeDelete(data: any, _trx: any, req): Promise { - await this.handleHooks('before.delete', data, req) + await this.handleHooks('before.delete', data, req); } public async afterDelete(data: any, _trx: any, req): Promise { if (req?.headers?.['xc-gui']) { - this.builder.getXcMeta().audit( - this.builder?.getProjectId(), - this.builder?.getDbAlias(), - 'nc_audit', - { - model_name: this._tn, - model_id: req?.params?.id, - op_type: 'DATA', - op_sub_type: 'DELETE', - description: `${req?.params.id} deleted from ${this._tn}`, - ip: req?.clientIp, - user: req?.user?.email - } - ) + this.builder + .getXcMeta() + .audit( + this.builder?.getProjectId(), + this.builder?.getDbAlias(), + 'nc_audit', + { + model_name: this._tn, + model_id: req?.params?.id, + op_type: 'DATA', + op_sub_type: 'DELETE', + description: `${req?.params.id} deleted from ${this._tn}`, + ip: req?.clientIp, + user: req?.user?.email + } + ); } - await this.handleHooks('after.delete', data, req) + await this.handleHooks('after.delete', data, req); } private async handleHooks(hookName, data, req): Promise { // const data = _data; - // handle form view data submission - if (hookName === 'after.insert' && req?.query?.form && this.builder?.formViews?.[this.tn]?.[req.query.form]) { + if ( + hookName === 'after.insert' && + req?.query?.form && + this.builder?.formViews?.[this.tn]?.[req.query.form] + ) { const formView = this.builder?.formViews?.[this.tn]?.[req.query.form]; - const emails = Object.entries(formView?.query_params?.extraViewParams?.formParams?.emailMe || {}).filter(a => a[1]).map(a => a[0]) + const emails = Object.entries( + formView?.query_params?.extraViewParams?.formParams?.emailMe || {} + ) + .filter(a => a[1]) + .map(a => a[0]); if (emails?.length) { const transformedData = data; for (const col of this.columns) { @@ -96,12 +104,27 @@ class BaseModel> extends BaseModelSql { if (typeof transformedData[col._cn] === 'string') { transformedData[col._cn] = JSON.parse(transformedData[col._cn]); } - transformedData[col._cn] = (transformedData[col._cn] || []).map((attachment) => { - if (['jpeg', 'gif', 'png', 'apng', 'svg', 'bmp', 'ico', 'jpg'].includes(attachment.title.split('.').pop())) { - return `` - } - return `${attachment.title}` - }).join(' '); + transformedData[col._cn] = (transformedData[col._cn] || []) + .map(attachment => { + if ( + [ + 'jpeg', + 'gif', + 'png', + 'apng', + 'svg', + 'bmp', + 'ico', + 'jpg' + ].includes(attachment.title.split('.').pop()) + ) { + return ``; + } + return `${attachment.title}`; + }) + .join(' '); + } else if (typeof transformedData[col._cn] === 'object') { + transformedData[col._cn] = JSON.stringify(transformedData[col._cn]); } } // todo: notification template @@ -113,16 +136,16 @@ class BaseModel> extends BaseModelSql { tn: this.tn, _tn: this._tn }) - }) + }); } } try { - if (this.tn in this.builder.hooks - && hookName in this.builder.hooks[this.tn] - && this.builder.hooks[this.tn][hookName] + if ( + this.tn in this.builder.hooks && + hookName in this.builder.hooks[this.tn] && + this.builder.hooks[this.tn][hookName] ) { - /* if (hookName === 'after.update') { try { data = await this.nestedRead(req.params.id, this.defaultNestedQueryParams) @@ -131,36 +154,65 @@ class BaseModel> extends BaseModelSql { } }*/ - for (const hook of this.builder.hooks[this.tn][hookName]) { if (!hook.active) { - continue + continue; } - console.log('Hook handler ::::' + this.tn + '::::', this.builder.hooks[this.tn][hookName]) - console.log('Hook handler ::::' + this.tn + '::::', data) - + console.log( + 'Hook handler ::::' + this.tn + '::::', + this.builder.hooks[this.tn][hookName] + ); + console.log('Hook handler ::::' + this.tn + '::::', data); if (!this.validateCondition(hook.condition, data, req)) { continue; } - switch (hook.notification?.type) { case 'Email': this.emailAdapter?.mailSend({ - to: this.parseBody(hook.notification?.payload?.to, req, data, hook.notification?.payload), - subject: this.parseBody(hook.notification?.payload?.subject, req, data, hook.notification?.payload), - html: this.parseBody(hook.notification?.payload?.body, req, data, hook.notification?.payload) - }) + to: this.parseBody( + hook.notification?.payload?.to, + req, + data, + hook.notification?.payload + ), + subject: this.parseBody( + hook.notification?.payload?.subject, + req, + data, + hook.notification?.payload + ), + html: this.parseBody( + hook.notification?.payload?.body, + req, + data, + hook.notification?.payload + ) + }); break; case 'URL': - this.handleHttpWebHook(hook.notification?.payload, req, data) + this.handleHttpWebHook(hook.notification?.payload, req, data); break; default: - if (this.webhookNotificationAdapters && hook.notification?.type && hook.notification?.type in this.webhookNotificationAdapters) { - this.webhookNotificationAdapters[hook.notification.type].sendMessage(this.parseBody(hook.notification?.payload?.body, req, data, hook.notification?.payload), hook.notification?.payload) + if ( + this.webhookNotificationAdapters && + hook.notification?.type && + hook.notification?.type in this.webhookNotificationAdapters + ) { + this.webhookNotificationAdapters[ + hook.notification.type + ].sendMessage( + this.parseBody( + hook.notification?.payload?.body, + req, + data, + hook.notification?.payload + ), + hook.notification?.payload + ); } - break + break; } // await axios.post(this.builder.hooks[this.tn][hookName].url, {data}, { @@ -169,7 +221,7 @@ class BaseModel> extends BaseModelSql { } } } catch (e) { - console.log('hooks :: error', hookName, e.message) + console.log('hooks :: error', hookName, e.message); } } @@ -178,7 +230,7 @@ class BaseModel> extends BaseModelSql { const req = this.axiosRequestMake(apiMeta, apiReq, data); await require('axios')(req); } catch (e) { - console.log(e) + console.log(e); } } @@ -186,54 +238,72 @@ class BaseModel> extends BaseModelSql { if (apiMeta.body) { try { apiMeta.body = JSON.parse(apiMeta.body, (_key, value) => { - return typeof value === 'string' ? this.parseBody(value, apiReq, data, apiMeta) : value; + return typeof value === 'string' + ? this.parseBody(value, apiReq, data, apiMeta) + : value; }); } catch (e) { - apiMeta.body = this.parseBody(apiMeta.body, apiReq, data, apiMeta) + apiMeta.body = this.parseBody(apiMeta.body, apiReq, data, apiMeta); console.log(e); } } if (apiMeta.auth) { try { apiMeta.auth = JSON.parse(apiMeta.auth, (_key, value) => { - return typeof value === 'string' ? this.parseBody(value, apiReq, data, apiMeta) : value; + return typeof value === 'string' + ? this.parseBody(value, apiReq, data, apiMeta) + : value; }); } catch (e) { - apiMeta.auth = this.parseBody(apiMeta.auth, apiReq, data, apiMeta) + apiMeta.auth = this.parseBody(apiMeta.auth, apiReq, data, apiMeta); console.log(e); } } apiMeta.response = {}; const req = { - params: apiMeta.parameters ? apiMeta.parameters.reduce((paramsObj, param) => { - if (param.name && param.enabled) { - paramsObj[param.name] = this.parseBody(param.value, apiReq, data, apiMeta); - } - return paramsObj; - }, {}) : {}, + params: apiMeta.parameters + ? apiMeta.parameters.reduce((paramsObj, param) => { + if (param.name && param.enabled) { + paramsObj[param.name] = this.parseBody( + param.value, + apiReq, + data, + apiMeta + ); + } + return paramsObj; + }, {}) + : {}, url: this.parseBody(apiMeta.path, apiReq, data, apiMeta), method: apiMeta.method, data: apiMeta.body, - headers: apiMeta.headers ? apiMeta.headers.reduce((headersObj, header) => { - if (header.name && header.enabled) { - headersObj[header.name] = this.parseBody(header.value, apiReq, data, apiMeta); - } - return headersObj; - }, {}) : {}, + headers: apiMeta.headers + ? apiMeta.headers.reduce((headersObj, header) => { + if (header.name && header.enabled) { + headersObj[header.name] = this.parseBody( + header.value, + apiReq, + data, + apiMeta + ); + } + return headersObj; + }, {}) + : {}, withCredentials: true }; return req; } - // @ts-ignore private get emailAdapter(): IEmailAdapter { return this.builder?.app?.metaMgr?.emailAdapter; } - // @ts-ignore - private get webhookNotificationAdapters(): { [key: string]: IWebhookNotificationAdapter } { + private get webhookNotificationAdapters(): { + [key: string]: IWebhookNotificationAdapter; + } { return this.builder?.app?.metaMgr?.webhookNotificationAdapters; } @@ -253,28 +323,34 @@ class BaseModel> extends BaseModelSql { res = data[field] !== con.value; break; case 'is like': - res = data[field]?.toLowerCase()?.indexOf(con.value?.toLowerCase()) > -1; + res = + data[field]?.toLowerCase()?.indexOf(con.value?.toLowerCase()) > -1; break; case 'is not like': - res = data[field]?.toLowerCase()?.indexOf(con.value?.toLowerCase()) === -1; + res = + data[field]?.toLowerCase()?.indexOf(con.value?.toLowerCase()) === + -1; break; case 'is empty': - res = data[field] === '' || data[field] === null || data[field] === undefined; + res = + data[field] === '' || + data[field] === null || + data[field] === undefined; break; case 'is not empty': - res = !(data[field] === '' || data[field] === null || data[field] === undefined); + res = !( + data[field] === '' || + data[field] === null || + data[field] === undefined + ); break; case 'is null': - res = - res = data[field] === null; + res = res = data[field] === null; break; case 'is not null': res = data[field] !== null; break; - - - /* todo: case '<': return condition + `~not(${filt.field},lt,${filt.value})`; case '<=': @@ -285,25 +361,28 @@ class BaseModel> extends BaseModelSql { return condition + `~not(${filt.field},ge,${filt.value})`;*/ } - return con.logicOp === 'or' ? valid || res : valid && res; - }, true); return isValid; } - private parseBody(template: string, req: any, data: any, payload: any): string { + private parseBody( + template: string, + req: any, + data: any, + payload: any + ): string { if (!template) { return template; } - return Handlebars.compile(template, {noEscape: true})({ + return Handlebars.compile(template, { noEscape: true })({ data, user: req?.user, payload, env: process.env - }) + }); } } diff --git a/packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts b/packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts index f7e7f4b56b..e5aee56f0c 100644 --- a/packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts +++ b/packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts @@ -3540,7 +3540,7 @@ export default class NcMetaMgr { const model = apiBuilder?.xcModels?.[viewMeta.model_name]; if (model) { - // req.query.form = viewMeta.form_id + req.query.form = queryParams?.selectedViewId; await model.nestedInsert(insertObject, null, req); // todo: map nested data