Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add getEntriesData endpoint #227

Merged
merged 24 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c70679a
Add getEntriesData endpoint
stepanenkoxx Dec 27, 2024
3292ab3
Add dlsEnabled check
stepanenkoxx Dec 27, 2024
0bc143c
Add getEntriesData endpoint
stepanenkoxx Dec 27, 2024
af8e47b
Fix generic type
stepanenkoxx Dec 28, 2024
6f3ce39
Fix checkFolderEntriesPermissions
stepanenkoxx Dec 28, 2024
94088c2
Add getEntriesData endpoint
stepanenkoxx Dec 28, 2024
5cc2ab8
fix checkBulkPermission type
stepanenkoxx Dec 28, 2024
414cc21
Merge branch 'main' into CHARTS-10806-add-get-entries-data-endpoint
stepanenkoxx Jan 9, 2025
106582f
Merge branch 'main' into CHARTS-10806-add-get-entries-data-endpoint
stepanenkoxx Jan 13, 2025
410e4ac
Update to new controller
stepanenkoxx Jan 13, 2025
e8e9419
Fix permission
stepanenkoxx Jan 13, 2025
6323782
make scope param optional
stepanenkoxx Jan 13, 2025
5d6f22a
fix api tag
stepanenkoxx Jan 13, 2025
8a74b2e
Merge branch 'main' into CHARTS-10806-add-get-entries-data-endpoint
stepanenkoxx Jan 14, 2025
98fc5b3
Some review fixes
stepanenkoxx Jan 14, 2025
0a4b7b9
keep entries order
stepanenkoxx Jan 15, 2025
32bb370
Merge branch 'main' into CHARTS-10806-add-get-entries-data-endpoint
stepanenkoxx Jan 15, 2025
3369f9a
Merge branch 'main' into CHARTS-10806-add-get-entries-data-endpoint
stepanenkoxx Jan 15, 2025
cf480af
tests
stepanenkoxx Jan 15, 2025
9403e13
log fields
stepanenkoxx Jan 15, 2025
522eff8
remove folder tests
stepanenkoxx Jan 16, 2025
0067d3b
fixes
stepanenkoxx Jan 16, 2025
9fc6c61
Merge branch 'main' into CHARTS-10806-add-get-entries-data-endpoint
stepanenkoxx Jan 17, 2025
ef5f4ca
review fixes
stepanenkoxx Jan 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/components/response-presenter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ export default ({data}: {data: any}): ST.ServiceResponse => {
};
};

export async function prepareResponseAsync({data}: {data: any}): Promise<ST.ServiceResponse> {
export async function prepareResponseAsync<T extends any = any>({
imsitnikov marked this conversation as resolved.
Show resolved Hide resolved
data,
}: {
data: T;
}): Promise<ST.ServiceResponse<T>> {
const response = await Utils.macrotasksEncodeData(data);

if (response.results) {
Expand Down
12 changes: 1 addition & 11 deletions src/const/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,7 @@ export const RETURN_WORKBOOK_COLUMNS = [
'createdAt',
];

export const ALLOWED_SCOPE_VALUES = [
'dataset',
'pdf',
'folder',
'dash',
'connection',
'widget',
'config',
'presentation',
'report',
];
export const ALLOWED_SCOPE_VALUES = Object.values(EntryScope);

export const ID_VARIABLES = [
'ids',
Expand Down
2 changes: 2 additions & 0 deletions src/controllers/entries/get-entries-data/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const NOT_FOUND_ERROR_CODE = 'NOT_FOUND';
export const ACCESS_DENIED_ERROR_CODE = 'ACCESS_DENIED';
75 changes: 75 additions & 0 deletions src/controllers/entries/get-entries-data/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {AppRouteHandler, Request, Response} from '@gravity-ui/expresskit';

import {ApiTag} from '../../../components/api-docs';
import {makeReqParser, z, zc} from '../../../components/zod';
import {CONTENT_TYPE_JSON} from '../../../const';
import {EntryScope} from '../../../db/models/new/entry/types';
import {getJoinedEntriesRevisionsByIds} from '../../../services/new/entry';

import type {GetEntriesDataResponseBody} from './response-model';
import {entriesData} from './response-model';

const requestSchema = {
body: z.object({
entryIds: zc.encodedIdArray({min: 1, max: 1000}),
scope: z.nativeEnum(EntryScope).optional(),
type: z.string().optional(),
fields: z.string().array().min(1).max(100),
}),
};

export type GetEntriesDataRequestBody = z.infer<typeof requestSchema.body>;

const parseReq = makeReqParser(requestSchema);

const controller: AppRouteHandler = async (
req: Request,
res: Response<GetEntriesDataResponseBody>,
) => {
const {body} = await parseReq(req);

const result = await getJoinedEntriesRevisionsByIds(
{ctx: req.ctx},
{
entryIds: body.entryIds,
scope: body.scope,
type: body.type,
},
);

req.ctx.log('FILTERED_FIELDS', {
fields: body.fields,
});

const response = entriesData.format({result, entryIds: body.entryIds, fields: body.fields});

res.status(200).send(response);
};

controller.api = {
summary: 'Get entries data',
tags: [ApiTag.Entries],
request: {
body: {
content: {
[CONTENT_TYPE_JSON]: {
schema: requestSchema.body,
},
},
},
},
responses: {
200: {
description: entriesData.schema.description ?? '',
content: {
[CONTENT_TYPE_JSON]: {
schema: entriesData.schema,
},
},
},
},
};

controller.manualDecodeId = true;

export {controller as getEntriesData};
94 changes: 94 additions & 0 deletions src/controllers/entries/get-entries-data/response-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import _ from 'lodash';

import {z, zc} from '../../../components/zod';
import {EntryScope} from '../../../db/models/new/entry/types';
import type {GetJoinedEntriesRevisionsByIdsResult} from '../../../services/new/entry';
import Utils from '../../../utils';

import {ACCESS_DENIED_ERROR_CODE, NOT_FOUND_ERROR_CODE} from './constants';

const errorSchema = z.object({
error: z.object({
code: z.enum([NOT_FOUND_ERROR_CODE, ACCESS_DENIED_ERROR_CODE]),
}),
});

const resultSchema = z.object({
result: z.object({
scope: z.nativeEnum(EntryScope),
type: z.string(),
data: z.record(z.unknown()),
}),
});

const schema = z
.object({
entryId: zc.encodedId(),
})
.and(z.union([resultSchema, errorSchema]))
.array()
.describe('Entries data');

type ResponseItemResult = z.infer<typeof resultSchema>['result'];

export type GetEntriesDataResponseBody = z.infer<typeof schema>;

const format = ({
result,
entryIds,
fields,
}: {
result: GetJoinedEntriesRevisionsByIdsResult;
entryIds: string[];
fields: string[];
}): GetEntriesDataResponseBody => {
const {entries, accessDeniedEntryIds} = result;

const formattedResult: GetEntriesDataResponseBody = [];

entryIds.forEach((entryId) => {
const entry = entries[entryId];
const encodedEntryId = Utils.encodeId(entryId);

if (entry) {
let responseData: ResponseItemResult['data'];
const {data, scope, type} = entry;

if (data) {
responseData = fields.reduce<ResponseItemResult['data']>((acc, fieldPath) => {
acc[fieldPath] = _.get(data, fieldPath);

return acc;
}, {});
} else {
responseData = {};
}

formattedResult.push({
entryId: encodedEntryId,
result: {
scope,
type,
data: responseData,
},
});
} else if (accessDeniedEntryIds.includes(entryId)) {
formattedResult.push({
entryId: encodedEntryId,
error: {code: ACCESS_DENIED_ERROR_CODE},
});
} else {
formattedResult.push({
entryId: encodedEntryId,
error: {code: NOT_FOUND_ERROR_CODE},
});
}
});

return formattedResult;
};

export const entriesData = {
schema,
format,
};
24 changes: 14 additions & 10 deletions src/controllers/entries.ts → src/controllers/entries/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {Request, Response} from '@gravity-ui/expresskit';

import {prepareResponseAsync} from '../components/response-presenter';
import {US_MASTER_TOKEN_HEADER} from '../const';
import {EntryScope} from '../db/models/new/entry/types';
import {prepareResponseAsync} from '../../components/response-presenter';
import {US_MASTER_TOKEN_HEADER} from '../../const';
import {EntryScope} from '../../db/models/new/entry/types';
import {
DeleteEntryData,
GetEntryRevisionsData,
Expand All @@ -13,9 +13,9 @@ import {
renameEntry,
switchRevisionEntry,
updateEntry,
} from '../services/entry';
import EntryService from '../services/entry.service';
import NavigationService from '../services/navigation.service';
} from '../../services/entry';
import EntryService from '../../services/entry.service';
import NavigationService from '../../services/navigation.service';
import {
GetEntryArgs,
GetEntryMetaPrivateArgs,
Expand All @@ -24,15 +24,17 @@ import {
getEntry,
getEntryMeta,
getEntryMetaPrivate,
} from '../services/new/entry';
} from '../../services/new/entry';
import {
formatEntryModel,
formatGetEntryMetaPrivateResponse,
formatGetEntryMetaResponse,
formatGetEntryResponse,
} from '../services/new/entry/formatters';
import * as ST from '../types/services.types';
import Utils from '../utils';
} from '../../services/new/entry/formatters';
import * as ST from '../../types/services.types';
import Utils from '../../utils';

import {getEntriesData} from './get-entries-data';

export default {
getEntry: async (req: Request, res: Response) => {
Expand Down Expand Up @@ -320,4 +322,6 @@ export default {

res.status(code).send(response);
},

getEntriesData,
};
6 changes: 3 additions & 3 deletions src/registry/common/components/dls/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ export interface DLSConstructor {
checkPermissionsArgs: MT.CheckPermissionDlsConfig,
) => Promise<any>;

checkBulkPermission(
checkBulkPermission<E extends object>(
Copy link
Contributor Author

@stepanenkoxx stepanenkoxx Dec 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should probably be {entryId: string} not object
But we have some usages where entity type is {entryId?: string}

{ctx, trx}: {ctx: AppContext; trx?: TransactionOrKnex},
checkBulkPermissionArgs: MT.CheckBulkPermissionsDlsConfig,
): Promise<any[]>;
checkBulkPermissionArgs: MT.CheckBulkPermissionsDlsConfig<E>,
): Promise<Array<E & MT.DlsEntity>>;

addEntity(
{ctx, trx}: {ctx: AppContext; trx?: TransactionOrKnex},
Expand Down
5 changes: 5 additions & 0 deletions src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ export function getRoutes(_nodekit: NodeKit, options: GetRoutesOptions) {
private: true,
}),

getEntriesData: makeRoute({
route: 'POST /v1/get-entries-data',
handler: entriesController.getEntriesData,
}),

verifyLockExistence: makeRoute({
route: 'GET /v1/locks/:entryId',
handler: locksController.verifyExistence,
Expand Down
2 changes: 1 addition & 1 deletion src/services/entry/actions/create-in-workbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const validateCreateEntryInWorkbook = makeSchemaValidator({
},
scope: {
type: 'string',
enum: ['connection', 'dataset', 'dash', 'widget', 'presentation', 'report'],
enum: ['connection', 'dataset', 'dash', 'widget', 'report'],
},
type: {
type: 'string',
Expand Down
Loading
Loading