Browse Source

Merge branch 'develop' of https://github.com/nocodb/nocodb into develop

pull/1668/head
Wing-Kam Wong 2 years ago
parent
commit
ab1b832cc7
  1. 4
      .github/workflows/release-nightly-dev.yml
  2. 13
      packages/nc-gui/components/project/spreadsheet/components/editableCell/editableAttachmentCell.vue
  3. 132
      packages/nocodb-sdk/src/lib/Api.ts
  4. 51
      packages/nocodb/src/lib/noco/meta/api/attachmentApis.ts
  5. 18
      packages/nocodb/src/lib/noco/meta/api/publicApis/publicDataApis.ts
  6. 33
      scripts/sdk/swagger.json

4
.github/workflows/release-nightly-dev.yml

@ -12,8 +12,8 @@ on:
- DEV
# - PROD
schedule:
# at the end of every day
- cron: '0 0 * * *'
# every 6 hours
- cron: '0 */6 * * *'
jobs:
# enrich tag for nightly auto release

13
packages/nc-gui/components/project/spreadsheet/components/editableCell/editableAttachmentCell.vue

@ -333,11 +333,14 @@ export default {
this.uploading = true
for (const file of this.$refs.file.files) {
try {
const data = await this.$api.dbView.upload(this.$store.state.project.projectId, this.viewId, {
files: file,
json: '{}'
})
const data = await this.$api.dbViewRow.upload(
'noco',
this.projectName,
this.meta.title,
this.column.title, {
files: file,
json: '{}'
})
this.localState.push(...data)
} catch (e) {

132
packages/nocodb-sdk/src/lib/Api.ts

@ -1449,23 +1449,6 @@ export class Api<
}),
};
dbTableColumn = {
/**
* @description Read project details
*
* @tags DB Table column
* @name List
* @summary Column List
* @request GET:/api/v1/db/meta/tables/{tableId}/columns
* @response `200` `ColumnListType`
* @response `201` `ColumnType` Created
*/
list: (tableId: string, params: RequestParams = {}) =>
this.request<ColumnListType, any>({
path: `/api/v1/db/meta/tables/${tableId}/columns`,
method: 'GET',
...params,
}),
/**
* No description
*
@ -1488,23 +1471,6 @@ export class Api<
...params,
}),
/**
* @description Read project details
*
* @tags DB Table column
* @name Read
* @summary Column Read
* @request GET:/api/v1/db/meta/columns/{columnId}
* @response `200` `ColumnType` OK
*/
read: (columnId: string, params: RequestParams = {}) =>
this.request<ColumnType, any>({
path: `/api/v1/db/meta/columns/${columnId}`,
method: 'GET',
format: 'json',
...params,
}),
/**
* No description
*
@ -1620,7 +1586,7 @@ export class Api<
*
* @tags DB View
* @name ShowAllColumn
* @request POST:/api/v1/db/meta/views/{viewId}/showAll
* @request POST:/api/v1/db/meta/views/{viewId}/show-all
* @response `200` `void` OK
*/
showAllColumn: (
@ -1629,7 +1595,7 @@ export class Api<
params: RequestParams = {}
) =>
this.request<void, any>({
path: `/api/v1/db/meta/views/${viewId}/showAll`,
path: `/api/v1/db/meta/views/${viewId}/show-all`,
method: 'POST',
query: query,
...params,
@ -1640,7 +1606,7 @@ export class Api<
*
* @tags DB View
* @name HideAllColumn
* @request POST:/api/v1/db/meta/views/{viewId}/hideAll
* @request POST:/api/v1/db/meta/views/{viewId}/hide-all
* @response `200` `void` OK
*/
hideAllColumn: (
@ -1649,7 +1615,7 @@ export class Api<
params: RequestParams = {}
) =>
this.request<void, any>({
path: `/api/v1/db/meta/views/${viewId}/hideAll`,
path: `/api/v1/db/meta/views/${viewId}/hide-all`,
method: 'POST',
query: query,
...params,
@ -1842,28 +1808,6 @@ export class Api<
format: 'json',
...params,
}),
/**
* No description
*
* @tags DB View
* @name Upload
* @summary Attachment
* @request POST:/projects/{projectId}/views/{viewId}/upload
*/
upload: (
projectId: string,
viewId: string,
data: { files?: any; json?: string },
params: RequestParams = {}
) =>
this.request<any, any>({
path: `/projects/${projectId}/views/${viewId}/upload`,
method: 'POST',
body: data,
type: ContentType.FormData,
...params,
}),
};
dbViewShare = {
/**
@ -1968,22 +1912,6 @@ export class Api<
...params,
}),
/**
* No description
*
* @tags DB View Column
* @name Read
* @request GET:/api/v1/db/meta/views/{viewId}/columns/{columnId}
* @response `200` `any` OK
*/
read: (viewId: string, columnId: string, params: RequestParams = {}) =>
this.request<any, any>({
path: `/api/v1/db/meta/views/${viewId}/columns/${columnId}`,
method: 'GET',
format: 'json',
...params,
}),
/**
* No description
*
@ -2850,6 +2778,30 @@ export class Api<
wrapped: true,
...params,
}),
/**
* No description
*
* @tags DB View row
* @name Upload
* @summary Attachment
* @request POST:/api/v1/db/data-attachment/{orgs}/{projectName}/{tableName}/{columnName}
*/
upload: (
orgs: string,
projectName: string,
tableName: string,
columnName: string,
data: { files?: any; json?: string },
params: RequestParams = {}
) =>
this.request<any, any>({
path: `/api/v1/db/data-attachment/${orgs}/${projectName}/${tableName}/${columnName}`,
method: 'POST',
body: data,
type: ContentType.FormData,
...params,
}),
};
public = {
/**
@ -2883,14 +2835,14 @@ export class Api<
*/
dataCreate: (
sharedViewUuid: string,
data: any,
data: object,
params: RequestParams = {}
) =>
this.request<any, any>({
path: `/api/v1/db/public/shared-view/${sharedViewUuid}/rows`,
method: 'POST',
body: data,
type: ContentType.Json,
type: ContentType.FormData,
format: 'json',
...params,
}),
@ -2919,30 +2871,6 @@ export class Api<
...params,
}),
/**
* No description
*
* @tags Public
* @name DataNestedExcludedList
* @request GET:/api/v1/db/public/shared-view/{sharedViewUuid}/rows/{rowId}/{relationType}/{columnName}/exclude
* @response `200` `any` OK
*/
dataNestedExcludedList: (
sharedViewUuid: string,
rowId: string,
relationType: 'mm' | 'hm',
columnName: string,
query?: { limit?: string; offset?: string },
params: RequestParams = {}
) =>
this.request<any, any>({
path: `/api/v1/db/public/shared-view/${sharedViewUuid}/rows/${rowId}/${relationType}/${columnName}/exclude`,
method: 'GET',
query: query,
format: 'json',
...params,
}),
/**
* No description
*

51
packages/nocodb/src/lib/noco/meta/api/attachmentApis.ts

@ -12,12 +12,13 @@ import NcPluginMgrv2 from '../helpers/NcPluginMgrv2';
// const storageAdapter = new Local();
export async function upload(req: Request, res: Response) {
const destPath = path.join(
'nc',
'uploads',
req.params.projectId,
req.params.viewId
);
const filePath = sanitizeUrlPath([
req.params.orgs,
req.params.projectName,
req.params.tableName,
req.params.columnName
]);
const destPath = path.join('nc', 'uploads', ...filePath);
const storageAdapter = await NcPluginMgrv2.storageAdapter();
const attachments = await Promise.all(
@ -30,9 +31,9 @@ export async function upload(req: Request, res: Response) {
);
if (!url) {
url = `${(req as any).ncSiteUrl}/download/${req.params.projectId}/${
req.params.viewId
}/${fileName}`;
url = `${
(req as any).ncSiteUrl
}/api/v1/db/data-attachment/${filePath.join('/')}/${fileName}`;
}
return {
@ -67,8 +68,10 @@ export async function fileRead(req, res) {
path.join(
'nc',
'uploads',
req.params.projectId,
req.params.viewId,
req.params.orgs,
req.params.projectName,
req.params.tableName,
req.params.columnName,
req.params.fileName
)
)
@ -82,15 +85,6 @@ export async function fileRead(req, res) {
}
const router = Router({ mergeParams: true });
router.post(
'/projects/:projectId/views/:viewId/upload',
multer({
storage: multer.diskStorage({})
}).any(),
ncMetaAclMw(upload, 'upload')
);
router.get('/download/:projectId/:viewId/:fileName', catchError(fileRead));
router.get(/^\/dl\/([^/]+)\/([^/]+)\/(.+)$/, async (req, res) => {
try {
// const type = mimetypes[path.extname(req.params.fileName).slice(1)] || 'text/plain';
@ -122,4 +116,21 @@ router.get(/^\/dl\/([^/]+)\/([^/]+)\/(.+)$/, async (req, res) => {
res.status(404).send('Not found');
}
});
export function sanitizeUrlPath(paths) {
return paths.map(url => url.replace(/[/.?#]+/g, '_'));
}
router.post(
'/api/v1/db/data-attachment/:orgs/:projectName/:tableName/:columnName',
multer({
storage: multer.diskStorage({})
}).any(),
ncMetaAclMw(upload, 'upload')
);
router.get(
'/api/v1/db/data-attachment/:orgs/:projectName/:tableName/:columnName/:fileName',
catchError(fileRead)
);
export default router;

18
packages/nocodb/src/lib/noco/meta/api/publicApis/publicDataApis.ts

@ -15,6 +15,7 @@ import path from 'path';
import { nanoid } from 'nanoid';
import { mimeIcons } from '../../../../utils/mimeTypes';
import slash from 'slash';
import { sanitizeUrlPath } from '../attachmentApis';
export async function dataList(req: Request, res: Response) {
try {
@ -83,6 +84,7 @@ async function dataInsert(
id: view?.fk_model_id
});
const base = await Base.get(model.base_id);
const project = await base.getProject();
const baseModel = await Model.getBaseModelSQL({
id: model.id,
@ -122,18 +124,26 @@ async function dataInsert(
for (const file of req.files || []) {
// remove `_` prefix and `[]` suffix
const fieldName = file?.fieldname?.replace(/^_|\[\d*]$/g, '');
const filePath = sanitizeUrlPath([
'noco',
project.title,
model.title,
fieldName
]);
if (fieldName in fields && fields[fieldName].uidt === UITypes.Attachment) {
attachments[fieldName] = attachments[fieldName] || [];
const fileName = `${nanoid(6)}_${file.originalname}`;
let url = await storageAdapter.fileCreate(
slash(path.join('nc', 'uploads', base.project_id, view.id, fileName)),
slash(path.join('nc', 'uploads', ...filePath, fileName)),
file
);
if (!url) {
url = `${(req as any).ncSiteUrl}/download/${base.project_id}/${
view.id
}/${fileName}`;
url = `${
(req as any).ncSiteUrl
}/api/v1/db/data-attachment/${filePath.join('/')}/${fileName}`;
}
attachments[fieldName].push({

33
scripts/sdk/swagger.json

@ -3282,13 +3282,13 @@
}
},
"/projects/{projectId}/views/{viewId}/upload": {
"/api/v1/db/data-attachment/{orgs}/{projectName}/{tableName}/{columnName}": {
"post": {
"summary": "Attachment",
"operationId": "db-view-upload",
"operationId": "db-view-row-upload",
"responses": {},
"tags": [
"DB View"
"DB View row"
],
"requestBody": {
"content": {
@ -3312,7 +3312,7 @@
"schema": {
"type": "string"
},
"name": "projectId",
"name": "orgs",
"in": "path",
"required": true
},
@ -3320,7 +3320,23 @@
"schema": {
"type": "string"
},
"name": "viewId",
"name": "projectName",
"in": "path",
"required": true
},
{
"schema": {
"type": "string"
},
"name": "tableName",
"in": "path",
"required": true
},
{
"schema": {
"type": "string"
},
"name": "columnName",
"in": "path",
"required": true
}
@ -3395,8 +3411,11 @@
},
"requestBody": {
"content": {
"application/json": {
"schema": {}
"multipart/form-data": {
"schema": {
"type": "object",
"properties": { }
}
}
}
},

Loading…
Cancel
Save