diff --git a/packages/noco-docs/content/en/getting-started/installation.md b/packages/noco-docs/content/en/getting-started/installation.md index 2f341aee2a..f019870064 100644 --- a/packages/noco-docs/content/en/getting-started/installation.md +++ b/packages/noco-docs/content/en/getting-started/installation.md @@ -509,6 +509,7 @@ It is mandatory to configure `NC_DB` environment variables for production usecas | NC_S3_ACCESS_KEY | No | For S3 storage plugin - AWS access key credential for accessing resource | | | | NC_S3_ACCESS_SECRET | No | For S3 storage plugin - AWS access secret credential for accessing resource | | | | NC_ADMIN_EMAIL | No | For updating/creating super admin with provided email and password | | | +| NC_ATTACHMENT_FIELD_SIZE | No | For setting the attachment field size(in Bytes) | Defaults to 20MB | | | NC_ADMIN_PASSWORD | No | For updating/creating super admin with provided email and password. Your password should have at least 8 letters with one uppercase, one number and one special letter(Allowed special chars $&+,:;=?@#|'.^*()%!_-" ) | | | | NODE_OPTIONS | No | For passing Node.js [options](https://nodejs.org/api/cli.html#node_optionsoptions) to instance | | | | NC_MINIMAL_DBS | No | Create a new SQLite file for each project. All the db files are stored in `nc_minimal_dbs` folder in current working directory. (This option restricts project creation on external sources) | | | diff --git a/packages/nocodb/src/lib/constants/index.ts b/packages/nocodb/src/lib/constants/index.ts index e52388f60a..c2fdcb32cf 100644 --- a/packages/nocodb/src/lib/constants/index.ts +++ b/packages/nocodb/src/lib/constants/index.ts @@ -1,2 +1,4 @@ export const NC_LICENSE_KEY = 'nc-license-key'; export const NC_APP_SETTINGS = 'nc-app-settings'; +export const NC_ATTACHMENT_FIELD_SIZE = + +process.env['NC_ATTACHMENT_FIELD_SIZE'] || 20 * 1024 * 1024; // 20 MB diff --git a/packages/nocodb/src/lib/meta/NcMetaMgr.ts b/packages/nocodb/src/lib/meta/NcMetaMgr.ts index 789279dde6..b44d3df03c 100644 --- a/packages/nocodb/src/lib/meta/NcMetaMgr.ts +++ b/packages/nocodb/src/lib/meta/NcMetaMgr.ts @@ -41,6 +41,7 @@ import { defaultConnectionConfig } from '../utils/NcConfigFactory'; import xcMetaDiff from './handlers/xcMetaDiff'; import { UITypes } from 'nocodb-sdk'; import { Tele } from 'nc-help'; +import { NC_ATTACHMENT_FIELD_SIZE } from '../constants'; const randomID = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 10); const XC_PLUGIN_DET = 'XC_PLUGIN_DET'; @@ -132,6 +133,9 @@ export default class NcMetaMgr { storage: multer.diskStorage({ // dest: path.join(this.config.toolDir, 'uploads') }), + limits: { + fieldSize: NC_ATTACHMENT_FIELD_SIZE, + }, }); // router.post(this.config.dashboardPath, upload.single('file')); router.post(this.config.dashboardPath, upload.any()); diff --git a/packages/nocodb/src/lib/meta/NcMetaMgrv2.ts b/packages/nocodb/src/lib/meta/NcMetaMgrv2.ts index 371b353427..596249036f 100644 --- a/packages/nocodb/src/lib/meta/NcMetaMgrv2.ts +++ b/packages/nocodb/src/lib/meta/NcMetaMgrv2.ts @@ -11,6 +11,7 @@ import NcPluginMgr from '../v1-legacy/plugins/NcPluginMgr'; import NcMetaIO from './NcMetaIO'; import { defaultConnectionConfig } from '../utils/NcConfigFactory'; import ncCreateLookup from './handlersv2/ncCreateLookup'; +import { NC_ATTACHMENT_FIELD_SIZE } from '../constants'; // import ncGetMeta from './handlersv2/ncGetMeta'; export default class NcMetaMgrv2 { @@ -71,6 +72,9 @@ export default class NcMetaMgrv2 { storage: multer.diskStorage({ // dest: path.join(this.config.toolDir, 'uploads') }), + limits: { + fieldSize: NC_ATTACHMENT_FIELD_SIZE, + }, }); // router.post(this.config.dashboardPath, upload.single('file')); router.post(this.config.dashboardPath, upload.any()); diff --git a/packages/nocodb/src/lib/meta/api/attachmentApis.ts b/packages/nocodb/src/lib/meta/api/attachmentApis.ts index 8af6ebfa46..4eb3f7597e 100644 --- a/packages/nocodb/src/lib/meta/api/attachmentApis.ts +++ b/packages/nocodb/src/lib/meta/api/attachmentApis.ts @@ -9,6 +9,7 @@ import { Tele } from 'nc-help'; import ncMetaAclMw from '../helpers/ncMetaAclMw'; import catchError from '../helpers/catchError'; import NcPluginMgrv2 from '../helpers/NcPluginMgrv2'; +import { NC_ATTACHMENT_FIELD_SIZE } from '../../constants'; // const storageAdapter = new Local(); export async function upload(req: Request, res: Response) { @@ -151,6 +152,9 @@ router.post( '/api/v1/db/storage/upload', multer({ storage: multer.diskStorage({}), + limits: { + fieldSize: NC_ATTACHMENT_FIELD_SIZE, + }, }).any(), ncMetaAclMw(upload, 'upload') ); diff --git a/packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts b/packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts index 90eaddeabf..862f2f849f 100644 --- a/packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts +++ b/packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts @@ -18,6 +18,7 @@ import slash from 'slash'; import { sanitizeUrlPath } from '../attachmentApis'; import getAst from '../../../db/sql-data-mapper/lib/sql/helpers/getAst'; import { getColumnByIdOrName } from '../dataApis/helpers'; +import { NC_ATTACHMENT_FIELD_SIZE } from '../../../constants'; export async function dataList(req: Request, res: Response) { try { @@ -451,6 +452,9 @@ router.post( '/api/v1/db/public/shared-view/:sharedViewUuid/rows', multer({ storage: multer.diskStorage({}), + limits: { + fieldSize: NC_ATTACHMENT_FIELD_SIZE, + }, }).any(), catchError(dataInsert) ); diff --git a/packages/nocodb/src/lib/services/test/TestResetService/resetMysqlSakilaProject.ts b/packages/nocodb/src/lib/services/test/TestResetService/resetMysqlSakilaProject.ts index b50438487a..b010579522 100644 --- a/packages/nocodb/src/lib/services/test/TestResetService/resetMysqlSakilaProject.ts +++ b/packages/nocodb/src/lib/services/test/TestResetService/resetMysqlSakilaProject.ts @@ -71,11 +71,13 @@ const isSakilaMysqlToBeReset = async ( return true; } - if (!project) return false; + if (!project) return true; const audits = await Audit.projectAuditList(project.id, {}); - return audits?.length > 0; + // todo: Will be fixed in the data resetting revamp + console.log(`audits:resetMysqlSakilaProject:${parallelId}`, audits?.length); + return true; }; const resetSakilaMysql = async ( diff --git a/tests/playwright/fixtures/sampleFiles/sampleImage.jpeg b/tests/playwright/fixtures/sampleFiles/sampleImage.jpeg new file mode 100644 index 0000000000..9e88102c07 Binary files /dev/null and b/tests/playwright/fixtures/sampleFiles/sampleImage.jpeg differ diff --git a/tests/playwright/pages/Dashboard/Form/index.ts b/tests/playwright/pages/Dashboard/Form/index.ts index 2f44e06a5d..b04ac3326f 100644 --- a/tests/playwright/pages/Dashboard/Form/index.ts +++ b/tests/playwright/pages/Dashboard/Form/index.ts @@ -7,6 +7,7 @@ export class FormPage extends BasePage { readonly dashboard: DashboardPage; readonly toolbar: ToolbarPage; + // todo: All the locator should be private readonly addAllButton: Locator; readonly removeAllButton: Locator; readonly submitButton: Locator; diff --git a/tests/playwright/pages/SharedForm/index.ts b/tests/playwright/pages/SharedForm/index.ts index 6aa548a9af..0079bde67d 100644 --- a/tests/playwright/pages/SharedForm/index.ts +++ b/tests/playwright/pages/SharedForm/index.ts @@ -16,7 +16,7 @@ export class SharedFormPage extends BasePage { async submit() { await this.waitForResponse({ - uiAction: this.get().locator('[data-testid="shared-form-submit-button"]').click(), + uiAction: this.get().getByTestId('shared-form-submit-button').click(), httpMethodsToMatch: ['POST'], requestUrlPathToMatch: '/rows', }); diff --git a/tests/playwright/tests/columnAttachments.spec.ts b/tests/playwright/tests/columnAttachments.spec.ts index 475c07fb14..f4ef56049e 100644 --- a/tests/playwright/tests/columnAttachments.spec.ts +++ b/tests/playwright/tests/columnAttachments.spec.ts @@ -31,6 +31,15 @@ test.describe('Attachment column', () => { columnHeader: 'testAttach', }); } + await dashboard.grid.cell.attachment.addFile({ + index: 7, + columnHeader: 'testAttach', + filePath: `${process.cwd()}/fixtures/sampleFiles/sampleImage.jpeg`, + }); + await dashboard.grid.cell.attachment.verifyFile({ + index: 7, + columnHeader: 'testAttach', + }); await dashboard.viewSidebar.createFormView({ title: 'Form 1', diff --git a/tests/playwright/tests/viewForm.spec.ts b/tests/playwright/tests/viewForm.spec.ts index 2f96356f9b..734f73bfc0 100644 --- a/tests/playwright/tests/viewForm.spec.ts +++ b/tests/playwright/tests/viewForm.spec.ts @@ -3,6 +3,7 @@ import { DashboardPage } from '../pages/Dashboard'; import { SettingTab } from '../pages/Dashboard/Settings'; import setup from '../setup'; import { FormPage } from '../pages/Dashboard/Form'; +import { SharedFormPage } from '../pages/SharedForm'; // todo: Move most of the ui actions to page object and await on the api response test.describe('Form view', () => { @@ -201,4 +202,32 @@ test.describe('Form view', () => { }); await dashboard.settings.close(); }); + + test('Form share, verify attachment file', async () => { + await dashboard.treeView.createTable({ title: 'New' }); + + await dashboard.grid.column.create({ + title: 'Attachment', + type: 'Attachment', + }); + + await dashboard.viewSidebar.createFormView({ title: 'NewForm' }); + await dashboard.form.toolbar.clickShareView(); + const formLink = await dashboard.form.toolbar.shareView.getShareLink(); + + await dashboard.rootPage.goto(formLink); + + const sharedForm = new SharedFormPage(dashboard.rootPage); + await sharedForm.cell.attachment.addFile({ + columnHeader: 'Attachment', + filePath: `${process.cwd()}/fixtures/sampleFiles/sampleImage.jpeg`, + }); + await sharedForm.cell.fillText({ + columnHeader: 'Title', + text: 'Text', + }); + + await sharedForm.submit(); + await sharedForm.verifySuccessMessage(); + }); });