Browse Source

Merge pull request #4538 from nocodb/fix/attachment-file-field-size-issue

fix(test): Made default file field size limit to 20MB and is configurable using NC_ATTACHMENT_FIELD_SIZE env variable
pull/3668/head
Muhammed Mustafa 2 years ago committed by GitHub
parent
commit
a25e488119
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      packages/noco-docs/content/en/getting-started/installation.md
  2. 2
      packages/nocodb/src/lib/constants/index.ts
  3. 4
      packages/nocodb/src/lib/meta/NcMetaMgr.ts
  4. 4
      packages/nocodb/src/lib/meta/NcMetaMgrv2.ts
  5. 4
      packages/nocodb/src/lib/meta/api/attachmentApis.ts
  6. 4
      packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts
  7. 6
      packages/nocodb/src/lib/services/test/TestResetService/resetMysqlSakilaProject.ts
  8. BIN
      tests/playwright/fixtures/sampleFiles/sampleImage.jpeg
  9. 1
      tests/playwright/pages/Dashboard/Form/index.ts
  10. 2
      tests/playwright/pages/SharedForm/index.ts
  11. 9
      tests/playwright/tests/columnAttachments.spec.ts
  12. 29
      tests/playwright/tests/viewForm.spec.ts

1
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_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_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_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 <code>$&+,:;=?@#&#124;'.^*()%!_-"</code> ) | | | | 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 <code>$&+,:;=?@#&#124;'.^*()%!_-"</code> ) | | |
| NODE_OPTIONS | No | For passing Node.js [options](https://nodejs.org/api/cli.html#node_optionsoptions) to instance | | | | 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) | | | | 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) | | |

2
packages/nocodb/src/lib/constants/index.ts

@ -1,2 +1,4 @@
export const NC_LICENSE_KEY = 'nc-license-key'; export const NC_LICENSE_KEY = 'nc-license-key';
export const NC_APP_SETTINGS = 'nc-app-settings'; 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

4
packages/nocodb/src/lib/meta/NcMetaMgr.ts

@ -41,6 +41,7 @@ import { defaultConnectionConfig } from '../utils/NcConfigFactory';
import xcMetaDiff from './handlers/xcMetaDiff'; import xcMetaDiff from './handlers/xcMetaDiff';
import { UITypes } from 'nocodb-sdk'; import { UITypes } from 'nocodb-sdk';
import { Tele } from 'nc-help'; import { Tele } from 'nc-help';
import { NC_ATTACHMENT_FIELD_SIZE } from '../constants';
const randomID = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 10); const randomID = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 10);
const XC_PLUGIN_DET = 'XC_PLUGIN_DET'; const XC_PLUGIN_DET = 'XC_PLUGIN_DET';
@ -132,6 +133,9 @@ export default class NcMetaMgr {
storage: multer.diskStorage({ storage: multer.diskStorage({
// dest: path.join(this.config.toolDir, 'uploads') // 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.single('file'));
router.post(this.config.dashboardPath, upload.any()); router.post(this.config.dashboardPath, upload.any());

4
packages/nocodb/src/lib/meta/NcMetaMgrv2.ts

@ -11,6 +11,7 @@ import NcPluginMgr from '../v1-legacy/plugins/NcPluginMgr';
import NcMetaIO from './NcMetaIO'; import NcMetaIO from './NcMetaIO';
import { defaultConnectionConfig } from '../utils/NcConfigFactory'; import { defaultConnectionConfig } from '../utils/NcConfigFactory';
import ncCreateLookup from './handlersv2/ncCreateLookup'; import ncCreateLookup from './handlersv2/ncCreateLookup';
import { NC_ATTACHMENT_FIELD_SIZE } from '../constants';
// import ncGetMeta from './handlersv2/ncGetMeta'; // import ncGetMeta from './handlersv2/ncGetMeta';
export default class NcMetaMgrv2 { export default class NcMetaMgrv2 {
@ -71,6 +72,9 @@ export default class NcMetaMgrv2 {
storage: multer.diskStorage({ storage: multer.diskStorage({
// dest: path.join(this.config.toolDir, 'uploads') // 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.single('file'));
router.post(this.config.dashboardPath, upload.any()); router.post(this.config.dashboardPath, upload.any());

4
packages/nocodb/src/lib/meta/api/attachmentApis.ts

@ -9,6 +9,7 @@ import { Tele } from 'nc-help';
import ncMetaAclMw from '../helpers/ncMetaAclMw'; import ncMetaAclMw from '../helpers/ncMetaAclMw';
import catchError from '../helpers/catchError'; import catchError from '../helpers/catchError';
import NcPluginMgrv2 from '../helpers/NcPluginMgrv2'; import NcPluginMgrv2 from '../helpers/NcPluginMgrv2';
import { NC_ATTACHMENT_FIELD_SIZE } from '../../constants';
// const storageAdapter = new Local(); // const storageAdapter = new Local();
export async function upload(req: Request, res: Response) { export async function upload(req: Request, res: Response) {
@ -151,6 +152,9 @@ router.post(
'/api/v1/db/storage/upload', '/api/v1/db/storage/upload',
multer({ multer({
storage: multer.diskStorage({}), storage: multer.diskStorage({}),
limits: {
fieldSize: NC_ATTACHMENT_FIELD_SIZE,
},
}).any(), }).any(),
ncMetaAclMw(upload, 'upload') ncMetaAclMw(upload, 'upload')
); );

4
packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts

@ -18,6 +18,7 @@ import slash from 'slash';
import { sanitizeUrlPath } from '../attachmentApis'; import { sanitizeUrlPath } from '../attachmentApis';
import getAst from '../../../db/sql-data-mapper/lib/sql/helpers/getAst'; import getAst from '../../../db/sql-data-mapper/lib/sql/helpers/getAst';
import { getColumnByIdOrName } from '../dataApis/helpers'; import { getColumnByIdOrName } from '../dataApis/helpers';
import { NC_ATTACHMENT_FIELD_SIZE } from '../../../constants';
export async function dataList(req: Request, res: Response) { export async function dataList(req: Request, res: Response) {
try { try {
@ -451,6 +452,9 @@ router.post(
'/api/v1/db/public/shared-view/:sharedViewUuid/rows', '/api/v1/db/public/shared-view/:sharedViewUuid/rows',
multer({ multer({
storage: multer.diskStorage({}), storage: multer.diskStorage({}),
limits: {
fieldSize: NC_ATTACHMENT_FIELD_SIZE,
},
}).any(), }).any(),
catchError(dataInsert) catchError(dataInsert)
); );

6
packages/nocodb/src/lib/services/test/TestResetService/resetMysqlSakilaProject.ts

@ -71,11 +71,13 @@ const isSakilaMysqlToBeReset = async (
return true; return true;
} }
if (!project) return false; if (!project) return true;
const audits = await Audit.projectAuditList(project.id, {}); 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 ( const resetSakilaMysql = async (

BIN
tests/playwright/fixtures/sampleFiles/sampleImage.jpeg

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

1
tests/playwright/pages/Dashboard/Form/index.ts

@ -7,6 +7,7 @@ export class FormPage extends BasePage {
readonly dashboard: DashboardPage; readonly dashboard: DashboardPage;
readonly toolbar: ToolbarPage; readonly toolbar: ToolbarPage;
// todo: All the locator should be private
readonly addAllButton: Locator; readonly addAllButton: Locator;
readonly removeAllButton: Locator; readonly removeAllButton: Locator;
readonly submitButton: Locator; readonly submitButton: Locator;

2
tests/playwright/pages/SharedForm/index.ts

@ -16,7 +16,7 @@ export class SharedFormPage extends BasePage {
async submit() { async submit() {
await this.waitForResponse({ 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'], httpMethodsToMatch: ['POST'],
requestUrlPathToMatch: '/rows', requestUrlPathToMatch: '/rows',
}); });

9
tests/playwright/tests/columnAttachments.spec.ts

@ -31,6 +31,15 @@ test.describe('Attachment column', () => {
columnHeader: 'testAttach', 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({ await dashboard.viewSidebar.createFormView({
title: 'Form 1', title: 'Form 1',

29
tests/playwright/tests/viewForm.spec.ts

@ -3,6 +3,7 @@ import { DashboardPage } from '../pages/Dashboard';
import { SettingTab } from '../pages/Dashboard/Settings'; import { SettingTab } from '../pages/Dashboard/Settings';
import setup from '../setup'; import setup from '../setup';
import { FormPage } from '../pages/Dashboard/Form'; 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 // todo: Move most of the ui actions to page object and await on the api response
test.describe('Form view', () => { test.describe('Form view', () => {
@ -201,4 +202,32 @@ test.describe('Form view', () => {
}); });
await dashboard.settings.close(); 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();
});
}); });

Loading…
Cancel
Save