Skip to content

Commit

Permalink
Add new methods markCollectionsAsDeleted and markWorkbooksAsDeleted (#…
Browse files Browse the repository at this point in the history
…197)

* Add to registry method markWorkbooksAsDeleted

* Add new method for delete workbooks

* Add clear permissions

* Add new method markCollectionsAsDeleted

* Refactor

* Add getting patents

* Rm

* Fix check pemissions

* fix
  • Loading branch information
Sergey-weber authored Nov 8, 2024
1 parent 4d67a31 commit 50743c8
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 108 deletions.
4 changes: 4 additions & 0 deletions src/registry/common/entities/collection/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ export const Collection: CollectionConstructor = class Collection implements Col
this.permissions = permissions;
}

async deletePermissions(): Promise<void> {
this.permissions = undefined;
}

async fetchAllPermissions() {
this.permissions = this.getAllPermissions();
return Promise.resolve();
Expand Down
2 changes: 2 additions & 0 deletions src/registry/common/entities/structure-item/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export interface StructureItemInstance {

setPermissions(permissions: CollectionPermissions | WorkbookPermissions): void;

deletePermissions(args: {parentIds: string[]; skipCheckPermissions?: boolean}): Promise<void>;

enableAllPermissions(): void;

fetchAllPermissions(args: {parentIds: string[]}): Promise<void>;
Expand Down
4 changes: 4 additions & 0 deletions src/registry/common/entities/workbook/workbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export const Workbook: WorkbookConstructor<WorkbookInstance> = class Workbook
this.permissions = permissions;
}

async deletePermissions(): Promise<void> {
this.permissions = undefined;
}

enableAllPermissions() {
this.permissions = {
listAccessBindings: true,
Expand Down
161 changes: 90 additions & 71 deletions src/services/new/collection/delete-collections.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import {ServiceArgs} from '../types';
import {getPrimary} from '../utils';
import {getPrimary, getReplica} from '../utils';
import {deleteWorkbooks} from '../workbook';
import {makeSchemaValidator} from '../../../components/validation-schema-compiler';
import {CURRENT_TIMESTAMP, US_ERRORS} from '../../../const';
import {raw, transaction} from 'objection';
import {US_ERRORS} from '../../../const';
import {transaction} from 'objection';
import {CollectionModel, CollectionModelColumn} from '../../../db/models/new/collection';
import {WorkbookModel, WorkbookModelColumn} from '../../../db/models/new/workbook';
import Utils from '../../../utils';
import {CollectionPermission} from '../../../entities/collection';
import {AppError} from '@gravity-ui/nodekit';
import {getCollectionsListByIds} from './get-collections-list-by-ids';
import {markCollectionsAsDeleted} from './utils/mark-collections-as-deleted';
import {getParents, getParentsIdsFromMap} from './utils';
import {registry} from '../../../registry';
import {CollectionInstance} from '../../../registry/common/entities/collection/types';

const validateArgs = makeSchemaValidator({
type: 'object',
Expand All @@ -32,11 +36,7 @@ export const deleteCollections = async (
) => {
const {collectionIds} = args;

const {
tenantId,
projectId,
user: {userId},
} = ctx.get('info');
const {tenantId, projectId} = ctx.get('info');

ctx.log('DELETE_COLLECTIONS_START', {
collectionIds: await Utils.macrotasksMap(collectionIds, (id) => Utils.encodeId(id)),
Expand All @@ -49,65 +49,91 @@ export const deleteCollections = async (
const targetTrx = getPrimary(trx);

await getCollectionsListByIds(
{ctx, trx: targetTrx, skipValidation, skipCheckPermissions},
{ctx, trx: getReplica(trx), skipValidation, skipCheckPermissions},
{collectionIds, permission: CollectionPermission.Delete},
);

const result = await transaction(targetTrx, async (transactionTrx) => {
const recursiveName = 'collectionChildren';

const collectionsForDelete = await CollectionModel.query(transactionTrx)
.withRecursive(recursiveName, (qb1) => {
qb1.select()
.from(CollectionModel.tableName)
.where({
[CollectionModelColumn.TenantId]: tenantId,
[CollectionModelColumn.ProjectId]: projectId,
[CollectionModelColumn.DeletedAt]: null,
})
.whereIn([CollectionModelColumn.CollectionId], collectionIds)
.union((qb2) => {
qb2.select(`${CollectionModel.tableName}.*`)
.from(CollectionModel.tableName)
.where({
[`${CollectionModel.tableName}.${CollectionModelColumn.TenantId}`]:
tenantId,
[`${CollectionModel.tableName}.${CollectionModelColumn.ProjectId}`]:
projectId,
[`${CollectionModel.tableName}.${CollectionModelColumn.DeletedAt}`]:
null,
})
.join(
recursiveName,
`${recursiveName}.${CollectionModelColumn.CollectionId}`,
`${CollectionModel.tableName}.${CollectionModelColumn.ParentId}`,
);
});
})
.select()
.from(recursiveName)
.timeout(CollectionModel.DEFAULT_QUERY_TIMEOUT);

const collectionsForDeleteIds = collectionsForDelete.map((item) => item.collectionId);

const workbooksForDelete = await WorkbookModel.query(transactionTrx)
.select()
.where(WorkbookModelColumn.CollectionId, 'in', collectionsForDeleteIds)
.where({
[WorkbookModelColumn.DeletedAt]: null,
})
.timeout(WorkbookModel.DEFAULT_QUERY_TIMEOUT);

for (const workbook of workbooksForDelete) {
if (workbook.isTemplate) {
throw new AppError("Collection with workbook template can't be deleted", {
code: US_ERRORS.COLLECTION_WITH_WORKBOOK_TEMPLATE_CANT_BE_DELETED,
const recursiveName = 'collectionChildren';

const collectionsForDelete = await CollectionModel.query(getReplica(trx))
.withRecursive(recursiveName, (qb1) => {
qb1.select()
.from(CollectionModel.tableName)
.where({
[CollectionModelColumn.TenantId]: tenantId,
[CollectionModelColumn.ProjectId]: projectId,
[CollectionModelColumn.DeletedAt]: null,
})
.whereIn([CollectionModelColumn.CollectionId], collectionIds)
.union((qb2) => {
qb2.select(`${CollectionModel.tableName}.*`)
.from(CollectionModel.tableName)
.where({
[`${CollectionModel.tableName}.${CollectionModelColumn.TenantId}`]:
tenantId,
[`${CollectionModel.tableName}.${CollectionModelColumn.ProjectId}`]:
projectId,
[`${CollectionModel.tableName}.${CollectionModelColumn.DeletedAt}`]:
null,
})
.join(
recursiveName,
`${recursiveName}.${CollectionModelColumn.CollectionId}`,
`${CollectionModel.tableName}.${CollectionModelColumn.ParentId}`,
);
});
}
})
.select()
.from(recursiveName)
.timeout(CollectionModel.DEFAULT_QUERY_TIMEOUT);

const collectionsForDeleteIds = collectionsForDelete.map((item) => item.collectionId);

const collectionsMap = new Map<CollectionInstance, string[]>();

const parents = await getParents({
ctx,
trx: getReplica(trx),
collectionIds: collectionsForDeleteIds,
});

const parentsMap = new Map<string, Nullable<string>>();

parents.forEach((parent: CollectionModel) => {
parentsMap.set(parent.collectionId, parent.parentId);
});

const {Collection} = registry.common.classes.get();

collectionsForDelete.forEach((model) => {
const parentId = model.parentId;

const parentsForCollection = getParentsIdsFromMap(parentId, parentsMap);

const collection = new Collection({ctx, model});

collectionsMap.set(collection, parentsForCollection);
});

const workbooksForDelete = await WorkbookModel.query(getReplica(trx))
.select()
.where(WorkbookModelColumn.CollectionId, 'in', collectionsForDeleteIds)
.where({
[WorkbookModelColumn.DeletedAt]: null,
})
.timeout(WorkbookModel.DEFAULT_QUERY_TIMEOUT);

for (const workbook of workbooksForDelete) {
if (workbook.isTemplate) {
throw new AppError("Collection with workbook template can't be deleted", {
code: US_ERRORS.COLLECTION_WITH_WORKBOOK_TEMPLATE_CANT_BE_DELETED,
});
}
}

const workbookIds = workbooksForDelete.map((workbook) => workbook.workbookId);
const workbookIds = workbooksForDelete.map((workbook) => workbook.workbookId);

const result = await transaction(targetTrx, async (transactionTrx) => {
if (workbookIds.length) {
await deleteWorkbooks(
{ctx, trx: transactionTrx, skipCheckPermissions: true},
Expand All @@ -117,17 +143,10 @@ export const deleteCollections = async (
);
}

const deletedCollections = await CollectionModel.query(transactionTrx)
.patch({
[CollectionModelColumn.DeletedBy]: userId,
[CollectionModelColumn.DeletedAt]: raw(CURRENT_TIMESTAMP),
})
.where(CollectionModelColumn.CollectionId, 'in', collectionsForDeleteIds)
.andWhere({
[CollectionModelColumn.DeletedAt]: null,
})
.returning('*')
.timeout(CollectionModel.DEFAULT_QUERY_TIMEOUT);
const deletedCollections = await markCollectionsAsDeleted(
{ctx, trx, skipCheckPermissions: true},
{collectionsMap},
);

return deletedCollections;
});
Expand Down
18 changes: 18 additions & 0 deletions src/services/new/collection/utils/get-parents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,21 @@ export const getCollectionsParentIds = async ({
const parents = await getParents({ctx, trx, collectionIds});
return parents.map((item) => item.collectionId);
};

export const getParentsIdsFromMap = (
collectionId: string | null,
parentsMap: Map<string, Nullable<string>>,
): string[] => {
let id: Nullable<string> = collectionId;
const arr: string[] = id ? [id] : [];

while (id !== null) {
const curr: Nullable<string> = parentsMap.get(id) || null;

if (curr) arr.push(curr);

id = curr;
}

return arr;
};
48 changes: 48 additions & 0 deletions src/services/new/collection/utils/mark-collections-as-deleted.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {raw} from 'objection';
import {CURRENT_TIMESTAMP} from '../../../../const';
import {ServiceArgs} from '../../types';
import {getPrimary} from '../../utils';
import {CollectionModel, CollectionModelColumn} from '../../../../db/models/new/collection';
import {CollectionInstance} from '../../../../registry/common/entities/collection/types';

export const markCollectionsAsDeleted = async (
{ctx, trx, skipCheckPermissions}: ServiceArgs,
{collectionsMap}: {collectionsMap: Map<CollectionInstance, string[]>},
) => {
const collectionIds: string[] = [];

collectionsMap.forEach((parentIds, collectionInstance) => {
collectionIds.push(collectionInstance.model.collectionId);
});

const {
user: {userId},
} = ctx.get('info');

const deletedCollections = await CollectionModel.query(getPrimary(trx))
.patch({
[CollectionModelColumn.DeletedBy]: userId,
[CollectionModelColumn.DeletedAt]: raw(CURRENT_TIMESTAMP),
})
.where(CollectionModelColumn.CollectionId, 'in', collectionIds)
.andWhere({
[CollectionModelColumn.DeletedAt]: null,
})
.returning('*')
.timeout(CollectionModel.DEFAULT_QUERY_TIMEOUT);

const deletePermissionsPromises: Promise<void>[] = [];

collectionsMap.forEach((parentIds, collectionInstance) => {
deletePermissionsPromises.push(
collectionInstance.deletePermissions({
parentIds,
skipCheckPermissions,
}),
);
});

await Promise.all(deletePermissionsPromises);

return deletedCollections;
};
39 changes: 21 additions & 18 deletions src/services/new/workbook/delete-workbooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ import {getParentIds} from '../collection/utils/get-parents';
import {ServiceArgs} from '../types';
import {getPrimary} from '../utils';
import {makeSchemaValidator} from '../../../components/validation-schema-compiler';
import {US_ERRORS, CURRENT_TIMESTAMP} from '../../../const';
import {raw, transaction} from 'objection';
import {WorkbookModel, WorkbookModelColumn} from '../../../db/models/new/workbook';
import {US_ERRORS} from '../../../const';
import {transaction} from 'objection';
import Lock from '../../../db/models/lock';
import {Entry, EntryColumn} from '../../../db/models/new/entry';
import Utils, {makeUserId} from '../../../utils';
import {WorkbookPermission} from '../../../entities/workbook';
import {markEntryAsDeleted} from '../../entry/crud';
import {getWorkbooksListByIds} from './get-workbooks-list-by-ids';
import {markWorkbooksAsDeleted} from './utils';
import {WorkbookInstance} from '../../../registry/common/entities/workbook/types';

const validateArgs = makeSchemaValidator({
type: 'object',
Expand Down Expand Up @@ -57,16 +58,18 @@ export const deleteWorkbooks = async (
{workbookIds},
);

const workbooksMap: Map<WorkbookInstance, string[]> = new Map();

let parentIds: string[] = [];

const checkDeletePermissionPromises = workbooks.map(async (workbook) => {
if (workbook.model.isTemplate) {
throw new AppError("Workbook template can't be deleted", {
code: US_ERRORS.WORKBOOK_TEMPLATE_CANT_BE_DELETED,
});
}

if (accessServiceEnabled && !skipCheckPermissions) {
let parentIds: string[] = [];

if (accessServiceEnabled) {
if (workbook.model.collectionId !== null) {
parentIds = await getParentIds({
ctx,
Expand All @@ -75,24 +78,24 @@ export const deleteWorkbooks = async (
});
}

await workbook.checkPermission({
parentIds,
permission: WorkbookPermission.Delete,
});
workbooksMap.set(workbook, parentIds);

if (!skipCheckPermissions) {
await workbook.checkPermission({
parentIds,
permission: WorkbookPermission.Delete,
});
}
}
});

await Promise.all(checkDeletePermissionPromises);

const result = await transaction(targetTrx, async (transactionTrx) => {
const deletedWorkbooks = await WorkbookModel.query(transactionTrx)
.patch({
[WorkbookModelColumn.DeletedBy]: userId,
[WorkbookModelColumn.DeletedAt]: raw(CURRENT_TIMESTAMP),
})
.whereIn([WorkbookModelColumn.WorkbookId], workbookIds)
.returning('*')
.timeout(WorkbookModel.DEFAULT_QUERY_TIMEOUT);
const deletedWorkbooks = await markWorkbooksAsDeleted(
{ctx, trx, skipCheckPermissions: true},
{workbooksMap},
);

const entries = await Entry.query(transactionTrx)
.select()
Expand Down
Loading

0 comments on commit 50743c8

Please sign in to comment.