Skip to content

Commit 376284a

Browse files
committed
Change GQL Resource.tools to a secured list so canCreate can be supplied
1 parent f7f2839 commit 376284a

File tree

5 files changed

+35
-12
lines changed

5 files changed

+35
-12
lines changed

src/components/tools/tool-usage/resource-tools.resolver.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import { Parent, ResolveField, Resolver } from '@nestjs/graphql';
22
import { Loader, type LoaderOf } from '@seedcompany/data-loader';
33
import { Resource } from '~/common';
4-
import { ToolUsage } from './dto';
4+
import { SecuredToolUsageList } from './dto';
55
import { ToolUsageByContainerLoader } from './tool-usage-by-container.loader';
66

77
@Resolver(() => Resource)
88
export class ResourceToolsResolver {
9-
@ResolveField(() => [ToolUsage], {
9+
@ResolveField(() => SecuredToolUsageList, {
1010
description: 'Tools used in this resource',
1111
})
1212
async tools(
1313
@Parent() resource: Resource,
1414
@Loader(() => ToolUsageByContainerLoader)
1515
loader: LoaderOf<ToolUsageByContainerLoader>,
16-
): Promise<readonly ToolUsage[]> {
16+
): Promise<SecuredToolUsageList> {
1717
const { usages } = await loader.load(resource);
1818
return usages;
1919
}

src/components/tools/tool-usage/tool-usage-by-container.loader.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import {
66
type LoaderOptionsOf,
77
} from '~/core/data-loader';
88
import { ToolLoader } from '../tool/tool.loader';
9-
import { type ToolUsage } from './dto';
9+
import { type SecuredToolUsageList } from './dto';
1010
import { ToolUsageLoader } from './tool-usage.loader';
1111
import { ToolUsageService } from './tool-usage.service';
1212

1313
export interface UsagesByContainer {
1414
container: Resource;
15-
usages: readonly ToolUsage[];
15+
usages: SecuredToolUsageList;
1616
}
1717

1818
@LoaderFactory()
@@ -35,7 +35,7 @@ export class ToolUsageByContainerLoader
3535
const res = await this.usages.readManyForContainers(ids);
3636

3737
const canonicalUsages = await ctx.getLoader(ToolUsageLoader);
38-
const usages = res.flatMap((u) => u.usages);
38+
const usages = res.flatMap((u) => u.usages.items);
3939
canonicalUsages.primeAll(usages);
4040

4141
const canonicalTools = await ctx.getLoader(ToolLoader);

src/components/tools/tool-usage/tool-usage.gel.repository.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class ToolUsageRepository
3333
($) => {
3434
const containers = e.cast(e.Resource, e.array_unpack($.containers));
3535
return e.select(containers, (container) => ({
36-
container: e.select(container, (c) => ({ id: c.id })),
36+
container: e.select(container, resAsBaseNode),
3737
usages: e.select(container.tools, this.hydrate),
3838
}));
3939
},

src/components/tools/tool-usage/tool-usage.neo4j.repository.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
merge,
1414
variable,
1515
} from '~/core/database/query';
16+
import { type BaseNode } from '~/core/database/results';
1617
import { toolFilters } from '../tool/tool.neo4j.repository';
1718
import {
1819
type CreateToolUsage,
@@ -68,9 +69,9 @@ export class ToolUsageRepository extends DtoRepository(ToolUsage) {
6869
.return(collect('dto').as('usages')),
6970
)
7071
.return<{
71-
container: { id: ID };
72+
container: BaseNode;
7273
usages: ReadonlyArray<UnsecuredDto<ToolUsage>>;
73-
}>(['container { .id }', 'usages'])
74+
}>(['container', 'usages'])
7475
.run();
7576
return result;
7677
}

src/components/tools/tool-usage/tool-usage.service.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
22
import { mapKeys } from '@seedcompany/common';
33
import {
44
DuplicateException,
5+
EnhancedResource,
56
type ID,
67
InputException,
78
isIdLike,
@@ -10,7 +11,7 @@ import {
1011
ServerException,
1112
type UnsecuredDto,
1213
} from '~/common';
13-
import { HandleIdLookup, ResourceLoader } from '~/core';
14+
import { HandleIdLookup, ResourceLoader, ResourceResolver } from '~/core';
1415
import { type BaseNode, isBaseNode } from '~/core/database/results';
1516
import { Privileges } from '../../authorization';
1617
import { Tool } from '../tool/dto';
@@ -27,6 +28,7 @@ export class ToolUsageService {
2728
constructor(
2829
private readonly privileges: Privileges,
2930
private readonly resources: ResourceLoader,
31+
private readonly resourceResolver: ResourceResolver,
3032
private readonly repo: ToolUsageRepository,
3133
) {}
3234

@@ -56,10 +58,30 @@ export class ToolUsageService {
5658
const containersById = mapKeys.fromList(containers, (r) => r.id).asMap;
5759
const rows = await this.repo.listForContainers(containers.map((r) => r.id));
5860
return rows.map((row): UsagesByContainer => {
59-
const container = containersById.get(row.container.id)!;
61+
const container = containersById.get(row.container.properties.id)!;
62+
63+
const typeName =
64+
container.__typename ??
65+
this.resourceResolver.resolveTypeByBaseNode(row.container);
66+
const containerType = EnhancedResource.resolve(
67+
typeName,
68+
) as EnhancedResource<typeof Resource>;
69+
70+
const usages = row.usages.flatMap(
71+
(dto) => this.secure(dto, container) ?? [],
72+
);
6073
return {
6174
container,
62-
usages: row.usages.flatMap((dto) => this.secure(dto, container) ?? []),
75+
usages: {
76+
items: usages,
77+
total: usages.length,
78+
hasMore: false,
79+
80+
canRead: true,
81+
canCreate: this.privileges
82+
.for(containerType, container)
83+
.can('create', 'tools'),
84+
},
6385
};
6486
});
6587
}

0 commit comments

Comments
 (0)