Browse Source

fix(nocodb): update api

pull/7611/head
DarkPhoenix2704 9 months ago
parent
commit
8cc4f7e5e3
  1. 35
      packages/nc-gui/composables/useCalendarViewStore.ts
  2. 28
      packages/nc-gui/composables/useSharedView.ts
  3. 15
      packages/nocodb/src/controllers/public-datas.controller.ts
  4. 72
      packages/nocodb/src/db/BaseModelSqlv2.ts
  5. 77
      packages/nocodb/src/schema/swagger-v2.json
  6. 77
      packages/nocodb/src/schema/swagger.json
  7. 59
      packages/nocodb/src/services/datas.service.ts
  8. 66
      packages/nocodb/src/services/public-datas.service.ts

35
packages/nc-gui/composables/useCalendarViewStore.ts

@ -90,7 +90,7 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
const { sorts, nestedFilters } = useSmartsheetStoreOrThrow() const { sorts, nestedFilters } = useSmartsheetStoreOrThrow()
const { sharedView, fetchSharedViewData } = useSharedView() const { sharedView, fetchSharedViewData, fetchSharedViewActiveDate } = useSharedView()
const calendarMetaData = ref<CalendarType>({}) const calendarMetaData = ref<CalendarType>({})
@ -452,7 +452,7 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
prevDate = prevDate!.format('YYYY-MM-DD HH:mm:ssZ') prevDate = prevDate!.format('YYYY-MM-DD HH:mm:ssZ')
nextDate = nextDate!.format('YYYY-MM-DD HH:mm:ssZ') nextDate = nextDate!.format('YYYY-MM-DD HH:mm:ssZ')
fromDate = pageDate.value.format('YYYY-MM-DD HH:mm:ssZ') fromDate = fromDate!.format('YYYY-MM-DD HH:mm:ssZ')
const activeDateFilter: Array<any> = [] const activeDateFilter: Array<any> = []
@ -510,14 +510,21 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
}) })
if (!base?.value?.id || !meta.value?.id || !viewMeta.value?.id) return if (!base?.value?.id || !meta.value?.id || !viewMeta.value?.id) return
const res = await api.dbViewRow.calendarCount('noco', base.value.id!, meta.value!.id!, viewMeta.value.id, { const res = !isPublic.value
...queryParams.value, ? await api.dbViewRow.calendarCount('noco', base.value.id!, meta.value!.id!, viewMeta.value.id, {
...{}, ...queryParams.value,
...{}, ...{},
...{ filterArrJson: JSON.stringify([...filterJSON.value, ...activeDateFilter]) }, ...{},
}) ...{ filterArrJson: JSON.stringify([...filterJSON.value, ...activeDateFilter]) },
})
: await fetchSharedViewActiveDate({
sortsArr: sorts.value,
filtersArr: activeDateFilter,
})
if (res) { if (res) {
activeDates.value = res.map((dateObj: unknown) => dayjs(dateObj.date)) activeDates.value = res.map((dateObj: unknown) => dayjs(dateObj))
} else {
activeDates.value = []
} }
} }
@ -730,8 +737,14 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
if (sideBarFilterOption.value === 'selectedDate') { if (sideBarFilterOption.value === 'selectedDate') {
await loadSidebarData() await loadSidebarData()
} }
} else if (activeCalendarView.value === 'year') {
if (value.year() !== oldValue.year()) {
await Promise.all([loadCalendarData(), loadSidebarData(), await fetchActiveDates()])
} else if (sideBarFilterOption.value === 'selectedDate') {
await loadSidebarData()
}
} else { } else {
await Promise.all([loadCalendarData(), loadSidebarData()]) await Promise.all([loadSidebarData()])
} }
if (activeCalendarView.value === 'year' && value.year() !== oldValue.year()) { if (activeCalendarView.value === 'year' && value.year() !== oldValue.year()) {
@ -748,7 +761,7 @@ const [useProvideCalendarViewStore, useCalendarViewStore] = useInjectionState(
watch(selectedMonth, async (value, oldValue) => { watch(selectedMonth, async (value, oldValue) => {
if (activeCalendarView.value !== 'month') return if (activeCalendarView.value !== 'month') return
if (value.month() !== oldValue.month()) { if (value.month() !== oldValue.month()) {
await Promise.all([loadCalendarData(), loadSidebarData()]) await Promise.all([loadCalendarData(), loadSidebarData(), fetchActiveDates()])
} }
}) })

28
packages/nc-gui/composables/useSharedView.ts

@ -148,6 +148,33 @@ export function useSharedView() {
) )
} }
const fetchSharedViewActiveDate = async (param: {
sortsArr: SortType[]
filtersArr: FilterType[]
sort?: any[]
where?: string
}) => {
if (!sharedView.value)
return {
list: [],
pageInfo: {},
}
return await $api.public.calendarCount(
sharedView.value.uuid!,
{
...param,
filterArrJson: JSON.stringify(param.filtersArr ?? nestedFilters.value),
sortArrJson: JSON.stringify(param.sortsArr ?? sorts.value),
} as any,
{
headers: {
'xc-password': password.value,
},
},
)
}
const fetchSharedViewGroupedData = async ( const fetchSharedViewGroupedData = async (
columnId: string, columnId: string,
{ sortsArr, filtersArr }: { sortsArr: SortType[]; filtersArr: FilterType[] }, { sortsArr, filtersArr }: { sortsArr: SortType[]; filtersArr: FilterType[] },
@ -200,6 +227,7 @@ export function useSharedView() {
meta, meta,
nestedFilters, nestedFilters,
fetchSharedViewData, fetchSharedViewData,
fetchSharedViewActiveDate,
fetchSharedViewGroupedData, fetchSharedViewGroupedData,
paginationData, paginationData,
sorts, sorts,

15
packages/nocodb/src/controllers/public-datas.controller.ts

@ -34,6 +34,21 @@ export class PublicDatasController {
return pagedResponse; return pagedResponse;
} }
@Get([
'/api/v1/db/public/shared-view/:sharedViewUuid/countByDate',
'/api/v2/public/shared-view/:sharedViewUuid/countByDate',
])
async countByDate(
@Req() req: Request,
@Param('sharedViewUuid') sharedViewUuid: string,
) {
return await this.publicDatasService.getCalendarRecordCount({
query: req.query,
password: req.headers?.['xc-password'] as string,
sharedViewUuid,
});
}
@Get([ @Get([
'/api/v1/db/public/shared-view/:sharedViewUuid/groupby', '/api/v1/db/public/shared-view/:sharedViewUuid/groupby',
'/api/v2/public/shared-view/:sharedViewUuid/groupby', '/api/v2/public/shared-view/:sharedViewUuid/groupby',

72
packages/nocodb/src/db/BaseModelSqlv2.ts

@ -21,7 +21,7 @@ import { customAlphabet } from 'nanoid';
import DOMPurify from 'isomorphic-dompurify'; import DOMPurify from 'isomorphic-dompurify';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { Logger } from '@nestjs/common'; import { Logger } from '@nestjs/common';
import type { CalendarRangeType, SortType } from 'nocodb-sdk'; import type { SortType } from 'nocodb-sdk';
import type { Knex } from 'knex'; import type { Knex } from 'knex';
import type LookupColumn from '~/models/LookupColumn'; import type LookupColumn from '~/models/LookupColumn';
import type { XKnex } from '~/db/CustomKnex'; import type { XKnex } from '~/db/CustomKnex';
@ -251,76 +251,6 @@ class BaseModelSqlv2 {
return !!(await this.execAndParse(qb, null, { raw: true, first: true })); return !!(await this.execAndParse(qb, null, { raw: true, first: true }));
} }
public async countByRanges({
ranges,
model,
filterArr,
}: {
ranges: Partial<any>[];
model: Model;
filterArr?: Filter[];
}) {
const columns = await model.getColumns();
const queryRanges = [];
for (const range of ranges) {
let query;
if (range?.fk_from_column_id && range?.fk_to_column_id) {
query = this.dbDriver(
this.dbDriver.raw(
`(SELECT generate_series(
??,
??,
'1 day'
)::timestamptz AS date, ??::timestamptz, ??::timestamptz FROM ??) AS ??`,
[
columns.find((c) => c.id === range.fk_from_column_id).column_name,
columns.find((c) => c.id === range.fk_to_column_id).column_name,
columns.find((c) => c.id === range.fk_from_column_id).column_name,
columns.find((c) => c.id === range.fk_to_column_id).column_name,
this.tnPath,
range.id,
],
),
);
} else if (range.fk_from_column_id) {
query = this.dbDriver(
this.dbDriver.raw(
`(SELECT ??::timestamptz AS date, ??::timestamptz FROM ??) AS ?? `,
[
columns.find((c) => c.id === range.fk_from_column_id).column_name,
columns.find((c) => c.id === range.fk_from_column_id).column_name,
this.tnPath,
range.id,
],
),
);
}
if (query) {
await conditionV2(this, filterArr, query);
queryRanges.push(query);
}
}
const unionQuery = this.dbDriver.raw(
queryRanges.reduce(
(acc, range) =>
acc ? `${acc} UNION ALL ${range.toQuery()}` : range.toQuery(),
'',
),
);
const qb = this.dbDriver(this.dbDriver.raw(`(${unionQuery}) AS ??`, ['nc']))
.select('date')
.count('* as count')
.groupBy('date')
.orderBy('date');
return await this.execAndParse(qb);
}
// todo: add support for sortArrJson // todo: add support for sortArrJson
public async findOne( public async findOne(
args: { args: {

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

@ -7273,6 +7273,83 @@
"description": "List Shared View Grouped Data" "description": "List Shared View Grouped Data"
} }
}, },
"/api/v2/public/shared-view/{sharedViewUuid}/countByDate": {
"parameters": [
{
"schema": {
"type": "string",
"example": "24a6d0bb-e45d-4b1a-bfef-f492d870de9f"
},
"name": "sharedViewUuid",
"in": "path",
"required": true,
"description": "Shared View UUID"
},
{
"schema": {
"type": "string"
},
"in": "header",
"name": "xc-password",
"description": "Shared view password"
}
],
"get": {
"summary": "Count of Records in Dates in Calendar View",
"operationId": "public-calendar-count",
"parameters": [
{
"schema": {
"type": "array"
},
"in": "query",
"name": "sort"
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "where"
},
{
"schema": {
"type": "integer",
"minimum": 1
},
"in": "query",
"name": "limit"
},
{
"schema": {
"type": "integer",
"minimum": 0
},
"in": "query",
"name": "offset"
},
{
"$ref": "#/components/parameters/xc-auth"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
}
},
"tags": [
"Public"
]
}
},
"/api/v2/public/shared-view/{sharedViewUuid}/rows": { "/api/v2/public/shared-view/{sharedViewUuid}/rows": {
"parameters": [ "parameters": [
{ {

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

@ -12118,6 +12118,83 @@
"description": "List Shared View Grouped Data" "description": "List Shared View Grouped Data"
} }
}, },
"/api/v1/db/public/shared-view/{sharedViewUuid}/countByDate": {
"parameters": [
{
"schema": {
"type": "string",
"example": "24a6d0bb-e45d-4b1a-bfef-f492d870de9f"
},
"name": "sharedViewUuid",
"in": "path",
"required": true,
"description": "Shared View UUID"
},
{
"schema": {
"type": "string"
},
"in": "header",
"name": "xc-password",
"description": "Shared view password"
}
],
"get": {
"summary": "Count of Records in Dates in Calendar View",
"operationId": "public-calendar-count",
"parameters": [
{
"schema": {
"type": "array"
},
"in": "query",
"name": "sort"
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "where"
},
{
"schema": {
"type": "integer",
"minimum": 1
},
"in": "query",
"name": "limit"
},
{
"schema": {
"type": "integer",
"minimum": 0
},
"in": "query",
"name": "offset"
},
{
"$ref": "#/components/parameters/xc-auth"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
}
},
"tags": [
"Public"
]
}
},
"/api/v1/db/public/shared-view/{sharedViewUuid}/rows": { "/api/v1/db/public/shared-view/{sharedViewUuid}/rows": {
"parameters": [ "parameters": [
{ {

59
packages/nocodb/src/services/datas.service.ts

@ -3,6 +3,7 @@ import { isSystemColumn, ViewTypes } from 'nocodb-sdk';
import * as XLSX from 'xlsx'; import * as XLSX from 'xlsx';
import papaparse from 'papaparse'; import papaparse from 'papaparse';
import { nocoExecute } from 'nc-help'; import { nocoExecute } from 'nc-help';
import dayjs from 'dayjs';
import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2'; import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2';
import type { PathParams } from '~/modules/datas/helpers'; import type { PathParams } from '~/modules/datas/helpers';
import { getDbRows, getViewAndModelByAliasOrId } from '~/modules/datas/helpers'; import { getDbRows, getViewAndModelByAliasOrId } from '~/modules/datas/helpers';
@ -214,8 +215,6 @@ export class DatasService {
if (view.type !== ViewTypes.CALENDAR) if (view.type !== ViewTypes.CALENDAR)
NcError.badRequest('View is not a calendar view'); NcError.badRequest('View is not a calendar view');
const source = await Source.get(view.source_id);
const { ranges } = await CalendarRange.read(view.id); const { ranges } = await CalendarRange.read(view.id);
if (!ranges.length) NcError.badRequest('No ranges found'); if (!ranges.length) NcError.badRequest('No ranges found');
@ -224,32 +223,48 @@ export class DatasService {
id: view.fk_model_id, id: view.fk_model_id,
}); });
const baseModel = await Model.getBaseModelSQL({ const data = await this.getDataList({
id: view.fk_model_id,
viewId: view?.id,
dbDriver: await NcConnectionMgrv2.get(source),
});
const { dependencyFields } = await getAst({
model, model,
query,
view, view,
extractOnlyRangeFields: true, query,
}); });
const listArgs: any = dependencyFields; if (!data) NcError.notFound('Data not found');
try {
listArgs.filterArr = JSON.parse(listArgs.filterArrJson);
} catch (e) {}
try {
listArgs.sortArr = JSON.parse(listArgs.sortArrJson);
} catch (e) {}
return await baseModel.countByRanges({ const dates: Array<string> = [];
model,
ranges, ranges.forEach((range) => {
...listArgs, data.list.forEach((date) => {
const from =
date[
model.columns.find((c) => c.id === range.fk_from_column_id).title
];
let to;
if (range.fk_to_column_id) {
to =
date[
model.columns.find((c) => c.id === range.fk_to_column_id).title
];
}
if (from && to) {
const fromDt = dayjs(from);
const toDt = dayjs(to);
let current = fromDt;
while (current.isSameOrBefore(toDt)) {
dates.push(current.format('YYYY-MM-DD HH:mm:ssZ'));
current = current.add(1, 'day');
}
} else if (from) {
dates.push(dayjs(from).format('YYYY-MM-DD HH:mm:ssZ'));
}
});
}); });
return dates;
} }
async getFindOne(param: { model: Model; view: View; query: any }) { async getFindOne(param: { model: Model; view: View; query: any }) {

66
packages/nocodb/src/services/public-datas.service.ts

@ -5,7 +5,9 @@ import { ErrorMessages, UITypes, ViewTypes } from 'nocodb-sdk';
import slash from 'slash'; import slash from 'slash';
import { nocoExecute } from 'nc-help'; import { nocoExecute } from 'nc-help';
import dayjs from 'dayjs';
import type { LinkToAnotherRecordColumn } from '~/models'; import type { LinkToAnotherRecordColumn } from '~/models';
import { CalendarRange } from '~/models';
import { NcError } from '~/helpers/catchError'; import { NcError } from '~/helpers/catchError';
import getAst from '~/helpers/getAst'; import getAst from '~/helpers/getAst';
import NcPluginMgrv2 from '~/helpers/NcPluginMgrv2'; import NcPluginMgrv2 from '~/helpers/NcPluginMgrv2';
@ -97,6 +99,70 @@ export class PublicDatasService {
return new PagedResponseImpl(data, { ...param.query, count }); return new PagedResponseImpl(data, { ...param.query, count });
} }
async getCalendarRecordCount(param: {
sharedViewUuid: string;
password?: string;
query: any;
}) {
const { sharedViewUuid, password, query = {} } = param;
const view = await View.getByUUID(sharedViewUuid);
if (!view) NcError.notFound('Not found');
if (view.password && view.password !== password) {
return NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
}
if (view.type !== ViewTypes.CALENDAR)
NcError.badRequest('View is not a calendar view');
const { ranges } = await CalendarRange.read(view.id);
const model = await Model.getByIdOrName({
id: view.fk_model_id,
});
const columns = await model.getColumns();
const data: any = await this.dataList({
sharedViewUuid,
password,
query,
});
if (!data) NcError.notFound('Data not found');
const dates: Array<string> = [];
ranges.forEach((range) => {
data.list.forEach((date) => {
const from =
date[columns.find((c) => c.id === range.fk_from_column_id).title];
let to;
if (range.fk_to_column_id) {
to = date[columns.find((c) => c.id === range.fk_to_column_id).title];
}
if (from && to) {
const fromDt = dayjs(from);
const toDt = dayjs(to);
let current = fromDt;
while (current.isSameOrBefore(toDt)) {
dates.push(current.format('YYYY-MM-DD HH:mm:ssZ'));
current = current.add(1, 'day');
}
} else if (from) {
dates.push(dayjs(from).format('YYYY-MM-DD HH:mm:ssZ'));
}
});
});
return dates;
}
// todo: Handle the error case where view doesnt belong to model // todo: Handle the error case where view doesnt belong to model
async groupedDataList(param: { async groupedDataList(param: {
sharedViewUuid: string; sharedViewUuid: string;

Loading…
Cancel
Save