Browse Source

Merge branch 'develop' into refactor/timezone-locale

pull/5601/head
Wing-Kam Wong 1 year ago
parent
commit
88a9802147
  1. 7
      .github/workflows/release-docker.yml
  2. 4
      .github/workflows/release-npm.yml
  3. 13
      .github/workflows/release-pr.yml
  4. 6
      packages/nc-gui/components/cell/Currency.vue
  5. 6
      packages/nc-gui/components/cell/Decimal.vue
  6. 5
      packages/nc-gui/components/cell/Duration.vue
  7. 6
      packages/nc-gui/components/cell/Email.vue
  8. 6
      packages/nc-gui/components/cell/Float.vue
  9. 6
      packages/nc-gui/components/cell/Integer.vue
  10. 8
      packages/nc-gui/components/cell/Percent.vue
  11. 8
      packages/nc-gui/components/cell/Text.vue
  12. 6
      packages/nc-gui/components/cell/TextArea.vue
  13. 5
      packages/nc-gui/components/cell/Url.vue
  14. 9
      packages/nc-gui/components/smartsheet/expanded-form/index.vue
  15. 8
      packages/nc-gui/components/webhook/Editor.vue
  16. 1
      packages/nc-gui/context/index.ts
  17. 6
      packages/nocodb-nest/Dockerfile
  18. 100
      packages/nocodb-nest/litestream/Dockerfile
  19. 8
      packages/nocodb-nest/package.json
  20. 51
      packages/nocodb-nest/src/db/BaseModelSqlv2.ts
  21. 13
      packages/nocodb-nest/src/guards/global/global.guard.ts
  22. 3
      packages/nocodb-nest/src/helpers/webhookHelpers.ts
  23. 4
      packages/nocodb-nest/src/meta/migrations/XcMigrationSourcev2.ts
  24. 34
      packages/nocodb-nest/src/meta/migrations/v2/nc_030_add_description_field.ts
  25. 1
      packages/nocodb-nest/src/schema/swagger.json
  26. 3
      packages/nocodb-nest/src/services/hooks.service.ts
  27. 18
      packages/nocodb-nest/src/services/public-datas.service.ts
  28. 65
      packages/nocodb-nest/src/strategies/authtoken.strategy/authtoken.strategy.ts
  29. 4
      packages/nocodb-nest/src/strategies/jwt.strategy.ts
  30. 2
      packages/nocodb/src/lib/migrations/XcMigrationSourcev2.ts
  31. 6
      packages/nocodb/src/lib/migrations/v2/nc_030_add_description_field.ts
  32. 15
      scripts/upgradeNcGui.js
  33. 6
      scripts/upgradeNocodbSdk.js
  34. 6
      tests/playwright/setup/index.ts

7
.github/workflows/release-docker.yml

@ -43,7 +43,7 @@ jobs:
buildx:
runs-on: ubuntu-latest
env:
working-directory: ./packages/nocodb
working-directory: ./packages/nocodb-nest
steps:
- name: Get Docker Repository
id: get-docker-repository
@ -58,7 +58,7 @@ jobs:
if [[ ${{ github.event.inputs.currentVersion || inputs.currentVersion || 'N/A' }} != 'N/A' ]]; then
DOCKER_BUILD_TAG=${{ github.event.inputs.currentVersion || inputs.currentVersion }}-${{ github.event.inputs.tag || inputs.tag }}
fi
if [[ ${{ inputs.isDaily || 'N' }} == 'Y' ]]; then
if [[ ${{ inputs.isDaily || 'N' }} == 'Y' ]]; then
DOCKER_REPOSITORY=${DOCKER_REPOSITORY}-daily
else
DOCKER_REPOSITORY=${DOCKER_REPOSITORY}-timely
@ -90,7 +90,7 @@ jobs:
cd packages/nocodb-sdk
npm install && npm run build
cd ../..
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} node scripts/upgradeNocodbSdk.js &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} node scripts/upgradeNocodbSdk.js &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} targetVersion=${{ github.event.inputs.tag || inputs.tag }} node scripts/bumpNcGuiVersion.js &&
cd packages/nc-gui
npm install
@ -104,7 +104,6 @@ jobs:
- name: Build nocodb and docker files
run: |
npm run build
npm run docker:build
working-directory: ${{ env.working-directory }}

4
.github/workflows/release-npm.yml

@ -35,7 +35,7 @@ jobs:
release:
runs-on: ubuntu-latest
env:
working-directory: ./packages/nocodb
working-directory: ./packages/nocodb-nest
steps:
- name: Checkout
uses: actions/checkout@v3
@ -62,7 +62,7 @@ jobs:
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} targetVersion=${{ github.event.inputs.tag || inputs.tag }} npm run build:copy:publish &&
cd ../.. &&
sleep 60 &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} node scripts/upgradeNcGui.js && cd packages/nocodb && npm install && npm run obfuscate:build:publish
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} node scripts/upgradeNcGui.js && cd packages/nocodb-nest && npm install && npm run obfuscate:build:publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Create Pull Request

13
.github/workflows/release-pr.yml

@ -13,6 +13,7 @@ on:
- "packages/nc-gui/**"
- "packages/nc-plugin/**"
- "packages/nocodb/**"
- "packages/nocodb-nest/**"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@ -116,13 +117,13 @@ jobs:
- name: Upload Rendered Compose File as Artifact
uses: actions/upload-artifact@v3
with:
name: preview-spec
name: preview-spec
path: docker-compose.rendered.yml
retention-days: 2
- name: Serialize PR Event to File
run: |
cat << EOF > event.json
${{ toJSON(github.event) }}
${{ toJSON(github.event) }}
EOF
- name: Upload PR Event as Artifact
uses: actions/upload-artifact@v3
@ -130,7 +131,7 @@ jobs:
name: preview-spec
path: event.json
retention-days: 2
# Add a comment for PR executable build
# leave-executable-comment:
# if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' && github.event.pull_request.draft == false && github.base_ref == 'develop' && github.event.action != 'closed' }}
@ -177,12 +178,12 @@ jobs:
- name: Serialize PR Event to File
run: |
cat << EOF > event.json
${{ toJSON(github.event) }}
${{ toJSON(github.event) }}
EOF
- name: Upload PR Event as Artifact
uses: actions/upload-artifact@v3
with:
name: preview-spec
path: event.json
retention-days: 2
retention-days: 2

6
packages/nc-gui/components/cell/Currency.vue

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import { ColumnInj, EditModeInj, computed, inject, parseProp, useVModel } from '#imports'
import { ColumnInj, EditModeInj, IsExpandedFormOpenInj, computed, inject, parseProp, useVModel } from '#imports'
interface Props {
modelValue: number | null | undefined
@ -52,7 +52,9 @@ const currency = computed(() => {
}
})
const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
const isExpandedFormOpen = inject(IsExpandedFormOpenInj)!
const focus: VNodeRef = (el) => !isExpandedFormOpen && (el as HTMLInputElement)?.focus()
const submitCurrency = () => {
if (lastSaved.value !== vModel.value) {

6
packages/nc-gui/components/cell/Decimal.vue

@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { VNodeRef } from '@vue/runtime-core'
import { EditModeInj, inject, useVModel } from '#imports'
import { EditModeInj, IsExpandedFormOpenInj, inject, useVModel } from '#imports'
interface Props {
// when we set a number, then it is number type
@ -36,7 +36,9 @@ const vModel = computed({
},
})
const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
const isExpandedFormOpen = inject(IsExpandedFormOpenInj)!
const focus: VNodeRef = (el) => !isExpandedFormOpen && (el as HTMLInputElement)?.focus()
</script>
<template>

5
packages/nc-gui/components/cell/Duration.vue

@ -3,6 +3,7 @@ import type { VNodeRef } from '@vue/runtime-core'
import {
ColumnInj,
EditModeInj,
IsExpandedFormOpenInj,
computed,
convertDurationToSeconds,
convertMS2Duration,
@ -73,7 +74,9 @@ const submitDuration = () => {
isEdited.value = false
}
const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
const isExpandedFormOpen = inject(IsExpandedFormOpenInj)!
const focus: VNodeRef = (el) => !isExpandedFormOpen && (el as HTMLInputElement)?.focus()
</script>
<template>

6
packages/nc-gui/components/cell/Email.vue

@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { VNodeRef } from '@vue/runtime-core'
import { EditModeInj, IsSurveyFormInj, computed, inject, useI18n, validateEmail } from '#imports'
import { EditModeInj, IsExpandedFormOpenInj, IsSurveyFormInj, computed, inject, useI18n, validateEmail } from '#imports'
interface Props {
modelValue: string | null | undefined
@ -35,7 +35,9 @@ const vModel = computed({
const validEmail = computed(() => vModel.value && validateEmail(vModel.value))
const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
const isExpandedFormOpen = inject(IsExpandedFormOpenInj)!
const focus: VNodeRef = (el) => !isExpandedFormOpen && (el as HTMLInputElement)?.focus()
watch(
() => editEnabled.value,

6
packages/nc-gui/components/cell/Float.vue

@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { VNodeRef } from '@vue/runtime-core'
import { EditModeInj, inject, useVModel } from '#imports'
import { EditModeInj, IsExpandedFormOpenInj, inject, useVModel } from '#imports'
interface Props {
// when we set a number, then it is number type
@ -36,7 +36,9 @@ const vModel = computed({
},
})
const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
const isExpandedFormOpen = inject(IsExpandedFormOpenInj)!
const focus: VNodeRef = (el) => !isExpandedFormOpen && (el as HTMLInputElement)?.focus()
</script>
<template>

6
packages/nc-gui/components/cell/Integer.vue

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import { EditModeInj, inject, useVModel } from '#imports'
import { EditModeInj, IsExpandedFormOpenInj, inject, useVModel } from '#imports'
interface Props {
// when we set a number, then it is number type
@ -36,7 +36,9 @@ const vModel = computed({
},
})
const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
const isExpandedFormOpen = inject(IsExpandedFormOpenInj)!
const focus: VNodeRef = (el) => !isExpandedFormOpen && (el as HTMLInputElement)?.focus()
function onKeyDown(evt: KeyboardEvent) {
return evt.key === '.' && evt.preventDefault()

8
packages/nc-gui/components/cell/Percent.vue

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import { EditModeInj, inject, useVModel } from '#imports'
import { EditModeInj, IsExpandedFormOpenInj, inject, useVModel } from '#imports'
interface Props {
modelValue?: number | string | null
@ -27,9 +27,9 @@ const vModel = computed({
},
})
const focus: VNodeRef = (el) => {
;(el as HTMLInputElement)?.focus()
}
const isExpandedFormOpen = inject(IsExpandedFormOpenInj)!
const focus: VNodeRef = (el) => !isExpandedFormOpen && (el as HTMLInputElement)?.focus()
</script>
<template>

8
packages/nc-gui/components/cell/Text.vue

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import { EditModeInj, ReadonlyInj, inject, ref, useVModel } from '#imports'
import { EditModeInj, IsExpandedFormOpenInj, ReadonlyInj, inject, ref, useVModel } from '#imports'
interface Props {
modelValue?: string | null
@ -23,9 +23,9 @@ const readonly = inject(ReadonlyInj, ref(false))
const vModel = useVModel(props, 'modelValue', emits)
const focus: VNodeRef = (el) => {
;(el as HTMLInputElement)?.focus()
}
const isExpandedFormOpen = inject(IsExpandedFormOpenInj)!
const focus: VNodeRef = (el) => !isExpandedFormOpen && (el as HTMLInputElement)?.focus()
</script>
<template>

6
packages/nc-gui/components/cell/TextArea.vue

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import { EditModeInj, RowHeightInj, inject, useVModel } from '#imports'
import { EditModeInj, IsExpandedFormOpenInj, RowHeightInj, inject, useVModel } from '#imports'
const props = defineProps<{
modelValue?: string | number
@ -19,7 +19,9 @@ const { showNull } = useGlobal()
const vModel = useVModel(props, 'modelValue', emits, { defaultValue: '' })
const focus: VNodeRef = (el) => (el as HTMLTextAreaElement)?.focus()
const isExpandedFormOpen = inject(IsExpandedFormOpenInj)!
const focus: VNodeRef = (el) => !isExpandedFormOpen && (el as HTMLTextAreaElement)?.focus()
</script>
<template>

5
packages/nc-gui/components/cell/Url.vue

@ -4,6 +4,7 @@ import {
CellUrlDisableOverlayInj,
ColumnInj,
EditModeInj,
IsExpandedFormOpenInj,
IsSurveyFormInj,
computed,
inject,
@ -62,7 +63,9 @@ const url = computed(() => {
const { cellUrlOptions } = useCellUrlConfig(url)
const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
const isExpandedFormOpen = inject(IsExpandedFormOpenInj)!
const focus: VNodeRef = (el) => !isExpandedFormOpen && (el as HTMLInputElement)?.focus()
watch(
() => editEnabled.value,

9
packages/nc-gui/components/smartsheet/expanded-form/index.vue

@ -5,6 +5,7 @@ import type { Ref } from 'vue'
import {
CellClickHookInj,
FieldsInj,
IsExpandedFormOpenInj,
IsFormInj,
IsKanbanInj,
MetaInj,
@ -180,10 +181,14 @@ if (isKanban.value) {
}
}
const cellWrapperEl = ref<HTMLElement>()
provide(IsExpandedFormOpenInj, isExpanded)
const cellWrapperEl = ref()
onMounted(() => {
setTimeout(() => (cellWrapperEl.value?.querySelector('input,select,textarea') as HTMLInputElement)?.focus())
setTimeout(() => {
cellWrapperEl.value?.$el?.querySelector('input,select,textarea')?.focus()
}, 300)
})
const addNewRow = () => {

8
packages/nc-gui/components/webhook/Editor.vue

@ -66,7 +66,9 @@ const hook = reactive<
version: 'v2',
})
const urlTabKey = ref('params')
const isBodyShown = ref(hook.version === 'v1' || (hook.version === 'v2' && appInfo.ee))
const urlTabKey = ref(isBodyShown.value ? 'body' : 'params')
const apps: Record<string, any> = ref()
@ -596,7 +598,7 @@ onMounted(async () => {
<a-col :span="24">
<a-tabs v-model:activeKey="urlTabKey" type="card" closeable="false" class="shadow-sm">
<a-tab-pane v-if="hook.version === 'v1'" key="body" tab="Body">
<a-tab-pane v-if="isBodyShown" key="body" tab="Body">
<LazyMonacoEditor
v-model="hook.notification.payload.body"
disable-deep-compare
@ -716,7 +718,7 @@ onMounted(async () => {
<a-row>
<a-col :span="24">
<div v-if="!(hook.version === 'v2' && hook.notification.type === 'URL')" class="text-gray-600">
<div v-if="isBodyShown" class="text-gray-600">
<div class="flex items-center">
<em>Use context variable <strong>data</strong> to refer the record under consideration</em>

1
packages/nc-gui/context/index.ts

@ -19,6 +19,7 @@ export const IsGridInj: InjectionKey<Ref<boolean>> = Symbol('is-grid-injection')
export const IsGalleryInj: InjectionKey<Ref<boolean>> = Symbol('is-gallery-injection')
export const IsKanbanInj: InjectionKey<Ref<boolean>> = Symbol('is-kanban-injection')
export const IsLockedInj: InjectionKey<Ref<boolean>> = Symbol('is-locked-injection')
export const IsExpandedFormOpenInj: InjectionKey<Ref<boolean>> = Symbol('is-expanded-form-open-injection')
export const CellValueInj: InjectionKey<Ref<any>> = Symbol('cell-value-injection')
export const ActiveViewInj: InjectionKey<Ref<ViewType>> = Symbol('active-view-injection')
export const ReadonlyInj: InjectionKey<Ref<boolean>> = Symbol('readonly-injection')

6
packages/nocodb-nest/Dockerfile

@ -31,9 +31,9 @@ COPY ./package*.json ./
COPY ./docker/main.js ./docker/main.js
#COPY ./docker/start.sh /usr/src/appEntry/start.sh
COPY ./docker/start-litestream.sh /usr/src/appEntry/start.sh
COPY ./src/lib/public/css/*.css ./docker/public/css/
COPY ./src/lib/public/js/*.js ./docker/public/js/
COPY ./src/lib/public/favicon.ico ./docker/public/
COPY ./public/css/*.css ./docker/public/css/
COPY ./public/js/*.js ./docker/public/js/
COPY ./public/favicon.ico ./docker/public/
# install production dependencies,
# reduce node_module size with modclean & removing sqlite deps,

100
packages/nocodb-nest/litestream/Dockerfile

@ -0,0 +1,100 @@
FROM golang:alpine3.14 as lt
WORKDIR /usr/src/
RUN apk add --no-cache git make musl-dev gcc
# build litestream
RUN git clone https://github.com/benbjohnson/litestream.git litestream
RUN cd litestream ; go install ./cmd/litestream
RUN cp $GOPATH/bin/litestream /usr/src/lt
FROM node:12 as builder
WORKDIR /usr/src/app
# Copy application dependency manifests to the container image.
# A wildcard is used to ensure both package.json AND package-lock.json are copied.
# Copying this separately prevents re-running npm ci on every code change.
COPY ./package*.json ./
COPY ./docker/main.js ./docker/main.js
#COPY ./docker/start.sh /usr/src/appEntry/start.sh
COPY ./docker/start-litestream.sh /usr/src/appEntry/start.sh
# install production dependencies,
# reduce node_module size with modclean & removing sqlite deps,
# package built code into app.tar.gz & add execute permission to start.sh
RUN npm ci --production --quiet
RUN npx modclean --patterns="default:*" --ignore="nc-lib-gui/**,dayjs/**,express-status-monitor/**" --run
RUN rm -rf ./node_modules/sqlite3/deps
RUN tar -czf ../appEntry/app.tar.gz ./*
RUN chmod +x /usr/src/appEntry/start.sh
FROM alpine:3.14
#ENV AWS_ACCESS_KEY_ID=
#ENV AWS_SECRET_ACCESS_KEY=
#ENV AWS_BUCKET=
#WORKDIR /usr/src/
#
## Install go lang
#RUN apk add --no-cache git make musl-dev go
#
## Configure Go
#ENV GOROOT /usr/lib/go
#ENV GOPATH /go
#ENV PATH /go/bin:$PATH
#
#RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin
#
## build litestream
#
#RUN git clone https://github.com/benbjohnson/litestream.git litestream
#RUN cd litestream ; go install ./cmd/litestream
# Bug fix for segfault ( Convert PT_GNU_STACK program header into PT_PAX_FLAGS )
#RUN apk --update --no-cache add paxctl \
# && paxctl -cm $(which node)
WORKDIR /usr/src/app
ENV NC_DOCKER 0.6
ENV PORT 8080
ENV NC_TOOL_DIR=/usr/app/data/
# Copy application dependency manifests to the container image.
# A wildcard is used to ensure both package.json AND package-lock.json are copied.
# Copying this separately prevents re-running npm install on every code change.
#COPY ./build/ ./build/
#COPY ./docker/main.js ./docker/main.js
#COPY ./package.json ./
RUN apk --update --no-cache add \
nodejs \
tar
# Copy litestream binary build
COPY --from=lt /usr/src/lt /usr/src/appEntry/litestream
# Copy packaged production code & main entry file
COPY --from=builder /usr/src/appEntry/ /usr/src/appEntry/
# Run the web service on container startup.
#CMD [ "node", "docker/index.js" ]
ENTRYPOINT ["sh", "/usr/src/appEntry/start.sh"]

8
packages/nocodb-nest/package.json

@ -1,7 +1,7 @@
{
"name": "nocodb-nest",
"version": "0.0.1",
"description": "NocoDB Backend (Nest)",
"name": "nocodb",
"version": "0.106.1",
"description": "NocoDB Backend",
"main": "dist/bundle.js",
"author": {
"name": "NocoDB Inc",
@ -15,11 +15,11 @@
"bugs": {
"url": "https://github.com/nocodb/nocodb/issues"
},
"private": true,
"license": "AGPL-3.0-or-later",
"scripts": {
"build": "nest build",
"build:obfuscate": "EE=true webpack --config webpack.config.js",
"obfuscate:build:publish": "npm run build:obfuscate && npm publish .",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",

51
packages/nocodb-nest/src/db/BaseModelSqlv2.ts

@ -1602,17 +1602,16 @@ class BaseModelSqlv2 {
// hide if column marked as hidden in view
// of if column is system field and system field is hidden
if (
fieldsSet
? !fieldsSet.has(column.title)
: !extractPkAndPv &&
!(viewOrTableColumn instanceof Column) &&
(!(viewOrTableColumn as GridViewColumn)?.show ||
(!view?.show_system_fields &&
column.uidt !== UITypes.ForeignKey &&
!column.pk &&
isSystemColumn(column)))
)
shouldSkipField(
fieldsSet,
viewOrTableColumn,
view,
column,
extractPkAndPv,
)
) {
continue;
}
if (!checkColumnRequired(column, fields, extractPkAndPv)) continue;
@ -3385,4 +3384,36 @@ function haveFormulaColumn(columns: Column[]) {
return columns.some((c) => c.uidt === UITypes.Formula);
}
function shouldSkipField(
fieldsSet,
viewOrTableColumn,
view,
column,
extractPkAndPv,
) {
if (fieldsSet) {
return !fieldsSet.has(column.title);
} else {
if (!extractPkAndPv) {
if (!(viewOrTableColumn instanceof Column)) {
if (
!(viewOrTableColumn as GridViewColumn)?.show &&
!(column.rqd && !column.cdf && !column.ai) &&
!column.pk &&
column.uidt !== UITypes.ForeignKey
)
return true;
if (
!view?.show_system_fields &&
column.uidt !== UITypes.ForeignKey &&
!column.pk &&
isSystemColumn(column)
)
return true;
}
}
return false;
}
}
export { BaseModelSqlv2 };

13
packages/nocodb-nest/src/guards/global/global.guard.ts

@ -13,14 +13,17 @@ export class GlobalGuard extends AuthGuard(['jwt']) {
async canActivate(context: ExecutionContext) {
let result;
try {
result = await this.extractBoolVal(super.canActivate(context));
} catch (e) {
console.log(e);
}
const req = context.switchToHttp().getRequest();
if (req.headers?.['xc-auth']) {
try {
result = await this.extractBoolVal(super.canActivate(context));
} catch (e) {
console.log(e);
}
}
if (result && !req.headers['xc-shared-base-id']) {
if (
req.path.indexOf('/user/me') === -1 &&

3
packages/nocodb-nest/src/helpers/webhookHelpers.ts

@ -1,6 +1,7 @@
import Handlebars from 'handlebars';
import { v4 as uuidv4 } from 'uuid';
import { Filter, HookLog } from '../models';
import Noco from '../Noco';
import NcPluginMgrv2 from './NcPluginMgrv2';
import type { Column, FormView, Hook, Model, View } from '../models';
import type { HookLogType } from 'nocodb-sdk';
@ -135,7 +136,7 @@ export async function validateCondition(filters: Filter[], data: any) {
}
export function constructWebHookData(hook, model, view, prevData, newData) {
if (hook.version === 'v2') {
if (hook.version === 'v2' && !Noco.isEE()) {
// extend in the future - currently only support records
const scope = 'records';

4
packages/nocodb-nest/src/meta/migrations/XcMigrationSourcev2.ts

@ -17,6 +17,7 @@ import * as nc_026_map_view from './v2/nc_026_map_view';
import * as nc_027_add_comparison_sub_op from './v2/nc_027_add_comparison_sub_op';
import * as nc_028_add_enable_scanner_in_form_columns_meta_table from './v2/nc_028_add_enable_scanner_in_form_columns_meta_table';
import * as nc_029_webhook from './v2/nc_029_webhook';
import * as nc_030_add_description_field from './v2/nc_030_add_description_field';
// Create a custom migration source class
export default class XcMigrationSourcev2 {
@ -45,6 +46,7 @@ export default class XcMigrationSourcev2 {
'nc_027_add_comparison_sub_op',
'nc_028_add_enable_scanner_in_form_columns_meta_table',
'nc_029_webhook',
'nc_030_add_description_field',
]);
}
@ -92,6 +94,8 @@ export default class XcMigrationSourcev2 {
return nc_028_add_enable_scanner_in_form_columns_meta_table;
case 'nc_029_webhook':
return nc_029_webhook;
case 'nc_030_add_description_field':
return nc_030_add_description_field;
}
}
}

34
packages/nocodb-nest/src/meta/migrations/v2/nc_030_add_description_field.ts

@ -0,0 +1,34 @@
import type { Knex } from 'knex';
import { MetaTable } from '../../meta.service'
const up = async (knex: Knex) => {
await knex.schema.alterTable(MetaTable.BASES, (table) => {
table.string('description', 255);
});
await knex.schema.alterTable(MetaTable.MODELS, (table) => {
table.string('description', 255);
});
await knex.schema.alterTable(MetaTable.VIEWS, (table) => {
table.string('description', 255);
});
await knex.schema.alterTable(MetaTable.COLUMNS, (table) => {
table.string('description', 255);
});
};
const down = async (knex) => {
await knex.schema.alterTable(MetaTable.BASES, (table) => {
table.dropColumn('description');
});
await knex.schema.alterTable(MetaTable.MODELS, (table) => {
table.dropColumn('description');
});
await knex.schema.alterTable(MetaTable.VIEWS, (table) => {
table.dropColumn('description');
});
await knex.schema.alterTable(MetaTable.COLUMNS, (table) => {
table.dropColumn('description');
});
};
export { up, down };

1
packages/nocodb-nest/src/schema/swagger.json

@ -17087,7 +17087,6 @@
"description": "The license key",
"example": "1234567890",
"maxLength": 255,
"minLength": 10,
"type": "string"
}
},

3
packages/nocodb-nest/src/services/hooks.service.ts

@ -8,6 +8,7 @@ import {
} from '../helpers/populateSamplePayload';
import { invokeWebhook } from '../helpers/webhookHelpers';
import { Hook, HookLog, Model } from '../models';
import Noco from '../Noco';
import type { HookReqType, HookTestReqType, HookType } from 'nocodb-sdk';
@Injectable()
@ -107,7 +108,7 @@ export class HooksService {
}) {
const model = await Model.getByIdOrName({ id: param.tableId });
if (param.version === 'v1') {
if (param.version === 'v1' || (param.version === 'v2' && Noco.isEE())) {
return await populateSamplePayload(model, false, param.operation);
}
return await populateSamplePayloadV2(model, false, param.operation);

18
packages/nocodb-nest/src/services/public-datas.service.ts

@ -305,7 +305,9 @@ export class PublicDatasService {
if (!view) NcError.notFound('Not found');
if (view.type !== ViewTypes.FORM) NcError.notFound('Not found');
if (view.type !== ViewTypes.FORM && view.type !== ViewTypes.GALLERY) {
NcError.notFound('Not found');
}
if (view.password && view.password !== param.password) {
NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
@ -360,8 +362,13 @@ export class PublicDatasService {
const view = await View.getByUUID(param.sharedViewUuid);
if (!view) NcError.notFound('Not found');
if (view.type !== ViewTypes.GRID && view.type !== ViewTypes.KANBAN)
if (
view.type !== ViewTypes.GRID &&
view.type !== ViewTypes.KANBAN &&
view.type !== ViewTypes.GALLERY
) {
NcError.notFound('Not found');
}
if (view.password && view.password !== param.password) {
NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
@ -426,8 +433,13 @@ export class PublicDatasService {
const view = await View.getByUUID(param.sharedViewUuid);
if (!view) NcError.notFound('Not found');
if (view.type !== ViewTypes.GRID && view.type !== ViewTypes.KANBAN)
if (
view.type !== ViewTypes.GRID &&
view.type !== ViewTypes.KANBAN &&
view.type !== ViewTypes.GALLERY
) {
NcError.notFound('Not found');
}
if (view.password && view.password !== param.password) {
NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);

65
packages/nocodb-nest/src/strategies/authtoken.strategy/authtoken.strategy.ts

@ -2,53 +2,44 @@ import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-custom';
import { ApiToken, ProjectUser, User } from '../../models';
import type { Request } from 'express';
@Injectable()
export class AuthTokenStrategy extends PassportStrategy(Strategy, 'authtoken') {
constructor() {
super({
headerFields: ['xc-token'],
passReqToCallback: true,
});
}
// eslint-disable-next-line @typescript-eslint/ban-types
async validate(req: Request, token: string, done: Function) {
async validate(req: any, callback: Function) {
try {
const apiToken = await ApiToken.getByToken(token);
if (!apiToken) {
return done({ msg: 'Invalid token' });
}
let user;
if (req.headers['xc-token']) {
const apiToken = await ApiToken.getByToken(req.headers['xc-token']);
if (!apiToken) {
return callback({ msg: 'Invalid token' });
}
const user: any = {};
if (!apiToken.fk_user_id) {
user.roles = 'editor';
return done(null, user);
}
user = {};
if (!apiToken.fk_user_id) {
user.roles = 'editor';
return callback(null, user);
}
const dbUser: Record<string, any> = await User.get(apiToken.fk_user_id);
if (!dbUser) {
return done({ msg: 'User not found' });
}
const dbUser: Record<string, any> = await User.get(apiToken.fk_user_id);
if (!dbUser) {
return callback({ msg: 'User not found' });
}
dbUser.is_api_token = true;
if (req['ncProjectId']) {
const projectUser = await ProjectUser.get(
req['ncProjectId'],
dbUser.id,
);
user.roles = projectUser?.roles || dbUser.roles;
user.roles = user.roles === 'owner' ? 'owner,creator' : user.roles;
// + (user.roles ? `,${user.roles}` : '');
// todo : cache
// await NocoCache.set(`${CacheScope.USER}:${key}`, user);
return done(null, user);
dbUser.is_api_token = true;
if (req['ncProjectId']) {
const projectUser = await ProjectUser.get(
req['ncProjectId'],
dbUser.id,
);
user.roles = projectUser?.roles || dbUser.roles;
user.roles = user.roles === 'owner' ? 'owner,creator' : user.roles;
return callback(null, user);
}
}
return done(null, dbUser);
return callback(null, user);
} catch (error) {
return done(error);
return callback(error);
}
}
}

4
packages/nocodb-nest/src/strategies/jwt.strategy.ts

@ -1,6 +1,6 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { Strategy } from 'passport-jwt';
import { OrgUserRoles } from 'nocodb-sdk';
import NocoCache from '../cache/NocoCache';
import { ProjectUser, User } from '../models';

2
packages/nocodb/src/lib/migrations/XcMigrationSourcev2.ts

@ -46,7 +46,7 @@ export default class XcMigrationSourcev2 {
'nc_027_add_comparison_sub_op',
'nc_028_add_enable_scanner_in_form_columns_meta_table',
'nc_029_webhook',
'nc_030_add_description_field'
'nc_030_add_description_field',
]);
}

6
packages/nocodb/src/lib/migrations/v2/nc_030_add_description_field.ts

@ -2,9 +2,6 @@ import { MetaTable } from '../../utils/globals';
import type { Knex } from 'knex';
const up = async (knex: Knex) => {
await knex.schema.alterTable(MetaTable.PROJECT, (table) => {
table.string('description', 255);
});
await knex.schema.alterTable(MetaTable.BASES, (table) => {
table.string('description', 255);
});
@ -20,9 +17,6 @@ const up = async (knex: Knex) => {
};
const down = async (knex) => {
await knex.schema.alterTable(MetaTable.PROJECT, (table) => {
table.dropColumn('description');
});
await knex.schema.alterTable(MetaTable.BASES, (table) => {
table.dropColumn('description');
});

15
scripts/upgradeNcGui.js

@ -22,8 +22,8 @@ const replacePackageName = (filePath) => {
const bumbVersionAndSave = () => {
// upgrade nc-lib-gui version in nocodb
execSync(`cd packages/nocodb && npm install --save --save-exact ${ncLibPackage.name}@${ncLibPackage.version}`, {});
const nocodbPackageFilePath = path.join(__dirname, '..', 'packages', 'nocodb', 'package.json')
execSync(`cd packages/nocodb-nest && npm install --save --save-exact ${ncLibPackage.name}@${ncLibPackage.version}`, {});
const nocodbPackageFilePath = path.join(__dirname, '..', 'packages', 'nocodb-nest', 'package.json')
const nocoLibPackage = JSON.parse(fs.readFileSync(nocodbPackageFilePath))
if (process.env.targetEnv === 'DEV') {
nocoLibPackage.name = `${nocoLibPackage.name}-daily`
@ -35,11 +35,12 @@ const bumbVersionAndSave = () => {
if (process.env.targetEnv === 'DEV') {
// replace nc-lib-gui by nc-lib-gui-daily if it is nightly build / pr release
const filePaths = [
path.join(__dirname, '..', 'packages', 'nocodb', 'Dockerfile'),
path.join(__dirname, '..', 'packages', 'nocodb', 'litestream', 'Dockerfile'),
path.join(__dirname, '..', 'packages', 'nocodb', 'package.json'),
path.join(__dirname, '..', 'packages', 'nocodb', 'README.md'),
path.join(__dirname, '..', 'packages', 'nocodb', 'src', 'lib', 'Noco.ts'),
path.join(__dirname, '..', 'packages', 'nocodb-nest', 'Dockerfile'),
path.join(__dirname, '..', 'packages', 'nocodb-nest', 'litestream', 'Dockerfile'),
path.join(__dirname, '..', 'packages', 'nocodb-nest', 'package.json'),
path.join(__dirname, '..', 'packages', 'nocodb-nest', 'src', 'Noco.ts'),
path.join(__dirname, '..', 'packages', 'nocodb-nest', 'src', 'nocobuild.ts'),
path.join(__dirname, '..', 'packages', 'nocodb-nest', 'src', 'middlewares', 'gui', 'gui.middleware.ts'),
]
Promise.all(filePaths.map(filePath => { return replacePackageName(filePath) })).then(() => {
bumbVersionAndSave();

6
scripts/upgradeNocodbSdk.js

@ -20,7 +20,7 @@ const replacePackageName = (filePath) => {
const bumbVersionAndSave = () => {
// upgrade nocodb-sdk version in nocodb
execSync(`cd packages/nocodb && npm install --save --save-exact ${nocodbSdkPackage.name}@${nocodbSdkPackage.version}`, {});
execSync(`cd packages/nocodb-nest && npm install --save --save-exact ${nocodbSdkPackage.name}@${nocodbSdkPackage.version}`, {});
// upgrade nocodb-sdk version in nc-gui
execSync(`cd packages/nc-gui && npm install --save --save-exact ${nocodbSdkPackage.name}@${nocodbSdkPackage.version}`, {});
}
@ -47,9 +47,9 @@ const dfs = function(dir) {
const searchAndReplace = (target) => {
let list = [
...dfs(path.resolve(path.join(__dirname, '..', 'packages', 'nc-gui'))),
...dfs(path.resolve(path.join(__dirname, '..', 'packages', 'nocodb'))),
...dfs(path.resolve(path.join(__dirname, '..', 'packages', 'nocodb-nest'))),
path.join(__dirname, '..', 'packages', 'nc-gui', 'package.json'),
path.join(__dirname, '..', 'packages', 'nocodb', 'package.json')
path.join(__dirname, '..', 'packages', 'nocodb-nest', 'package.json')
]
return Promise.all(list.map(d => {
return new Promise((resolve, reject) => {

6
tests/playwright/setup/index.ts

@ -48,6 +48,12 @@ const setup = async ({ page, isEmptyProject }: { page: Page; isEmptyProject?: bo
}
const token = response.data.token;
try {
await axios.post(`http://localhost:8080/api/v1/license`, { key: '' }, { headers: { 'xc-auth': token } });
} catch (e) {
console.error(`Error resetting project: ${process.env.TEST_PARALLEL_INDEX}`, e);
}
await page.addInitScript(
async ({ token }) => {
try {

Loading…
Cancel
Save