Browse Source

fix(nocodb): attachment related backend review changes

pull/9722/head
Ramesh Mane 2 days ago
parent
commit
f8520b8a47
  1. 6
      packages/nocodb-sdk/src/lib/enums.ts
  2. 10
      packages/nocodb/src/controllers/attachments-secure.controller.ts
  3. 15
      packages/nocodb/src/controllers/attachments.controller.ts
  4. 28
      packages/nocodb/src/schema/swagger-v2.json
  5. 28
      packages/nocodb/src/schema/swagger.json
  6. 61
      packages/nocodb/src/services/attachments.service.ts

6
packages/nocodb-sdk/src/lib/enums.ts

@ -440,3 +440,9 @@ export enum ViewLockType {
Locked = 'locked',
Collaborative = 'collaborative',
}
export enum PublicAttachmentScope {
WORKSPACEPICS = 'workspacePics',
PROFILEPICS = 'profilePics',
ORGANIZATIONPICS = 'organizationPics',
}

10
packages/nocodb/src/controllers/attachments-secure.controller.ts

@ -15,7 +15,11 @@ import {
} from '@nestjs/common';
import { AnyFilesInterceptor } from '@nestjs/platform-express';
import { Response } from 'express';
import type { AttachmentReqType, FileType } from 'nocodb-sdk';
import type {
AttachmentReqType,
FileType,
PublicAttachmentScope,
} from 'nocodb-sdk';
import type { NcRequest } from '~/interface/config';
import { NcContext } from '~/interface/config';
import { GlobalGuard } from '~/guards/global/global.guard';
@ -43,11 +47,13 @@ export class AttachmentsSecureController {
@UseInterceptors(UploadAllowedInterceptor, AnyFilesInterceptor())
async upload(
@UploadedFiles() files: Array<FileType>,
@Query('scope') scope?: PublicAttachmentScope,
@Req() req: NcRequest & { user: { id: string } },
) {
const attachments = await this.attachmentsService.upload({
files: files,
req,
scope,
});
return attachments;
@ -59,11 +65,13 @@ export class AttachmentsSecureController {
@UseGuards(MetaApiLimiterGuard, GlobalGuard)
async uploadViaURL(
@Body() body: Array<AttachmentReqType>,
@Query('scope') scope?: PublicAttachmentScope,
@Req() req: NcRequest & { user: { id: string } },
) {
const attachments = await this.attachmentsService.uploadViaURL({
urls: body,
req,
scope,
});
return attachments;

15
packages/nocodb/src/controllers/attachments.controller.ts

@ -16,7 +16,11 @@ import {
import { AnyFilesInterceptor } from '@nestjs/platform-express';
import { Response } from 'express';
import contentDisposition from 'content-disposition';
import type { AttachmentReqType, FileType } from 'nocodb-sdk';
import type {
AttachmentReqType,
FileType,
PublicAttachmentScope,
} from 'nocodb-sdk';
import { UploadAllowedInterceptor } from '~/interceptors/is-upload-allowed/is-upload-allowed.interceptor';
import { GlobalGuard } from '~/guards/global/global.guard';
import { AttachmentsService } from '~/services/attachments.service';
@ -42,11 +46,16 @@ export class AttachmentsController {
@Post(['/api/v1/db/storage/upload', '/api/v2/storage/upload'])
@HttpCode(200)
@UseInterceptors(UploadAllowedInterceptor, AnyFilesInterceptor())
async upload(@UploadedFiles() files: Array<FileType>, @Req() req: NcRequest) {
async upload(
@UploadedFiles() files: Array<FileType>,
@Query('scope') scope?: PublicAttachmentScope,
@Req() req: NcRequest,
) {
const attachments = await this.attachmentsService.upload({
files: files,
path: req.query?.path?.toString(),
req,
scope,
});
return attachments;
@ -59,12 +68,14 @@ export class AttachmentsController {
async uploadViaURL(
@Body() body: Array<AttachmentReqType>,
@Query('path') path: string,
@Query('scope') scope?: PublicAttachmentScope,
@Req() req: NcRequest,
) {
const attachments = await this.attachmentsService.uploadViaURL({
urls: body,
path,
req,
scope,
});
return attachments;

28
packages/nocodb/src/schema/swagger-v2.json

@ -11649,6 +11649,20 @@
},
{
"$ref": "#/components/parameters/xc-token"
},
{
"schema": {
"enum": [
"workspacePics",
"profilePics",
"organizationPics"
],
"type": "string",
"example": "workspacePics"
},
"name": "scope",
"in": "query",
"description": "The scope of the attachment"
}
],
"description": "Upload attachment"
@ -11688,6 +11702,20 @@
},
{
"$ref": "#/components/parameters/xc-token"
},
{
"schema": {
"enum": [
"workspacePics",
"profilePics",
"organizationPics"
],
"type": "string",
"example": "workspacePics"
},
"name": "scope",
"in": "query",
"description": "The scope of the attachment"
}
],
"description": "Upload attachment by URL. Used in Airtable Migration."

28
packages/nocodb/src/schema/swagger.json

@ -16417,6 +16417,20 @@
},
{
"$ref": "#/components/parameters/xc-auth"
},
{
"schema": {
"enum": [
"workspacePics",
"profilePics",
"organizationPics"
],
"type": "string",
"example": "workspacePics"
},
"name": "scope",
"in": "query",
"description": "The scope of the attachment"
}
],
"description": "Upload attachment"
@ -16454,6 +16468,20 @@
},
{
"$ref": "#/components/parameters/xc-auth"
},
{
"schema": {
"enum": [
"workspacePics",
"profilePics",
"organizationPics"
],
"type": "string",
"example": "workspacePics"
},
"name": "scope",
"in": "query",
"description": "The scope of the attachment"
}
],
"description": "Upload attachment by URL. Used in Airtable Migration."

61
packages/nocodb/src/services/attachments.service.ts

@ -1,6 +1,6 @@
import path from 'path';
import Url from 'url';
import { AppEvents } from 'nocodb-sdk';
import { AppEvents, PublicAttachmentScope } from 'nocodb-sdk';
import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
import { nanoid } from 'nanoid';
import mime from 'mime/lite';
@ -52,17 +52,27 @@ export class AttachmentsService {
private readonly jobsService: IJobsService,
) {}
async upload(param: { files: FileType[]; req?: NcRequest; path?: string }) {
async upload(param: {
files: FileType[];
req?: NcRequest;
path?: string;
scope?: PublicAttachmentScope;
}) {
const userId = param.req?.user.id || 'anonymous';
param.path =
param.path || `${moment().format('YYYY/MM/DD')}/${hash(userId)}`;
param.path = param.scope
? `${hash(userId)}`
: param.path || `${moment().format('YYYY/MM/DD')}/${hash(userId)}`;
// TODO: add getAjvValidatorMw
const filePath = this.sanitizeUrlPath(
param.path?.toString()?.split('/') || [''],
);
const destPath = path.join('nc', 'uploads', ...filePath);
const _destPath = path.join(
'nc',
param.scope ? param.scope : 'uploads',
...filePath,
);
const storageAdapter = await NcPluginMgrv2.storageAdapter();
@ -79,10 +89,18 @@ export class AttachmentsService {
queue.addAll(
param.files?.map((file) => async () => {
try {
const destPath = param.scope
? path.join(_destPath, `${nanoid(5)}`)
: _destPath;
const originalName = utf8ify(file.originalname);
const fileName = `${normalizeFilename(
path.parse(originalName).name,
)}_${nanoid(5)}${path.extname(originalName)}`;
const fileName = param.scope
? `${normalizeFilename(
path.parse(originalName).name,
)}${path.extname(originalName)}`
: `${normalizeFilename(path.parse(originalName).name)}_${nanoid(
5,
)}${path.extname(originalName)}`;
const tempMetadata: {
width?: number;
@ -186,16 +204,23 @@ export class AttachmentsService {
urls: AttachmentReqType[];
req?: NcRequest;
path?: string;
scope?: PublicAttachmentScope;
}) {
const userId = param.req?.user.id || 'anonymous';
param.path =
param.path || `${moment().format('YYYY/MM/DD')}/${hash(userId)}`;
param.path = param.scope
? `${hash(userId)}`
: param.path || `${moment().format('YYYY/MM/DD')}/${hash(userId)}`;
const filePath = this.sanitizeUrlPath(
param?.path?.toString()?.split('/') || [''],
);
const destPath = path.join('nc', 'uploads', ...filePath);
const _destPath = path.join(
'nc',
param.scope ? param.scope : 'uploads',
...filePath,
);
const storageAdapter = await NcPluginMgrv2.storageAdapter();
@ -214,6 +239,10 @@ export class AttachmentsService {
try {
const { url, fileName: _fileName } = urlMeta;
const destPath = param.scope
? path.join(_destPath, `${nanoid(5)}`)
: _destPath;
let mimeType,
response,
size,
@ -230,9 +259,13 @@ export class AttachmentsService {
const decodedPath = decodeURIComponent(parsedUrl.pathname);
const fileNameWithExt = _fileName || path.basename(decodedPath);
const fileName = `${normalizeFilename(
path.parse(fileNameWithExt).name,
)}_${nanoid(5)}${path.extname(fileNameWithExt)}`;
const fileName = param.scope
? `${normalizeFilename(
path.parse(fileNameWithExt).name,
)}${path.extname(fileNameWithExt)}`
: `${normalizeFilename(path.parse(fileNameWithExt).name)}_${nanoid(
5,
)}${path.extname(fileNameWithExt)}`;
if (!mimeType) {
mimeType = mime.getType(path.extname(fileNameWithExt).slice(1));

Loading…
Cancel
Save